From 2815369bb883e23511bdbb0e91ee93ec6e6bc2cf Mon Sep 17 00:00:00 2001 From: ugozapad Date: Sat, 28 Feb 2026 00:19:25 +0300 Subject: [PATCH] Lua script --- data/levels/test/test.xml | 5 +- data/scripts/game_init.lua | 7 ++- src/engine/world.cpp | 4 +- src/game/game.cpp | 101 +++++++++++++++++++++++++++++++++++-- src/game/game.h | 4 ++ src/game/game_object.cpp | 72 ++++++++++++++++++++++++++ src/game/game_object.h | 14 +++++ src/render/render.cpp | 2 + 8 files changed, 202 insertions(+), 7 deletions(-) diff --git a/data/levels/test/test.xml b/data/levels/test/test.xml index 5edc3c9..b2a7dcd 100644 --- a/data/levels/test/test.xml +++ b/data/levels/test/test.xml @@ -8,5 +8,8 @@ + + + - \ No newline at end of file + \ No newline at end of file diff --git a/data/scripts/game_init.lua b/data/scripts/game_init.lua index 374d35f..cfd0924 100644 --- a/data/scripts/game_init.lua +++ b/data/scripts/game_init.lua @@ -1,8 +1,13 @@ -- Game initialization script +-- загружаем скрипты +load_script("game_object.lua") + -- глобальная таблица сущностей g_entity_table = { -- Lua class -- CPP class -- Description - { "actor_player", "ActorBase", "Player actor entity" } + { "game_object", "Entity", "Test Lua Entity" } + + } \ No newline at end of file diff --git a/src/engine/world.cpp b/src/engine/world.cpp index ec6e91b..60e2125 100644 --- a/src/engine/world.cpp +++ b/src/engine/world.cpp @@ -62,8 +62,8 @@ void World::Render() // Render entities for (int i = 0; i < m_entities.size(); i++) { - if (frustum.CullBoundingBox(m_entities[i]->GetBoundingBox())) - continue; + //if (frustum.CullBoundingBox(m_entities[i]->GetBoundingBox())) + // continue; m_entities[i]->Render(); } diff --git a/src/game/game.cpp b/src/game/game.cpp index d9327fd..dbd74ce 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -6,6 +6,7 @@ #include "ientity.h" #include "entitymanager.h" #include "world.h" +#include "game_object.h" #include @@ -67,10 +68,20 @@ void registerClasses() // base thing GetLuaState().GetGlobals().RegisterDirect("load_script", &luaLoadScript); + GetLuaState().DoString("g_factory = {}"); registerEngine(); } +struct LuaPrototype +{ + std::string m_luaname; + std::string m_enginename; + std::string m_description; +}; + +std::vector g_prototypes; + void initializeEntityPrototypesFromLua() { using namespace LuaPlus; @@ -80,9 +91,27 @@ void initializeEntityPrototypesFromLua() LuaObject entityTable = it.GetValue(); assert(entityTable.IsTable()); - for (LuaTableIterator it2(entityTable); it2; it2.Next()) { - Logger::Msg("%s", it2.GetValue().ToString()); + if (entityTable.GetTableCount() < 3) + { + Core::Error("Entry in entity prototype table is bad, missing argument"); } + + LuaObject luaname = entityTable[1]; + LuaObject classname = entityTable[2]; + LuaObject description = entityTable[3]; + + Logger::Msg("lua ent: name: %s classname: %s description: %s", luaname.ToString(), classname.ToString(), description.ToString()); + + LuaPrototype prototype; + prototype.m_luaname = luaname.ToString(); + prototype.m_enginename = classname.ToString(); + prototype.m_description = description.ToString(); + g_prototypes.push_back(prototype); + + + /*for (LuaTableIterator it2(entityTable); it2; it2.Next()) { + Logger::Msg("%s", it2.GetValue().ToString()); + }*/ } } @@ -149,6 +178,8 @@ void Game::LoadLevelXML(const char* mapname) buffer, result.description(), result.offset); } +// std::map properties; + for (pugi::xml_node entity : doc.child("Level").child("Entities").children("Entity")) { pugi::xml_attribute entityname = entity.attribute("name"); pugi::xml_attribute classname = entity.attribute("classname"); @@ -162,11 +193,75 @@ void Game::LoadLevelXML(const char* mapname) } } - IEntityBase* entity = g_entityManager->CreateEntity(classname.as_string()); + IEntityBase* entity = Lua_CreateEntity(classname.as_string()); + + // this is pure C++ entity :) + if (!entity) + entity = g_entityManager->CreateEntity(classname.as_string()); + + //IEntityBase* entity = g_entityManager->CreateEntity(classname.as_string()); g_world->AddEntity(entity); } } +IEntityBase* Game::Lua_CreateEntity(const char* classname) +{ + using namespace LuaPlus; + + //if (!classname) + // classname = "Entity"; + + SDL_assert_always(classname); + + LuaPrototype* pluaprototype = nullptr; + + // find a prototype + for (std::vector::iterator it = g_prototypes.begin(); + it != g_prototypes.end(); + ++it) + { + if (strcmp((*it).m_luaname.c_str(), classname) == 0) + { + pluaprototype = &(*it); + break; + } + } + + if (pluaprototype) + { + Entity* entity = static_cast(g_entityManager->CreateEntity(pluaprototype->m_enginename.c_str())); + SDL_assert_always(entity); + + // get a prototype + LuaObject prototype = GetLuaState().GetGlobal(pluaprototype->m_luaname.c_str()); + SDL_assert_always(!prototype.IsNil()); + prototype.SetObject("__index", prototype); + + // generate table + LuaObject factory = GetLuaState().GetGlobal("g_factory"); + + // generate name + std::string entityname = pluaprototype->m_luaname + "_" + std::to_string(factory.GetTableCount()); + + // create an table + LuaObject entityTable = GetLuaState().GetGlobals().CreateTable(entityname.c_str()); + entityTable.SetMetatable(prototype); + entityTable.SetString("m_name", entityname.c_str()); + + // push in to the factory + factory.SetObject(entityname.c_str(), entityTable); + + // link to the entity + entity->InitFromTable(entityTable); + + return entity; + } + + //IEntityBase* entity = g_entityManager->CreateEntity(classname); + + return nullptr; +} + void Game::Shutdown() { } diff --git a/src/game/game.h b/src/game/game.h index 549f78f..ae74b81 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -1,6 +1,8 @@ #ifndef GAME_H #define GAME_H +class IEntityBase; + class Game { public: @@ -9,6 +11,8 @@ public: void LoadLevelXML(const char* mapname); + IEntityBase* Lua_CreateEntity(const char* classname); + void Shutdown(); }; diff --git a/src/game/game_object.cpp b/src/game/game_object.cpp index 363901a..5d33cb1 100644 --- a/src/game/game_object.cpp +++ b/src/game/game_object.cpp @@ -2,6 +2,15 @@ #include "game_object.h" #include +// Lua wrappers +void Entity_LoadModel(LuaPlus::LuaState* state) +{ + LuaPlus::LuaStack stack(state); + + Entity* entity = (Entity*)stack[1].GetByName("__object").GetLightUserdata(); + entity->LoadModel(stack[2].GetString()); +} + REGISTER_ENTITY(Entity); Entity::Entity() : @@ -11,6 +20,32 @@ Entity::Entity() : Entity::~Entity() { + if (m_onShutdownFunction.IsFunction()) + { + LuaPlus::LuaFunctionVoid function = m_onShutdownFunction; + function(m_luaObject); + } + + if (m_luaObject.IsTable()) + { + LuaPlus::LuaObject name = m_luaObject["m_name"]; + if (name.IsString()) + { + LuaPlus::LuaObject factory = GetLuaState().GetGlobal("g_factory"); + factory.SetNil(m_luaObject); + } + + m_luaObject.AssignNil(); + } +} + +void Entity::Update(float dt) +{ + if ( m_onUpdateFunction.IsFunction()) + { + LuaPlus::LuaFunctionVoid function = m_onUpdateFunction; + function(m_luaObject, dt); + } } void Entity::Render() @@ -24,6 +59,43 @@ void Entity::LoadModel(const char* filename) m_model = g_modelSystem->LoadModel(filename); } +void Entity::SetVisible(bool visible) +{ +} + +bool Entity::GetVisible() +{ + return true; +} + +void Entity::InitFromTable(LuaPlus::LuaObject& _object) +{ + SDL_assert_always(!_object.IsNil() && "Invalid object passed"); + + // catch table instance + m_luaObject = _object; + + // find functions + m_onInitFunction = m_luaObject.GetByName("on_init"); + m_onShutdownFunction = m_luaObject.GetByName("on_shutdown"); + m_onUpdateFunction = m_luaObject.GetByName("on_update"); + + // check + SDL_assert_always(m_onInitFunction.IsFunction() || m_onShutdownFunction.IsFunction() || m_onUpdateFunction.IsFunction()); + + // register entity functions + m_luaObject.RegisterDirect("load_model", &Entity_LoadModel); + //m_luaObject.RegisterDirect("set_visible", &Entity::SetVisible); + //m_luaObject.RegisterDirect("get_visible", &Entity::GetVisible); + + // assign C++ object + m_luaObject.SetLightUserdata("__object", this); + + // call init + LuaPlus::LuaFunctionVoid onInitFunction = m_onInitFunction; + onInitFunction(m_luaObject); +} + REGISTER_ENTITY(TempPlayer); TempPlayer::TempPlayer() diff --git a/src/game/game_object.h b/src/game/game_object.h index c9732e5..423f9c6 100644 --- a/src/game/game_object.h +++ b/src/game/game_object.h @@ -7,6 +7,8 @@ #include "render/model.h" #include "render/modelsystem.h" +#include "game_lua_help.h" + enum EMovmentDir { EMovementDir_None = 1 << 0, @@ -22,12 +24,24 @@ public: Entity(); virtual ~Entity(); + virtual void Update(float dt); virtual void Render(); + // Game entity extensions virtual void LoadModel(const char* filename); + void SetVisible(bool visible); + bool GetVisible(); + + + void InitFromTable(LuaPlus::LuaObject& _object); protected: Model* m_model; + + LuaPlus::LuaObject m_luaObject; + LuaPlus::LuaObject m_onInitFunction; + LuaPlus::LuaObject m_onShutdownFunction; + LuaPlus::LuaObject m_onUpdateFunction; }; class TempPlayer : public Entity diff --git a/src/render/render.cpp b/src/render/render.cpp index 27e4bec..0b808cf 100644 --- a/src/render/render.cpp +++ b/src/render/render.cpp @@ -87,6 +87,8 @@ void Render::Init(SDL_Window* pWindow) m_pWindow = pWindow; SDL_assert(m_pWindow); + Msg("Initializing renderer ..."); + // Create OpenGL context m_pGLContext = SDL_GL_CreateContext(m_pWindow); SDL_GL_MakeCurrent(m_pWindow, m_pGLContext);