Zepha/src/client/scene/MainMenuScene.cpp

177 lines
6.3 KiB
C++
Raw Normal View History

#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>
#include "MainMenuScene.h"
2020-08-13 00:55:18 -07:00
#include "util/Log.h"
#include "ConnectScene.h"
#include "client/Client.h"
2021-08-19 13:33:08 -07:00
#include "client/gui/BoxElement.h"
2021-08-20 16:19:10 -07:00
#include "client/gui/TextElement.h"
2020-08-13 00:55:18 -07:00
#include "client/menu/SubgameDef.h"
#include "client/gui/basic/GuiText.h"
#include "game/atlas/asset/AtlasTexture.h"
#include "client/gui/basic/GuiContainer.h"
2020-08-13 00:55:18 -07:00
#include "client/gui/compound/GuiImageButton.h"
2021-08-19 13:33:08 -07:00
MainMenuScene::MainMenuScene(Client& client) : Scene(client),
2021-08-20 22:48:38 -07:00
root(client.renderer.window, client.game->textures),
2021-08-24 01:48:53 -07:00
sandboxElem(root.create<Gui::BoxElement>()),
2021-08-20 22:48:38 -07:00
sandbox(client, root, sandboxElem) {
2021-08-19 13:33:08 -07:00
2020-11-08 22:57:34 -08:00
client.renderer.setClearColor(0, 0, 0);
2021-08-19 13:33:08 -07:00
client.renderer.window.input.setMouseLocked(false);
2020-11-08 22:57:34 -08:00
2021-08-20 22:48:38 -07:00
using Expr = Gui::Expression;
2021-08-19 13:33:08 -07:00
root.addStylesheet({
{ "navigation", {{
2021-08-24 01:48:53 -07:00
{ Gui::Prop::SIZE, array<Expr, 2> { Expr(""), Expr("18dp") } }
2021-08-19 13:33:08 -07:00
}}},
{ "navigationWrap", {{
2021-08-24 01:48:53 -07:00
{ Gui::Prop::DIRECTION, string("row") },
{ Gui::Prop::POS, array<Expr, 2> { Expr("0"), Expr("0") } }
2021-08-19 13:33:08 -07:00
}}},
{ "navigationBackground", {{
2021-08-24 01:48:53 -07:00
{ Gui::Prop::SIZE, array<Expr, 2> { Expr("64dp"), Expr("18dp") } },
{ Gui::Prop::BACKGROUND, string("menu_bar_bg") }
2021-08-19 13:33:08 -07:00
}}},
{ "navigationButton", {{
2021-08-24 01:48:53 -07:00
{ Gui::Prop::SIZE, array<Expr, 2> { Expr("16dp"), Expr("16dp") } },
{ Gui::Prop::CURSOR, string("pointer") }
2021-08-19 13:33:08 -07:00
}}}
});
2021-08-20 22:48:38 -07:00
root.body->append(sandboxElem);
2021-08-24 01:48:53 -07:00
let navigation = root.body->append<Gui::BoxElement>({{{ Gui::Prop::CLASS, vec<string> { "navigation" } }}});
let navigationBG = navigation->append<Gui::BoxElement>({{{ Gui::Prop::CLASS, vec<string> { "navigationWrap" } }}});
2021-08-20 16:19:10 -07:00
2021-08-19 13:33:08 -07:00
for (usize i = 0; i < 2000 / Gui::PX_SCALE / 64; i++)
2021-08-24 01:48:53 -07:00
navigationBG->append<Gui::BoxElement>({{{ Gui::Prop::CLASS, vec<string> { "navigationBackground" } }}});
let navigationList = navigation->append<Gui::BoxElement>({{
{ Gui::Prop::CLASS, vec<string> { "navigationWrap" } },
{ Gui::Prop::GAP, array<Expr, 2> { Expr("1dp"), Expr("1dp") } },
{ Gui::Prop::PADDING, array<Expr, 4> { Expr("1dp"), Expr("1dp"), Expr("1dp"), Expr("1dp") } }
}});
navigationList->append<Gui::BoxElement>({{
{ Gui::Prop::CLASS, vec<string> { "navigationButton" } },
{ Gui::Prop::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_multiplayer)") },
{ Gui::Prop::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_multiplayer)") }
}});
let contentButton = navigationList->append<Gui::BoxElement>({{
{ Gui::Prop::CLASS, vec<string> { "navigationButton" } },
{ Gui::Prop::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_content)") },
{ Gui::Prop::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_content)") }
}});
2021-08-20 16:19:10 -07:00
2021-08-22 11:58:52 -07:00
contentButton->onClick([&](u32 button, bool down) {
if (button != GLFW_MOUSE_BUTTON_1 || !down) return;
client.scene.setScene(make_unique<ConnectScene>(client, Address { "127.0.0.1" }));
});
2021-08-24 01:48:53 -07:00
navigationList->append<Gui::BoxElement>({{
{ Gui::Prop::BACKGROUND, string("#fff5") },
{ Gui::Prop::SIZE, array<Expr, 2> { Expr("1dp"), Expr("10dp") } },
{ Gui::Prop::MARGIN, array<Expr, 4> { Expr("2dp"), Expr("3dp"), Expr("2dp"), Expr("3dp") } }
}});
2021-09-23 23:16:23 -07:00
let subgamesPath = std::filesystem::path("..") / "subgames";
std::filesystem::directory_iterator iter(subgamesPath);
for (let& file : iter) {
if (!file.is_directory()) continue;
try {
if (!std::filesystem::exists(file.path() / "conf.json")) throw std::runtime_error("Missing a conf.json");
if (!std::filesystem::exists(file.path() / "mods")) throw std::runtime_error("Missing a mods folder");
nlohmann::json json {};
try {
std::ifstream(file.path() / "conf.json") >> json;
}
catch (...) {
throw std::runtime_error("conf.json has a syntax error");
}
if (!json.is_object())
throw std::runtime_error("conf.json has a syntax error.");
if (!json["name"].is_string() || json["name"] == "")
throw std::runtime_error("conf.json is missing 'name'");
if (!json["version"].is_string() || json["version"] == "")
throw std::runtime_error("conf.json is missing 'version'");
const AtlasTexture icon = std::filesystem::exists(file.path() / "icon.png")
? client.game->textures.addFile((file.path() / "icon.png").string(), false)
2021-09-23 23:16:23 -07:00
: client.game->textures["menu_flag_missing"];
subgames.push_back({ icon, { json["name"], json["description"], json["version"] }, file.path() });
2021-09-23 23:16:23 -07:00
}
catch(const std::runtime_error& e) {
std::cout << Log::err << "Failed to load subgame '"
<< file.path().filename().string() << "', " << e.what() << "." << std::endl;
}
}
std::sort(subgames.begin(), subgames.end(),
[](SubgameDef& a, SubgameDef& b) { return a.config.name < b.config.name; });
2021-08-20 16:19:10 -07:00
for (usize i = 0; i < subgames.size(); i++) {
let& subgame = subgames[i];
2021-08-24 01:48:53 -07:00
let elem = navigationList->append<Gui::BoxElement>({{
{ Gui::Prop::CLASS, vec<string> { "navigationButton" } },
{ Gui::Prop::BACKGROUND, string("crop(0, 0, 16, 16, " + subgame.iconRef.getIdentifier() + ")") },
{ Gui::Prop::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, " + subgame.iconRef.getIdentifier() + ")") }
2021-08-24 01:48:53 -07:00
}});
elem->onClick([&](u32 button, bool down) {
2021-08-22 11:58:52 -07:00
if (button != GLFW_MOUSE_BUTTON_1 || !down) return;
selectedSubgame = &subgame;
sandbox.load(*selectedSubgame);
});
2021-08-20 16:19:10 -07:00
}
if (subgames.size() > 0) {
selectedSubgame = &subgames[0];
2021-08-20 22:48:38 -07:00
sandbox.load(*selectedSubgame);
2021-08-20 16:19:10 -07:00
}
2021-08-20 18:28:13 -07:00
navigationList->append<Gui::BoxElement>();
2021-08-20 16:19:10 -07:00
2021-08-24 01:48:53 -07:00
navigationList->append<Gui::BoxElement>({{
{ Gui::Prop::CLASS, vec<string> { "navigationButton" } },
{ Gui::Prop::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_settings)") },
{ Gui::Prop::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_settings)") }
}});
let closeButton = navigationList->append<Gui::BoxElement>({{
{ Gui::Prop::CLASS, vec<string> { "navigationButton" } },
{ Gui::Prop::BACKGROUND, string("crop(0, 0, 16, 16, menu_flag_quit)") },
{ Gui::Prop::BACKGROUND_HOVER, string("crop(16, 0, 16, 16, menu_flag_quit)") }
}});
2021-08-20 16:19:10 -07:00
2021-08-22 11:58:52 -07:00
closeButton->onClick([](u32 button, bool down) {
if (button != GLFW_MOUSE_BUTTON_1 || !down) return;
exit(0);
});
}
void MainMenuScene::update() {
2021-08-19 20:45:39 -07:00
root.update();
2021-08-22 11:58:52 -07:00
sandbox.update(client.getDelta());
}
void MainMenuScene::draw() {
2021-08-19 13:33:08 -07:00
let& renderer = client.renderer;
renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls();
2020-11-08 22:57:34 -08:00
renderer.enableTexture(client.game->textures.getTexture());
2021-08-19 13:33:08 -07:00
renderer.beginGUIDrawCalls();
root.draw(renderer);
}