Lua script

This commit is contained in:
2026-02-28 00:19:25 +03:00
parent 5434239b47
commit 2815369bb8
8 changed files with 202 additions and 7 deletions

View File

@@ -8,5 +8,8 @@
<Entity classname="TempPlayer">
<IsDisableled value="false" />
</Entity>
<Entity classname="game_object">
<IsDisableled value="false" />
</Entity>
</Entities>
</Level>
</Level>

View File

@@ -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" }
}

View File

@@ -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();
}

View File

@@ -6,6 +6,7 @@
#include "ientity.h"
#include "entitymanager.h"
#include "world.h"
#include "game_object.h"
#include <pugixml.hpp>
@@ -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<LuaPrototype> 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<std::string, std::string> 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<LuaPrototype>::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<Entity*>(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()
{
}

View File

@@ -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();
};

View File

@@ -2,6 +2,15 @@
#include "game_object.h"
#include <SDL3/SDL.h>
// 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()

View File

@@ -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

View File

@@ -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);