diff --git a/.github/workflows/tec.yml b/.github/workflows/tec.yml index d8982af3..e01276ef 100644 --- a/.github/workflows/tec.yml +++ b/.github/workflows/tec.yml @@ -21,35 +21,35 @@ jobs: os: [ windows-latest, - windows-2019, + windows-2022, ubuntu-latest, - ubuntu-20.04, - macOS-latest, + ubuntu-22.04, + macos-latest-large, ] arch: [x86, x64] include: - os: windows-latest vcpkgTripletOs: windows - - os: windows-2019 + - os: windows-2022 vcpkgTripletOs: windows - os: ubuntu-latest vcpkgTripletOs: linux - - os: ubuntu-20.04 + - os: ubuntu-22.04 vcpkgTripletOs: linux - - os: macOS-latest + - os: macos-latest-large vcpkgTripletOs: osx exclude: - os: ubuntu-latest arch: x86 - - os: ubuntu-20.04 + - os: ubuntu-22.04 arch: x86 - - os: macOS-latest + - os: macos-latest-large arch: x86 env: buildDir: "${{ github.workspace }}/build" BUILD_PRESET: release CONFIG_PRESET: ninja-multi-vcpkg-ci - VCPKG_COMMIT_ID: 10b7a178346f3f0abef60cecd5130e295afd8da4 + VCPKG_COMMIT_ID: dd3097e305afa53f7b4312371f62058d2e665320 VCPKG_DEFAULT_TRIPLET: ${{ matrix.arch }}-${{ matrix.vcpkgTripletOs }} steps: - uses: actions/checkout@v4 @@ -72,9 +72,9 @@ jobs: buildPreset: ${{ env.CONFIG_PRESET }}-${{ env.BUILD_PRESET }} testPreset: ${{ env.CONFIG_PRESET }}-${{ env.BUILD_PRESET }} - name: Upload the build artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: "trillek-${{ matrix.os }}" + name: "trillek-${{ matrix.os }}-${{ matrix.arch }}" path: | assets/ ${{ env.CLIENT_BUILD_DIR }}/trillek-client @@ -153,8 +153,8 @@ jobs: windows-latest, windows-2016, ubuntu-latest, - ubuntu-20.04, - macOS-latest, + ubuntu-22.04, + macos-latest-large, ] arch: [x64] if: startsWith(github.ref, 'refs/tags/v') @@ -163,12 +163,12 @@ jobs: - name: Download a single artifact uses: actions/download-artifact@v4 with: - name: "trillek-${{ matrix.os }}" + name: "trillek-${{ matrix.os }}-${{ matrix.arch }}" - name: Package release run: | - zip --junk-paths -r -u trillek-${{ matrix.os }}.zip build/client - zip --junk-paths -r -u trillek-${{ matrix.os }}.zip build/server - zip -r -u trillek-${{ matrix.os }}.zip assets/ + zip --junk-paths -r -u trillek-${{ matrix.os }}-${{ matrix.arch }}.zip build/client + zip --junk-paths -r -u trillek-${{ matrix.os }}-${{ matrix.arch }}.zip build/server + zip -r -u trillek-${{ matrix.os }}-${{ matrix.arch }}.zip assets/ - name: Upload Release Asset id: upload-release-asset uses: actions/upload-release-asset@v1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6279bbea..4e29fa5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.28) project(trillek VERSION 0.1 DESCRIPTION "Trillek Game Engine" LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) diff --git a/README.md b/README.md index 00b050c7..44b7f4af 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,24 @@ Install the following. This is a pretty extensive list and may be more than need * `ninja-multi-vcpkg-debug` - Debug configuration test preset * `ninja-multi-vcpkg-release` - Release configuration test preset +# Configuration +The client can be configured using a Lua configuration file at `assets/scripts/config.lua`. If the file doesn't exist, default values will be used. + +## Auto-Connect for Local Development +For local development, you can enable automatic connection to a local server by setting the following in your config file: + +```lua +-- Window settings +window_width = 1024 +window_height = 768 + +-- Auto-connect settings (for local development) +auto_connect = true +default_username = "player" +``` + +When `auto_connect` is enabled and `default_username` is set, the client will automatically connect to `localhost` on startup, eliminating the need to manually enter credentials each time. If auto-connect fails, the connection window will be shown as normal. + # Documentation Documentation is done via Doxygen for C++ code and supplementary docs must be maintained for the Lua API in `docs/`. diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 3652aec2..c6f7fe46 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -8,6 +8,7 @@ add_interface_lib( TARGET ${CLIENT_LIB_NAME} FILE_LIST + client-app.cpp game.cpp imgui-system.cpp client-game-state-queue.cpp diff --git a/client/client-app.cpp b/client/client-app.cpp new file mode 100644 index 00000000..172a24af --- /dev/null +++ b/client/client-app.cpp @@ -0,0 +1,297 @@ +#include "client-app.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "events.hpp" +#include "filesystem.hpp" +#include "net-message.hpp" +#include "resources/md5anim.hpp" +#include "resources/md5mesh.hpp" +#include "resources/obj.hpp" +#include "resources/script-file.hpp" +#include "resources/vorbis-stream.hpp" +#include "server-connection.hpp" + +namespace tec { + +void BuildTestVoxelVolume(); + +namespace { + +void RegisterFileFactories() { + AddFileFactory(); + AddFileFactory(); + AddFileFactory(); + AddFileFactory(); + AddFileFactory(); +} + +std::string CalculateAspectRatioString(unsigned int window_width, unsigned int window_height) { + double ratio = static_cast(window_width) / static_cast(window_height); + double intVal = std::floor(ratio); + double precision = 1000; + double fraction = std::round((ratio - intVal) * precision); + double gcd = std::gcd(static_cast(fraction), static_cast(precision)); + double numer = fraction / gcd; + double denom = precision / gcd; + + std::ostringstream aspect_ratio; + aspect_ratio << static_cast(std::round((intVal * denom) + numer)) << ":" + << static_cast(std::round(denom)); + return aspect_ratio.str(); +} + +} // anonymous namespace + +ClientApp::ClientApp(int argc, char* argv[]) { + auto log_level = ParseLogLevel(argc, argv); + InitializeLogger(log_level); + + log_->info("Asset path: {}", Path::GetAssetsBasePath()); + + game_ = std::make_unique(os_); + LoadConfiguration(); + InitializeWindow(); + InitializeGame(); + InitializeGUI(); + RegisterConsoleCommands(); + SetupAutoConnect(); + RegisterGUIWindows(); + + RegisterFileFactories(); + BuildTestVoxelVolume(); +} + +spdlog::level::level_enum ClientApp::ParseLogLevel(int argc, char* argv[]) { + auto log_level = spdlog::level::info; + for (int i = 1; i < argc; i++) { + if (std::string(argv[i]) == "-v") { + log_level = spdlog::level::debug; + } + else if (std::string(argv[i]) == "-vv") { + log_level = spdlog::level::trace; + } + } + return log_level; +} + +void ClientApp::InitializeLogger(spdlog::level::level_enum log_level) { + std::vector sinks; + sinks.push_back(std::make_shared()); + sinks.push_back(std::make_shared(console_)); + log_ = std::make_shared("console_log", begin(sinks), end(sinks)); + log_->set_level(log_level); + log_->set_pattern("%v"); + spdlog::register_logger(log_); +} + +void ClientApp::LoadConfiguration() { + window_width_ = game_->config_script->environment.get_or("window_width", WINDOW_WIDTH); + window_height_ = game_->config_script->environment.get_or("window_height", WINDOW_HEIGHT); + default_username_ = game_->config_script->environment.get_or("default_username", std::string("")); + auto_connect_ = game_->config_script->environment.get_or("auto_connect", false); +} + +void ClientApp::InitializeWindow() { + log_->info("Initializing OpenGL..."); + if (!os_.InitializeWindow(window_width_, window_height_, "Trillek Engine 0.14", 4, 0)) { + log_->warn("The OpenGL 4.0 context wasn't created properly, attempting fallback"); + if (!os_.InitializeWindow(window_width_, window_height_, "Trillek Engine 0.14", 3, 3)) { + log_->error("Exiting. Can not create OpenGL 4.0 or 3.3 context. please update drivers and try again."); + exit(1); + } + } + + const std::string default_aspect_ratio = CalculateAspectRatioString(window_width_, window_height_); + const std::string aspect_ratio = game_->config_script->environment.get_or("aspect_ratio", default_aspect_ratio); + auto numer = stoi(aspect_ratio.substr(0, aspect_ratio.find(':'))); + auto denom = stoi(aspect_ratio.substr(aspect_ratio.find(':') + 1)); + os_.SetWindowAspectRatio(numer, denom); +} + +void ClientApp::InitializeGame() { + console_.AddConsoleCommand("exit", "exit : Exit from TEC", [this](const std::string&) { os_.Quit(); }); + game_->Startup(console_); +} + +void ClientApp::InitializeGUI() { + log_->info("Initializing GUI system..."); + gui_ = std::make_unique(os_.GetWindow()); + gui_->CreateGUI(); + + // Create GUI windows + auto& connection = game_->GetServerConnection(); + active_entity_tooltip_ = std::make_unique(*game_); + server_connect_window_ = std::make_unique(connection); + ping_times_window_ = std::make_unique(connection); + debug_info_window_ = std::make_unique(*game_); + + ServerConnectWindow::SetUsername(default_username_); +} + +void ClientApp::RegisterConsoleCommands() { + auto& connection = game_->GetServerConnection(); + auto* lua_sys = game_->GetLuaSystem(); + + console_.AddConsoleCommand("msg", "msg : Send a message to all clients.", + [&connection](const std::string& message) { + connection.SendChatMessage(message); + }); + + console_.AddConsoleCommand("lua", "lua : Execute a string in lua", + [lua_sys](const std::string& message) { + lua_sys->ExecuteString(message); + }); + + console_.AddConsoleCommand( + "connect", + "connect [username][ip] : Connect to a server [ip] with the provided [username]", + [&connection](const std::string& args) { + std::vector splitArgs = SplitString(args); + if (splitArgs.size() >= 2) { + connection.Connect(splitArgs[1]); + std::string username = splitArgs[0]; + connection.RegisterConnectFunc([&connection, username]() { + proto::UserLogin user_login; + user_login.set_username(username); + user_login.set_password(""); + networking::MessageOut msg(networking::LOGIN); + user_login.SerializeToZeroCopyStream(&msg); + connection.Send(msg); + }); + } + }); + + console_.AddSlashHandler([&connection](const std::string& chat_command_message) { + std::size_t argument_break_offset = chat_command_message.find_first_of(" "); + auto data = std::make_shared(); + data->command = chat_command_message.substr(0, argument_break_offset); + + if (argument_break_offset < chat_command_message.size()) { + std::string command_args = chat_command_message.substr(argument_break_offset + 1); + data->args = SplitString(command_args); + } + EventSystem::Get()->Emit(data); + + if (connection.GetClientID() != 0) { + proto::ChatCommand chat_command(data->Out()); + networking::MessageOut msg(networking::CHAT_COMMAND); + chat_command.SerializeToZeroCopyStream(&msg); + connection.Send(msg); + } + }); + + lua_sys->GetGlobalState().set("OS", &os_); +} + +void ClientApp::SetupAutoConnect() { + auto& connection = game_->GetServerConnection(); + + if (auto_connect_ && !default_username_.empty()) { + log_->info("Auto-connecting to localhost as '{}'", default_username_); + + // Register handlers before connecting to avoid race condition + connection.RegisterConnectFunc([&connection, username = default_username_, log = log_]() { + proto::UserLogin user_login; + user_login.set_username(username); + user_login.set_password(""); + networking::MessageOut msg(networking::LOGIN); + user_login.SerializeToZeroCopyStream(&msg); + connection.Send(msg); + log->info("Auto-login sent for user '{}'", username); + }); + + // Hide the connect window on successful AUTHENTICATED message + std::string window_name = server_connect_window_->GetWindowName(); + connection.RegisterMessageHandler( + networking::MessageType::AUTHENTICATED, + [gui = gui_.get(), window_name, log = log_](networking::MessageIn&) { + log->info("Auto-connect authentication successful"); + gui->HideWindow(window_name); + }); + + if (!connection.Connect(networking::LOCAL_HOST)) { + log_->warn("Auto-connect failed, showing connect window"); + gui_->ShowWindow(server_connect_window_->GetWindowName()); + } + } + else { + gui_->ShowWindow(server_connect_window_->GetWindowName()); + } +} + +void ClientApp::RegisterGUIWindows() { + auto& connection = game_->GetServerConnection(); + + gui_->AddWindowDrawFunction(server_connect_window_->GetWindowName(), + [window = server_connect_window_.get(), gui = gui_.get()]() { + window->Draw(gui); + }); + + gui_->AddWindowDrawFunction(ping_times_window_->GetWindowName(), + [window = ping_times_window_.get(), gui = gui_.get()]() { + window->Draw(gui); + }); + + gui_->AddWindowDrawFunction(console_.GetWindowName(), + [console = &console_, gui = gui_.get()]() { + console->Draw(gui); + }); + gui_->ShowWindow(console_.GetWindowName()); + + gui_->AddWindowDrawFunction(active_entity_tooltip_->GetWindowName(), + [window = active_entity_tooltip_.get(), gui = gui_.get()]() { + window->Draw(gui); + }); + gui_->ShowWindow(active_entity_tooltip_->GetWindowName()); + + gui_->AddWindowDrawFunction(debug_info_window_->GetWindowName(), + [window = debug_info_window_.get(), gui = gui_.get()]() { + window->Draw(gui); + }); + + connection.RegisterMessageHandler( + networking::MessageType::CLIENT_ID, + [gui = gui_.get(), window = ping_times_window_.get(), log = log_](networking::MessageIn& message) { + std::string client_id = message.ToString(); + log->info("You are connected as client ID {}", client_id); + gui->ShowWindow(window->GetWindowName()); + }); +} + +int ClientApp::Run() { + os_.DetachContext(); + + std::thread gameThread([this]() { + os_.MakeCurrent(); + + while (!os_.Closing()) { + const double delta = os_.GetDeltaTime(); + + game_->Update(delta); + gui_->Update(delta); + console_.Update(delta); + os_.SwapBuffers(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + }); + + while (!os_.Closing()) { + os_.OSMessageLoop(); + } + + gameThread.join(); + OS::Terminate(); + + return 0; +} + +} // namespace tec diff --git a/client/client-app.hpp b/client/client-app.hpp new file mode 100644 index 00000000..8d3659da --- /dev/null +++ b/client/client-app.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include +#include + +#include +#include + +#include "game.hpp" +#include "gui/active-entity-tooltip.hpp" +#include "gui/console.hpp" +#include "gui/debug-info.hpp" +#include "gui/server-connect.hpp" +#include "imgui-system.hpp" +#include "os.hpp" + +namespace tec { + +/** + * @brief Main client application class that manages initialization and lifecycle + */ +class ClientApp { +public: + ClientApp(int argc, char* argv[]); + ~ClientApp() = default; + + // Run the application main loop + int Run(); + +private: + // Initialization methods + void InitializeLogger(spdlog::level::level_enum log_level); + void InitializeWindow(); + void InitializeGame(); + void InitializeGUI(); + void RegisterConsoleCommands(); + void SetupAutoConnect(); + void RegisterGUIWindows(); + + // Configuration + spdlog::level::level_enum ParseLogLevel(int argc, char* argv[]); + void LoadConfiguration(); + + // Member variables + Console console_; + OS os_; + std::shared_ptr log_; + std::unique_ptr game_; + std::unique_ptr gui_; + + // GUI windows + std::unique_ptr active_entity_tooltip_; + std::unique_ptr server_connect_window_; + std::unique_ptr ping_times_window_; + std::unique_ptr debug_info_window_; + + // Configuration values + std::string default_username_; + bool auto_connect_ = false; + unsigned int window_width_ = WINDOW_WIDTH; + unsigned int window_height_ = WINDOW_HEIGHT; +}; + +} // namespace tec diff --git a/client/imgui-system.cpp b/client/imgui-system.cpp index b23ef86d..ba2bdcdf 100644 --- a/client/imgui-system.cpp +++ b/client/imgui-system.cpp @@ -37,25 +37,6 @@ IMGUISystem::IMGUISystem(GLFWwindow* _window) { io.LogFilename = logfilename.c_str(); #endif - // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. - io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; - io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; - io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; - io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; - io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; - io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; - io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; - io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; - io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; - io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; - io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; - io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; - io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; - io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; - io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; - io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; - io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; - io.SetClipboardTextFn = SetClipboardText; io.GetClipboardTextFn = GetClipboardText; @@ -64,6 +45,9 @@ IMGUISystem::IMGUISystem(GLFWwindow* _window) { if (!IMGUISystem::font_texture) { CreateDeviceObjects(); } + + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init(); } IMGUISystem::~IMGUISystem() { @@ -92,6 +76,8 @@ IMGUISystem::~IMGUISystem() { ImGui::GetIO().Fonts->TexID = 0; font_texture = 0; } + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); } @@ -282,7 +268,7 @@ void IMGUISystem::CreateDeviceObjects() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Store our identifier - io.Fonts->TexID = (void*)(intptr_t)font_texture; + io.Fonts->TexID = font_texture; // Cleanup (don't clear the input data if you want to append new fonts later) io.Fonts->ClearInputData(); @@ -424,10 +410,10 @@ void IMGUISystem::On(eid, std::shared_ptr data) { void IMGUISystem::On(eid, std::shared_ptr data) { auto& io = ImGui::GetIO(); if (data->action == KeyboardEvent::KEY_DOWN) { - io.KeysDown[data->key] = true; + io.KeysData[data->key].Down = true; } else if (data->action == KeyboardEvent::KEY_UP) { - io.KeysDown[data->key] = false; + io.KeysData[data->key].Down = false; } if (data->action == KeyboardEvent::KEY_CHAR) { @@ -438,8 +424,8 @@ void IMGUISystem::On(eid, std::shared_ptr data) { } (void)data->mods; // Modifiers are not reliable across systems - io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; - io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; - io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; + io.KeyCtrl = io.KeysData[GLFW_KEY_LEFT_CONTROL].Down || io.KeysData[GLFW_KEY_RIGHT_CONTROL].Down; + io.KeyShift = io.KeysData[GLFW_KEY_LEFT_SHIFT].Down || io.KeysData[GLFW_KEY_RIGHT_SHIFT].Down; + io.KeyAlt = io.KeysData[GLFW_KEY_LEFT_ALT].Down || io.KeysData[GLFW_KEY_RIGHT_ALT].Down; } } // end namespace tec diff --git a/client/imgui-system.hpp b/client/imgui-system.hpp index c051c0e1..50f18f1d 100644 --- a/client/imgui-system.hpp +++ b/client/imgui-system.hpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "command-queue.hpp" #include "event-system.hpp" diff --git a/client/main.cpp b/client/main.cpp index ee6115ef..e1290b71 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -1,226 +1,11 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "filesystem.hpp" -#include "game.hpp" -#include "gui/active-entity-tooltip.hpp" -#include "gui/console.hpp" -#include "gui/debug-info.hpp" -#include "gui/server-connect.hpp" -#include "imgui-system.hpp" -#include "net-message.hpp" -#include "os.hpp" -#include "resources/md5anim.hpp" -#include "resources/md5mesh.hpp" -#include "resources/obj.hpp" -#include "resources/script-file.hpp" -#include "resources/vorbis-stream.hpp" -#include "server-connection.hpp" +#include "client-app.hpp" namespace tec { -void RegisterFileFactories() { - AddFileFactory(); - AddFileFactory(); - AddFileFactory(); - AddFileFactory(); - AddFileFactory(); -} +// Forward declaration for external linkage void BuildTestVoxelVolume(); } // namespace tec -auto InitializeLogger(spdlog::level::level_enum log_level, tec::Console& console) { - std::vector sinks; - sinks.push_back(std::make_shared()); - sinks.push_back(std::make_shared(console)); - auto log = std::make_shared("console_log", begin(sinks), end(sinks)); - log->set_level(log_level); - log->set_pattern("%v"); // [%l] [thread %t] %v"); // Format on stdout - spdlog::register_logger(log); - return log; -} - -// TODO write a proper arguments parser -// Now only search for -v or -vv to set log level -auto ParseLogLevel(int argc, char* argv[]) { - auto log_level = spdlog::level::info; - for (int i = 1; i < argc; i++) { - if (std::string(argv[i]) == "-v") { - log_level = spdlog::level::debug; - } - else if (std::string(argv[i]) == "-vv") { - log_level = spdlog::level::trace; - } - } - return log_level; -} - -/** - * \brief Finds an approximate aspect ratio - * Adapted from - * https://www.geeksforgeeks.org/convert-given-decimal-number-into-an-irreducible-fraction/ Could be - * further enhanced to compare values against a known set of ratios to find the best match \return - * std:string The aspect ratio in the form of "A:B" - */ -std::string CalculateAspectRatioString(const unsigned int window_width, const unsigned int window_height) { - double ratio = static_cast(window_width) / static_cast(window_height); - double intVal = std::floor(ratio); - double precision = 1000; - double fraction = std::round((ratio - intVal) * precision); - double gcd = std::gcd(static_cast(fraction), static_cast(precision)); - double numer = fraction / gcd; - double denom = precision / gcd; - - std::ostringstream aspect_ratio; - aspect_ratio << static_cast(std::round((intVal * denom) + numer)) << ":" - << static_cast(std::round(denom)); - return aspect_ratio.str(); -} - int main(int argc, char* argv[]) { - tec::Console console; - tec::OS os; - - auto log = InitializeLogger(ParseLogLevel(argc, argv), console); - - log->info("Asset path: {}", tec::Path::GetAssetsBasePath()); - - tec::Game game(os); - - const unsigned int window_width = game.config_script->environment.get_or("window_width", WINDOW_WIDTH); - const unsigned int window_height = game.config_script->environment.get_or("window_height", WINDOW_HEIGHT); - std::string window_title = "Trillek Engine 0.14"; - - log->info("Initializing OpenGL..."); - if (!os.InitializeWindow(window_width, window_height, window_title, 4, 0)) { - log->warn("The OpenGL 4.0 context wasn't created properly, attempting fallback"); - if (!os.InitializeWindow(window_width, window_height, window_title, 3, 3)) { - log->error("Exiting. Can not create OpenGL 4.0 or 3.3 context. please update drivers and try again."); - exit(1); - } - } - - const std::string default_aspect_ratio = CalculateAspectRatioString(window_width, window_height); - const std::string aspect_ratio = game.config_script->environment.get_or("aspect_ratio", default_aspect_ratio); - auto numer = stoi(aspect_ratio.substr(0, aspect_ratio.find(':'))); - auto denom = stoi(aspect_ratio.substr(aspect_ratio.find(':') + 1)); - os.SetWindowAspectRatio(numer, denom); - console.AddConsoleCommand("exit", "exit : Exit from TEC", [&os](const std::string&) { os.Quit(); }); - game.Startup(console); - - tec::ActiveEntityTooltip active_entity_tooltip(game); - tec::networking::ServerConnection& connection = game.GetServerConnection(); - tec::ServerConnectWindow server_connect_window(connection); - tec::PingTimesWindow ping_times_window(connection); - tec::DebugInfo debug_info_window(game); - tec::ServerConnectWindow::SetUsername(game.config_script->environment.get_or("default_username", std::string(""))); - - console.AddConsoleCommand("msg", "msg : Send a message to all clients.", [&connection](const std::string& message) { - connection.SendChatMessage(message); - }); - - log->info("Initializing GUI system..."); - tec::IMGUISystem gui(os.GetWindow()); - gui.CreateGUI(); - gui.AddWindowDrawFunction(server_connect_window.GetWindowName(), [&server_connect_window, &gui]() { - server_connect_window.Draw(&gui); - }); - gui.ShowWindow(server_connect_window.GetWindowName()); - gui.AddWindowDrawFunction( - ping_times_window.GetWindowName(), [&ping_times_window, &gui]() { ping_times_window.Draw(&gui); }); - gui.AddWindowDrawFunction(console.GetWindowName(), [&console, &gui]() { console.Draw(&gui); }); - gui.ShowWindow(console.GetWindowName()); - gui.AddWindowDrawFunction(active_entity_tooltip.GetWindowName(), [&active_entity_tooltip, &gui]() { - active_entity_tooltip.Draw(&gui); - }); - gui.ShowWindow(active_entity_tooltip.GetWindowName()); - gui.AddWindowDrawFunction( - debug_info_window.GetWindowName(), [&debug_info_window, &gui]() { debug_info_window.Draw(&gui); }); - - connection.RegisterMessageHandler( - tec::networking::MessageType::CLIENT_ID, - [&gui, &ping_times_window, &log](tec::networking::MessageIn& message) { - std::string client_id = message.ToString(); - log->info("You are connected as client ID {}", client_id); - gui.ShowWindow(ping_times_window.GetWindowName()); - }); - - tec::LuaSystem* lua_sys = game.GetLuaSystem(); - lua_sys->GetGlobalState().set("OS", &os); // register instance - - tec::RegisterFileFactories(); - tec::BuildTestVoxelVolume(); - - console.AddConsoleCommand("lua", "lua : Execute a string in lua", [&lua_sys](const std::string& message) { - lua_sys->ExecuteString(message); - }); - console.AddConsoleCommand( - "connect", - "connect [username][ip] : Connect to a server [ip] with the provided [username]", - [&connection](const std::string& args) { - std::vector splitArgs = tec::SplitString(args); - if (splitArgs.size() >= 2) { - connection.Connect(splitArgs[1]); - std::string username = splitArgs[0]; - connection.RegisterConnectFunc([&connection, username]() { - tec::proto::UserLogin user_login; - user_login.set_username(username); - user_login.set_password(""); - tec::networking::MessageOut msg(tec::networking::LOGIN); - user_login.SerializeToZeroCopyStream(&msg); - connection.Send(msg); - }); - } - }); - console.AddSlashHandler([&connection](const std::string& chat_command_message) { - std::size_t argument_break_offset = chat_command_message.find_first_of(" "); - std::shared_ptr data = std::make_shared(); - data->command = chat_command_message.substr(0, argument_break_offset); - - if (argument_break_offset < chat_command_message.size()) { - std::string command_args = chat_command_message.substr(argument_break_offset + 1); - data->args = tec::SplitString(command_args); - } - tec::EventSystem::Get()->Emit(data); // Handle command locally - - if (connection.GetClientID() != 0) { // If connected, send command to server - tec::proto::ChatCommand chat_command(data->Out()); - tec::networking::MessageOut msg(tec::networking::CHAT_COMMAND); - chat_command.SerializeToZeroCopyStream(&msg); - connection.Send(msg); - } - }); - - os.DetachContext(); - - std::thread gameThread([&]() { - os.MakeCurrent(); - - while (!os.Closing()) { - const double delta = os.GetDeltaTime(); - - game.Update(delta); - gui.Update(delta); - console.Update(delta); - os.SwapBuffers(); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - }); - - while (!os.Closing()) { - os.OSMessageLoop(); - } - - gameThread.join(); - tec::OS::Terminate(); - - return 0; + tec::ClientApp app(argc, argv); + return app.Run(); } diff --git a/vcpkg.json b/vcpkg.json index e71ab0ac..7a06cb0b 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -12,11 +12,14 @@ "openal-soft", "protobuf", "zlib", - "imgui", + { + "name": "imgui", + "features":["glfw-binding","opengl3-binding"] + }, "spdlog", "sol2", "gtest" ], "supports": "(windows & x86) | (windows & x64) | (linux & x64) | (osx & x64)", - "builtin-baseline": "10b7a178346f3f0abef60cecd5130e295afd8da4" + "builtin-baseline": "dd3097e305afa53f7b4312371f62058d2e665320" }