diff --git a/.gitignore b/.gitignore index f44438a..73c9de7 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ build/ .vscode/compile_commands.json 参考代码/ *.pvf +nul diff --git a/Frostbite2D/include/frostbite2D/platform/windows.h b/Frostbite2D/include/frostbite2D/platform/windows.h new file mode 100644 index 0000000..57e8812 --- /dev/null +++ b/Frostbite2D/include/frostbite2D/platform/windows.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef _WIN32 + +#include + +namespace frostbite2D { + +void windowsInit(); + +} // namespace frostbite2D + +#endif diff --git a/Frostbite2D/include/frostbite2D/script/squirrel_vm.h b/Frostbite2D/include/frostbite2D/script/squirrel_vm.h new file mode 100644 index 0000000..652ebe3 --- /dev/null +++ b/Frostbite2D/include/frostbite2D/script/squirrel_vm.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include +#include // Squirrel核心头文件 +#include // Squirrel标准IO库 +#include // 新增:包含 sqstd_seterrorhandlers 等辅助函数 +#include // 新增:包含 sqstd_register_bloblib 函数 +#include // 新增:包含 sqstd_register_systemlib 函数 +#include // 新增:包含 sqstd_register_mathlib 函数 +#include // 新增:包含 sqstd_register_stringlib 函数 + +#include + +namespace frostbite2D { + +class SquirrelVM { +public: + static SquirrelVM &get(); + + void setScriptDirectory(const std::string &path); + void setDebugMode(bool enable); + + bool init(); + void shutdown(); + void loadScript(); + + HSQUIRRELVM getVM() const { return vm_; } + bool isValid() const { return vm_ != nullptr; } + +private: + SquirrelVM() = default; + ~SquirrelVM() = default; + + SquirrelVM(const SquirrelVM &) = delete; + SquirrelVM &operator=(const SquirrelVM &) = delete; + + static void printCallback(HSQUIRRELVM vm, const char *s, ...); + static void errorCallback(HSQUIRRELVM vm, const char *s, ...); + + bool loadScriptFile(const std::string &path); + + HSQUIRRELVM vm_ = nullptr; + bool initialized_ = false; + std::string scriptDirectory_; + bool debugMode_ = false; +}; + +} // namespace frostbite2D diff --git a/Frostbite2D/src/frostbite2D/core/application.cpp b/Frostbite2D/src/frostbite2D/core/application.cpp index 494bf60..4d542cb 100644 --- a/Frostbite2D/src/frostbite2D/core/application.cpp +++ b/Frostbite2D/src/frostbite2D/core/application.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,10 @@ bool Application::init(const AppConfig& config) { switchInit(); #endif + #ifdef _WIN32 + windowsInit(); + #endif + // 初始化核心模块 if (!initCoreModules()) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize core modules"); diff --git a/Frostbite2D/src/frostbite2D/platform/windows.cpp b/Frostbite2D/src/frostbite2D/platform/windows.cpp new file mode 100644 index 0000000..a0bec62 --- /dev/null +++ b/Frostbite2D/src/frostbite2D/platform/windows.cpp @@ -0,0 +1,14 @@ +#include + +#ifdef _WIN32 + +namespace frostbite2D { + +void windowsInit() { + SetConsoleOutputCP(CP_UTF8); + SetConsoleCP(CP_UTF8); +} + +} // namespace frostbite2D + +#endif diff --git a/Frostbite2D/src/frostbite2D/script/squirrel_vm.cpp b/Frostbite2D/src/frostbite2D/script/squirrel_vm.cpp new file mode 100644 index 0000000..2bb8aa1 --- /dev/null +++ b/Frostbite2D/src/frostbite2D/script/squirrel_vm.cpp @@ -0,0 +1,155 @@ +#include + +#include +#include + +namespace frostbite2D { + +SquirrelVM &SquirrelVM::get() { + static SquirrelVM instance; + return instance; +} + +void SquirrelVM::setScriptDirectory(const std::string &path) { + scriptDirectory_ = path; +} + +void SquirrelVM::setDebugMode(bool enable) { debugMode_ = enable; } + +bool SquirrelVM::init() { + if (initialized_) { + return true; + } + + vm_ = sq_open(1024); + if (!vm_) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, "[Squirrel] Failed to create VM"); + return false; + } + + sqstd_seterrorhandlers(vm_); + sq_pushroottable(vm_); + sqstd_register_bloblib(vm_); + sqstd_register_iolib(vm_); + sqstd_register_systemlib(vm_); + sqstd_register_mathlib(vm_); + sqstd_register_stringlib(vm_); + + sq_setprintfunc(vm_, printCallback, errorCallback); + + loadScript(); + + initialized_ = true; + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, + "[Squirrel] VM initialized (Squirrel %s)", SQUIRREL_VERSION); + + return true; +} + +void SquirrelVM::loadScript() { + + std::string scriptDir = + scriptDirectory_.empty() ? "scripts" : scriptDirectory_; + std::string configPath = scriptDir + "/scripts.json"; + + Asset &asset = Asset::get(); + std::optional jsonContent = asset.readFileToString(configPath); + + if (!jsonContent) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, + "[Squirrel] Failed to load scripts config: %s", + configPath.c_str()); + return; + } + + try { + auto json = nlohmann::json::parse(*jsonContent); + auto files = json["files"]; + + for (const auto &filePath : files) { + std::string fullPath = scriptDir + "/" + std::string(filePath); + loadScriptFile(fullPath); + } + } catch (const std::exception &e) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, + "[Squirrel] Failed to parse scripts.json: %s", e.what()); + } +} + +bool SquirrelVM::loadScriptFile(const std::string &path) { + Asset &asset = Asset::get(); + std::optional content = asset.readFileToString(path); + + if (!content) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, "[Squirrel] Failed to read script: %s", + path.c_str()); + return false; + } + + const SQChar *script = content->c_str(); + + SQInteger size = static_cast(content->size()); + + if (SQ_FAILED(sq_compilebuffer(vm_, script, size, path.c_str(), SQTrue))) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, + "[Squirrel] Failed to compile script: %s", path.c_str()); + return false; + } + + sq_pushroottable(vm_); + + if (SQ_FAILED(sq_call(vm_, 1, SQTrue, SQTrue))) { + SDL_LogError(SDL_LOG_CATEGORY_ERROR, + "[Squirrel] Failed to execute script: %s", path.c_str()); + sq_pop(vm_, 2); + return false; + } + + sq_pop(vm_, 2); + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[Squirrel] Loaded script: %s", + path.c_str()); + return true; +} + +void SquirrelVM::shutdown() { + if (vm_) { + sq_close(vm_); + vm_ = nullptr; + } + initialized_ = false; + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[Squirrel] VM shutdown"); +} + +void SquirrelVM::printCallback(HSQUIRRELVM vm, const char *s, ...) { + va_list args; + va_start(args, s); + + int size = vsnprintf(nullptr, 0, s, args); + va_end(args); + + if (size > 0) { + std::vector buffer(size + 1); + va_start(args, s); + vsnprintf(buffer.data(), buffer.size(), s, args); + va_end(args); + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[Squirrel] %s", buffer.data()); + } +} + +void SquirrelVM::errorCallback(HSQUIRRELVM vm, const char *s, ...) { + va_list args; + va_start(args, s); + + int size = vsnprintf(nullptr, 0, s, args); + va_end(args); + + if (size > 0) { + std::vector buffer(size + 1); + va_start(args, s); + vsnprintf(buffer.data(), buffer.size(), s, args); + va_end(args); + SDL_LogError(SDL_LOG_CATEGORY_ERROR, "[Squirrel Error] %s", buffer.data()); + } +} + +} // namespace frostbite2D diff --git a/Game/assets/scripts/main.nut b/Game/assets/scripts/main.nut new file mode 100644 index 0000000..7463211 --- /dev/null +++ b/Game/assets/scripts/main.nut @@ -0,0 +1,2 @@ +print("中文测试!") +error("中文测试错误!") diff --git a/Game/src/main.cpp b/Game/src/main.cpp index 0c5d7cb..bcc0a28 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -29,6 +29,8 @@ #include #include +#include + using namespace frostbite2D; int main(int argc, char **argv) { @@ -45,8 +47,10 @@ int main(int argc, char **argv) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize application!"); return -1; } - + // SDL_Log("Starting main loop..."); + SquirrelVM::get().setScriptDirectory("assets/scripts"); + SquirrelVM::get().init(); auto &pvf = PvfArchive::get(); if (pvf.open("assets/Script.pvf")) { diff --git a/platform/linux.lua b/platform/linux.lua index 90cf367..7734bc7 100644 --- a/platform/linux.lua +++ b/platform/linux.lua @@ -4,6 +4,7 @@ add_requires("libsdl2_image") add_requires("libsdl2_mixer") add_requires("glm") add_requires("zlib") +add_requires("squirrel") target("Frostbite2D") set_kind("binary") @@ -19,6 +20,7 @@ target("Frostbite2D") add_packages("libsdl2_mixer") add_packages("glm") add_packages("zlib") + add_packages("squirrel") -- 复制着色器文件到输出目录 after_build(function (target) diff --git a/platform/mingw.lua b/platform/mingw.lua index 47decea..ecb686e 100644 --- a/platform/mingw.lua +++ b/platform/mingw.lua @@ -7,6 +7,7 @@ add_requires("libsdl2_mixer", {configs = {shared = true}}) add_requires("libsdl2_ttf", {configs = {shared = true}}) add_requires("glm") add_requires("zlib") +add_requires("squirrel") target("Frostbite2D") set_kind("binary") @@ -23,6 +24,7 @@ target("Frostbite2D") add_packages("libsdl2_ttf") add_packages("glm") add_packages("zlib") + add_packages("squirrel") -- 复制 assets 目录到输出目录 after_build(function (target) diff --git a/platform/switch.lua b/platform/switch.lua index 51bb757..91fb688 100644 --- a/platform/switch.lua +++ b/platform/switch.lua @@ -1,4 +1,5 @@ + target("Frostbite2D") set_kind("binary") add_files(path.join(os.projectdir(), "Frostbite2D/src/**.cpp")) @@ -40,7 +41,7 @@ target("Frostbite2D") add_includedirs(path.join(devkitPro, "portlibs/switch/include/SDL2")) add_linkdirs(path.join(devkitPro, "portlibs/switch/lib")) - add_syslinks("SDL2_mixer", "SDL2_image", "SDL2_ttf", "SDL2", "freetype", "harfbuzz" , "bz2" , "webp", "png", "jpeg", "z", "opusfile", "opus", "vorbisidec", "ogg","modplug", "mpg123", "FLAC", "GLESv2", "EGL", "glapi", "drm_nouveau",{public = true}) + add_syslinks("SDL2_mixer", "SDL2_image", "SDL2_ttf", "SDL2", "freetype", "harfbuzz" , "squirrel_static", "sqstdlib_static", "bz2" , "webp", "png", "jpeg", "z", "opusfile", "opus", "vorbisidec", "ogg","modplug", "mpg123", "FLAC", "GLESv2", "EGL", "glapi", "drm_nouveau",{public = true}) add_syslinks("nx", "m")