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.
master
Auri 2020-11-03 23:29:30 -08:00
parent 8d6e19500a
commit a9a12a89d9
35 changed files with 472 additions and 361 deletions

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">
<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 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="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">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />

View File

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

View File

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

View File

@ -19,7 +19,14 @@
#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[]) {
return StartGame(argc, argv);
}

View File

@ -11,9 +11,18 @@
#include "client/Client.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
std::map<std::string, std::string> args;
for (int i = 1; i < argc; i++) {
@ -32,76 +41,83 @@ std::map<std::string, std::string> parseArgs(int argc, char* argv[]) {
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[]) {
std::string path = argv[0];
Address addr {"127.0.0.1", 32000};
Mode mode = Mode::CLIENT;
std::string subgame = "";
bool ascii = true;
//Parse the arguments map
for (auto arg : parseArgs(argc, argv)) {
switch (Util::hash(arg.first.c_str())) {
default: {
std::cout << Log::err << "Invalid argument " << arg.first << "." << Log::endl;
return -1;
}
case Util::hash("--mode"): {
try {
unsigned short port = Address::DEFAULT_PORT;
std::string subgame = "";
bool ascii = true;
/**
* Handle command line arguments.
* @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;
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;
}
case Util::hash("--port"): {
addr.port = static_cast<unsigned short>(stoi(arg.second));
// case Util::hash("--address"):
// addr.host = arg.second;
// break;
case Util::hash("--port"):
port = static_cast<unsigned short>(stoi(arg.second));
break;
}
case Util::hash("--address"): {
addr.host = arg.second;
break;
}
case Util::hash("--subgame"): {
case Util::hash("--subgame"):
subgame = arg.second;
break;
}
case Util::hash("--noascii"): {
case Util::hash("--noascii"):
ascii = false;
break;
}
}
}
// Obligatory ASCII Art is obligatory.
if (ascii) {
Log::clear();
std::cout << "\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;
}
//Start the game
switch (mode) {
default: {
std::cout << Log::err << "Mode not set." << Log::endl;
return -1;
if (ascii) {
Log::clear();
std::cout <<
"\n"
"\t\t ____ ____ ____ _ _ __ \n"
"\t\t(__ )( __)( _ \\/ )( \\ / _\\ \n"
"\t\t / _/ ) _) ) __/) __ (/ \\\n"
"\t\t(____)(____)(__) \\_)(_/\\_/\\_/\n" << std::endl;
}
switch (mode) {
case Mode::CLIENT: {
Client c(path, addr, {1366, 768});
break;
}
Client c({1366, 768});
break; }
case Mode::SERVER: {
Server s(addr.port, subgame);
break;
Server s(port, subgame);
break; }
}
return 0;
}
return 0;
};
catch (const std::exception& e) {
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 "Client.h"
#include "../util/Log.h"
#include "../util/Timer.h"
#include "LocalServerInstance.h"
@ -14,55 +10,60 @@
#include "scene/ConnectScene.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),
addr(addr),
executablePath(path) {
/**
* Creates a client window and starts the main event loop.
* Initially opens to the main menu.
* @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::unique_ptr<Scene> scene = std::make_unique<MainMenuScene>(state);
// std::unique_ptr<Scene> scene = std::make_unique<LuaErrorScene>(state, "whoopsie poopsie did a fucky wucky");
sceneManager.setScene(std::move(scene));
scene.setScene(std::make_unique<MainMenuScene>(*this));
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() {
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();
state.delta = now - timeElapsed;
delta = now - timeElapsed;
timeElapsed = now;
glfwPollEvents();
sceneManager.update();
renderer.update(state.delta);
state.fps = 1000.0 / (t.elapsedNs() / 1000000.0);
}
Client::~Client() {
sceneManager.cleanupScene();
if (localServer) localServer->stop();
scene.update();
renderer.update(delta);
}

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
#include "util/net/Address.h"
#include "client/ClientState.h"
#include "game/LocalSubgame.h"
#include "client/graph/Renderer.h"
#include "client/scene/SceneManager.h"
#include "client/conn/ServerConnection.h"
class LocalServerInstance;
class Client {
public:
Client(const std::string& path, const Address& addr, glm::ivec2 dims);
~Client();
Client(const Client& o) = delete;
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:
void loop();
std::string executablePath;
Address addr {};
Renderer renderer;
ClientState state;
SceneManager sceneManager;
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;
#endif
}
LocalServerInstance::~LocalServerInstance() {
stop();
}

View File

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

View File

@ -43,7 +43,7 @@ DebugGui::DebugGui(glm::vec2 bufferSize, SubgamePtr game, WorldPtr world) :
add(genGraph);
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);
auto fpsGraph = std::make_shared<GuiLabelledGraph>("fpsGraph");

View File

@ -1,6 +1,4 @@
//
// Created by aurailus on 2019-12-12.
//
#include <fstream>
#include <iostream>
#include <cute_files/cute_files.h>
@ -8,6 +6,7 @@
#include "MenuSandbox.h"
#include "lua/LuaMod.h"
#include "client/Client.h"
#include "lua/ErrorFormatter.h"
#include "client/menu/SubgameDef.h"
#include "client/gui/basic/GuiText.h"
@ -18,12 +17,13 @@
#include "lua/modules/mSetGui.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),
state(state),
client(client),
container(container),
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() {
container->remove("error");
@ -48,7 +48,7 @@ void MenuSandbox::loadApi() {
ClientApi::gui_element(lua);
MenuApi::set_gui (builder, win, lua, core);
MenuApi::start_game (state, core);
MenuApi::start_game (client, core);
bindModules();
@ -87,9 +87,10 @@ sol::protected_function_result MenuSandbox::runFileSandboxed(const std::string&
env["_FILE"] = f.path;
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) {
@ -149,7 +150,7 @@ void MenuSandbox::loadAndRunMod(const std::string &modPath) {
std::string texPath = modPath + "/textures";
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;
@ -158,7 +159,7 @@ void MenuSandbox::loadAndRunMod(const std::string &modPath) {
void MenuSandbox::showError(const std::string& what, const std::string& 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");
container->add(errWrap);

View File

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

View File

@ -6,22 +6,31 @@
#include "ConnectScene.h"
#include "client/Client.h"
#include "util/net/Packet.h"
#include "util/net/Address.h"
#include "client/ClientState.h"
#include "util/net/PacketView.h"
#include "client/graph/Renderer.h"
#include "client/gui/basic/GuiRect.h"
#include "client/gui/basic/GuiText.h"
#include "game/atlas/asset/AssetType.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");
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");
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);
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});
});
}
void ConnectScene::update() {
state.game.textures.update();
client.game->textures.update();
switch (connectState) {
default:
@ -57,7 +66,7 @@ void ConnectScene::update() {
break;
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;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
@ -67,7 +76,8 @@ void ConnectScene::update() {
auto statusText = components.get<GuiText>("statusText");
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;
Packet resp(Packet::Type::BLOCK_IDENTIFIER_LIST);
@ -78,7 +88,7 @@ void ConnectScene::update() {
}
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;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
@ -88,7 +98,7 @@ void ConnectScene::update() {
auto statusText = components.get<GuiText>("statusText");
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);
resp.sendTo(connection.getPeer(), Packet::Channel::CONNECT);
@ -97,7 +107,7 @@ void ConnectScene::update() {
auto statusText = components.get<GuiText>("statusText");
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;
Packet resp(Packet::Type::MODS);
@ -108,7 +118,7 @@ void ConnectScene::update() {
}
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;
if (connection.pollEvents(&e) && e.type == ENET_EVENT_TYPE_RECEIVE) {
PacketView p(e.packet);
@ -118,10 +128,10 @@ void ConnectScene::update() {
if (p.type == Packet::Type::MODS) {
auto luaMod = LuaMod::fromPacket(p);
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) {
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");
@ -134,7 +144,7 @@ void ConnectScene::update() {
}
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;
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 uncompressed = gzip::decompress(data.data(), data.length());
state.game.textures.addImage(
reinterpret_cast<unsigned char *>(const_cast<char *>(uncompressed.data())),
assetName, true, width, height);
client.game->textures.addImage(
reinterpret_cast<unsigned char *>(const_cast<char *>(uncompressed.data())),
assetName, true, width, height);
}
else if (t == AssetType::MODEL) {
std::string format = 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>());
@ -174,11 +184,11 @@ void ConnectScene::update() {
statusText->setText(statusText->getText() + "Received " + std::to_string(count) + "x media files.\n");
}
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");
connectState = State::DONE;
state.desiredState = "game";
client.scene.setScene(std::make_unique<GameScene>(client));
}
}
break;
@ -206,7 +216,7 @@ void ConnectScene::handleConnecting() {
case ServerConnection::State::ATTEMPTING_CONNECT:
connection.processConnecting();
dotsTime += state.delta;
dotsTime += client.getDelta();
if (dotsTime > 1) {
dotsTime -= 1;
statusText->setText(statusText->getText() + ".");
@ -225,12 +235,12 @@ void ConnectScene::handleConnecting() {
}
void ConnectScene::draw() {
Renderer& renderer = state.renderer;
Renderer& renderer = client.renderer;
renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
renderer.enableTexture(&state.game.textures.atlasTexture);
renderer.enableTexture(&client.game->textures.atlasTexture);
components.draw(renderer);
@ -238,5 +248,5 @@ void ConnectScene::draw() {
}
void ConnectScene::cleanup() {
state.renderer.window.removeResizeCallback("scene");
client.renderer.window.removeResizeCallback("scene");
}

View File

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

View File

@ -4,36 +4,36 @@
#include "GameScene.h"
#include "client/ClientState.h"
#include "client/Client.h"
#include "util/net/PacketView.h"
#include "client/graph/Renderer.h"
GameScene::GameScene(ClientState& state) : Scene(state),
game(std::make_shared<LocalSubgame>(state.game)),
world(std::make_shared<LocalWorld>(game, state.connection, state.renderer)),
debugGui(state.renderer.window.getSize(), game, world) {
GameScene::GameScene(Client& client) : Scene(client),
world(std::make_shared<LocalWorld>(client.game, client.connection, client.renderer)),
debugGui(client.renderer.window.getSize(), client.game, world) {
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();
game .l()->init(world, world.l()->getPlayer(), state);
client.game->init(world, world.l()->getPlayer(), client);
world.l()->updatePlayerDimension();
state.renderer.window.addResizeCallback("gamescene", Util::bind_this(&debugGui, &DebugGui::bufferResized));
state.renderer.setClearColor(148, 194, 240);
state.renderer.window.input.lockMouse(true);
client.renderer.window.addResizeCallback("gamescene", Util::bind_this(&debugGui, &DebugGui::bufferResized));
client.renderer.setClearColor(148, 194, 240);
client.renderer.window.input.lockMouse(true);
}
void GameScene::update() {
Window& window = state.renderer.window;
Window& window = client.renderer.window;
game.l()->update(state.delta);
world->update(state.delta);
client.game->update(client.getDelta());
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);
world.l()->getNet().serverSideChunkGens = 0;
@ -52,11 +52,11 @@ void GameScene::update() {
}
void GameScene::draw() {
Renderer& renderer = state.renderer;
Renderer& renderer = client.renderer;
Camera& camera = renderer.camera;
renderer.beginChunkDeferredCalls();
renderer.enableTexture(&game.l()->textures.atlasTexture);
renderer.enableTexture(&client.game->textures.atlasTexture);
drawCalls = world.l()->renderChunks(renderer);
@ -67,7 +67,7 @@ void GameScene::draw() {
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
renderer.enableTexture(&game.l()->textures.atlasTexture);
renderer.enableTexture(&client.game->textures.atlasTexture);
world.l()->getPlayer().l()->drawHud(renderer);
debugGui.draw(renderer);
@ -77,5 +77,5 @@ void GameScene::draw() {
}
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 {
public:
explicit GameScene(ClientState& state);
GameScene(Client& client);
void update() override;
void draw() override;
void cleanup() override;
public:
SubgamePtr game;
WorldPtr world;
DebugGui debugGui;

View File

@ -4,18 +4,18 @@
#include "LuaErrorScene.h"
#include "client/Client.h"
#include "client/graph/Font.h"
#include "client/ClientState.h"
#include "client/graph/Renderer.h"
#include "client/gui/basic/GuiRect.h"
#include "client/gui/basic/GuiText.h"
LuaErrorScene::LuaErrorScene(ClientState &state, const std::string &err) : Scene(state), err(err) {
state.renderer.setClearColor(0, 0, 0);
state.renderer.window.input.lockMouse(false);
LuaErrorScene::LuaErrorScene(Client& client, const std::string &err) : Scene(client), err(err) {
client.renderer.setClearColor(0, 0, 0);
client.renderer.window.input.lockMouse(false);
Font f(state.game.textures, state.game.textures["font"]);
glm::ivec2 win = state.renderer.window.getSize();
Font f(client.game->textures, client.game->textures["font"]);
glm::ivec2 win = client.renderer.window.getSize();
auto container = std::make_shared<GuiRect>("container");
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});
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});
});
}
void LuaErrorScene::update() {
state.game.textures.update();
client.game->textures.update();
}
void LuaErrorScene::draw() {
Renderer& renderer = state.renderer;
Renderer& renderer = client.renderer;
renderer.beginChunkDeferredCalls();
renderer.endDeferredCalls();
renderer.beginGUIDrawCalls();
renderer.enableTexture(&state.game.textures.atlasTexture);
renderer.enableTexture(&client.game->textures.atlasTexture);
components.draw(renderer);
@ -57,5 +57,5 @@ void LuaErrorScene::draw() {
}
void LuaErrorScene::cleanup() {
state.renderer.window.removeResizeCallback("scene");
client.renderer.window.removeResizeCallback("scene");
}

View File

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

View File

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

View File

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

View File

@ -4,27 +4,55 @@
#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() {
if (!scene) return;
scene->update();
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() {
if (scene != nullptr) {
scene->cleanup();
scene = nullptr;
}
if (scene) scene->cleanup();
scene = nullptr;
}
/*
* Clean up the scene on destruction.
*/
SceneManager::~SceneManager() {
cleanupScene();
}

View File

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

View File

@ -4,24 +4,42 @@
#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),
lua(std::make_unique<LocalLuaParser>(*this)),
biomes(std::make_unique<LocalBiomeAtlas>()),
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) {
lua->update(delta);
textures.update();
}
LocalSubgame::~LocalSubgame() {}

View File

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

View File

@ -4,8 +4,8 @@
#include "LocalLuaParser.h"
#include "client/Client.h"
#include "ErrorFormatter.h"
#include "client/ClientState.h"
#include "client/graph/Renderer.h"
#include "register/RegisterItems.h"
#include "register/RegisterBlocks.h"
@ -33,12 +33,12 @@
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);
loadApi(world, player);
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();
}

View File

@ -4,21 +4,21 @@
#pragma once
#include "LuaParser.h"
#include "lua/LuaParser.h"
#include "LocalModHandler.h"
#include "LuaKeybindHandler.h"
#include "../util/CovariantPtr.h"
#include "util/CovariantPtr.h"
#include "lua/LocalModHandler.h"
#include "lua/LuaKeybindHandler.h"
class LocalPlayer;
class Client;
class LocalWorld;
class ClientState;
class LocalPlayer;
class LocalSubgame;
class LocalLuaParser : public LuaParser {
public:
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;

View File

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

View File

@ -4,21 +4,23 @@
#pragma once
#include "../Lua.h"
#include "client/ClientState.h"
#include "lua/Lua.h"
#include "client/Client.h"
#include "util/net/Address.h"
#include "client/scene/ConnectScene.h"
namespace MenuApi {
void start_game(ClientState& state, sol::table& core) {
void start_game(Client& client, sol::table& core) {
//TODO: Don't hardcode the subgame
core.set_function("start_game", [&]() {
state.subgame = "zeus";
state.desiredState = "connect";
core.set_function("game_connect", [&](std::string address) {
client.scene.setScene(std::make_unique<ConnectScene>(client, Address::fromString(address)));
});
core.set_function("start_game_local", [&]() {
state.subgame = "zeus";
state.desiredState = "local";
core.set_function("game_host", [&](sol::this_state s) {
sol::state_view state(s);
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>
class CovariantPtr {
std::shared_ptr<B> b = nullptr;
public:
CovariantPtr() = default;
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 {
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;
};