refactor: 移除事件系统和音频系统相关代码

移除不再使用的事件队列(EventQueue)、事件分发器(EventDispatcher)、音频引擎(AudioEngine)和声音(Sound)相关代码
删除utils/data.h数据存储模块
清理相关头文件引用和成员变量
This commit is contained in:
ChestnutYueyue 2026-02-27 19:25:54 +08:00
parent ea081b9dd3
commit 24b86b4916
18 changed files with 1 additions and 5176 deletions

View File

@ -9,10 +9,7 @@ namespace extra2d {
// 前向声明
class Input;
class AudioEngine;
class TimerManager;
class EventQueue;
class EventDispatcher;
// ============================================================================
// Application 配置
@ -56,10 +53,7 @@ public:
Window &window() { return *window_; }
Input &input();
AudioEngine &audio();
TimerManager &timers();
EventQueue &eventQueue();
EventDispatcher &eventDispatcher();
float deltaTime() const { return deltaTime_; }
float totalTime() const { return totalTime_; }
@ -78,8 +72,6 @@ private:
UniquePtr<Window> window_;
UniquePtr<TimerManager> timerManager_;
UniquePtr<EventQueue> eventQueue_;
UniquePtr<EventDispatcher> eventDispatcher_;
bool initialized_ = false;
bool running_ = false;

View File

@ -1,47 +0,0 @@
#pragma once
#include <core/intrusive_ptr.h>
#include <string>
#include <unordered_map>
namespace extra2d {
class Sound;
class AudioEngine {
public:
static AudioEngine &getInstance();
AudioEngine(const AudioEngine &) = delete;
AudioEngine &operator=(const AudioEngine &) = delete;
AudioEngine(AudioEngine &&) = delete;
AudioEngine &operator=(AudioEngine &&) = delete;
bool initialize();
void shutdown();
IntrusivePtr<Sound> loadSound(const std::string &filePath);
IntrusivePtr<Sound> loadSound(const std::string &name,
const std::string &filePath);
IntrusivePtr<Sound> getSound(const std::string &name);
void unloadSound(const std::string &name);
void unloadAllSounds();
void setMasterVolume(float volume);
float getMasterVolume() const;
void pauseAll();
void resumeAll();
void stopAll();
private:
AudioEngine() = default;
~AudioEngine();
std::unordered_map<std::string, IntrusivePtr<Sound>> sounds_;
float masterVolume_ = 1.0f;
bool initialized_ = false;
};
} // namespace extra2d

View File

@ -1,57 +0,0 @@
#pragma once
#include <core/ref_counted.h>
#include <string>
struct Mix_Chunk;
namespace extra2d {
class AudioEngine;
class Sound : public RefCounted {
public:
~Sound();
Sound(const Sound&) = delete;
Sound& operator=(const Sound&) = delete;
bool play();
void pause();
void resume();
void stop();
bool isPlaying() const;
bool isPaused() const;
void setVolume(float volume);
float getVolume() const { return volume_; }
void setLooping(bool looping);
bool isLooping() const { return looping_; }
void setPitch(float pitch);
float getPitch() const { return pitch_; }
float getDuration() const;
float getCursor() const;
void setCursor(float seconds);
const std::string& getFilePath() const { return filePath_; }
const std::string& name() const { return name_; }
private:
friend class AudioEngine;
Sound(const std::string& name, const std::string& filePath, Mix_Chunk* chunk);
std::string name_;
std::string filePath_;
Mix_Chunk* chunk_ = nullptr;
int channel_ = -1; // SDL_mixer 分配的通道,-1 表示未播放
float volume_ = 1.0f;
float pitch_ = 1.0f;
bool looping_ = false;
};
} // namespace extra2d

View File

@ -1,172 +0,0 @@
#pragma once
#include <cstdint>
#include <core/types.h>
#include <core/vec2.h>
#include <variant>
namespace extra2d {
// ============================================================================
// 事件类型枚举
// ============================================================================
enum class EventType {
None = 0,
// 窗口事件
WindowClose,
WindowResize,
WindowFocus,
WindowLostFocus,
WindowMoved,
// 键盘事件
KeyPressed,
KeyReleased,
KeyRepeat,
// 鼠标事件
MouseButtonPressed,
MouseButtonReleased,
MouseMoved,
MouseScrolled,
// UI 事件
UIHoverEnter,
UIHoverExit,
UIPressed,
UIReleased,
UIClicked,
// 游戏手柄事件
GamepadConnected,
GamepadDisconnected,
GamepadButtonPressed,
GamepadButtonReleased,
GamepadAxisMoved,
// 触摸事件 (移动端)
TouchBegan,
TouchMoved,
TouchEnded,
TouchCancelled,
// 自定义事件
Custom
};
// ============================================================================
// 键盘事件数据
// ============================================================================
struct KeyEvent {
int keyCode;
int scancode;
int mods; // 修饰键 (Shift, Ctrl, Alt, etc.)
};
// ============================================================================
// 鼠标事件数据
// ============================================================================
struct MouseButtonEvent {
int button;
int mods;
Vec2 position;
};
struct MouseMoveEvent {
Vec2 position;
Vec2 delta;
};
struct MouseScrollEvent {
Vec2 offset;
Vec2 position;
};
// ============================================================================
// 窗口事件数据
// ============================================================================
struct WindowResizeEvent {
int width;
int height;
};
struct WindowMoveEvent {
int x;
int y;
};
// ============================================================================
// 游戏手柄事件数据
// ============================================================================
struct GamepadButtonEvent {
int gamepadId;
int button;
};
struct GamepadAxisEvent {
int gamepadId;
int axis;
float value;
};
// ============================================================================
// 触摸事件数据
// ============================================================================
struct TouchEvent {
int touchId;
Vec2 position;
};
// ============================================================================
// 自定义事件数据
// ============================================================================
struct CustomEvent {
uint32_t id;
void *data;
};
// ============================================================================
// 事件结构
// ============================================================================
struct Event {
EventType type = EventType::None;
double timestamp = 0.0;
bool handled = false;
// 事件数据联合体
std::variant<std::monostate, KeyEvent, MouseButtonEvent, MouseMoveEvent,
MouseScrollEvent, WindowResizeEvent, WindowMoveEvent,
GamepadButtonEvent, GamepadAxisEvent, TouchEvent, CustomEvent>
data;
// 便捷访问方法
bool isWindowEvent() const {
return type == EventType::WindowClose || type == EventType::WindowResize ||
type == EventType::WindowFocus ||
type == EventType::WindowLostFocus || type == EventType::WindowMoved;
}
bool isKeyboardEvent() const {
return type == EventType::KeyPressed || type == EventType::KeyReleased ||
type == EventType::KeyRepeat;
}
bool isMouseEvent() const {
return type == EventType::MouseButtonPressed ||
type == EventType::MouseButtonReleased ||
type == EventType::MouseMoved || type == EventType::MouseScrolled;
}
// 静态工厂方法
static Event createWindowResize(int width, int height);
static Event createWindowClose();
static Event createKeyPress(int keyCode, int scancode, int mods);
static Event createKeyRelease(int keyCode, int scancode, int mods);
static Event createMouseButtonPress(int button, int mods, const Vec2 &pos);
static Event createMouseButtonRelease(int button, int mods, const Vec2 &pos);
static Event createMouseMove(const Vec2 &pos, const Vec2 &delta);
static Event createMouseScroll(const Vec2 &offset, const Vec2 &pos);
};
} // namespace extra2d

View File

@ -1,56 +0,0 @@
#pragma once
#include <core/types.h>
#include <event/event.h>
#include <functional>
#include <unordered_map>
#include <vector>
namespace extra2d {
// ============================================================================
// 事件监听器 ID
// ============================================================================
using ListenerId = uint64_t;
// ============================================================================
// 事件分发器
// ============================================================================
class EventDispatcher {
public:
using EventCallback = std::function<void(Event &)>;
EventDispatcher();
~EventDispatcher() = default;
// 添加监听器
ListenerId addListener(EventType type, EventCallback callback);
// 移除监听器
void removeListener(ListenerId id);
void removeAllListeners(EventType type);
void removeAllListeners();
// 分发事件
void dispatch(Event &event);
void dispatch(const Event &event);
// 处理事件队列
void processQueue(class EventQueue &queue);
// 统计
size_t getListenerCount(EventType type) const;
size_t getTotalListenerCount() const;
private:
struct Listener {
ListenerId id;
EventType type;
EventCallback callback;
};
std::unordered_map<EventType, std::vector<Listener>> listeners_;
ListenerId nextId_;
};
} // namespace extra2d

View File

@ -1,40 +0,0 @@
#pragma once
#include <core/types.h>
#include <event/event.h>
#include <mutex>
#include <queue>
namespace extra2d {
// ============================================================================
// 事件队列 - 线程安全的事件队列
// ============================================================================
class EventQueue {
public:
EventQueue();
~EventQueue() = default;
// 添加事件到队列
void push(const Event &event);
void push(Event &&event);
// 从队列取出事件
bool poll(Event &event);
// 查看队列头部事件(不移除)
bool peek(Event &event) const;
// 清空队列
void clear();
// 队列状态
bool empty() const;
size_t size() const;
private:
std::queue<Event> queue_;
mutable std::mutex mutex_;
};
} // namespace extra2d

View File

@ -16,18 +16,7 @@
#include <platform/input.h>
#include <platform/window.h>
// Event
#include <event/event.h>
#include <event/event_dispatcher.h>
#include <event/event_queue.h>
#include <platform/input_codes.h>
// Audio
#include <audio/audio_engine.h>
#include <audio/sound.h>
// Utils
#include <utils/data.h>
#include <utils/logger.h>
#include <utils/random.h>
#include <utils/timer.h>

View File

@ -11,7 +11,6 @@
namespace extra2d {
// 前向声明
class EventQueue;
class Input;
// ============================================================================
@ -102,10 +101,6 @@ public:
void setUserData(void *data) { userData_ = data; }
void *getUserData() const { return userData_; }
// 事件队列
void setEventQueue(EventQueue *queue) { eventQueue_ = queue; }
EventQueue *getEventQueue() const { return eventQueue_; }
// 获取输入管理器
Input *getInput() const { return input_.get(); }
@ -142,7 +137,6 @@ private:
float contentScaleY_;
bool enableDpiScale_;
void *userData_;
EventQueue *eventQueue_;
UniquePtr<Input> input_;
ResizeCallback resizeCallback_;

View File

@ -1,217 +0,0 @@
#pragma once
#include <core/types.h>
#include <functional>
#include <string>
#include <vector>
namespace extra2d {
// ============================================================================
// 存档类型枚举
// ============================================================================
enum class SaveDataType {
Account, // 用户存档(与特定用户关联)
Common, // 公共存档(所有用户共享)
Cache, // 缓存数据(可删除)
Device, // 设备存档
Temporary, // 临时数据
};
// ============================================================================
// 用户ID结构封装 Switch AccountUid
// ============================================================================
struct UserId {
uint64_t uid[2] = {0, 0};
bool isValid() const { return uid[0] != 0 || uid[1] != 0; }
bool operator==(const UserId &other) const {
return uid[0] == other.uid[0] && uid[1] == other.uid[1];
}
bool operator!=(const UserId &other) const { return !(*this == other); }
};
// ============================================================================
// DataStore 类 - 数据持久化(支持 Switch 存档系统)
// ============================================================================
class DataStore {
public:
DataStore();
~DataStore();
// ------------------------------------------------------------------------
// 文件操作
// ------------------------------------------------------------------------
/// 加载 INI 文件
bool load(const std::string &filename);
/// 保存到 INI 文件
bool save(const std::string &filename);
/// 获取当前文件名
const std::string &getFilename() const { return filename_; }
// ------------------------------------------------------------------------
// Switch 存档系统支持
// ------------------------------------------------------------------------
/**
* @brief Switch
* @param type
* @param userId IDAccount
* @param mountName "save"
* @return
*/
bool mountSaveData(SaveDataType type = SaveDataType::Account,
const UserId &userId = UserId(),
const std::string &mountName = "save");
/**
* @brief
* @param mountName
*/
void unmountSaveData(const std::string &mountName = "save");
/**
* @brief
* @param mountName
* @return
*/
bool commitSaveData(const std::string &mountName = "save");
/**
* @brief
*/
bool isSaveDataMounted() const { return saveDataMounted_; }
/**
* @brief
*/
std::string getSaveDataPath(const std::string &path = "") const;
// ------------------------------------------------------------------------
// 用户账户管理
// ------------------------------------------------------------------------
/**
* @brief ID
* @return IDID
*/
static UserId getCurrentUserId();
/**
* @brief ID
*/
void setDefaultUserId(const UserId &userId) { defaultUserId_ = userId; }
/**
* @brief ID
*/
UserId getDefaultUserId() const { return defaultUserId_; }
// ------------------------------------------------------------------------
// 数据读写
// ------------------------------------------------------------------------
/// 获取字符串值
std::string getString(const std::string &section, const std::string &key,
const std::string &defaultValue = "");
/// 获取整数值
int getInt(const std::string &section, const std::string &key,
int defaultValue = 0);
/// 获取浮点数值
float getFloat(const std::string &section, const std::string &key,
float defaultValue = 0.0f);
/// 获取布尔值
bool getBool(const std::string &section, const std::string &key,
bool defaultValue = false);
/// 设置字符串值
void setString(const std::string &section, const std::string &key,
const std::string &value);
/// 设置整数值
void setInt(const std::string &section, const std::string &key, int value);
/// 设置浮点数值
void setFloat(const std::string &section, const std::string &key,
float value);
/// 设置布尔值
void setBool(const std::string &section, const std::string &key, bool value);
/// 删除键
void removeKey(const std::string &section, const std::string &key);
/// 删除整个 section
void removeSection(const std::string &section);
/// 检查键是否存在
bool hasKey(const std::string &section, const std::string &key);
/// 检查 section 是否存在
bool hasSection(const std::string &section);
/// 清除所有数据
void clear();
// ------------------------------------------------------------------------
// 事务支持
// ------------------------------------------------------------------------
/**
* @brief
*/
void beginTransaction();
/**
* @brief
* @return
*/
bool commit();
/**
* @brief
*/
void rollback();
/**
* @brief
*/
bool isInTransaction() const { return inTransaction_; }
// ------------------------------------------------------------------------
// 工具方法
// ------------------------------------------------------------------------
/// 获取所有 section 名称
std::vector<std::string> getAllSections() const;
/// 获取指定 section 的所有 key
std::vector<std::string> getAllKeys(const std::string &section) const;
/// 从存档加载(自动处理挂载路径)
bool loadFromSave(const std::string &path);
/// 保存到存档(自动处理挂载路径和提交)
bool saveToSave(const std::string &path);
private:
class Impl;
UniquePtr<Impl> impl_;
std::string filename_;
std::string mountName_;
UserId defaultUserId_;
bool saveDataMounted_ = false;
bool inTransaction_ = false;
bool dirty_ = false;
// 内部辅助方法
bool internalSave(const std::string &filename);
};
} // namespace extra2d

View File

@ -1,7 +1,4 @@
#include <app/application.h>
#include <audio/audio_engine.h>
#include <event/event_dispatcher.h>
#include <event/event_queue.h>
#include <platform/input.h>
#include <platform/window.h>
#include <utils/logger.h>
@ -102,10 +99,6 @@ bool Application::init(const AppConfig &config) {
}
timerManager_ = unique<TimerManager>();
eventQueue_ = unique<EventQueue>();
eventDispatcher_ = unique<EventDispatcher>();
AudioEngine::getInstance().initialize();
initialized_ = true;
running_ = true;
@ -120,11 +113,7 @@ void Application::shutdown() {
E2D_LOG_INFO("Shutting down application...");
AudioEngine::getInstance().shutdown();
timerManager_.reset();
eventQueue_.reset();
eventDispatcher_.reset();
if (window_) {
window_->destroy();
@ -208,10 +197,6 @@ void Application::mainLoop() {
window_->pollEvents();
if (eventDispatcher_ && eventQueue_) {
eventDispatcher_->processQueue(*eventQueue_);
}
if (!paused_) {
update();
}
@ -237,12 +222,6 @@ void Application::update() {
Input &Application::input() { return *window_->getInput(); }
AudioEngine &Application::audio() { return AudioEngine::getInstance(); }
TimerManager &Application::timers() { return *timerManager_; }
EventQueue &Application::eventQueue() { return *eventQueue_; }
EventDispatcher &Application::eventDispatcher() { return *eventDispatcher_; }
} // namespace extra2d

View File

@ -1,134 +0,0 @@
#include "audio/audio_engine.h"
#include "audio/sound.h"
#include "utils/logger.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
namespace extra2d {
AudioEngine &AudioEngine::getInstance() {
static AudioEngine instance;
return instance;
}
AudioEngine::~AudioEngine() { shutdown(); }
bool AudioEngine::initialize() {
if (initialized_) {
return true;
}
// 初始化 SDL 音频子系统
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
E2D_LOG_ERROR("Failed to initialize SDL audio: {}", SDL_GetError());
return false;
}
// 打开音频设备
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0) {
E2D_LOG_ERROR("Failed to open audio: {}", Mix_GetError());
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return false;
}
// 分配混音通道
Mix_AllocateChannels(32);
initialized_ = true;
E2D_LOG_INFO("AudioEngine initialized successfully (SDL2_mixer)");
return true;
}
void AudioEngine::shutdown() {
if (!initialized_) {
return;
}
unloadAllSounds();
Mix_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
initialized_ = false;
E2D_LOG_INFO("AudioEngine shutdown");
}
IntrusivePtr<Sound> AudioEngine::loadSound(const std::string &filePath) {
return loadSound(filePath, filePath);
}
IntrusivePtr<Sound> AudioEngine::loadSound(const std::string &name,
const std::string &filePath) {
if (!initialized_) {
E2D_LOG_ERROR("AudioEngine not initialized");
return nullptr;
}
// 检查是否已存在
auto it = sounds_.find(name);
if (it != sounds_.end()) {
return it->second;
}
Mix_Chunk *chunk = Mix_LoadWAV(filePath.c_str());
if (!chunk) {
E2D_LOG_ERROR("Failed to load sound: {} ({})", filePath, Mix_GetError());
return nullptr;
}
auto sound = IntrusivePtr<Sound>(new Sound(name, filePath, chunk));
sounds_[name] = sound;
E2D_LOG_DEBUG("Loaded sound: {}", filePath);
return sound;
}
IntrusivePtr<Sound> AudioEngine::getSound(const std::string &name) {
auto it = sounds_.find(name);
if (it != sounds_.end()) {
return it->second;
}
return nullptr;
}
void AudioEngine::unloadSound(const std::string &name) {
auto it = sounds_.find(name);
if (it != sounds_.end()) {
sounds_.erase(it);
E2D_LOG_DEBUG("Unloaded sound: {}", name);
}
}
void AudioEngine::unloadAllSounds() {
stopAll();
sounds_.clear();
E2D_LOG_DEBUG("Unloaded all sounds");
}
void AudioEngine::setMasterVolume(float volume) {
masterVolume_ = volume;
int mixVol = static_cast<int>(volume * MIX_MAX_VOLUME);
Mix_Volume(-1, mixVol); // 所有通道
Mix_VolumeMusic(mixVol); // 音乐
}
float AudioEngine::getMasterVolume() const { return masterVolume_; }
void AudioEngine::pauseAll() {
Mix_Pause(-1); // 暂停所有通道
}
void AudioEngine::resumeAll() {
Mix_Resume(-1); // 恢复所有通道
}
void AudioEngine::stopAll() {
for (auto &pair : sounds_) {
if (pair.second) {
pair.second->stop();
}
}
}
} // namespace extra2d

View File

@ -1,112 +0,0 @@
#include <SDL2/SDL_mixer.h>
#include <audio/sound.h>
#include <utils/logger.h>
namespace extra2d {
Sound::Sound(const std::string &name, const std::string &filePath,
Mix_Chunk *chunk)
: name_(name), filePath_(filePath), chunk_(chunk) {}
Sound::~Sound() {
if (channel_ >= 0) {
Mix_HaltChannel(channel_);
channel_ = -1;
}
if (chunk_) {
Mix_FreeChunk(chunk_);
chunk_ = nullptr;
}
}
bool Sound::play() {
if (!chunk_) {
E2D_LOG_WARN("Sound::play() failed: chunk is null for {}", name_);
return false;
}
int loops = looping_ ? -1 : 0;
int newChannel = Mix_PlayChannel(-1, chunk_, loops);
if (newChannel < 0) {
E2D_LOG_WARN("Sound::play() failed: no free channel for {} ({})", name_, Mix_GetError());
return false;
}
channel_ = newChannel;
int mixVol = static_cast<int>(volume_ * MIX_MAX_VOLUME);
Mix_Volume(channel_, mixVol);
return true;
}
void Sound::pause() {
if (channel_ >= 0) {
Mix_Pause(channel_);
}
}
void Sound::resume() {
if (channel_ >= 0) {
Mix_Resume(channel_);
}
}
void Sound::stop() {
if (channel_ >= 0) {
Mix_HaltChannel(channel_);
channel_ = -1;
}
}
bool Sound::isPlaying() const {
if (channel_ < 0) {
return false;
}
return Mix_Playing(channel_) && !Mix_Paused(channel_);
}
bool Sound::isPaused() const {
if (channel_ < 0) {
return false;
}
return Mix_Paused(channel_) != 0;
}
void Sound::setVolume(float volume) {
volume_ = volume;
if (channel_ >= 0) {
int mixVol = static_cast<int>(volume * MIX_MAX_VOLUME);
Mix_Volume(channel_, mixVol);
}
}
void Sound::setLooping(bool looping) {
looping_ = looping;
// SDL_mixer 的循环在播放时设置,运行中无法更改
// 如果需要即时生效,需要重新播放
}
void Sound::setPitch(float pitch) {
pitch_ = pitch;
// SDL2_mixer 不直接支持变速播放
// 需要更高级的音频处理才能实现
}
float Sound::getDuration() const {
// SDL2_mixer 没有直接获取时长的 API
// 返回 0 表示不支持
return 0.0f;
}
float Sound::getCursor() const {
// SDL2_mixer 没有直接获取播放位置的 API
return 0.0f;
}
void Sound::setCursor(float /*seconds*/) {
// SDL2_mixer 不支持 seek 到特定位置 (对 chunks)
}
} // namespace extra2d

View File

@ -1,60 +0,0 @@
#include <event/event.h>
namespace extra2d {
Event Event::createWindowResize(int width, int height) {
Event event;
event.type = EventType::WindowResize;
event.data = WindowResizeEvent{width, height};
return event;
}
Event Event::createWindowClose() {
Event event;
event.type = EventType::WindowClose;
return event;
}
Event Event::createKeyPress(int keyCode, int scancode, int mods) {
Event event;
event.type = EventType::KeyPressed;
event.data = KeyEvent{keyCode, scancode, mods};
return event;
}
Event Event::createKeyRelease(int keyCode, int scancode, int mods) {
Event event;
event.type = EventType::KeyReleased;
event.data = KeyEvent{keyCode, scancode, mods};
return event;
}
Event Event::createMouseButtonPress(int button, int mods, const Vec2 &pos) {
Event event;
event.type = EventType::MouseButtonPressed;
event.data = MouseButtonEvent{button, mods, pos};
return event;
}
Event Event::createMouseButtonRelease(int button, int mods, const Vec2 &pos) {
Event event;
event.type = EventType::MouseButtonReleased;
event.data = MouseButtonEvent{button, mods, pos};
return event;
}
Event Event::createMouseMove(const Vec2 &pos, const Vec2 &delta) {
Event event;
event.type = EventType::MouseMoved;
event.data = MouseMoveEvent{pos, delta};
return event;
}
Event Event::createMouseScroll(const Vec2 &offset, const Vec2 &pos) {
Event event;
event.type = EventType::MouseScrolled;
event.data = MouseScrollEvent{offset, pos};
return event;
}
} // namespace extra2d

View File

@ -1,69 +0,0 @@
#include <algorithm>
#include <event/event_dispatcher.h>
#include <event/event_queue.h>
namespace extra2d {
EventDispatcher::EventDispatcher() : nextId_(1) {}
ListenerId EventDispatcher::addListener(EventType type,
EventCallback callback) {
ListenerId id = nextId_++;
listeners_[type].push_back({id, type, callback});
return id;
}
void EventDispatcher::removeListener(ListenerId id) {
for (auto &[type, listeners] : listeners_) {
auto it = std::remove_if(listeners.begin(), listeners.end(),
[id](const Listener &l) { return l.id == id; });
if (it != listeners.end()) {
listeners.erase(it, listeners.end());
return;
}
}
}
void EventDispatcher::removeAllListeners(EventType type) {
listeners_.erase(type);
}
void EventDispatcher::removeAllListeners() { listeners_.clear(); }
void EventDispatcher::dispatch(Event &event) {
auto it = listeners_.find(event.type);
if (it != listeners_.end()) {
for (auto &listener : it->second) {
if (event.handled)
break;
listener.callback(event);
}
}
}
void EventDispatcher::dispatch(const Event &event) {
Event mutableEvent = event;
dispatch(mutableEvent);
}
void EventDispatcher::processQueue(EventQueue &queue) {
Event event;
while (queue.poll(event)) {
dispatch(event);
}
}
size_t EventDispatcher::getListenerCount(EventType type) const {
auto it = listeners_.find(type);
return (it != listeners_.end()) ? it->second.size() : 0;
}
size_t EventDispatcher::getTotalListenerCount() const {
size_t count = 0;
for (const auto &[type, listeners] : listeners_) {
count += listeners.size();
}
return count;
}
} // namespace extra2d

View File

@ -1,53 +0,0 @@
#include <event/event_queue.h>
namespace extra2d {
EventQueue::EventQueue() = default;
void EventQueue::push(const Event &event) {
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(event);
}
void EventQueue::push(Event &&event) {
std::lock_guard<std::mutex> lock(mutex_);
queue_.push(std::move(event));
}
bool EventQueue::poll(Event &event) {
std::lock_guard<std::mutex> lock(mutex_);
if (queue_.empty()) {
return false;
}
event = queue_.front();
queue_.pop();
return true;
}
bool EventQueue::peek(Event &event) const {
std::lock_guard<std::mutex> lock(mutex_);
if (queue_.empty()) {
return false;
}
event = queue_.front();
return true;
}
void EventQueue::clear() {
std::lock_guard<std::mutex> lock(mutex_);
while (!queue_.empty()) {
queue_.pop();
}
}
bool EventQueue::empty() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.empty();
}
size_t EventQueue::size() const {
std::lock_guard<std::mutex> lock(mutex_);
return queue_.size();
}
} // namespace extra2d

View File

@ -1,4 +1,3 @@
#include <event/event_queue.h>
#include <platform/input.h>
#include <platform/window.h>
#include <utils/logger.h>
@ -13,8 +12,7 @@ Window::Window()
: sdlWindow_(nullptr), glContext_(nullptr), currentCursor_(nullptr),
width_(1280), height_(720), vsync_(true), shouldClose_(false),
fullscreen_(true), focused_(true), contentScaleX_(1.0f),
contentScaleY_(1.0f), enableDpiScale_(true), userData_(nullptr),
eventQueue_(nullptr) {
contentScaleY_(1.0f), enableDpiScale_(true), userData_(nullptr) {
// 初始化光标数组
for (int i = 0; i < 9; ++i) {
sdlCursors_[i] = nullptr;

View File

@ -1,444 +0,0 @@
#include <simpleini/SimpleIni.h>
#include <utils/data.h>
#include <utils/logger.h>
// Switch 平台特定头文件
#ifdef __SWITCH__
#include <switch.h>
#include <switch/services/fs.h>
#endif
namespace extra2d {
class DataStore::Impl {
public:
CSimpleIniA ini;
};
DataStore::DataStore() : impl_(unique<Impl>()) {}
DataStore::~DataStore() {
// 如果在事务中,尝试提交
if (inTransaction_ && dirty_) {
commit();
}
// 如果存档已挂载,卸载
if (saveDataMounted_) {
unmountSaveData(mountName_);
}
}
// ============================================================================
// 文件操作
// ============================================================================
bool DataStore::load(const std::string &filename) {
filename_ = filename;
SI_Error rc = impl_->ini.LoadFile(filename.c_str());
dirty_ = false;
return rc >= 0;
}
bool DataStore::save(const std::string &filename) {
// 如果在事务中,只标记为脏,不实际写入
if (inTransaction_) {
dirty_ = true;
return true;
}
const std::string &targetFile = filename.empty() ? filename_ : filename;
if (targetFile.empty()) {
E2D_LOG_ERROR("DataStore::save: 没有指定文件名");
return false;
}
return internalSave(targetFile);
}
bool DataStore::internalSave(const std::string &filename) {
SI_Error rc = impl_->ini.SaveFile(filename.c_str());
if (rc < 0) {
E2D_LOG_ERROR("DataStore::save: 保存文件失败: {}", filename);
return false;
}
dirty_ = false;
return true;
}
// ============================================================================
// Switch 存档系统支持
// ============================================================================
#ifdef __SWITCH__
bool DataStore::mountSaveData(SaveDataType type, const UserId &userId,
const std::string &mountName) {
// 如果已经挂载,先卸载
if (saveDataMounted_) {
unmountSaveData(mountName_);
}
Result rc = 0;
AccountUid uid = {userId.uid[0], userId.uid[1]};
// 如果没有提供用户ID尝试获取当前用户
if (type == SaveDataType::Account && !userId.isValid()) {
UserId currentUid = getCurrentUserId();
uid.uid[0] = currentUid.uid[0];
uid.uid[1] = currentUid.uid[1];
if (uid.uid[0] == 0 && uid.uid[1] == 0) {
E2D_LOG_ERROR("DataStore::mountSaveData: 无法获取当前用户ID");
return false;
}
}
// 使用 fsdevMountSaveData 挂载
// 注意这里使用当前应用程序ID (0 表示当前应用)
u64 applicationId = 0;
rc = fsdevMountSaveData(mountName.c_str(), applicationId, uid);
if (R_FAILED(rc)) {
E2D_LOG_ERROR("DataStore::mountSaveData: 挂载失败: 0x{:X}", rc);
return false;
}
mountName_ = mountName;
saveDataMounted_ = true;
defaultUserId_ = UserId{uid.uid[0], uid.uid[1]};
E2D_LOG_INFO("DataStore::mountSaveData: 成功挂载存档: {}", mountName);
return true;
}
void DataStore::unmountSaveData(const std::string &mountName) {
if (!saveDataMounted_) {
return;
}
// 先提交更改
if (dirty_) {
commitSaveData(mountName_);
}
fsdevUnmountDevice(mountName.c_str());
saveDataMounted_ = false;
mountName_.clear();
E2D_LOG_INFO("DataStore::unmountSaveData: 已卸载存档");
}
bool DataStore::commitSaveData(const std::string &mountName) {
if (!saveDataMounted_) {
E2D_LOG_WARN("DataStore::commitSaveData: 存档未挂载");
return false;
}
Result rc = fsdevCommitDevice(mountName.c_str());
if (R_FAILED(rc)) {
E2D_LOG_ERROR("DataStore::commitSaveData: 提交失败: 0x{:X}", rc);
return false;
}
E2D_LOG_DEBUG("DataStore::commitSaveData: 提交成功");
return true;
}
std::string DataStore::getSaveDataPath(const std::string &path) const {
if (!saveDataMounted_) {
return path;
}
return mountName_ + ":/" + path;
}
UserId DataStore::getCurrentUserId() {
UserId result;
Result rc = accountInitialize(AccountServiceType_Application);
if (R_FAILED(rc)) {
E2D_LOG_ERROR("DataStore::getCurrentUserId: accountInitialize 失败: 0x{:X}",
rc);
return result;
}
AccountUid uid;
rc = accountGetPreselectedUser(&uid);
accountExit();
if (R_SUCCEEDED(rc)) {
result.uid[0] = uid.uid[0];
result.uid[1] = uid.uid[1];
E2D_LOG_DEBUG("DataStore::getCurrentUserId: 获取成功: 0x{:X}{:X}",
result.uid[1], result.uid[0]);
} else {
E2D_LOG_ERROR("DataStore::getCurrentUserId: 获取失败: 0x{:X}", rc);
}
return result;
}
#else
// 非 Switch 平台的存根实现
bool DataStore::mountSaveData(SaveDataType type, const UserId &userId,
const std::string &mountName) {
(void)type;
(void)userId;
(void)mountName;
E2D_LOG_WARN("DataStore::mountSaveData: 非 Switch 平台,存档功能不可用");
return false;
}
void DataStore::unmountSaveData(const std::string &mountName) {
(void)mountName;
saveDataMounted_ = false;
}
bool DataStore::commitSaveData(const std::string &mountName) {
(void)mountName;
return true;
}
std::string DataStore::getSaveDataPath(const std::string &path) const {
return path;
}
UserId DataStore::getCurrentUserId() { return UserId(); }
#endif
// ============================================================================
// 数据读写
// ============================================================================
std::string DataStore::getString(const std::string &section,
const std::string &key,
const std::string &defaultValue) {
const char *value =
impl_->ini.GetValue(section.c_str(), key.c_str(), defaultValue.c_str());
return value ? value : defaultValue;
}
int DataStore::getInt(const std::string &section, const std::string &key,
int defaultValue) {
return static_cast<int>(
impl_->ini.GetLongValue(section.c_str(), key.c_str(), defaultValue));
}
float DataStore::getFloat(const std::string &section, const std::string &key,
float defaultValue) {
const char *value =
impl_->ini.GetValue(section.c_str(), key.c_str(), nullptr);
if (value) {
try {
return std::stof(value);
} catch (...) {
return defaultValue;
}
}
return defaultValue;
}
bool DataStore::getBool(const std::string &section, const std::string &key,
bool defaultValue) {
return impl_->ini.GetBoolValue(section.c_str(), key.c_str(), defaultValue);
}
void DataStore::setString(const std::string &section, const std::string &key,
const std::string &value) {
impl_->ini.SetValue(section.c_str(), key.c_str(), value.c_str());
dirty_ = true;
// 不在事务中时自动保存
if (!inTransaction_ && !filename_.empty()) {
save("");
}
}
void DataStore::setInt(const std::string &section, const std::string &key,
int value) {
impl_->ini.SetLongValue(section.c_str(), key.c_str(), value);
dirty_ = true;
if (!inTransaction_ && !filename_.empty()) {
save("");
}
}
void DataStore::setFloat(const std::string &section, const std::string &key,
float value) {
impl_->ini.SetValue(section.c_str(), key.c_str(),
std::to_string(value).c_str());
dirty_ = true;
if (!inTransaction_ && !filename_.empty()) {
save("");
}
}
void DataStore::setBool(const std::string &section, const std::string &key,
bool value) {
impl_->ini.SetBoolValue(section.c_str(), key.c_str(), value);
dirty_ = true;
if (!inTransaction_ && !filename_.empty()) {
save("");
}
}
void DataStore::removeKey(const std::string &section, const std::string &key) {
impl_->ini.Delete(section.c_str(), key.c_str());
dirty_ = true;
if (!inTransaction_ && !filename_.empty()) {
save("");
}
}
void DataStore::removeSection(const std::string &section) {
impl_->ini.Delete(section.c_str(), nullptr);
dirty_ = true;
if (!inTransaction_ && !filename_.empty()) {
save("");
}
}
bool DataStore::hasKey(const std::string &section, const std::string &key) {
return impl_->ini.GetValue(section.c_str(), key.c_str(), nullptr) != nullptr;
}
bool DataStore::hasSection(const std::string &section) {
return impl_->ini.GetSection(section.c_str()) != nullptr;
}
void DataStore::clear() {
impl_->ini.Reset();
dirty_ = true;
if (!inTransaction_ && !filename_.empty()) {
save("");
}
}
// ============================================================================
// 事务支持
// ============================================================================
void DataStore::beginTransaction() {
if (inTransaction_) {
E2D_LOG_WARN("DataStore::beginTransaction: 已经处于事务中");
return;
}
inTransaction_ = true;
dirty_ = false;
E2D_LOG_DEBUG("DataStore::beginTransaction: 事务开始");
}
bool DataStore::commit() {
if (!inTransaction_) {
E2D_LOG_WARN("DataStore::commit: 不在事务中");
return false;
}
// 如果有文件名,写入文件
bool result = true;
if (!filename_.empty() && dirty_) {
result = internalSave(filename_);
// 如果挂载了存档,提交更改
if (result && saveDataMounted_) {
result = commitSaveData(mountName_);
}
}
inTransaction_ = false;
E2D_LOG_DEBUG("DataStore::commit: 事务提交 {}", result ? "成功" : "失败");
return result;
}
void DataStore::rollback() {
if (!inTransaction_) {
E2D_LOG_WARN("DataStore::rollback: 不在事务中");
return;
}
// 重新加载文件来恢复数据
if (!filename_.empty()) {
impl_->ini.Reset();
SI_Error rc = impl_->ini.LoadFile(filename_.c_str());
if (rc < 0) {
E2D_LOG_ERROR("DataStore::rollback: 重新加载文件失败: {}", filename_);
}
} else {
// 如果没有文件名,清空数据
impl_->ini.Reset();
}
inTransaction_ = false;
dirty_ = false;
E2D_LOG_DEBUG("DataStore::rollback: 事务已回滚");
}
// ============================================================================
// 工具方法
// ============================================================================
std::vector<std::string> DataStore::getAllSections() const {
std::vector<std::string> sections;
CSimpleIniA::TNamesDepend sectionList;
impl_->ini.GetAllSections(sectionList);
for (const auto &section : sectionList) {
sections.emplace_back(section.pItem);
}
return sections;
}
std::vector<std::string>
DataStore::getAllKeys(const std::string &section) const {
std::vector<std::string> keys;
CSimpleIniA::TNamesDepend keyList;
impl_->ini.GetAllKeys(section.c_str(), keyList);
for (const auto &key : keyList) {
keys.emplace_back(key.pItem);
}
return keys;
}
bool DataStore::loadFromSave(const std::string &path) {
if (!saveDataMounted_) {
E2D_LOG_ERROR("DataStore::loadFromSave: 存档未挂载");
return false;
}
std::string fullPath = getSaveDataPath(path);
return load(fullPath);
}
bool DataStore::saveToSave(const std::string &path) {
if (!saveDataMounted_) {
E2D_LOG_ERROR("DataStore::saveToSave: 存档未挂载");
return false;
}
std::string fullPath = getSaveDataPath(path);
bool result = save(fullPath);
// 自动提交
if (result) {
result = commitSaveData(mountName_);
}
return result;
}
} // namespace extra2d

File diff suppressed because it is too large Load Diff