Removed ClientState entirely and restructured client data passing.

* Updated the fenv polyfill.
* Added a fromString helper to Address.
* Added documentation comments to some classes. More to come!
* Configured CLion code style settings.
This commit is contained in:
Auri 2020-11-03 23:29:30 -08:00
parent 8d6e19500a
commit a9a12a89d9
35 changed files with 472 additions and 361 deletions

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

View File

@ -7,8 +7,9 @@
<inspection_tool class="ClangTidyInspection" enabled="true" level="WARNING" enabled_by_default="true"> <inspection_tool class="ClangTidyInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="clangTidyChecks" value="*,-android-*,-bugprone-bool-pointer-implicit-conversion,-cert-env33-c,-cert-dcl50-cpp,-cert-dcl59-cpp,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-cstyle-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-*,-google-*,google-default-arguments,google-explicit-constructor,google-runtime-member-string-references,google-runtime-operator,-hicpp-braces-around-statements,-hicpp-named-parameter,-hicpp-no-array-decay,-hicpp-no-assembler,-hicpp-no-malloc,-hicpp-function-size,-hicpp-special-member-functions,-hicpp-vararg,-llvm-*,-objc-*,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-simplify-boolean-expr,-readability-braces-around-statements,-readability-identifier-naming,-readability-function-size,-readability-redundant-member-init,-misc-bool-pointer-implicit-conversion,-misc-definitions-in-headers,-misc-unused-alias-decls,-misc-unused-parameters,-misc-unused-using-decls,-modernize-use-using,-modernize-use-default-member-init,-clang-diagnostic-*,-clang-analyzer-*,-cert-msc30-c,-cert-msc50-cpp,-bugprone-integer-division,-modernize-use-auto" /> <option name="clangTidyChecks" value="*,-android-*,-bugprone-bool-pointer-implicit-conversion,-cert-env33-c,-cert-dcl50-cpp,-cert-dcl59-cpp,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-cstyle-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-*,-google-*,google-default-arguments,google-explicit-constructor,google-runtime-member-string-references,google-runtime-operator,-hicpp-braces-around-statements,-hicpp-named-parameter,-hicpp-no-array-decay,-hicpp-no-assembler,-hicpp-no-malloc,-hicpp-function-size,-hicpp-special-member-functions,-hicpp-vararg,-llvm-*,-objc-*,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-simplify-boolean-expr,-readability-braces-around-statements,-readability-identifier-naming,-readability-function-size,-readability-redundant-member-init,-misc-bool-pointer-implicit-conversion,-misc-definitions-in-headers,-misc-unused-alias-decls,-misc-unused-parameters,-misc-unused-using-decls,-modernize-use-using,-modernize-use-default-member-init,-clang-diagnostic-*,-clang-analyzer-*,-cert-msc30-c,-cert-msc50-cpp,-bugprone-integer-division,-modernize-use-auto" />
</inspection_tool> </inspection_tool>
<inspection_tool class="LongLine" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OCDFAInspection" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="OCDFAInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OCUnusedMacro" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="OCInconsistentNaming" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false"> <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" /> <option name="processCode" value="true" />
<option name="processLiterals" value="true" /> <option name="processLiterals" value="true" />

View File

@ -1,3 +1,6 @@
local debug = _G['debug']
_G['debug'] = nil
if not setfenv then if not setfenv then
_G['setfenv'] = function(fn, env) _G['setfenv'] = function(fn, env)
local i = 1 local i = 1

View File

@ -1,8 +1,6 @@
add_library(Zepha_Core add_library(Zepha_Core
client/Client.cpp client/Client.cpp
client/Client.h client/Client.h
client/ClientState.cpp
client/ClientState.h
client/conn/ClientNetworkInterpreter.cpp client/conn/ClientNetworkInterpreter.cpp
client/conn/ClientNetworkInterpreter.h client/conn/ClientNetworkInterpreter.h
client/conn/ServerConnection.cpp client/conn/ServerConnection.cpp
@ -323,6 +321,6 @@ add_library(Zepha_Core
world/ServerWorld.h world/ServerWorld.h
world/World.cpp world/World.cpp
world/World.h world/World.h
) util/net/Address.cpp)
target_include_directories(Zepha_Core PUBLIC .) target_include_directories(Zepha_Core PUBLIC .)

View File

@ -19,7 +19,14 @@
#include "StartGame.h" #include "StartGame.h"
/**
* Main entrance point to the program. (Am I really describing what the main function is?)
* Intentionally kept minimal to allow for testing. Real startup logic is done in StartGame. *
* @param argc - Argument array length
* @param argv - Argument array
* @returns - A numerical value indicating exit status.
*/
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
return StartGame(argc, argv); return StartGame(argc, argv);
} }

View File

@ -11,9 +11,18 @@
#include "client/Client.h" #include "client/Client.h"
#include "server/Server.h" #include "server/Server.h"
enum class Mode { INVALID, CLIENT, SERVER }; enum class Mode { CLIENT, SERVER };
std::map<std::string, std::string> parseArgs(int argc, char* argv[]) {
/**
* Parses the arg list provided by the operating system into a map of key-value strings.
* @throws invalid_argument if it encounters a duplicate or improperly formatted argument.
* @param argc - Argument array length
* @param argv - Argument array
* @returns - A map of parsed arguments.
*/
std::map<std::string, std::string> ParseArgs(int argc, char* argv[]) {
//Collect arguments into `args` map //Collect arguments into `args` map
std::map<std::string, std::string> args; std::map<std::string, std::string> args;
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
@ -32,76 +41,83 @@ std::map<std::string, std::string> parseArgs(int argc, char* argv[]) {
return args; return args;
} }
/**
* Instantiates a Client or Server instance, depending on the arguments provided.
* @param argc - Argument array length
* @param argv - Argument array
* @returns - A numerical value indicating exit status.
*/
int StartGame(int argc, char* argv[]) { int StartGame(int argc, char* argv[]) {
std::string path = argv[0];
Address addr {"127.0.0.1", 32000};
Mode mode = Mode::CLIENT; Mode mode = Mode::CLIENT;
std::string subgame = "";
bool ascii = true;
//Parse the arguments map try {
for (auto arg : parseArgs(argc, argv)) { unsigned short port = Address::DEFAULT_PORT;
switch (Util::hash(arg.first.c_str())) { std::string subgame = "";
default: { bool ascii = true;
std::cout << Log::err << "Invalid argument " << arg.first << "." << Log::endl;
return -1; /**
} * Handle command line arguments.
case Util::hash("--mode"): { * @arg mode ("client" | "server") - Whether to initialize a client instance, or a server. Defaults to "client".
* @arg port (unsigned short) - The port that the server should listen on. Defaults to Address::DEFAULT_PORT.
* @arg subgame (std::string) - The subgame that the server should load.
* @arg noascii - Switch to disable ASCII from the console output.
*/
for (auto arg : ParseArgs(argc, argv)) {
switch (Util::hash(arg.first.c_str())) {
default:
throw std::runtime_error("Invalid argument '" + arg.first + "'.");
case Util::hash("--mode"):
if (arg.second == "client") mode = Mode::CLIENT; if (arg.second == "client") mode = Mode::CLIENT;
else if (arg.second == "server") mode = Mode::SERVER; else if (arg.second == "server") mode = Mode::SERVER;
else std::cout << Log::err << "Invalid mode argument." << Log::endl; else throw std::runtime_error("Invalid mode specified.");
break; break;
}
case Util::hash("--port"): { // case Util::hash("--address"):
addr.port = static_cast<unsigned short>(stoi(arg.second)); // addr.host = arg.second;
// break;
case Util::hash("--port"):
port = static_cast<unsigned short>(stoi(arg.second));
break; break;
}
case Util::hash("--address"): { case Util::hash("--subgame"):
addr.host = arg.second;
break;
}
case Util::hash("--subgame"): {
subgame = arg.second; subgame = arg.second;
break; break;
}
case Util::hash("--noascii"): { case Util::hash("--noascii"):
ascii = false; ascii = false;
break; break;
} }
} }
}
// Obligatory ASCII Art is obligatory. if (ascii) {
if (ascii) { Log::clear();
Log::clear(); std::cout <<
std::cout << "\n" "\n"
"\t\t▒███████▒▓█████ ██▓███ ██░ ██ ▄▄▄ \n" "\t\t ____ ____ ____ _ _ __ \n"
"\t\t▒ ▒ ▒ ▄▀░▓█ ▀ ▓██░ ██▒▓██░ ██▒▒████▄ \n" "\t\t(__ )( __)( _ \\/ )( \\ / _\\ \n"
"\t\t░ ▒ ▄▀▒░ ▒███ ▓██░ ██▓▒▒██▀▀██░▒██ ▀█▄ \n" "\t\t / _/ ) _) ) __/) __ (/ \\\n"
"\t\t ▄▀▒ ░▒▓█ ▄ ▒██▄█▓▒ ▒░▓█ ░██ ░██▄▄▄▄██ \n" "\t\t(____)(____)(__) \\_)(_/\\_/\\_/\n" << std::endl;
"\t\t▒███████▒░▒████▒▒██▒ ░ ░░▓█▒░██▓ ▓█ ▓██▒\n"
"\t\t░▒▒ ▓░▒░▒░░ ▒░ ░▒▓▒░ ░ ░ ▒ ░░▒░▒ ▒▒ ▓▒█░\n"
"\t\t░ ▒ ▒ ░ ▒ ░ ░ ░░▒ ░ ▒ ░▒░ ░ ▒ ▒▒ ░\n"
"\t\t ░ ░ ░ ░ ░░ ░ ░ ░ ▒ \n" << std::endl;
}
//Start the game
switch (mode) {
default: {
std::cout << Log::err << "Mode not set." << Log::endl;
return -1;
} }
switch (mode) {
case Mode::CLIENT: { case Mode::CLIENT: {
Client c(path, addr, {1366, 768}); Client c({1366, 768});
break; break; }
}
case Mode::SERVER: { case Mode::SERVER: {
Server s(addr.port, subgame); Server s(port, subgame);
break; break; }
} }
return 0;
} }
catch (const std::exception& e) {
return 0; std::cout << Log::err << "Zepha failed to start.\n" << e.what() << Log::endl;
}; return 1;
}
}

View File

@ -1,12 +1,8 @@
//
// Created by aurailus on 06/01/19.
//
#include <iostream> #include <iostream>
#include "Client.h" #include "Client.h"
#include "../util/Log.h"
#include "../util/Timer.h" #include "../util/Timer.h"
#include "LocalServerInstance.h" #include "LocalServerInstance.h"
@ -14,55 +10,60 @@
#include "scene/ConnectScene.h" #include "scene/ConnectScene.h"
#include "scene/MainMenuScene.h" #include "scene/MainMenuScene.h"
Client::Client(const std::string& path, const Address &addr, glm::ivec2 dims) :
state(path.substr(0, path.find_last_of('/') + 1), renderer), /**
renderer(dims), * Creates a client window and starts the main event loop.
addr(addr), * Initially opens to the main menu.
executablePath(path) { * @param window - The dimensions for the created window.
*/
Client::Client(glm::ivec2 window) :
renderer(window) {
std::cout << Log::info << "Starting Zepha Client." << Log::endl; std::cout << Log::info << "Starting Zepha Client." << Log::endl;
std::unique_ptr<Scene> scene = std::make_unique<MainMenuScene>(state); scene.setScene(std::make_unique<MainMenuScene>(*this));
// std::unique_ptr<Scene> scene = std::make_unique<LuaErrorScene>(state, "whoopsie poopsie did a fucky wucky");
sceneManager.setScene(std::move(scene));
while (!renderer.window.shouldClose()) loop(); while (!renderer.window.shouldClose()) loop();
} }
/**
* Get the last frame's delta time.
* @returns the delta time.
*/
double Client::getDelta() {
return delta;
}
/**
* Starts a local server and connects to it.
* @throws runtime_error if a local server is already running.
* @param subgame - The subgame for the local server to run.
*/
void Client::startLocalServer(const std::string& subgame) {
//TODO: Implement Local Server
// localServer = std::make_shared<LocalServerInstance>(executablePath, addr.port, state.subgame);
// localServer->start();
scene.setScene(std::make_unique<ConnectScene>(*this, Address { "127.0.0.1", Address::DEFAULT_PORT }));
}
/**
* The main event loop. Polls GLFW, and updates the scene and the renderer.
* Will be called by the Client constructor until render.window.shouldClose() returns true.
*/
void Client::loop() { void Client::loop() {
Timer t("Client Loop");
if (state.desiredState == "local") {
state.desiredState = "connect";
localServer = std::make_shared<LocalServerInstance>(executablePath, addr.port, state.subgame);
localServer->start();
}
if (state.desiredState == "connect") {
state.desiredState = "this";
std::unique_ptr<Scene> scene = std::make_unique<ConnectScene>(state, addr);
sceneManager.setScene(std::move(scene));
}
if (state.desiredState == "game") {
state.desiredState = "this";
std::unique_ptr<Scene> scene = std::make_unique<GameScene>(state);
sceneManager.setScene(std::move(scene));
}
double now = glfwGetTime(); double now = glfwGetTime();
state.delta = now - timeElapsed; delta = now - timeElapsed;
timeElapsed = now; timeElapsed = now;
glfwPollEvents(); glfwPollEvents();
sceneManager.update(); scene.update();
renderer.update(state.delta); renderer.update(delta);
state.fps = 1000.0 / (t.elapsedNs() / 1000000.0);
}
Client::~Client() {
sceneManager.cleanupScene();
if (localServer) localServer->stop();
} }

View File

@ -1,31 +1,41 @@
// /*
// Created by aurailus on 06/01/19. * Main Client object. Contains important properties, such as the renderer and scene manager.
// * Also manages the local server, if there is one.
*
* - Auri, 03/11/20
*/
#pragma once #pragma once
#include "util/net/Address.h" #include "util/net/Address.h"
#include "client/ClientState.h" #include "game/LocalSubgame.h"
#include "client/graph/Renderer.h" #include "client/graph/Renderer.h"
#include "client/scene/SceneManager.h" #include "client/scene/SceneManager.h"
#include "client/conn/ServerConnection.h"
class LocalServerInstance; class LocalServerInstance;
class Client { class Client {
public: public:
Client(const std::string& path, const Address& addr, glm::ivec2 dims); Client(const Client& o) = delete;
~Client(); explicit Client(glm::ivec2 window);
double getDelta();
void startLocalServer(const std::string& subgame);
Renderer renderer;
SceneManager scene;
ServerConnection connection {};
std::shared_ptr<LocalSubgame> game = std::make_shared<LocalSubgame>("../assets/textures");
private: private:
void loop(); void loop();
std::string executablePath;
Address addr {};
Renderer renderer;
ClientState state;
SceneManager sceneManager;
std::shared_ptr<LocalServerInstance> localServer = nullptr; std::shared_ptr<LocalServerInstance> localServer = nullptr;
double timeElapsed = 0.0f; double delta = 0;
double timeElapsed = 0;
}; };

View File

@ -1,17 +0,0 @@
//
// Created by aurailus on 2019-12-11.
//
#include "ClientState.h"
#ifdef _WIN32
ClientState::ClientState(const std::string& path, Renderer& renderer) :
path(path),
renderer(renderer),
defs(path + "assets\\textures") {}
#else
ClientState::ClientState(const std::string &path, Renderer &renderer) :
path(path),
renderer(renderer),
game(path + "../assets/textures") {}
#endif

View File

@ -1,29 +0,0 @@
//
// Created by aurailus on 06/01/19.
//
#pragma once
#include "game/LocalSubgame.h"
#include "client/conn/ServerConnection.h"
class Renderer;
class ClientState {
public:
ClientState(const std::string& path, Renderer& renderer);
std::string path;
std::string subgame;
Renderer& renderer;
ServerConnection connection {};
LocalSubgame game;
unsigned int seed = 0;
std::string desiredState = "this";
double fps = 0;
double delta = 0;
};

View File

@ -44,3 +44,7 @@ void LocalServerInstance::stop() {
std::cout << Log::err << "Local Server destructor not implemented on Windows!" << Log::endl; std::cout << Log::err << "Local Server destructor not implemented on Windows!" << Log::endl;
#endif #endif
} }
LocalServerInstance::~LocalServerInstance() {
stop();
}

View File

@ -18,6 +18,8 @@ public:
bool start(); bool start();
void stop(); void stop();
~LocalServerInstance();
private: private:
std::string path; std::string path;
std::string subgame; std::string subgame;

View File

@ -43,7 +43,7 @@ DebugGui::DebugGui(glm::vec2 bufferSize, SubgamePtr game, WorldPtr world) :
add(genGraph); add(genGraph);
auto packetGraph = std::make_shared<GuiLabelledGraph>("packetGraph"); auto packetGraph = std::make_shared<GuiLabelledGraph>("packetGraph");
packetGraph->create({244, 64}, {}, "Packets", 120, 512, genericHistogramRef, f); packetGraph->create({244, 64}, {}, "Packets", 120, 32, genericHistogramRef, f);
add(packetGraph); add(packetGraph);
auto fpsGraph = std::make_shared<GuiLabelledGraph>("fpsGraph"); auto fpsGraph = std::make_shared<GuiLabelledGraph>("fpsGraph");

View File

@ -1,6 +1,4 @@
//
// Created by aurailus on 2019-12-12.
//
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <cute_files/cute_files.h> #include <cute_files/cute_files.h>
@ -8,6 +6,7 @@
#include "MenuSandbox.h" #include "MenuSandbox.h"
#include "lua/LuaMod.h" #include "lua/LuaMod.h"
#include "client/Client.h"
#include "lua/ErrorFormatter.h" #include "lua/ErrorFormatter.h"
#include "client/menu/SubgameDef.h" #include "client/menu/SubgameDef.h"
#include "client/gui/basic/GuiText.h" #include "client/gui/basic/GuiText.h"
@ -18,12 +17,13 @@
#include "lua/modules/mSetGui.h" #include "lua/modules/mSetGui.h"
#include "lua/modules/mStartGame.h" #include "lua/modules/mStartGame.h"
MenuSandbox::MenuSandbox(glm::ivec2 &win, ClientState& state, std::shared_ptr<GuiContainer> container) : LuaParser(state.game), MenuSandbox::MenuSandbox(glm::ivec2 &win, Client& client, std::shared_ptr<GuiContainer> container) :
LuaParser(*client.game),
win(win), win(win),
state(state), client(client),
container(container), container(container),
luaContainer(std::dynamic_pointer_cast<GuiContainer>(container->add(std::make_shared<GuiContainer>("__lua")))), luaContainer(std::dynamic_pointer_cast<GuiContainer>(container->add(std::make_shared<GuiContainer>("__lua")))),
builder(state.game.textures, state.game.models, luaContainer) {} builder(client.game->textures, client.game->models, luaContainer) {}
void MenuSandbox::reset() { void MenuSandbox::reset() {
container->remove("error"); container->remove("error");
@ -48,7 +48,7 @@ void MenuSandbox::loadApi() {
ClientApi::gui_element(lua); ClientApi::gui_element(lua);
MenuApi::set_gui (builder, win, lua, core); MenuApi::set_gui (builder, win, lua, core);
MenuApi::start_game (state, core); MenuApi::start_game (client, core);
bindModules(); bindModules();
@ -87,9 +87,10 @@ sol::protected_function_result MenuSandbox::runFileSandboxed(const std::string&
env["_FILE"] = f.path; env["_FILE"] = f.path;
env["_MODNAME"] = mod.config.name; env["_MODNAME"] = mod.config.name;
return lua.safe_script(f.file, env, std::bind(&MenuSandbox::errorCallback, this, std::placeholders::_2), "@" + f.path, sol::load_mode::text); return lua.safe_script(f.file, env, std::bind(&MenuSandbox::errorCallback,
this, std::placeholders::_2), "@" + f.path, sol::load_mode::text);
} }
throw std::runtime_error("Error opening \"" + file + "\", file not found."); throw std::runtime_error("Error opening '" + file + "', file not found.");
} }
void MenuSandbox::loadAndRunMod(const std::string &modPath) { void MenuSandbox::loadAndRunMod(const std::string &modPath) {
@ -149,7 +150,7 @@ void MenuSandbox::loadAndRunMod(const std::string &modPath) {
std::string texPath = modPath + "/textures"; std::string texPath = modPath + "/textures";
if (cf_file_exists(texPath.data())) { if (cf_file_exists(texPath.data())) {
this->modAssets = state.game.textures.loadDirectory(texPath, false, true); this->modAssets = client.game->textures.loadDirectory(texPath, false, true);
} }
this->mod = mod; this->mod = mod;
@ -158,7 +159,7 @@ void MenuSandbox::loadAndRunMod(const std::string &modPath) {
void MenuSandbox::showError(const std::string& what, const std::string& subgame) { void MenuSandbox::showError(const std::string& what, const std::string& subgame) {
const std::string errPrefixText = "Encountered an error while loading the menu for " + subgame + " ;-;"; const std::string errPrefixText = "Encountered an error while loading the menu for " + subgame + " ;-;";
Font f(state.game.textures, state.game.textures["font"]); Font f(client.game->textures, client.game->textures["font"]);
auto errWrap = std::make_shared<GuiContainer>("error"); auto errWrap = std::make_shared<GuiContainer>("error");
container->add(errWrap); container->add(errWrap);

View File

@ -9,15 +9,15 @@
#include "lua/LuaMod.h" #include "lua/LuaMod.h"
#include "client/gui/GuiBuilder.h" #include "client/gui/GuiBuilder.h"
class Client;
class Subgame; class Subgame;
class AtlasRef; class AtlasRef;
class SubgameDef; class SubgameDef;
class ClientState;
class GuiContainer; class GuiContainer;
class MenuSandbox : LuaParser { class MenuSandbox : LuaParser {
public: public:
MenuSandbox(glm::ivec2& win, ClientState& state, std::shared_ptr<GuiContainer> container); MenuSandbox(glm::ivec2& window, Client& client, std::shared_ptr<GuiContainer> container);
void load(const SubgameDef& subgame); void load(const SubgameDef& subgame);
void update(double delta) override; void update(double delta) override;
@ -41,6 +41,6 @@ private:
std::shared_ptr<GuiContainer> luaContainer = nullptr; std::shared_ptr<GuiContainer> luaContainer = nullptr;
GuiBuilder builder; GuiBuilder builder;
ClientState& state; Client& client;
glm::ivec2& win; glm::ivec2& win;
}; };

View File

@ -6,22 +6,31 @@
#include "ConnectScene.h" #include "ConnectScene.h"
#include "client/Client.h"
#include "util/net/Packet.h" #include "util/net/Packet.h"
#include "util/net/Address.h" #include "util/net/Address.h"
#include "client/ClientState.h"
#include "util/net/PacketView.h" #include "util/net/PacketView.h"
#include "client/graph/Renderer.h" #include "client/graph/Renderer.h"
#include "client/gui/basic/GuiRect.h" #include "client/gui/basic/GuiRect.h"
#include "client/gui/basic/GuiText.h" #include "client/gui/basic/GuiText.h"
#include "game/atlas/asset/AssetType.h" #include "game/atlas/asset/AssetType.h"
#include "game/atlas/LocalDefinitionAtlas.h" #include "game/atlas/LocalDefinitionAtlas.h"
#include "GameScene.h"
ConnectScene::ConnectScene(ClientState &state, Address addr) : Scene(state),
connection(state.connection) {
state.renderer.setClearColor(10, 10, 10); /**
* Initializes a connection to the remote address,
* sets up the GUI, and attempts to download subgame assets.
*
* @param addr - The server address to connect to.
*/
Font f(state.game.textures, state.game.textures["font"]); ConnectScene::ConnectScene(Client &client, Address addr) : Scene(client),
connection(client.connection) {
client.renderer.setClearColor(10, 10, 10);
Font f(client.game->textures, client.game->textures["font"]);
auto statusText = std::make_shared<GuiText>("statusText"); auto statusText = std::make_shared<GuiText>("statusText");
statusText->create({2, 2}, {}, {}, {1, 1, 1, 1}, f); statusText->create({2, 2}, {}, {}, {1, 1, 1, 1}, f);
@ -31,18 +40,18 @@ ConnectScene::ConnectScene(ClientState &state, Address addr) : Scene(state),
auto loadBar = std::make_shared<GuiRect>("loadBar"); auto loadBar = std::make_shared<GuiRect>("loadBar");
loadBar->create({1, 32}, {}, {0.17, 0.75, 0.93, 1}); loadBar->create({1, 32}, {}, {0.17, 0.75, 0.93, 1});
loadBar->setPos({0, state.renderer.window.getSize().y - 32}); loadBar->setPos({0, client.renderer.window.getSize().y - 32});
components.add(loadBar); components.add(loadBar);
connection.attemptConnect(std::move(addr)); connection.attemptConnect(std::move(addr));
state.renderer.window.addResizeCallback("scene", [&](glm::ivec2 win) { client.renderer.window.addResizeCallback("scene", [&](glm::ivec2 win) {
components.get<GuiRect>("loadBar")->setPos({0, win.y - 32}); components.get<GuiRect>("loadBar")->setPos({0, win.y - 32});
}); });
} }
void ConnectScene::update() { void ConnectScene::update() {
state.game.textures.update(); client.game->textures.update();
switch (connectState) { switch (connectState) {
default: default:
@ -57,7 +66,7 @@ void ConnectScene::update() {
break; break;
case State::PROPERTIES: { case State::PROPERTIES: {
components.get<GuiRect>("loadBar")->setScale({state.renderer.window.getSize().x * 0.1, 32}); components.get<GuiRect>("loadBar")->setScale({client.renderer.window.getSize().x * 0.1, 32});
ENetEvent e; ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) { if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
@ -67,7 +76,8 @@ void ConnectScene::update() {
auto statusText = components.get<GuiText>("statusText"); auto statusText = components.get<GuiText>("statusText");
statusText->setText(statusText->getText() + "Received server properties.\n"); statusText->setText(statusText->getText() + "Received server properties.\n");
state.seed = p.d.read<unsigned int>(); // TODO: Reimplement this somewhere or something.
// state.seed = p.d.read<unsigned int>();
connectState = State::IDENTIFIER_LIST; connectState = State::IDENTIFIER_LIST;
Packet resp(Packet::Type::BLOCK_IDENTIFIER_LIST); Packet resp(Packet::Type::BLOCK_IDENTIFIER_LIST);
@ -78,7 +88,7 @@ void ConnectScene::update() {
} }
case State::IDENTIFIER_LIST: { case State::IDENTIFIER_LIST: {
components.get<GuiRect>("loadBar")->setScale({state.renderer.window.getSize().x * 0.2, 32}); components.get<GuiRect>("loadBar")->setScale({client.renderer.window.getSize().x * 0.2, 32});
ENetEvent e; ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) { if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
@ -88,7 +98,7 @@ void ConnectScene::update() {
auto statusText = components.get<GuiText>("statusText"); auto statusText = components.get<GuiText>("statusText");
statusText->setText(statusText->getText() + "Received block index-identifier table.\n"); statusText->setText(statusText->getText() + "Received block index-identifier table.\n");
state.game.getDefs().setIdentifiers(p.d.read<std::vector<std::string>>()); client.game->getDefs().setIdentifiers(p.d.read<std::vector<std::string>>());
Packet resp(Packet::Type::BIOME_IDENTIFIER_LIST); Packet resp(Packet::Type::BIOME_IDENTIFIER_LIST);
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT); resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
@ -97,7 +107,7 @@ void ConnectScene::update() {
auto statusText = components.get<GuiText>("statusText"); auto statusText = components.get<GuiText>("statusText");
statusText->setText(statusText->getText() + "Received biome index-identifier table.\nDownloading mods...\n"); statusText->setText(statusText->getText() + "Received biome index-identifier table.\nDownloading mods...\n");
state.game.getBiomes().setIdentifiers(p.d.read<std::vector<std::string>>()); client.game->getBiomes().setIdentifiers(p.d.read<std::vector<std::string>>());
connectState = State::MODS; connectState = State::MODS;
Packet resp(Packet::Type::MODS); Packet resp(Packet::Type::MODS);
@ -108,7 +118,7 @@ void ConnectScene::update() {
} }
case State::MODS: { case State::MODS: {
components.get<GuiRect>("loadBar")->setScale({state.renderer.window.getSize().x * 0.4, 32}); components.get<GuiRect>("loadBar")->setScale({client.renderer.window.getSize().x * 0.4, 32});
ENetEvent e; ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) { if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
PacketView p(e.packet); PacketView p(e.packet);
@ -118,10 +128,10 @@ void ConnectScene::update() {
if (p.type == Packet::Type::MODS) { if (p.type == Packet::Type::MODS) {
auto luaMod = LuaMod::fromPacket(p); auto luaMod = LuaMod::fromPacket(p);
statusText->setText(statusText->getText() + "Received mod " + luaMod.config.name + ".\n"); statusText->setText(statusText->getText() + "Received mod " + luaMod.config.name + ".\n");
state.game.getParser().getHandler().addLuaMod(std::move(luaMod)); client.game->getParser().getHandler().addLuaMod(std::move(luaMod));
} }
else if (p.type == Packet::Type::MOD_ORDER) { else if (p.type == Packet::Type::MOD_ORDER) {
state.game.getParser().getHandler().setModsOrder(p.d.read<std::vector<std::string>>()); client.game->getParser().getHandler().setModsOrder(p.d.read<std::vector<std::string>>());
statusText->setText(statusText->getText() + "Done downloading mods.\nReceived the mods order.\nDownloading media...\n"); statusText->setText(statusText->getText() + "Done downloading mods.\nReceived the mods order.\nDownloading media...\n");
@ -134,7 +144,7 @@ void ConnectScene::update() {
} }
case State::MEDIA: { case State::MEDIA: {
components.get<GuiRect>("loadBar")->setScale({state.renderer.window.getSize().x * 0.6, 32}); components.get<GuiRect>("loadBar")->setScale({client.renderer.window.getSize().x * 0.6, 32});
ENetEvent e; ENetEvent e;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) { if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
@ -156,15 +166,15 @@ void ConnectScene::update() {
std::string data = p.d.read<std::string>(); std::string data = p.d.read<std::string>();
std::string uncompressed = gzip::decompress(data.data(), data.length()); std::string uncompressed = gzip::decompress(data.data(), data.length());
state.game.textures.addImage( client.game->textures.addImage(
reinterpret_cast<unsigned char *>(const_cast<char *>(uncompressed.data())), reinterpret_cast<unsigned char *>(const_cast<char *>(uncompressed.data())),
assetName, true, width, height); assetName, true, width, height);
} }
else if (t == AssetType::MODEL) { else if (t == AssetType::MODEL) {
std::string format = p.d.read<std::string>(); std::string format = p.d.read<std::string>();
std::string data = p.d.read<std::string>(); std::string data = p.d.read<std::string>();
state.game.models.models.insert({assetName, SerializedModel{assetName, data, format}}); client.game->models.models.insert({assetName, SerializedModel{assetName, data, format}});
} }
t = static_cast<AssetType>(p.d.read<int>()); t = static_cast<AssetType>(p.d.read<int>());
@ -174,11 +184,11 @@ void ConnectScene::update() {
statusText->setText(statusText->getText() + "Received " + std::to_string(count) + "x media files.\n"); statusText->setText(statusText->getText() + "Received " + std::to_string(count) + "x media files.\n");
} }
else if (p.type == Packet::Type::MEDIA_DONE) { else if (p.type == Packet::Type::MEDIA_DONE) {
components.get<GuiRect>("loadBar")->setScale({state.renderer.window.getSize().x, 32}); components.get<GuiRect>("loadBar")->setScale({client.renderer.window.getSize().x, 32});
statusText->setText(statusText->getText() + "Done downloading media.\nJoining world...\n"); statusText->setText(statusText->getText() + "Done downloading media.\nJoining world...\n");
connectState = State::DONE; connectState = State::DONE;
state.desiredState = "game"; client.scene.setScene(std::make_unique<GameScene>(client));
} }
} }
break; break;
@ -206,7 +216,7 @@ void ConnectScene::handleConnecting() {
case ServerConnection::State::ATTEMPTING_CONNECT: case ServerConnection::State::ATTEMPTING_CONNECT:
connection.processConnecting(); connection.processConnecting();
dotsTime += state.delta; dotsTime += client.getDelta();
if (dotsTime > 1) { if (dotsTime > 1) {
dotsTime -= 1; dotsTime -= 1;
statusText->setText(statusText->getText() + "."); statusText->setText(statusText->getText() + ".");
@ -225,12 +235,12 @@ void ConnectScene::handleConnecting() {
} }
void ConnectScene::draw() { void ConnectScene::draw() {
Renderer& renderer = state.renderer; Renderer& renderer = client.renderer;
renderer.beginChunkDeferredCalls(); renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls(); renderer.endDeferredCalls();
renderer.beginGUIDrawCalls(); renderer.beginGUIDrawCalls();
renderer.enableTexture(&state.game.textures.atlasTexture); renderer.enableTexture(&client.game->textures.atlasTexture);
components.draw(renderer); components.draw(renderer);
@ -238,5 +248,5 @@ void ConnectScene::draw() {
} }
void ConnectScene::cleanup() { void ConnectScene::cleanup() {
state.renderer.window.removeResizeCallback("scene"); client.renderer.window.removeResizeCallback("scene");
} }

View File

@ -23,15 +23,14 @@ public:
DONE DONE
}; };
ConnectScene(ClientState& state, Address addr); ConnectScene(Client& state, Address addr);
void update() override; void update() override;
void draw() override;
void cleanup() override;
void handleConnecting(); void handleConnecting();
void draw() override;
void cleanup() override;
private: private:
State connectState = State::CONNECTING; State connectState = State::CONNECTING;
ServerConnection& connection; ServerConnection& connection;

View File

@ -4,36 +4,36 @@
#include "GameScene.h" #include "GameScene.h"
#include "client/ClientState.h" #include "client/Client.h"
#include "util/net/PacketView.h" #include "util/net/PacketView.h"
#include "client/graph/Renderer.h" #include "client/graph/Renderer.h"
GameScene::GameScene(ClientState& state) : Scene(state), GameScene::GameScene(Client& client) : Scene(client),
game(std::make_shared<LocalSubgame>(state.game)), world(std::make_shared<LocalWorld>(client.game, client.connection, client.renderer)),
world(std::make_shared<LocalWorld>(game, state.connection, state.renderer)), debugGui(client.renderer.window.getSize(), client.game, world) {
debugGui(state.renderer.window.getSize(), game, world) {
Packet r(Packet::Type::CONNECT_DATA_RECVD); Packet r(Packet::Type::CONNECT_DATA_RECVD);
r.sendTo(state.connection.getPeer(), Packet::Channel::CONNECT); r.sendTo(client.connection.getPeer(), Packet::Channel::CONNECT);
world.l()->connect(); world.l()->connect();
game .l()->init(world, world.l()->getPlayer(), state); client.game->init(world, world.l()->getPlayer(), client);
world.l()->updatePlayerDimension(); world.l()->updatePlayerDimension();
state.renderer.window.addResizeCallback("gamescene", Util::bind_this(&debugGui, &DebugGui::bufferResized)); client.renderer.window.addResizeCallback("gamescene", Util::bind_this(&debugGui, &DebugGui::bufferResized));
state.renderer.setClearColor(148, 194, 240); client.renderer.setClearColor(148, 194, 240);
state.renderer.window.input.lockMouse(true); client.renderer.window.input.lockMouse(true);
} }
void GameScene::update() { void GameScene::update() {
Window& window = state.renderer.window; Window& window = client.renderer.window;
game.l()->update(state.delta); client.game->update(client.getDelta());
world->update(state.delta); world->update(client.getDelta());
for (auto entity : entities) entity->update(state.delta); for (auto entity : entities) entity->update(client.getDelta());
debugGui.update(world.l()->getPlayer().l(), state.fps, world.l()->getActiveDimension().l()->getMeshChunkCount(), double lastFps = 1 / client.getDelta();
debugGui.update(world.l()->getPlayer().l(), lastFps, world.l()->getActiveDimension().l()->getMeshChunkCount(),
drawCalls, world.l()->getNet().serverSideChunkGens, world.l()->getNet().recvPackets); drawCalls, world.l()->getNet().serverSideChunkGens, world.l()->getNet().recvPackets);
world.l()->getNet().serverSideChunkGens = 0; world.l()->getNet().serverSideChunkGens = 0;
@ -52,11 +52,11 @@ void GameScene::update() {
} }
void GameScene::draw() { void GameScene::draw() {
Renderer& renderer = state.renderer; Renderer& renderer = client.renderer;
Camera& camera = renderer.camera; Camera& camera = renderer.camera;
renderer.beginChunkDeferredCalls(); renderer.beginChunkDeferredCalls();
renderer.enableTexture(&game.l()->textures.atlasTexture); renderer.enableTexture(&client.game->textures.atlasTexture);
drawCalls = world.l()->renderChunks(renderer); drawCalls = world.l()->renderChunks(renderer);
@ -67,7 +67,7 @@ void GameScene::draw() {
renderer.endDeferredCalls(); renderer.endDeferredCalls();
renderer.beginGUIDrawCalls(); renderer.beginGUIDrawCalls();
renderer.enableTexture(&game.l()->textures.atlasTexture); renderer.enableTexture(&client.game->textures.atlasTexture);
world.l()->getPlayer().l()->drawHud(renderer); world.l()->getPlayer().l()->drawHud(renderer);
debugGui.draw(renderer); debugGui.draw(renderer);
@ -77,5 +77,5 @@ void GameScene::draw() {
} }
void GameScene::cleanup() { void GameScene::cleanup() {
state.renderer.window.removeResizeCallback("gamescene"); client.renderer.window.removeResizeCallback("gamescene");
} }

View File

@ -17,14 +17,14 @@ class Drawable;
class GameScene : public Scene { class GameScene : public Scene {
public: public:
explicit GameScene(ClientState& state); GameScene(Client& client);
void update() override; void update() override;
void draw() override; void draw() override;
void cleanup() override; void cleanup() override;
public: public:
SubgamePtr game;
WorldPtr world; WorldPtr world;
DebugGui debugGui; DebugGui debugGui;

View File

@ -4,18 +4,18 @@
#include "LuaErrorScene.h" #include "LuaErrorScene.h"
#include "client/Client.h"
#include "client/graph/Font.h" #include "client/graph/Font.h"
#include "client/ClientState.h"
#include "client/graph/Renderer.h" #include "client/graph/Renderer.h"
#include "client/gui/basic/GuiRect.h" #include "client/gui/basic/GuiRect.h"
#include "client/gui/basic/GuiText.h" #include "client/gui/basic/GuiText.h"
LuaErrorScene::LuaErrorScene(ClientState &state, const std::string &err) : Scene(state), err(err) { LuaErrorScene::LuaErrorScene(Client& client, const std::string &err) : Scene(client), err(err) {
state.renderer.setClearColor(0, 0, 0); client.renderer.setClearColor(0, 0, 0);
state.renderer.window.input.lockMouse(false); client.renderer.window.input.lockMouse(false);
Font f(state.game.textures, state.game.textures["font"]); Font f(client.game->textures, client.game->textures["font"]);
glm::ivec2 win = state.renderer.window.getSize(); glm::ivec2 win = client.renderer.window.getSize();
auto container = std::make_shared<GuiRect>("container"); auto container = std::make_shared<GuiRect>("container");
container->create({800, 500}, {}, {0.05, 0.05, 0.05, 1}); container->create({800, 500}, {}, {0.05, 0.05, 0.05, 1});
@ -34,22 +34,22 @@ LuaErrorScene::LuaErrorScene(ClientState &state, const std::string &err) : Scene
errorText->setPos({16, 48}); errorText->setPos({16, 48});
container->add(errorText); container->add(errorText);
state.renderer.window.addResizeCallback("scene", [&](glm::ivec2 win) { client.renderer.window.addResizeCallback("scene", [&](glm::ivec2 win) {
components.get<GuiRect>("container")->setPos({win.x / 2 - 800 / 2, win.y / 2 - 500 / 2}); components.get<GuiRect>("container")->setPos({win.x / 2 - 800 / 2, win.y / 2 - 500 / 2});
}); });
} }
void LuaErrorScene::update() { void LuaErrorScene::update() {
state.game.textures.update(); client.game->textures.update();
} }
void LuaErrorScene::draw() { void LuaErrorScene::draw() {
Renderer& renderer = state.renderer; Renderer& renderer = client.renderer;
renderer.beginChunkDeferredCalls(); renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls(); renderer.endDeferredCalls();
renderer.beginGUIDrawCalls(); renderer.beginGUIDrawCalls();
renderer.enableTexture(&state.game.textures.atlasTexture); renderer.enableTexture(&client.game->textures.atlasTexture);
components.draw(renderer); components.draw(renderer);
@ -57,5 +57,5 @@ void LuaErrorScene::draw() {
} }
void LuaErrorScene::cleanup() { void LuaErrorScene::cleanup() {
state.renderer.window.removeResizeCallback("scene"); client.renderer.window.removeResizeCallback("scene");
} }

View File

@ -10,7 +10,7 @@
class LuaErrorScene : public Scene { class LuaErrorScene : public Scene {
public: public:
LuaErrorScene(ClientState& state, const std::string& err); LuaErrorScene(Client& client, const std::string& err);
void update() override; void update() override;
void draw() override; void draw() override;

View File

@ -10,28 +10,32 @@
#include "MainMenuScene.h" #include "MainMenuScene.h"
#include "util/Log.h" #include "util/Log.h"
#include "client/ClientState.h" #include "client/Client.h"
#include "client/graph/Renderer.h" #include "client/graph/Renderer.h"
#include "client/menu/SubgameDef.h" #include "client/menu/SubgameDef.h"
#include "client/gui/basic/GuiText.h" #include "client/gui/basic/GuiText.h"
#include "game/atlas/asset/AtlasRef.h" #include "game/atlas/asset/AtlasRef.h"
#include "client/gui/basic/GuiContainer.h"
#include "client/gui/compound/GuiImageButton.h" #include "client/gui/compound/GuiImageButton.h"
#include "ConnectScene.h"
MainMenuScene::MainMenuScene(ClientState& state) : MainMenuScene::MainMenuScene(Client& client) :
Scene(state), Scene(client),
sandbox(sandboxArea, state, menuContainer) { components(std::make_unique<GuiContainer>()),
menuContainer(std::make_shared<GuiContainer>("__menu")),
sandbox(sandboxArea, client, menuContainer) {
state.renderer.setClearColor(0, 0, 0); client.renderer.setClearColor(0, 0, 0);
state.renderer.window.input.lockMouse(false); client.renderer.window.input.lockMouse(false);
Font f(state.game.textures, state.game.textures["font"]); Font f(client.game->textures, client.game->textures["font"]);
win = state.renderer.window.getSize(); win = client.renderer.window.getSize();
sandboxArea = win - glm::ivec2(0, 18 * GS); sandboxArea = win - glm::ivec2(0, 18 * GS);
components.add(menuContainer); components->add(menuContainer);
branding = std::make_shared<GuiContainer>("zephaBranding"); branding = std::make_shared<GuiContainer>("zephaBranding");
components.add(branding); components->add(branding);
{ {
auto zephaText = std::make_shared<GuiText>("zephaText"); auto zephaText = std::make_shared<GuiText>("zephaText");
zephaText->create({GS, GS}, {}, {}, {1, 1, 1, 1}, f); zephaText->create({GS, GS}, {}, {}, {1, 1, 1, 1}, f);
@ -51,34 +55,42 @@ MainMenuScene::MainMenuScene(ClientState& state) :
auto navigationBarIcons = navigationBar->get<GuiContainer>("navigationBarIcons"); auto navigationBarIcons = navigationBar->get<GuiContainer>("navigationBarIcons");
components.add(navigationBar); components->add(navigationBar);
{ {
auto settingsButton = std::make_shared<GuiImageButton>("settingsButton"); auto settingsButton = std::make_shared<GuiImageButton>("settingsButton");
settingsButton->create({16 * GS, 16 * GS}, {}, settingsButton->create({16 * GS, 16 * GS}, {},
state.game.textures["crop(0, 0, 16, 16, menu_flag_settings)"], client.game->textures["crop(0, 0, 16, 16, menu_flag_settings)"],
state.game.textures["crop(16, 0, 16, 16, menu_flag_settings)"]); client.game->textures["crop(16, 0, 16, 16, menu_flag_settings)"]);
navigationBar->get<GuiContainer>("navigationBarIcons")->add(settingsButton); navigationBar->get<GuiContainer>("navigationBarIcons")->add(settingsButton);
auto closeButton = std::make_shared<GuiImageButton>("closeButton"); auto closeButton = std::make_shared<GuiImageButton>("closeButton");
closeButton->create({16 * GS, 16 * GS}, {}, closeButton->create({16 * GS, 16 * GS}, {},
state.game.textures["crop(0, 0, 16, 16, menu_flag_quit)"], client.game->textures["crop(0, 0, 16, 16, menu_flag_quit)"],
state.game.textures["crop(16, 0, 16, 16, menu_flag_quit)"]); client.game->textures["crop(16, 0, 16, 16, menu_flag_quit)"]);
closeButton->setCallback(GuiComponent::CallbackType::PRIMARY, [](bool down, glm::ivec2) { if (down) exit(0); }); closeButton->setCallback(GuiComponent::CallbackType::PRIMARY, [](bool down, glm::ivec2) { if (down) exit(0); });
navigationBar->get<GuiContainer>("navigationBarIcons")->add(closeButton); navigationBar->get<GuiContainer>("navigationBarIcons")->add(closeButton);
auto serversButton = std::make_shared<GuiImageButton>("serversButton"); auto serversButton = std::make_shared<GuiImageButton>("serversButton");
serversButton->create({16 * GS, 16 * GS}, {}, serversButton->create({16 * GS, 16 * GS}, {},
state.game.textures["crop(0, 0, 16, 16, menu_flag_multiplayer)"], client.game->textures["crop(0, 0, 16, 16, menu_flag_multiplayer)"],
state.game.textures["crop(16, 0, 16, 16, menu_flag_multiplayer)"]); client.game->textures["crop(16, 0, 16, 16, menu_flag_multiplayer)"]);
serversButton->setPos({GS, GS}); serversButton->setPos({GS, GS});
navigationBarIcons->add(serversButton); navigationBarIcons->add(serversButton);
auto contentButton = std::make_shared<GuiImageButton>("contentButton"); auto contentButton = std::make_shared<GuiImageButton>("contentButton");
contentButton->create({16 * GS, 16 * GS}, {}, contentButton->create({16 * GS, 16 * GS}, {},
state.game.textures["crop(0, 0, 16, 16, menu_flag_content)"], client.game->textures["crop(0, 0, 16, 16, menu_flag_content)"],
state.game.textures["crop(16, 0, 16, 16, menu_flag_content)"]); client.game->textures["crop(16, 0, 16, 16, menu_flag_content)"]);
contentButton->setPos({GS + GS * 18, GS}); contentButton->setPos({GS + GS * 18, GS});
contentButton->setCallback(GuiComponent::CallbackType::PRIMARY, [&](bool down, glm::ivec2) { if (down) state.desiredState = "connect"; }); contentButton->setCallback(GuiComponent::CallbackType::PRIMARY, [&](bool down, glm::ivec2) {
if (!down) return;
client.scene.setScene(std::make_unique<ConnectScene>(client, Address { "127.0.0.1" }));
});
navigationBarIcons->add(contentButton); navigationBarIcons->add(contentButton);
auto divider = std::make_shared<GuiRect>("divider"); auto divider = std::make_shared<GuiRect>("divider");
@ -91,16 +103,18 @@ MainMenuScene::MainMenuScene(ClientState& state) :
for (unsigned int i = 0; i < subgames.size(); i++) { for (unsigned int i = 0; i < subgames.size(); i++) {
auto &subgame = subgames[i]; auto &subgame = subgames[i];
auto button = std::make_shared<GuiImageButton>(subgame.config.name); auto button = std::make_shared<GuiImageButton>(subgame.config.name);
button->create({16 * GS, 16 * GS}, {}, button->create({16 * GS, 16 * GS}, {},
state.game.textures["crop(0, 0, 16, 16, " + subgame.iconRef->name + ")"], client.game->textures["crop(0, 0, 16, 16, " + subgame.iconRef->name + ")"],
state.game.textures["crop(16, 0, 16, 16, " + subgame.iconRef->name + ")"]); client.game->textures["crop(16, 0, 16, 16, " + subgame.iconRef->name + ")"]);
button->setPos({GS * 7 + GS * 18 * (i + 2), GS}); button->setPos({GS * 7 + GS * 18 * (i + 2), GS});
button->setCallback(GuiComponent::CallbackType::PRIMARY, [&, i](bool down, glm::ivec2) { button->setCallback(GuiComponent::CallbackType::PRIMARY, [&](bool down, glm::ivec2) {
if (down) { if (!down) return;
selectedSubgame = &subgame; selectedSubgame = &subgame;
sandbox.load(*selectedSubgame); sandbox.load(*selectedSubgame);
}
}); });
navigationBarIcons->add(button); navigationBarIcons->add(button);
} }
} }
@ -112,7 +126,7 @@ MainMenuScene::MainMenuScene(ClientState& state) :
positionElements(); positionElements();
state.renderer.window.addResizeCallback("mainmenu", [&](glm::ivec2 win) { client.renderer.window.addResizeCallback("mainmenu", [&](glm::ivec2 win) {
this->win = win; this->win = win;
sandboxArea = win - glm::ivec2(0, 18 * GS); sandboxArea = win - glm::ivec2(0, 18 * GS);
positionElements(); positionElements();
@ -120,7 +134,7 @@ MainMenuScene::MainMenuScene(ClientState& state) :
} }
void MainMenuScene::findSubgames() { void MainMenuScene::findSubgames() {
std::string subgamesPath = state.path + "../subgames"; std::string subgamesPath = "../subgames";
cf_dir_t subgamesDir; cf_dir_t subgamesDir;
cf_dir_open(&subgamesDir, subgamesPath.data()); cf_dir_open(&subgamesDir, subgamesPath.data());
@ -165,8 +179,8 @@ void MainMenuScene::findSubgames() {
std::string description = (j["description"].is_string() ? j["description"] : ""); std::string description = (j["description"].is_string() ? j["description"] : "");
std::string version = j["version"]; std::string version = j["version"];
std::shared_ptr<AtlasRef> icon = state.game.textures["menu_flag_missing"]; std::shared_ptr<AtlasRef> icon = client.game->textures["menu_flag_missing"];
if (hasIcon) icon = state.game.textures.loadImage(std::string(subgameFolder.path) + "/icon.png", name); if (hasIcon) icon = client.game->textures.loadImage(std::string(subgameFolder.path) + "/icon.png", name);
subgames.push_back({icon, {name, description, version}, subgameFolder.path}); subgames.push_back({icon, {name, description, version}, subgameFolder.path});
} }
@ -191,7 +205,7 @@ void MainMenuScene::positionElements() {
auto navigationBarBg = navigationBar->get<GuiContainer>("navigationBarBg"); auto navigationBarBg = navigationBar->get<GuiContainer>("navigationBarBg");
for (unsigned int i = 0; i < static_cast<float>(win.x) / 64.f / GS; i++) { for (unsigned int i = 0; i < static_cast<float>(win.x) / 64.f / GS; i++) {
auto segment = std::make_shared<GuiRect>("segment_" + std::to_string(i)); auto segment = std::make_shared<GuiRect>("segment_" + std::to_string(i));
segment->create({64 * GS, 18 * GS}, {}, state.game.textures["menu_bar_bg"]); segment->create({64 * GS, 18 * GS}, {}, client.game->textures["menu_bar_bg"]);
segment->setPos({i * 64 * GS, 0}); segment->setPos({i * 64 * GS, 0});
navigationBarBg->add(segment); navigationBarBg->add(segment);
} }
@ -202,23 +216,23 @@ void MainMenuScene::positionElements() {
} }
void MainMenuScene::update() { void MainMenuScene::update() {
state.game.textures.update(); client.game->textures.update();
sandbox.update(state.delta); sandbox.update(client.getDelta());
components.handleMouseInput(state.renderer.window); components->handleMouseInput(client.renderer.window);
} }
void MainMenuScene::draw() { void MainMenuScene::draw() {
state.renderer.beginChunkDeferredCalls(); client.renderer.beginChunkDeferredCalls();
state.renderer.endDeferredCalls(); client.renderer.endDeferredCalls();
state.renderer.beginGUIDrawCalls(); client.renderer.beginGUIDrawCalls();
state.renderer.enableTexture(&state.game.textures.atlasTexture); client.renderer.enableTexture(&client.game->textures.atlasTexture);
components.draw(state.renderer); components->draw(client.renderer);
state.renderer.swapBuffers(); client.renderer.swapBuffers();
} }
void MainMenuScene::cleanup() { void MainMenuScene::cleanup() {
state.renderer.window.setCursorHand(false); client.renderer.window.setCursorHand(false);
state.renderer.window.removeResizeCallback("mainmenu"); client.renderer.window.removeResizeCallback("mainmenu");
} }

View File

@ -8,13 +8,12 @@
#include "client/menu/SubgameDef.h" #include "client/menu/SubgameDef.h"
#include "client/menu/MenuSandbox.h" #include "client/menu/MenuSandbox.h"
#include "client/gui/basic/GuiContainer.h"
class ClientState; class Client;
class MainMenuScene : public Scene { class MainMenuScene : public Scene {
public: public:
explicit MainMenuScene(ClientState& state); explicit MainMenuScene(Client& client);
void update() override; void update() override;
void draw() override; void draw() override;
@ -24,15 +23,15 @@ private:
void positionElements(); void positionElements();
void findSubgames(); void findSubgames();
const float GS = 3; static constexpr float GS = 3;
glm::ivec2 win {}; glm::ivec2 win {};
glm::ivec2 sandboxArea {}; glm::ivec2 sandboxArea {};
GuiContainer components; std::unique_ptr<GuiContainer> components;
std::shared_ptr<GuiContainer> branding = nullptr; std::shared_ptr<GuiContainer> branding;
std::shared_ptr<GuiContainer> navigationBar = nullptr; std::shared_ptr<GuiContainer> navigationBar;
std::shared_ptr<GuiContainer> menuContainer = std::make_shared<GuiContainer>("__menu"); std::shared_ptr<GuiContainer> menuContainer;
MenuSandbox sandbox; MenuSandbox sandbox;

View File

@ -1,14 +1,17 @@
// /*
// Created by aurailus on 06/01/19. * Scene abstract superclass, provides base scene methods for use by SceneManager.
// * Stores a reference to the client, for children.
*
* - Auri, 03/11/20
*/
#pragma once #pragma once
class ClientState; class Client;
class Scene { class Scene {
public: public:
explicit Scene(ClientState& state) : state(state) {} explicit Scene(Client& client) : client(client) {}
virtual void update() = 0; virtual void update() = 0;
virtual void draw() = 0; virtual void draw() = 0;
@ -16,6 +19,6 @@ public:
virtual ~Scene() = default; virtual ~Scene() = default;
ClientState& state; Client& client;
}; };

View File

@ -4,27 +4,55 @@
#include "SceneManager.h" #include "SceneManager.h"
/**
* Sets a new scene as the current scene.
* Cleans up the old scene.
* @param newScene - The new current scene.
*/
void SceneManager::setScene(std::unique_ptr<Scene> newScene) {
cleanupScene();
scene = std::move(newScene);
}
/**
* Returns a reference to the current scene.
* @returns The current scene as a const reference.
*/
const Scene& SceneManager::getScene() {
return *scene;
}
/**
* Updates and renders the current scene, if there is one.
*/
void SceneManager::update() { void SceneManager::update() {
if (!scene) return;
scene->update(); scene->update();
scene->draw(); scene->draw();
} }
void SceneManager::setScene(std::unique_ptr<Scene> scene) {
if (this->scene != nullptr) cleanupScene();
this->scene = std::move(scene);
}
Scene& SceneManager::getScene() { /**
return *scene; * Cleans up the current scene and removes it.
} * There will be no current scene after this method executes.
*/
void SceneManager::cleanupScene() { void SceneManager::cleanupScene() {
if (scene != nullptr) { if (scene) scene->cleanup();
scene->cleanup(); scene = nullptr;
scene = nullptr;
}
} }
/*
* Clean up the scene on destruction.
*/
SceneManager::~SceneManager() { SceneManager::~SceneManager() {
cleanupScene(); cleanupScene();
} }

View File

@ -10,15 +10,14 @@
class SceneManager { class SceneManager {
public: public:
SceneManager() = default;
void setScene(std::unique_ptr<Scene> scene); void setScene(std::unique_ptr<Scene> scene);
Scene& getScene(); const Scene& getScene();
void update(); void update();
void cleanupScene(); void cleanupScene();
~SceneManager(); ~SceneManager();
private: private:
std::unique_ptr<Scene> scene = nullptr; std::unique_ptr<Scene> scene = nullptr;
}; };

View File

@ -4,24 +4,42 @@
#include "LocalSubgame.h" #include "LocalSubgame.h"
LocalSubgame::LocalSubgame(const std::string& texPath) :
texPath(texPath), /**
* Creates subgame instances, including the lua parser, and biome and block atlases.
* Also loads base assets into the texture atlas.
* @param baseAssets - The relative path to the base texture assets.
*/
LocalSubgame::LocalSubgame(const std::string& baseAssets) :
textures(2048), textures(2048),
lua(std::make_unique<LocalLuaParser>(*this)), lua(std::make_unique<LocalLuaParser>(*this)),
biomes(std::make_unique<LocalBiomeAtlas>()), biomes(std::make_unique<LocalBiomeAtlas>()),
defs(std::make_unique<LocalDefinitionAtlas>(textures)) { defs(std::make_unique<LocalDefinitionAtlas>(textures)) {
textures.loadDirectory(texPath); textures.loadDirectory(baseAssets);
} }
void LocalSubgame::init(WorldPtr world, PlayerPtr player, ClientState& state) {
lua->init(world, player, state); /**
* Initializes the Lua Parser.
* @param world - Passed in to the Lua Parser.
* @param player - Passed in to the Lua Parser.
* @param client - Passed in to the Lua Parser.
*/
void LocalSubgame::init(WorldPtr world, PlayerPtr player, Client& client) {
lua->init(world, player, client);
} }
/**
* Updates the lua parser and the texture atlas.
* @param delta - The last frame's delta time.
*/
void LocalSubgame::update(double delta) { void LocalSubgame::update(double delta) {
lua->update(delta); lua->update(delta);
textures.update(); textures.update();
} }
LocalSubgame::~LocalSubgame() {}

View File

@ -1,35 +1,32 @@
// /*
// The ClientGame class stores all of the subgame data for the client. * The Local Subgame stores all local subgame data.
// This data is used when in the GameScene. It is initialized when the client joins a game and cleared when they exit it. * Includes Block / Item definitions, biome definitions, the lua parser, models, and textures.
// The data within is in an undefined state until the init method is called. *
// Created by aurailus on 18/04/19. * - Auri, 03/11/20
// */
#pragma once #pragma once
#include "Subgame.h" #include "Subgame.h"
#include "game/atlas/asset/ModelStore.h"
#include "game/atlas/LocalBiomeAtlas.h"
#include "game/atlas/LocalDefinitionAtlas.h"
#include "game/atlas/TextureAtlas.h"
#include "util/CovariantPtr.h" #include "util/CovariantPtr.h"
#include "lua/LocalLuaParser.h" #include "lua/LocalLuaParser.h"
#include "game/atlas/TextureAtlas.h"
#include "game/atlas/LocalBiomeAtlas.h"
#include "game/atlas/asset/ModelStore.h"
#include "game/atlas/LocalDefinitionAtlas.h"
class LocalPlayer; class Client;
class LocalWorld; class LocalWorld;
class ClientState; class LocalPlayer;
class LocalSubgame : public Subgame { class LocalSubgame : public Subgame {
public: public:
explicit LocalSubgame(const std::string& texPath); explicit LocalSubgame(const std::string& baseAssets);
~LocalSubgame();
void init(WorldPtr world, PlayerPtr player, ClientState& state); void init(WorldPtr world, PlayerPtr player, Client& client);
void update(double delta); void update(double delta);
std::string texPath;
LocalDefinitionAtlas& getDefs() override { return *defs; }; LocalDefinitionAtlas& getDefs() override { return *defs; };
LocalBiomeAtlas& getBiomes() override { return *biomes; }; LocalBiomeAtlas& getBiomes() override { return *biomes; };
LocalLuaParser& getParser() override { return *lua; }; LocalLuaParser& getParser() override { return *lua; };

View File

@ -4,8 +4,8 @@
#include "LocalLuaParser.h" #include "LocalLuaParser.h"
#include "client/Client.h"
#include "ErrorFormatter.h" #include "ErrorFormatter.h"
#include "client/ClientState.h"
#include "client/graph/Renderer.h" #include "client/graph/Renderer.h"
#include "register/RegisterItems.h" #include "register/RegisterItems.h"
#include "register/RegisterBlocks.h" #include "register/RegisterBlocks.h"
@ -33,12 +33,12 @@
LocalLuaParser::LocalLuaParser(LocalSubgame& game): LuaParser(game), keybinds(this) {} LocalLuaParser::LocalLuaParser(LocalSubgame& game): LuaParser(game), keybinds(this) {}
void LocalLuaParser::init(WorldPtr world, PlayerPtr player, ClientState& state) { void LocalLuaParser::init(WorldPtr world, PlayerPtr player, Client& client) {
lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::debug); lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::math, sol::lib::table, sol::lib::debug);
loadApi(world, player); loadApi(world, player);
handler.executeMods(Util::bind_this(this, &LocalLuaParser::runFileSandboxed)); handler.executeMods(Util::bind_this(this, &LocalLuaParser::runFileSandboxed));
state.renderer.window.input.setCallback(Util::bind_this(&keybinds, &LuaKeybindHandler::keybindHandler)); client.renderer.window.input.setCallback(Util::bind_this(&keybinds, &LuaKeybindHandler::keybindHandler));
registerDefs(); registerDefs();
} }

View File

@ -4,21 +4,21 @@
#pragma once #pragma once
#include "LuaParser.h" #include "lua/LuaParser.h"
#include "LocalModHandler.h" #include "util/CovariantPtr.h"
#include "LuaKeybindHandler.h" #include "lua/LocalModHandler.h"
#include "../util/CovariantPtr.h" #include "lua/LuaKeybindHandler.h"
class LocalPlayer; class Client;
class LocalWorld; class LocalWorld;
class ClientState; class LocalPlayer;
class LocalSubgame; class LocalSubgame;
class LocalLuaParser : public LuaParser { class LocalLuaParser : public LuaParser {
public: public:
explicit LocalLuaParser(LocalSubgame& game); explicit LocalLuaParser(LocalSubgame& game);
void init(WorldPtr world, PlayerPtr player, ClientState& state); void init(WorldPtr world, PlayerPtr player, Client& client);
void update(double delta) override; void update(double delta) override;

View File

@ -9,11 +9,10 @@
#include <list> #include <list>
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
#include "lua/Lua.h"
#include "util/CovariantPtr.h"
#include "modules/SubgameModule.h" #include "modules/SubgameModule.h"
#include "Lua.h"
#include "../util/CovariantPtr.h"
class Subgame; class Subgame;
class LuaParser { class LuaParser {

View File

@ -4,21 +4,23 @@
#pragma once #pragma once
#include "../Lua.h" #include "lua/Lua.h"
#include "client/ClientState.h" #include "client/Client.h"
#include "util/net/Address.h"
#include "client/scene/ConnectScene.h"
namespace MenuApi { namespace MenuApi {
void start_game(ClientState& state, sol::table& core) { void start_game(Client& client, sol::table& core) {
//TODO: Don't hardcode the subgame //TODO: Don't hardcode the subgame
core.set_function("start_game", [&]() { core.set_function("game_connect", [&](std::string address) {
state.subgame = "zeus"; client.scene.setScene(std::make_unique<ConnectScene>(client, Address::fromString(address)));
state.desiredState = "connect";
}); });
core.set_function("start_game_local", [&]() { core.set_function("game_host", [&](sol::this_state s) {
state.subgame = "zeus"; sol::state_view state(s);
state.desiredState = "local"; const auto subgame = state.get<std::string>("zepha.__builtin.subgame");
client.startLocalServer(subgame);
}); });
} }
} }

View File

@ -41,6 +41,7 @@ class ServerInventoryRefs;
template <typename B, typename L, typename S> template <typename B, typename L, typename S>
class CovariantPtr { class CovariantPtr {
std::shared_ptr<B> b = nullptr; std::shared_ptr<B> b = nullptr;
public: public:
CovariantPtr() = default; CovariantPtr() = default;
CovariantPtr(std::nullptr_t) {}; CovariantPtr(std::nullptr_t) {};

36
src/util/net/Address.cpp Normal file
View File

@ -0,0 +1,36 @@
//
// Created by auri on 2020-11-03.
//
#include <stdexcept>
#include "Address.h"
/**
* Returns an Address object from the provided address string.
* Address string should be in standard dot + optional colon notation, e.g: 192.168.0.1:8000, 127.0.0.1.
* @throws std::invalid_argument - There is a value after a colon that cannot be converted into a valid numeric value.
* @throws std::out_of_range - There is a numeric port specified, but it is greater than the maximum unsigned short.
* @param addressString - The string to parse.
* @returns - An Address object with the specified address.
*/
Address Address::fromString(const std::string &addressString) {
std::string address;
unsigned short port;
size_t sep = addressString.find(':');
if (sep == std::string::npos) {
address = address;
port = Address::DEFAULT_PORT;
}
else {
address = addressString.substr(0, sep++); // Increment sep for next substr call.
unsigned int p = stoi(addressString.substr(sep, addressString.length() - sep));
if (p > 65535) throw std::out_of_range("Port value is greater than 65535.");
port = static_cast<unsigned short>(p);
}
return Address { address, port };
}

View File

@ -8,5 +8,9 @@
struct Address { struct Address {
std::string host; std::string host;
unsigned short port; unsigned short port = Address::DEFAULT_PORT;
static Address fromString(const std::string& addressString);
constexpr static unsigned short DEFAULT_PORT = 13110;
}; };