diff --git a/Makefile b/Makefile index 27429bc..ef9f58a 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ src/splashpack.cpp \ src/camera.cpp \ src/gtemath.cpp \ src/navmesh.cpp \ +src/lua.cpp \ output.o include third_party/nugget/psyqo/psyqo.mk diff --git a/output.bin b/output.bin index 317e6d2..e7ac205 100644 Binary files a/output.bin and b/output.bin differ diff --git a/src/lua.cpp b/src/lua.cpp index 92fb82b..ddcc1f0 100644 --- a/src/lua.cpp +++ b/src/lua.cpp @@ -1 +1,191 @@ -#include "lua.h" \ No newline at end of file +#include "lua.h" + +#include + +#include "gameobject.hh" +#include "psyqo-lua/lua.hh" + +constexpr const char METATABLE_SCRIPT[] = R"( + print("test") + metatableForAllGameObjects = { + __index = function(self, key) + if key == "position" then + local pos = rawget(self, key) + if pos == nil then + pos = get_position(self.__cpp_ptr) + rawset(self, key, pos) + end + return pos + end + return rawget(self, key) + end, + + __newindex = function(self, key, value) + if key == "position" then + -- Option 1: Directly update C++ + set_position(self.__cpp_ptr, value) + -- Option 2: Also update local cache: + rawset(self, key, value) + return + end + rawset(self, key, value) + end + } +)"; + +// Lua helpers + +int luaPrint(psyqo::Lua L) { + int n = L.getTop(); // Get the number of arguments + + for (int i = 1; i <= n; i++) { + if (i > 1) { + printf("\t"); // Tab between arguments + } + + // Check the type of the argument + if (L.isString(i)) { + printf("%s", L.toString(i)); // If it's a string, print it + } else if (L.isNumber(i)) { + printf("%g", L.toNumber(i)); // If it's a number, print it + } else { + // For other types, just print their type (you can expand this if needed) + printf("[%s]", L.typeName(i)); + } + } + printf("\n"); + + return 0; // No return value +} + +static int gameobjectSetPosition(lua_State* L) { + psxsplash::GameObject* go = (psxsplash::GameObject*)lua_touserdata(L, 1); + lua_newtable(L); + lua_pushnumber(L, go->position.x.raw()); + lua_setfield(L, -2, "x"); + lua_pushnumber(L, go->position.y.raw()); + lua_setfield(L, -2, "y"); + lua_pushnumber(L, go->position.z.raw()); + lua_setfield(L, -2, "z"); + return 1; +} + +static int gameobjectGetPosition(lua_State* L) { + psxsplash::GameObject* go = (psxsplash::GameObject*)lua_touserdata(L, 1); + + lua_getfield(L, 2, "x"); + psyqo::FixedPoint<> x(lua_tonumber(L, -1), psyqo::FixedPoint<>::RAW); + go->position.x = x; + lua_pop(L, 1); + lua_getfield(L, 2, "y"); + psyqo::FixedPoint<> y(lua_tonumber(L, -1), psyqo::FixedPoint<>::RAW); + go->position.x = x; + lua_pop(L, 1); + lua_getfield(L, 2, "z"); + psyqo::FixedPoint<> z(lua_tonumber(L, -1), psyqo::FixedPoint<>::RAW); + go->position.x = x; + lua_pop(L, 1); + + return 0; +} + +void psxsplash::Lua::Init() { + L.push(luaPrint); + L.setGlobal("print"); + + L.push(gameobjectGetPosition); + L.setGlobal("get_position"); + + L.push(gameobjectSetPosition); + L.setGlobal("set_position"); + + // Load and run the metatable script + if (L.loadBuffer(METATABLE_SCRIPT, "metatableForAllGameObjects") == 0) { + if (L.pcall(0, 0) == 0) { + // Script executed successfully + printf("Lua script 'metatableForAllGameObjects' loaded successfully\n"); + } else { + // Print Lua error if script execution fails + printf("Error executing Lua script: %s\n", L.isString(-1) ? L.toString(-1) : "Unknown error"); + L.pop(); + } + } else { + // Print Lua error if script loading fails + printf("Error loading Lua script: %s\n", L.isString(-1) ? L.toString(-1) : "Unknown error"); + L.pop(); + } + + // Check if the metatable was set as a global + L.getGlobal("metatableForAllGameObjects"); + if (L.isTable(-1)) { + printf("metatableForAllGameObjects successfully set as a global\n"); + } else { + printf("Warning: metatableForAllGameObjects not found after init\n"); + } + L.pop(); // Pop the global check +} + +void psxsplash::Lua::LoadLuaFile(const char* code, size_t len) { + if (L.loadBuffer(code, len) != LUA_OK) { + printf("Lua error: %s\n", L.toString(-1)); + L.pop(); + } + if (L.pcall(0, 0)) { + printf("Lua error: %s\n", L.toString(-1)); + L.pop(); + } +} + +void psxsplash::Lua::RegisterGameObject(GameObject* go) { + // Create a new Lua table for the GameObject + L.newTable(); + + // Set the __cpp_ptr field to store the C++ pointer + L.push(go); + L.setField(-2, "__cpp_ptr"); + + // Set the metatable for the table + L.getGlobal("metatableForAllGameObjects"); + if (L.isTable(-1)) { + L.setMetatable(-2); // Set the metatable for the table + } else { + printf("Warning: metatableForAllGameObjects not found\n"); + L.pop(); // Pop the invalid metatable + } + + L.push(go); + L.push(-2); + L.rawSet(LUA_REGISTRYINDEX); + + // Debugging: Confirm the GameObject was registered + printf("GameObject registered in Lua registry: %p\n", go); + + L.pop(); +} + +void psxsplash::Lua::CallOnCollide(GameObject* self, GameObject* other) { + L.getGlobal("onCollision"); + if (!L.isFunction(-1)) { + printf("Lua function 'onCollide' not found\n"); + L.pop(); + return; + } + + PushGameObject(self); + PushGameObject(other); + + if (L.pcall(2, 0)) { + printf("Lua error: %s\n", L.toString(-1)); + L.pop(); + } +} + +void psxsplash::Lua::PushGameObject(GameObject* go) { + L.push(go); + L.rawGet(LUA_REGISTRYINDEX); + + if (!L.isTable(-1)) { + printf("Warning: GameObject not found in Lua registry\n"); + L.pop(); + } +} diff --git a/src/lua.h b/src/lua.h index e69de29..9445f7f 100644 --- a/src/lua.h +++ b/src/lua.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "gameobject.hh" + +namespace psxsplash { +class Lua { + public: + void Init(); + + void LoadLuaFile(const char* code, size_t len); + void RegisterGameObject(GameObject* go); + void CallOnCollide(GameObject* self, GameObject* other); + + private: + void PushGameObject(GameObject* go); + psyqo::Lua L; +}; +} // namespace psxsplash \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b04f955..58769e7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,7 @@ #include "EASTL/algorithm.h" #include "camera.hh" +#include "lua.h" #include "navmesh.hh" #include "psyqo/vector.hh" #include "renderer.hh" @@ -30,6 +31,7 @@ class PSXSplash final : public psyqo::Application { void createScene() override; public: + psxsplash::Lua m_lua; psxsplash::SplashPackLoader m_loader; psyqo::Font<> m_font; @@ -75,6 +77,8 @@ void PSXSplash::prepare() { // Initialize the Renderer singleton psxsplash::Renderer::Init(gpu()); + + m_lua.Init(); } void PSXSplash::createScene() { @@ -84,7 +88,8 @@ void PSXSplash::createScene() { } void MainScene::start(StartReason reason) { - app.m_loader.LoadSplashpack(_binary_output_bin_start); + app.m_loader.LoadSplashpack(_binary_output_bin_start, app.m_lua); + app.m_lua.CallOnCollide(app.m_loader.gameObjects[0], app.m_loader.gameObjects[1]); psxsplash::Renderer::GetInstance().SetCamera(m_mainCamera); m_mainCamera.SetPosition(static_cast>(app.m_loader.playerStartPos.x), @@ -184,6 +189,7 @@ void MainScene::frame() { psxsplash::Renderer::GetInstance().RenderNavmeshPreview(*app.m_loader.navmeshes[0], true); } + app.m_font.chainprintf(gpu(), {{.x = 2, .y = 2}}, {{.r = 0xff, .g = 0xff, .b = 0xff}}, "FPS: %i", gpu().getRefreshRate() / deltaTime); diff --git a/src/splashpack.cpp b/src/splashpack.cpp index d5d6b3e..85bb4b5 100644 --- a/src/splashpack.cpp +++ b/src/splashpack.cpp @@ -5,6 +5,7 @@ #include #include "gameobject.hh" +#include "lua.h" #include "mesh.hh" #include "psyqo/fixed-point.hh" #include "psyqo/gte-registers.hh" @@ -15,6 +16,7 @@ namespace psxsplash { struct SPLASHPACKFileHeader { char magic[2]; uint16_t version; + uint16_t luaFileCount; uint16_t gameObjectCount; uint16_t navmeshCount; uint16_t textureAtlasCount; @@ -22,7 +24,15 @@ struct SPLASHPACKFileHeader { psyqo::GTE::PackedVec3 playerStartPos; psyqo::GTE::PackedVec3 playerStartRot; psyqo::FixedPoint<12, uint16_t> playerHeight; - uint16_t pad[1]; + uint16_t pad[2]; +}; + +struct SPLASHPACKLuaFile { + union { + uint32_t luaCodeOffset; + const char* luaCode; + }; + uint32_t length; }; struct SPLASHPACKTextureAtlas { @@ -39,7 +49,7 @@ struct SPLASHPACKClut { uint16_t pad; }; -void SplashPackLoader::LoadSplashpack(uint8_t *data) { +void SplashPackLoader::LoadSplashpack(uint8_t *data, psxsplash::Lua &lua) { psyqo::Kernel::assert(data != nullptr, "Splashpack loading data pointer is null"); psxsplash::SPLASHPACKFileHeader *header = reinterpret_cast(data); psyqo::Kernel::assert(memcmp(header->magic, "SP", 2) == 0, "Splashpack has incorrect magic"); @@ -53,9 +63,17 @@ void SplashPackLoader::LoadSplashpack(uint8_t *data) { uint8_t *curentPointer = data + sizeof(psxsplash::SPLASHPACKFileHeader); + for (uint16_t i = 0; i < header->luaFileCount; i++) { + psxsplash::SPLASHPACKLuaFile *luaHeader = reinterpret_cast(curentPointer); + luaHeader->luaCode = reinterpret_cast(data + luaHeader->luaCodeOffset); + lua.LoadLuaFile(luaHeader->luaCode, luaHeader->length); + curentPointer += sizeof(psxsplash::SPLASHPACKLuaFile); + } + for (uint16_t i = 0; i < header->gameObjectCount; i++) { psxsplash::GameObject *go = reinterpret_cast(curentPointer); go->polygons = reinterpret_cast(data + go->polygonsOffset); + lua.RegisterGameObject(go); gameObjects.push_back(go); curentPointer += sizeof(psxsplash::GameObject); } diff --git a/src/splashpack.hh b/src/splashpack.hh index 11273c8..9806bdc 100644 --- a/src/splashpack.hh +++ b/src/splashpack.hh @@ -5,11 +5,13 @@ #include #include "gameobject.hh" +#include "lua.h" #include "navmesh.hh" #include "psyqo/fixed-point.hh" namespace psxsplash { + class SplashPackLoader { public: eastl::vector gameObjects; @@ -18,7 +20,7 @@ class SplashPackLoader { psyqo::GTE::PackedVec3 playerStartPos, playerStartRot; psyqo::FixedPoint<12, uint16_t> playerHeight; - void LoadSplashpack(uint8_t *data); + void LoadSplashpack(uint8_t *data, Lua &lua); }; }; // namespace psxsplash \ No newline at end of file