mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
feat(app): add client/server CLI arguments and init guards
This commit is contained in:
@@ -12,6 +12,12 @@ namespace Cubed {
|
||||
|
||||
class App {
|
||||
public:
|
||||
struct Argument {
|
||||
bool is_client = false;
|
||||
int port = 25530;
|
||||
std::string ip{"127.0.0.1"};
|
||||
};
|
||||
|
||||
App();
|
||||
~App();
|
||||
static void cursor_position_callback(GLFWwindow* window, double xpos,
|
||||
@@ -60,9 +66,9 @@ private:
|
||||
inline static double fps_time_count = 0.0f;
|
||||
inline static int frame_count = 0;
|
||||
inline static int fps = 0;
|
||||
|
||||
void init();
|
||||
|
||||
Argument m_argument;
|
||||
void init(int argc, char** argv);
|
||||
void handle_argument(int argc, char** argv);
|
||||
auto init_camera();
|
||||
auto init_texture();
|
||||
auto init_world();
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
void send(Packet packet);
|
||||
void start(std::string ip, int port = 25530);
|
||||
bool is_connected() const;
|
||||
bool is_connect_error() const;
|
||||
|
||||
private:
|
||||
asio::io_context m_io;
|
||||
@@ -32,6 +33,7 @@ private:
|
||||
|
||||
std::atomic<bool> m_closed{false};
|
||||
std::atomic<bool> m_connected{false};
|
||||
std::atomic<bool> m_connect_error{false};
|
||||
// ClientWorld is managed by App
|
||||
ClientWorld& m_world;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
void stop();
|
||||
|
||||
// Run in another thread after initialization is complete
|
||||
void start_server();
|
||||
void start_server(int port = 25530);
|
||||
|
||||
int port() const;
|
||||
ServerWorld& server_world();
|
||||
@@ -23,6 +23,7 @@ private:
|
||||
std::thread m_net_thread;
|
||||
int m_port = 25530;
|
||||
std::atomic<bool> m_stopped{false};
|
||||
std::atomic<bool> m_started{false};
|
||||
ServerWorld m_world;
|
||||
std::mutex m_session_mutex;
|
||||
std::unordered_map<std::string, std::shared_ptr<Session>> m_session;
|
||||
|
||||
@@ -112,6 +112,7 @@ private:
|
||||
std::atomic<bool> m_gen_running{false};
|
||||
std::atomic<bool> m_need_gen_chunk{false};
|
||||
std::atomic<bool> m_is_rebuilding{false};
|
||||
std::atomic<bool> m_init{false};
|
||||
std::atomic<int> m_rendering_distance{24};
|
||||
std::atomic<int> m_pool_threads{0};
|
||||
std::atomic<int> m_max_threads{1};
|
||||
|
||||
@@ -99,6 +99,9 @@ private:
|
||||
bool m_water_depth_fade = true;
|
||||
bool m_pbr = true;
|
||||
bool m_flip_y = false;
|
||||
|
||||
bool m_init = false;
|
||||
|
||||
int m_shadow_mode = 0;
|
||||
int m_light_cull_face = 0;
|
||||
float m_aspect = 0.0f;
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Cubed {
|
||||
class TextureManager {
|
||||
private:
|
||||
bool m_need_reload = false;
|
||||
bool m_init = false;
|
||||
GLuint m_block_status_array = 0;
|
||||
GLuint m_texture_array = 0;
|
||||
GLuint m_cross_plane_array = 0;
|
||||
|
||||
35
include/Cubed/tools/arg_parser.hpp
Normal file
35
include/Cubed/tools/arg_parser.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
|
||||
namespace Cubed {
|
||||
class ArgParser {
|
||||
public:
|
||||
ArgParser(int argc, char** argv) : m_args(argv, argc) {};
|
||||
ArgParser(std::span<char*> args) : m_args(args) {}
|
||||
|
||||
bool has_next() const { return m_index < m_args.size(); }
|
||||
|
||||
std::string_view next() {
|
||||
if (!has_next()) {
|
||||
throw std::runtime_error("No more arguments");
|
||||
}
|
||||
return m_args[m_index++];
|
||||
}
|
||||
|
||||
std::string_view require_next(std::string_view option) {
|
||||
if (!has_next()) {
|
||||
throw std::runtime_error(
|
||||
std::format("{} requires an argument", option));
|
||||
}
|
||||
return next();
|
||||
}
|
||||
|
||||
private:
|
||||
std::span<char*> m_args;
|
||||
size_t m_index = 1;
|
||||
};
|
||||
} // namespace Cubed
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
|
||||
private:
|
||||
bool m_mouse_enable = false;
|
||||
bool m_imgui_init = false;
|
||||
float m_aspect;
|
||||
GLFWwindow* m_window;
|
||||
int m_width;
|
||||
|
||||
63
src/app.cpp
63
src/app.cpp
@@ -2,13 +2,13 @@
|
||||
|
||||
#include "Cubed/config.hpp"
|
||||
#include "Cubed/debug_collector.hpp"
|
||||
#include "Cubed/tools/arg_parser.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
#include "Cubed/tools/system_info.hpp"
|
||||
|
||||
#include <exception>
|
||||
#include <imgui_impl_glfw.h>
|
||||
|
||||
namespace Cubed {
|
||||
|
||||
App::App() {}
|
||||
@@ -33,9 +33,11 @@ void App::cursor_position_callback(GLFWwindow* window, double xpos,
|
||||
app->m_camera.update_cursor_position_camera(xpos, ypos);
|
||||
}
|
||||
}
|
||||
void App::init() {
|
||||
void App::init(int argc, char** argv) {
|
||||
handle_argument(argc, argv);
|
||||
m_window.init();
|
||||
m_window.imgui_init();
|
||||
|
||||
Logger::info("Window Init Success");
|
||||
|
||||
glfwSetWindowUserPointer(m_window.get_glfw_window(), this);
|
||||
@@ -53,6 +55,7 @@ void App::init() {
|
||||
glfwSetCursorEnterCallback(m_window.get_glfw_window(),
|
||||
cursor_enter_callback);
|
||||
glfwSetCharCallback(m_window.get_glfw_window(), char_callback);
|
||||
|
||||
ChunkGenerator::init();
|
||||
BlockManager::init();
|
||||
m_renderer.init();
|
||||
@@ -61,12 +64,13 @@ void App::init() {
|
||||
// MapTable::init_map();
|
||||
m_texture_manager.init_texture();
|
||||
Logger::info("Texture Load Success");
|
||||
|
||||
m_server.start_server();
|
||||
if (!m_argument.is_client) {
|
||||
m_server.start_server(m_argument.port);
|
||||
}
|
||||
|
||||
m_client = std::make_shared<NetworkClient>(m_client_world);
|
||||
|
||||
m_client->start("127.0.0.1", 25530);
|
||||
m_client->start(m_argument.ip, m_argument.port);
|
||||
// init will send packet
|
||||
m_client_world.init("test", m_client);
|
||||
|
||||
@@ -76,6 +80,53 @@ void App::init() {
|
||||
m_dev_panel.init();
|
||||
}
|
||||
|
||||
void App::handle_argument(int argc, char** argv) {
|
||||
|
||||
static const std::unordered_map<std::string_view,
|
||||
std::function<void(ArgParser&)>>
|
||||
HANDLERS{
|
||||
|
||||
{"--client", [&](ArgParser&) { m_argument.is_client = true; }},
|
||||
|
||||
{"--host", [&](ArgParser&) { m_argument.is_client = false; }},
|
||||
|
||||
{"-p",
|
||||
[&](ArgParser& p) {
|
||||
auto arg = p.require_next("-p");
|
||||
|
||||
auto r =
|
||||
std::from_chars(arg.begin(), arg.end(), m_argument.port);
|
||||
|
||||
if (r.ec != std::errc{} || r.ptr != arg.end()) {
|
||||
throw std::runtime_error(
|
||||
std::format("Invalid port: {}", arg));
|
||||
}
|
||||
|
||||
if (m_argument.port > 65535) {
|
||||
throw std::runtime_error(
|
||||
std::format("Port {} out of range", m_argument.port));
|
||||
}
|
||||
}},
|
||||
|
||||
{"--ip",
|
||||
[&](ArgParser& p) {
|
||||
auto arg = p.require_next("--ip");
|
||||
m_argument.ip = arg;
|
||||
}}
|
||||
|
||||
};
|
||||
ArgParser parser(argc, argv);
|
||||
|
||||
while (parser.has_next()) {
|
||||
auto arg = parser.next();
|
||||
if (auto it = HANDLERS.find(arg); it != HANDLERS.end()) {
|
||||
it->second(parser);
|
||||
} else {
|
||||
Logger::warn("Unknown argument: {}", arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void App::key_callback(GLFWwindow* window, int key, int scancode, int action,
|
||||
int mods) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
@@ -276,7 +327,7 @@ int App::start_cubed_application(int argc, char** argv) {
|
||||
App app;
|
||||
|
||||
try {
|
||||
app.init();
|
||||
app.init(argc, argv);
|
||||
Logger::info("Game Init Finish Start Run...");
|
||||
app.run();
|
||||
|
||||
|
||||
@@ -200,6 +200,9 @@ void ClientWorld::init(std::string_view player_name,
|
||||
LoginReq req;
|
||||
req.set_name(m_player.get_name());
|
||||
while (!client->is_connected()) {
|
||||
if (client->is_connect_error()) {
|
||||
throw std::runtime_error("Can't connect to the server");
|
||||
}
|
||||
std::this_thread::sleep_for(milliseconds(200));
|
||||
}
|
||||
// request login
|
||||
|
||||
@@ -20,7 +20,7 @@ void NetworkClient::start(std::string ip, int port) {
|
||||
}
|
||||
|
||||
bool NetworkClient::is_connected() const { return m_connected.load(); }
|
||||
|
||||
bool NetworkClient::is_connect_error() const { return m_connect_error.load(); }
|
||||
asio::awaitable<void> NetworkClient::connect(std::string ip, int port) {
|
||||
Logger::info("Connect Begin");
|
||||
try {
|
||||
@@ -38,6 +38,7 @@ asio::awaitable<void> NetworkClient::connect(std::string ip, int port) {
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
Logger::error("Client Error {}", e.what());
|
||||
m_connect_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ NetworkServer::NetworkServer(int port) : m_port(port) {}
|
||||
NetworkServer::~NetworkServer() { stop(); }
|
||||
|
||||
void NetworkServer::stop() {
|
||||
if (!m_started) {
|
||||
return;
|
||||
}
|
||||
if (m_stopped.exchange(true)) {
|
||||
return;
|
||||
}
|
||||
@@ -79,9 +82,10 @@ void NetworkServer::net_run() {
|
||||
Logger::info("Server Started!");
|
||||
}
|
||||
|
||||
void NetworkServer::start_server() {
|
||||
void NetworkServer::start_server(int port) {
|
||||
m_world.init_world();
|
||||
net_run();
|
||||
m_started = true;
|
||||
}
|
||||
|
||||
int NetworkServer::port() const { return m_port; }
|
||||
|
||||
@@ -15,6 +15,9 @@ namespace Cubed {
|
||||
ServerWorld::ServerWorld() {}
|
||||
|
||||
ServerWorld::~ServerWorld() {
|
||||
if (!m_init) {
|
||||
return;
|
||||
}
|
||||
stop_gen_thread();
|
||||
stop_server_thread();
|
||||
wait_all_chunk_tasks();
|
||||
@@ -60,6 +63,7 @@ void ServerWorld::init_world() {
|
||||
Logger::info("Chunk Block Init Finish, Time Consuming: {}", d);
|
||||
|
||||
start_server_thread();
|
||||
m_init = true;
|
||||
}
|
||||
|
||||
void ServerWorld::init_chunks() { hot_reload(); }
|
||||
|
||||
@@ -27,25 +27,27 @@ Renderer::Renderer(const Camera& camera, ClientWorld& world,
|
||||
m_texture_manager(texture_manager), m_world(world) {}
|
||||
|
||||
Renderer::~Renderer() {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glDeleteBuffers(1, &m_outline_vbo);
|
||||
glDeleteBuffers(1, &m_outline_indices_vbo);
|
||||
glDeleteBuffers(1, &m_sky_vbo);
|
||||
glDeleteBuffers(1, &m_ui_vbo);
|
||||
glDeleteBuffers(1, &m_text_vbo);
|
||||
glBindVertexArray(0);
|
||||
glDeleteVertexArrays(NUM_VAO, m_vao.data());
|
||||
glDeleteFramebuffers(1, &m_fbo);
|
||||
glDeleteTextures(1, &m_screen_texture);
|
||||
glDeleteTextures(1, &m_screen_depth_texture);
|
||||
if (m_init) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glDeleteBuffers(1, &m_outline_vbo);
|
||||
glDeleteBuffers(1, &m_outline_indices_vbo);
|
||||
glDeleteBuffers(1, &m_sky_vbo);
|
||||
glDeleteBuffers(1, &m_ui_vbo);
|
||||
glDeleteBuffers(1, &m_text_vbo);
|
||||
glBindVertexArray(0);
|
||||
glDeleteVertexArrays(NUM_VAO, m_vao.data());
|
||||
glDeleteFramebuffers(1, &m_fbo);
|
||||
glDeleteTextures(1, &m_screen_texture);
|
||||
glDeleteTextures(1, &m_screen_depth_texture);
|
||||
|
||||
glDeleteFramebuffers(1, &m_oit_fbo);
|
||||
glDeleteTextures(1, &m_accum_texture);
|
||||
glDeleteTextures(1, &m_reveal_texture);
|
||||
glDeleteTextures(1, &m_oit_depth_texture);
|
||||
glDeleteFramebuffers(1, &m_oit_fbo);
|
||||
glDeleteTextures(1, &m_accum_texture);
|
||||
glDeleteTextures(1, &m_reveal_texture);
|
||||
glDeleteTextures(1, &m_oit_depth_texture);
|
||||
|
||||
glDeleteFramebuffers(1, &m_depth_map_fbo);
|
||||
glDeleteTextures(1, &m_depth_map_texture);
|
||||
glDeleteFramebuffers(1, &m_depth_map_fbo);
|
||||
glDeleteTextures(1, &m_depth_map_texture);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::hot_reload() {
|
||||
@@ -171,6 +173,7 @@ void Renderer::init() {
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
m_init = true;
|
||||
}
|
||||
|
||||
const Shader& Renderer::get_shader(const std::string& name) const {
|
||||
|
||||
@@ -36,14 +36,16 @@ TextureManager::TextureManager() {}
|
||||
TextureManager::~TextureManager() { delet_texture(); }
|
||||
|
||||
void TextureManager::delet_texture() {
|
||||
glDeleteTextures(1, &m_texture_array);
|
||||
glDeleteTextures(1, &m_block_status_array);
|
||||
glDeleteTextures(1, &m_cross_plane_array);
|
||||
glDeleteTextures(1, &m_normal_texture_array);
|
||||
for (auto& id : m_item_textures) {
|
||||
glDeleteTextures(1, &id);
|
||||
if (m_init) {
|
||||
glDeleteTextures(1, &m_texture_array);
|
||||
glDeleteTextures(1, &m_block_status_array);
|
||||
glDeleteTextures(1, &m_cross_plane_array);
|
||||
glDeleteTextures(1, &m_normal_texture_array);
|
||||
for (auto& id : m_item_textures) {
|
||||
glDeleteTextures(1, &id);
|
||||
}
|
||||
Logger::info("Successfully delete all texture");
|
||||
}
|
||||
Logger::info("Successfully delete all texture");
|
||||
}
|
||||
|
||||
GLuint TextureManager::get_block_status_array() const {
|
||||
@@ -313,6 +315,7 @@ void TextureManager::init_texture() {
|
||||
init_block();
|
||||
init_block_status();
|
||||
init_ui();
|
||||
m_init = true;
|
||||
}
|
||||
|
||||
void TextureManager::update() {
|
||||
|
||||
@@ -18,10 +18,14 @@ static int windowed_width = 800, windowed_height = 600;
|
||||
Window::Window(Renderer& renderer) : m_renderer(renderer) {}
|
||||
|
||||
Window::~Window() {
|
||||
if (m_imgui_init) {
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
}
|
||||
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
if (ImGui::GetCurrentContext() != nullptr) {
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
if (m_window) {
|
||||
glfwDestroyWindow(m_window);
|
||||
@@ -212,6 +216,8 @@ void Window::imgui_init() {
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplGlfw_InitForOpenGL(m_window, false);
|
||||
ImGui_ImplOpenGL3_Init();
|
||||
|
||||
m_imgui_init = true;
|
||||
}
|
||||
|
||||
} // namespace Cubed
|
||||
Reference in New Issue
Block a user