refactor(core): add event system and scene management

- Introduce Event variant and Overloaded helper for input handling
- Move game state (camera, client_world, dev_panel) from App to WorldScene
- Add SceneManager with push/pop/change operations for scene stack
- Refactor input callbacks to dispatch events through scene hierarchy
- Extract Argument struct to separate header
- Update Renderer and WorldRenderer to accept world reference
- Replace global input state with event-driven processing in ClientPlayer, Camera, etc.
This commit is contained in:
2026-07-12 16:05:59 +08:00
parent 2d28488126
commit 5712ba0600
38 changed files with 1383 additions and 346 deletions

View File

@@ -1,27 +1,19 @@
#pragma once
#include "Cubed/audio/audio_engine.hpp"
#include "Cubed/gameplay/client_world.hpp"
#include "Cubed/gameplay/network_server.hpp"
#include "Cubed/gameplay/server_world.hpp"
#define GLFW_INCLUDE_NONE
#include "Cubed/camera.hpp"
#include "Cubed/argument.hpp"
#include "Cubed/config.hpp"
#include "Cubed/dev_panel.hpp"
#include "Cubed/render/renderer.hpp"
#include "Cubed/scene/scene_manager.hpp"
#include "Cubed/texture_manager.hpp"
#include "Cubed/window.hpp"
namespace Cubed {
class App {
public:
struct Argument {
bool is_client = false;
int port = 25530;
std::string ip{"127.0.0.1"};
std::string player{"Unknown"};
bool debug_on = true;
};
App();
~App();
static void cursor_position_callback(GLFWwindow* window, double xpos,
@@ -43,12 +35,9 @@ public:
static float delta_time();
static float get_fps();
Camera& camera();
DevPanel& dev_panel();
Renderer& renderer();
TextureManager& texture_manager();
Window& window();
ClientWorld& client_world();
ServerWorld& server_world();
Config& config();
const Argument& argument() const;
@@ -56,18 +45,17 @@ public:
private:
Config m_game_config;
Camera m_camera;
TextureManager m_texture_manager;
NetworkServer m_server;
std::shared_ptr<NetworkClient> m_client;
AudioEngine m_audio;
ClientWorld m_client_world;
DevPanel m_dev_panel;
Renderer m_renderer;
Window m_window;
SceneManager m_scene_manager;
inline static double last_time = glfwGetTime();
inline static double current_time = glfwGetTime();
inline static double dt = 0.0f;
@@ -86,6 +74,8 @@ private:
void render();
void run();
void update();
void dispatch_event(const Event& e);
};
} // namespace Cubed

View File

@@ -0,0 +1,11 @@
#pragma once
#include <string>
namespace Cubed {
struct Argument {
bool is_client = false;
int port = 25530;
std::string ip{"127.0.0.1"};
std::string player{"Unknown"};
bool debug_on = true;
};
} // namespace Cubed

View File

@@ -1,5 +1,6 @@
#pragma once
#include "Cubed/input/event.hpp"
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
@@ -28,6 +29,9 @@ private:
glm::vec3 camera_collision(glm::vec3 start, glm::vec3 end,
float radius = 0.2f);
bool handle_key_event(const KeyEvent& e);
bool handle_mouse_move_event(const MouseMoveEvent& e);
public:
Camera();
@@ -45,6 +49,7 @@ public:
glm::vec3 get_camera_front() const;
void change_perspective();
bool is_first_person() const;
bool handle_event(const Event& e);
};
} // namespace Cubed

View File

@@ -6,8 +6,9 @@
namespace Cubed {
class App;
class WorldScene;
class ClientPlayer;
class App;
class DevPanel {
struct ConfigView {
float fov = 70.0f;
@@ -32,12 +33,13 @@ class DevPanel {
};
public:
DevPanel(App& app);
DevPanel(WorldScene& app);
void init();
void render();
private:
App& m_app;
WorldScene& m_world_scene;
Config& m_config;
ConfigView m_config_view;
ClientPlayer* m_player;

View File

@@ -7,6 +7,7 @@
#include "Cubed/gameplay/game_time.hpp"
#include "Cubed/gameplay/player.hpp"
#include "Cubed/input.hpp"
#include "Cubed/input/event.hpp"
#include <absl/container/flat_hash_set.h>
#include <glm/glm.hpp>
@@ -23,6 +24,14 @@ public:
ClientPlayer(ClientWorld& world);
~ClientPlayer();
bool handle_mouse_button_event(const MouseButtonEvent& e);
bool handle_key_event(const KeyEvent& e);
bool handle_mouse_wheel_event(const MouseWheelEvent& e);
void update_front_vec(float offset_x, float offset_y);
bool update_player_move_state(Key key, KeyAction action);
bool update_scroll(float yoffset);
void update_chunk_set(const ChunkPosSet& set);
const ChunkPosSet& get_chunk_pos_set() const;
ChunkPosSet get_chunk_pos_set();
@@ -40,9 +49,6 @@ public:
void set_player_pos(const glm::vec3& pos);
void set_place_block(unsigned id);
void update(float delta_time);
void update_front_vec(float offset_x, float offset_y);
void update_player_move_state(int key, int action);
void update_scroll(double yoffset);
float& max_walk_speed();
float& max_run_speed();
@@ -137,11 +143,17 @@ private:
void update_direction();
void update_lookup_block();
bool place_block(MouseKey key);
void update_move(float delta_time);
void update_x_move(glm::vec3& player_pos);
void update_y_move(glm::vec3& player_pos);
void update_z_move(glm::vec3& player_pos);
void update_player_chunk();
void play_walk_sound(float dt);
Gait compute_gait() const;
};

View File

@@ -7,6 +7,7 @@
#include "Cubed/gameplay/client_player.hpp"
#include "Cubed/gameplay/game_time.hpp"
#include "Cubed/gameplay/network_client.hpp"
#include "Cubed/input/event.hpp"
#include "Cubed/tools/cubed_random.hpp"
#include "Cubed/tools/priority_thread_pool.hpp"
@@ -41,14 +42,15 @@ struct PlayerRenderData {
Gait gait;
float angle;
};
class WorldScene;
class ClientWorld {
public:
ClientWorld(AudioEngine& auido, Config& config);
ClientWorld(AudioEngine& auido, Config& config, WorldScene& scene);
~ClientWorld();
void init(std::string_view player_name,
std::shared_ptr<NetworkClient> client);
void update(float delta_time);
bool handle_event(const Event& e);
const std::optional<LookBlock>& get_look_block_pos() const;
ClientPlayer& get_player();
const ClientPlayer& get_player() const;
@@ -97,6 +99,7 @@ public:
static AABB get_block_aabb(const glm::ivec3& pos);
AudioEngine& get_audio();
Config& get_config();
WorldScene& world_scene();
template <typename Fn>
void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) {
m_ticktimers.emplace(
@@ -133,6 +136,7 @@ private:
ChunkHashMap m_chunks;
AudioEngine& m_audio;
Config& m_config;
WorldScene& m_world_scene;
std::vector<glm::vec4> m_planes;
std::jthread m_client_thread;

View File

@@ -0,0 +1,52 @@
#pragma once
#include "Cubed/input/key.hpp"
#include "Cubed/input/mouse.hpp"
#include <string>
#include <variant>
namespace Cubed {
struct MouseMoveEvent {
float xpos;
float ypos;
MouseMoveEvent(float x, float y) : xpos(x), ypos(y) {}
};
struct MouseButtonEvent {
MouseKey key;
KeyAction action;
MouseButtonEvent(MouseKey k, KeyAction a) : key(k), action(a) {}
};
struct MouseWheelEvent {
float offset;
MouseWheelEvent(float o) : offset(o) {}
};
struct KeyEvent {
Key key;
KeyAction action;
KeyEvent(Key k, KeyAction a) : key(k), action(a) {}
};
struct TextInputEvent {
std::string text;
TextInputEvent(std::string t) : text(std::move(t)) {}
};
using Event = std::variant<MouseMoveEvent, MouseButtonEvent, MouseWheelEvent,
KeyEvent, TextInputEvent>;
template <class... T> struct Overloaded : T... {
using T::operator()...;
};
template <class... T> Overloaded(T...) -> Overloaded<T...>;
} // namespace Cubed

127
include/Cubed/input/key.hpp Normal file
View File

@@ -0,0 +1,127 @@
#pragma once
namespace Cubed {
enum class Key {
// Letter keys
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
// Digit keys (main keyboard area)
DIGIT_0,
DIGIT_1,
DIGIT_2,
DIGIT_3,
DIGIT_4,
DIGIT_5,
DIGIT_6,
DIGIT_7,
DIGIT_8,
DIGIT_9,
// Function keys
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
// Control keys
BACKSPACE,
TAB,
ENTER,
ESCAPE,
SPACE,
CAPS_LOCK,
NUM_LOCK,
SCROLL_LOCK,
// Modifier keys
LEFT_SHIFT,
RIGHT_SHIFT,
LEFT_CTRL,
RIGHT_CTRL,
LEFT_ALT,
RIGHT_ALT,
LEFT_SUPER,
RIGHT_SUPER, // Windows / Command 键
// Navigation keys
INSERT,
DELETE,
HOME,
END,
PAGE_UP,
PAGE_DOWN,
LEFT,
RIGHT,
UP,
DOWN,
// Lock and system keys
PRINT_SCREEN,
PAUSE,
// Main keyboard area symbol keys
GRAVE_ACCENT, // `
MINUS, // -
EQUALS, // =
LEFT_BRACKET, // [
RIGHT_BRACKET, // ]
BACKSLASH, // \ /
SEMICOLON, // ;
APOSTROPHE, // '
COMMA, // ,
PERIOD, // .
SLASH, // /
// Numpad area
NUMPAD_0,
NUMPAD_1,
NUMPAD_2,
NUMPAD_3,
NUMPAD_4,
NUMPAD_5,
NUMPAD_6,
NUMPAD_7,
NUMPAD_8,
NUMPAD_9,
NUMPAD_ADD, // +
NUMPAD_SUBTRACT, // -
NUMPAD_MULTIPLY, // *
NUMPAD_DIVIDE, // /
NUMPAD_DECIMAL, // .
NUMPAD_ENTER
};
enum class KeyAction { PRESS, RELEASE };
} // namespace Cubed

View File

@@ -0,0 +1,25 @@
#pragma once
namespace Cubed {
enum class MouseKey {
LEFT_BUTTON,
RIGHT_BUTTON,
MIDDLE_BUTTON,
BACK_BUTTON, // Side button back
FORWARD_BUTTON, // Side button forward
WHEEL_UP,
WHEEL_DOWN,
WHEEL_LEFT,
WHEEL_RIGHT,
EXTRA_BUTTON_1, // Additional programmable buttons
EXTRA_BUTTON_2,
EXTRA_BUTTON_3,
EXTRA_BUTTON_4,
EXTRA_BUTTON_5
};
}

View File

@@ -5,6 +5,7 @@
#include <glad/glad.h>
namespace Cubed {
class ClientWorld;
class Renderer;
class PlayerRenderer {
public:
@@ -12,8 +13,9 @@ public:
PlayerRenderer(Renderer& renderer);
~PlayerRenderer();
void init();
void render(const Shader& shader);
void shadow_render(const Shader& shader, glm::mat4& light_matrix);
void render(const Shader& shader, ClientWorld& world);
void shadow_render(const Shader& shader, glm::mat4& light_matrix,
ClientWorld& world);
private:
struct PlayerVertex {

View File

@@ -15,8 +15,6 @@
#include <glm/glm.hpp>
#include <vector>
namespace Cubed {
class Camera;
class TextureManager;
class ClientWorld;
class DevPanel;
@@ -24,15 +22,15 @@ class Renderer {
public:
constexpr static int NUM_VAO = 7;
Renderer(const Camera& camera, ClientWorld& world,
const TextureManager& texture_manager, DevPanel& dev_panel,
Config& config);
Renderer(TextureManager& texture_manager, Config& config);
~Renderer();
void hot_reload();
void init(bool debug_on);
const Shader& get_shader(const std::string& name) const;
void begin_frame();
void end_frame();
void render();
void render_world(ClientWorld& world);
void render_lable(const Label& label);
void render_image(const Image& image);
@@ -63,9 +61,6 @@ public:
float& underwater_fog_density();
float& water_density();
const Camera& camera() const;
const ClientWorld& world() const;
ClientWorld& world();
const glm::mat4& world_proj_matrix() const;
const TextureManager& texture_mamger() const;
float delta_time() const;
@@ -75,12 +70,10 @@ public:
const glm::mat4& p_mat() const;
const std::vector<VertexArray>& vao() const;
void render_dev_panel(DevPanel& dev_panel);
private:
const Camera& m_camera;
DevPanel& m_dev_panel;
const TextureManager& m_texture_manager;
ClientWorld& m_world;
TextureManager& m_texture_manager;
bool m_init = false;
@@ -121,13 +114,8 @@ private:
void init_quad();
void init_text();
void day_night_calculation();
void render_sky();
void render_ui();
void render_crosshair();
void render_dev_panel();
};
} // namespace Cubed

View File

@@ -60,12 +60,12 @@ public:
void tex_image_2d(TextureFormat internalformat, TextureFormat format,
GLenum type, const void* data, GLsizei width,
GLsizei height, GLint level = 0, GLint border = 0) const;
GLsizei height, GLint level = 0, GLint border = 0);
void tex_image_3d(TextureFormat internalformat, TextureFormat format,
GLenum type, const void* data, GLsizei width,
GLsizei height, GLsizei depth, GLint level = 0,
GLint border = 0) const;
GLint border = 0);
void tex_sub_image_3d(TextureFormat format, GLenum type, const void* data,
GLint xoffset, GLint yoffset, GLint zoffset,
@@ -84,9 +84,13 @@ public:
void set_clamp_to_edge(bool r = true, bool s = true, bool t = true) const;
TextureType type() const;
float width() const;
float height() const;
private:
GLuint m_id = 0;
float m_width = 0;
float m_height = 0;
const TextureType M_TYPE;
GLenum get_gl_texture_type() const;
};

View File

@@ -39,7 +39,7 @@ public:
WorldRenderer& operator=(const WorldRenderer&) = delete;
WorldRenderer& operator=(WorldRenderer&&) = delete;
void init();
void render();
void render(ClientWorld& world);
void updata_framebuffer(int width, int height);
float& ambient_strength();
@@ -121,27 +121,26 @@ private:
glm::mat4 view_matrix;
ClientWorld& m_world;
const Camera& m_camera;
const TextureManager& m_texture_manager;
void day_night_calculation();
void day_night_calculation(ClientWorld& world);
void render_sky();
void render_sky(ClientWorld& world);
void render_world();
void render_world(ClientWorld& world);
void shadow_map_generate();
void shadow_map_generate(ClientWorld& world);
void render_underwater();
void render_outline();
void render_player();
void render_underwater(ClientWorld& world);
void render_outline(ClientWorld& world);
void render_player(ClientWorld& world);
void render_normal_block(const glm::mat4& model_mat,
const glm::mat4& mv_mat,
const glm::mat4& norm_mat);
const glm::mat4& mv_mat, const glm::mat4& norm_mat,
ClientWorld& world);
void render_transparent_block(const glm::mat4& mv_mat,
const glm::mat4& norm_mat);
const glm::mat4& norm_mat,
ClientWorld& world);
glm::vec3 quantize_sun_direction(const glm::vec3& sundir,
float angle_step_deg) const;

View File

@@ -1,11 +1,24 @@
#pragma once
#include "Cubed/input/event.hpp"
namespace Cubed {
class Renderer;
enum class SceneType { MAIN_MENU, WORLD };
class Scene {
public:
Scene() = default;
Scene(const Scene&) = delete;
Scene(Scene&&) = delete;
Scene& operator=(const Scene&) = delete;
Scene& operator=(Scene&&) = delete;
virtual ~Scene() = default;
virtual void update(float dt) = 0;
virtual void render() = 0;
virtual void render(Renderer& renderer) = 0;
virtual bool handle_event(const Event& e) = 0;
virtual void on_enter() {};
virtual void on_leave() {};
};
} // namespace Cubed

View File

@@ -0,0 +1,47 @@
#pragma once
#include "Cubed/scene/scene.hpp"
#include <memory>
#include <stack>
#include <vector>
namespace Cubed {
class App;
class SceneManager {
public:
SceneManager(const SceneManager&) = delete;
SceneManager(SceneManager&&) = delete;
SceneManager& operator=(const SceneManager&) = delete;
SceneManager& operator=(SceneManager&&) = delete;
SceneManager(App& app);
~SceneManager();
void update(float dt);
void render(Renderer& renderer);
bool handle_event(const Event& e);
void request_change(SceneType type);
void request_push(SceneType type);
void request_pop();
App& app();
private:
enum class OperationType { PUSH, POP, CHANGE };
struct SceneOperation {
OperationType type;
std::optional<SceneType> scene;
};
App& m_app;
std::vector<std::unique_ptr<Scene>> m_pending_delete_scene;
std::optional<SceneOperation> m_operation;
std::stack<std::unique_ptr<Scene>> m_scenes;
void process_operation();
void change(SceneType type);
void push(SceneType type);
void pop();
std::unique_ptr<Scene> create_scene(SceneType);
};
} // namespace Cubed

View File

@@ -0,0 +1,38 @@
#pragma once
#include "Cubed/argument.hpp"
#include "Cubed/camera.hpp"
#include "Cubed/dev_panel.hpp"
#include "Cubed/gameplay/client_world.hpp"
#include "Cubed/scene/scene.hpp"
namespace Cubed {
class SceneManager;
class WorldScene : public Scene {
public:
WorldScene(const WorldScene&) = delete;
WorldScene(WorldScene&&) = delete;
WorldScene& operator=(const WorldScene&) = delete;
WorldScene& operator=(WorldScene&&) = delete;
WorldScene(SceneManager& scene_manager);
~WorldScene();
void update(float dt) override;
void render(Renderer& renderer) override;
bool handle_event(const Event& e) override;
void on_enter() override;
void on_leave() override;
Camera& camera();
SceneManager& scene_manager();
ClientWorld& client_world();
private:
SceneManager& m_scene_manager;
DevPanel m_dev_panel;
Camera m_camera;
std::shared_ptr<NetworkClient> m_client;
ClientWorld m_client_world;
const Argument& m_argument;
};
} // namespace Cubed

View File

@@ -1,6 +1,7 @@
#pragma once
#include "Cubed/config.hpp"
#include "Cubed/gameplay/block.hpp"
#include "Cubed/input/event.hpp"
#include "Cubed/render/texture.hpp"
#include <glad/glad.h>
@@ -15,10 +16,10 @@ private:
std::unique_ptr<Texture> m_block_status_array;
std::unique_ptr<Texture> m_texture_array;
std::unique_ptr<Texture> m_cross_plane_array;
std::unique_ptr<Texture> m_ui_array;
std::unique_ptr<Texture> m_normal_texture_array;
std::unique_ptr<Texture> m_skin;
std::vector<std::unique_ptr<Texture>> m_item_textures;
std::unordered_map<std::string, std::unique_ptr<Texture>> m_ui_map;
GLfloat m_max_aniso = 0.0f;
Config& m_config;
int m_aniso = 1;
@@ -27,7 +28,7 @@ private:
void load_block_texture(unsigned block_id);
void load_block_item_texture(unsigned id);
void load_cross_plane_texture(unsigned id);
void load_ui_texture(unsigned id);
const Texture* load_image_texture(const std::string& path);
void load_pbr_texture(unsigned id);
void init_item();
void init_block();
@@ -35,6 +36,7 @@ private:
void init_block_status();
void init_skin();
void hot_reload();
bool handle_key_event(const KeyEvent& e);
public:
TextureManager(Config& config);
@@ -44,7 +46,7 @@ public:
const Texture* get_block_status_array() const;
const Texture* get_texture_array() const;
const Texture* get_cross_plane_array() const;
const Texture* get_ui_array() const;
const Texture* get_image_texture(const std::string& path);
const Texture* get_pbr_texture() const;
const std::vector<std::unique_ptr<Texture>>& item_textures() const;
const Texture* get_skin() const;
@@ -54,6 +56,7 @@ public:
void need_reload();
void update();
int max_aniso() const;
bool handle_event(const Event& e);
};
} // namespace Cubed

View File

@@ -0,0 +1,19 @@
#pragma once
#include "Cubed/ui/widget.hpp"
#include <functional>
namespace Cubed {
class Button : public Widget {
public:
Button();
template <typename F> Button& set_clicked(F&& f) {
m_clicked = std::move(f);
}
private:
std::function<void()> m_clicked;
};
} // namespace Cubed

View File

@@ -4,24 +4,21 @@
#include "Cubed/ui/widget.hpp"
#include "glm/ext/vector_float2.hpp"
#include <filesystem>
namespace Cubed {
class TextureManager;
class Image : public Widget {
public:
Image();
void update(float dt) override;
void render(Renderer& renderer) override;
Image& set_image(std::filesystem::path path);
Image& set_image(const std::string& path, TextureManager& texture_manager);
float width() const;
float height() const;
const Texture& texture() const;
const Texture* texture() const;
private:
Texture m_texture;
int m_width = 0;
int m_height = 0;
const Texture* m_texture = nullptr;
glm::vec2 m_pos{0.0f, 0.0f};
float m_scale = 1.0f;
};

View File

@@ -0,0 +1,13 @@
#pragma once
namespace Cubed {
class UIManager {
public:
UIManager(const UIManager&) = delete;
UIManager(UIManager&&) = delete;
UIManager& operator=(const UIManager&) = delete;
UIManager& operator=(UIManager&&) = delete;
private:
};
} // namespace Cubed

View File

@@ -19,6 +19,7 @@ public:
virtual Widget& set_scale(float scale);
virtual const glm::vec2& pos() const;
virtual float scale() const;
template <typename T, typename... Args> T& add_child(Args&&... args) {
auto widget = std::make_unique<T>(std::forward<Args>(args)...);
T& ref = *widget;

View File

@@ -1,11 +1,12 @@
#pragma once
#include "Cubed/config.hpp"
#include "Cubed/input/event.hpp"
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
namespace Cubed {
class Camera;
class Renderer;
class Window {
public:
@@ -19,11 +20,16 @@ public:
void imgui_init();
void update_viewport();
// end of frame to reload!
bool handle_event(const Event& e);
void hot_reload();
void toggle_fullscreen();
void toggle_mouse_able();
void set_camera(Camera* camera);
Camera* camera();
private:
bool m_mouse_enable = false;
bool m_imgui_init = false;
@@ -33,6 +39,9 @@ private:
int m_height;
Renderer& m_renderer;
Config& m_config;
Camera* m_camera = nullptr;
bool handle_key_event(const KeyEvent& e);
bool handle_mouse_button_event(const MouseButtonEvent& e);
};
} // namespace Cubed