Lua API implemented
This commit is contained in:
@@ -65,8 +65,6 @@ set(EDITSCENE_SOURCES
|
||||
systems/PrefabSystem.cpp
|
||||
ui/PrefabInstanceEditor.cpp
|
||||
|
||||
LuaScripting.cpp
|
||||
|
||||
systems/ItemSystem.cpp
|
||||
components/ItemModule.cpp
|
||||
components/InventoryModule.cpp
|
||||
@@ -149,6 +147,10 @@ set(EDITSCENE_SOURCES
|
||||
gizmo/Gizmo.cpp
|
||||
gizmo/Cursor3D.cpp
|
||||
physics/physics.cpp
|
||||
lua/LuaState.cpp
|
||||
lua/LuaEntityApi.cpp
|
||||
lua/LuaComponentApi.cpp
|
||||
lua/LuaEventApi.cpp
|
||||
)
|
||||
|
||||
set(EDITSCENE_HEADERS
|
||||
@@ -293,7 +295,10 @@ set(EDITSCENE_HEADERS
|
||||
gizmo/Gizmo.hpp
|
||||
gizmo/Cursor3D.hpp
|
||||
physics/physics.h
|
||||
LuaScripting.hpp
|
||||
lua/LuaState.hpp
|
||||
lua/LuaEntityApi.hpp
|
||||
lua/LuaComponentApi.hpp
|
||||
lua/LuaEventApi.hpp
|
||||
)
|
||||
|
||||
add_executable(editSceneEditor ${EDITSCENE_SOURCES} ${EDITSCENE_HEADERS})
|
||||
|
||||
@@ -84,6 +84,9 @@
|
||||
|
||||
#include <OgreRTShaderSystem.h>
|
||||
#include <imgui.h>
|
||||
#include "lua/LuaEntityApi.hpp"
|
||||
#include "lua/LuaComponentApi.hpp"
|
||||
#include "lua/LuaEventApi.hpp"
|
||||
|
||||
//=============================================================================
|
||||
// ImGuiRenderListener Implementation
|
||||
@@ -484,6 +487,28 @@ void EditorApp::setup()
|
||||
addInputListener(this);
|
||||
addInputListener(getImGuiInputListener());
|
||||
|
||||
// Initialize Lua scripting
|
||||
{
|
||||
lua_State *L = m_lua.getState();
|
||||
|
||||
// Store the Flecs world pointer in the Lua registry
|
||||
// so Lua API functions can access it.
|
||||
flecs::world *worldPtr = &m_world;
|
||||
lua_pushlightuserdata(L, worldPtr);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX,
|
||||
"EditSceneFlecsWorld");
|
||||
|
||||
// Register all Lua API modules.
|
||||
// Order matters: Entity API creates the "ecs" table,
|
||||
// Component and Event APIs add to it.
|
||||
editScene::registerLuaEntityApi(L);
|
||||
editScene::registerLuaComponentApi(L);
|
||||
editScene::registerLuaEventApi(L);
|
||||
|
||||
// Run late setup: load data.lua and initial scripts.
|
||||
m_lua.lateSetup();
|
||||
}
|
||||
|
||||
// Game mode can be set externally before setup() is called
|
||||
m_setupComplete = true;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <OgreRenderTargetListener.h>
|
||||
#include <flecs.h>
|
||||
#include <memory>
|
||||
#include "lua/LuaState.hpp"
|
||||
|
||||
// Forward declarations
|
||||
class EditorUISystem;
|
||||
@@ -261,6 +262,9 @@ private:
|
||||
bool m_setupComplete = false;
|
||||
bool m_debugBuoyancy = false;
|
||||
|
||||
// Lua scripting
|
||||
editScene::LuaState m_lua;
|
||||
|
||||
// Editor visualization nodes
|
||||
Ogre::SceneNode *m_gridNode = nullptr;
|
||||
Ogre::SceneNode *m_axisNode = nullptr;
|
||||
|
||||
1931
src/features/editScene/lua/LuaComponentApi.cpp
Normal file
1931
src/features/editScene/lua/LuaComponentApi.cpp
Normal file
File diff suppressed because it is too large
Load Diff
55
src/features/editScene/lua/LuaComponentApi.hpp
Normal file
55
src/features/editScene/lua/LuaComponentApi.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef EDITSCENE_LUA_COMPONENT_API_HPP
|
||||
#define EDITSCENE_LUA_COMPONENT_API_HPP
|
||||
#pragma once
|
||||
|
||||
#include <lua.hpp>
|
||||
|
||||
/**
|
||||
* @file LuaComponentApi.hpp
|
||||
* @brief Lua API for adding, removing, and modifying ECS components.
|
||||
*
|
||||
* Provides a generic component API where Lua scripts can add, get, set,
|
||||
* and remove components on entities. Each component type is registered
|
||||
* with a name string and a set of field accessors.
|
||||
*
|
||||
* Exposed Lua globals (in the "ecs" table):
|
||||
* ecs.add_component(id, "ComponentName") -> nil
|
||||
* ecs.remove_component(id, "ComponentName") -> nil
|
||||
* ecs.has_component(id, "ComponentName") -> bool
|
||||
* ecs.get_component(id, "ComponentName") -> table (field -> value)
|
||||
* ecs.set_component(id, "ComponentName", table) -> nil
|
||||
* ecs.get_field(id, "ComponentName", "fieldName") -> value
|
||||
* ecs.set_field(id, "ComponentName", "fieldName", value) -> nil
|
||||
*
|
||||
* Supported component names (case-sensitive):
|
||||
* "EntityName", "Transform", "Renderable", "Light", "Camera",
|
||||
* "RigidBody", "PhysicsCollider", "Character", "CharacterSlots",
|
||||
* "AnimationTree", "AnimationTreeTemplate", "BehaviorTree",
|
||||
* "GoapBlackboard", "GoapAction", "GoapGoal", "ActionDatabase",
|
||||
* "ActionDebug", "SmartObject", "Actuator", "EventHandler",
|
||||
* "GoapPlanner", "GoapRunner", "PathFollowing", "NavMesh",
|
||||
* "NavMeshGeometrySource", "NavMeshAgent", "Item", "Inventory",
|
||||
* "Lod", "LodSettings", "StaticGeometry", "StaticGeometryMember",
|
||||
* "ProceduralTexture", "ProceduralMaterial", "Primitive",
|
||||
* "TriangleBuffer", "Sun", "Skybox", "WaterPlane", "WaterPhysics",
|
||||
* "BuoyancyInfo", "StartupMenu", "Dialogue", "PlayerController",
|
||||
* "CellGrid", "Room", "ClearArea", "Roof", "Lot", "District",
|
||||
* "Town", "FurnitureTemplate", "PrefabInstance", "EditorMarker"
|
||||
*/
|
||||
|
||||
namespace editScene
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Register all component Lua API functions into the "ecs" global table.
|
||||
*
|
||||
* Adds functions for component manipulation (add, remove, has, get, set,
|
||||
* get_field, set_field) to the existing "ecs" table.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
*/
|
||||
void registerLuaComponentApi(lua_State *L);
|
||||
|
||||
} // namespace editScene
|
||||
|
||||
#endif // EDITSCENE_LUA_COMPONENT_API_HPP
|
||||
236
src/features/editScene/lua/LuaEntityApi.cpp
Normal file
236
src/features/editScene/lua/LuaEntityApi.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
#include "LuaEntityApi.hpp"
|
||||
#include "components/EditorMarker.hpp"
|
||||
#include <OgreLogManager.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace editScene
|
||||
{
|
||||
|
||||
// Global entity ID map
|
||||
LuaEntityIdMap g_luaEntityIdMap;
|
||||
|
||||
int luaEntityToId(flecs::entity e)
|
||||
{
|
||||
if (!e.is_valid())
|
||||
return -1;
|
||||
return g_luaEntityIdMap.addEntity(e);
|
||||
}
|
||||
|
||||
flecs::entity luaIdToEntity(int id)
|
||||
{
|
||||
return g_luaEntityIdMap.getEntity(id);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helper: get the Flecs world from the Lua registry
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static flecs::world getWorld(lua_State *L)
|
||||
{
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "EditSceneFlecsWorld");
|
||||
OgreAssert(lua_islightuserdata(L, -1), "Flecs world not registered");
|
||||
flecs::world *world =
|
||||
static_cast<flecs::world *>(lua_touserdata(L, -1));
|
||||
lua_pop(L, 1);
|
||||
return *world;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.create_entity() -> int (entity ID)
|
||||
// Creates a new entity with EditorMarkerComponent and returns its Lua ID.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int luaCreateEntity(lua_State *L)
|
||||
{
|
||||
flecs::world world = getWorld(L);
|
||||
flecs::entity e = world.entity();
|
||||
// Add EditorMarkerComponent so it appears in the editor hierarchy
|
||||
// (the component is forward-declared; we use a tag approach)
|
||||
e.add<EditorMarkerComponent>();
|
||||
int id = g_luaEntityIdMap.addEntity(e);
|
||||
lua_pushinteger(L, id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.destroy_entity(id) -> nil
|
||||
// Destroys an entity and removes it from the ID map.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int luaDestroyEntity(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TNUMBER);
|
||||
int id = lua_tointeger(L, 1);
|
||||
flecs::entity e = g_luaEntityIdMap.getEntity(id);
|
||||
if (e.is_alive()) {
|
||||
g_luaEntityIdMap.removeEntity(e);
|
||||
e.destruct();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.entity_exists(id) -> bool
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int luaEntityExists(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TNUMBER);
|
||||
int id = lua_tointeger(L, 1);
|
||||
lua_pushboolean(L, g_luaEntityIdMap.hasId(id) ? 1 : 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.get_player_entity() -> int (entity ID) or nil
|
||||
// Looks up the entity named "player" in the Flecs world.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int luaGetPlayerEntity(lua_State *L)
|
||||
{
|
||||
flecs::world world = getWorld(L);
|
||||
flecs::entity e = world.lookup("player");
|
||||
if (e.is_valid()) {
|
||||
int id = g_luaEntityIdMap.addEntity(e);
|
||||
lua_pushinteger(L, id);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.get_entity_by_name(name) -> int (entity ID) or nil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int luaGetEntityByName(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TSTRING);
|
||||
const char *name = lua_tostring(L, 1);
|
||||
flecs::world world = getWorld(L);
|
||||
flecs::entity e = world.lookup(name);
|
||||
if (e.is_valid()) {
|
||||
int id = g_luaEntityIdMap.addEntity(e);
|
||||
lua_pushinteger(L, id);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.set_entity_name(id, name) -> nil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int luaSetEntityName(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TNUMBER);
|
||||
luaL_checktype(L, 2, LUA_TSTRING);
|
||||
int id = lua_tointeger(L, 1);
|
||||
const char *name = lua_tostring(L, 2);
|
||||
flecs::entity e = g_luaEntityIdMap.getEntity(id);
|
||||
e.set_name(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.get_entity_name(id) -> string or nil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int luaGetEntityName(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TNUMBER);
|
||||
int id = lua_tointeger(L, 1);
|
||||
flecs::entity e = g_luaEntityIdMap.getEntity(id);
|
||||
const char *name = e.name();
|
||||
if (name && name[0]) {
|
||||
lua_pushstring(L, name);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.parent(id) -> int (parent ID) or nil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int luaGetParent(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TNUMBER);
|
||||
int id = lua_tointeger(L, 1);
|
||||
flecs::entity e = g_luaEntityIdMap.getEntity(id);
|
||||
flecs::entity parent = e.parent();
|
||||
if (parent.is_valid()) {
|
||||
int parentId = g_luaEntityIdMap.addEntity(parent);
|
||||
lua_pushinteger(L, parentId);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.children(id) -> table of child IDs
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int luaGetChildren(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TNUMBER);
|
||||
int id = lua_tointeger(L, 1);
|
||||
flecs::entity e = g_luaEntityIdMap.getEntity(id);
|
||||
|
||||
lua_newtable(L); // result table
|
||||
int index = 1;
|
||||
e.children([&](flecs::entity child) {
|
||||
int childId = g_luaEntityIdMap.addEntity(child);
|
||||
lua_pushinteger(L, childId);
|
||||
lua_rawseti(L, -2, index);
|
||||
index++;
|
||||
});
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Register all entity API functions
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void registerLuaEntityApi(lua_State *L)
|
||||
{
|
||||
// Create the "ecs" global table
|
||||
lua_newtable(L);
|
||||
|
||||
// Entity management
|
||||
lua_pushcfunction(L, luaCreateEntity);
|
||||
lua_setfield(L, -2, "create_entity");
|
||||
|
||||
lua_pushcfunction(L, luaDestroyEntity);
|
||||
lua_setfield(L, -2, "destroy_entity");
|
||||
|
||||
lua_pushcfunction(L, luaEntityExists);
|
||||
lua_setfield(L, -2, "entity_exists");
|
||||
|
||||
lua_pushcfunction(L, luaGetPlayerEntity);
|
||||
lua_setfield(L, -2, "get_player_entity");
|
||||
|
||||
lua_pushcfunction(L, luaGetEntityByName);
|
||||
lua_setfield(L, -2, "get_entity_by_name");
|
||||
|
||||
lua_pushcfunction(L, luaSetEntityName);
|
||||
lua_setfield(L, -2, "set_entity_name");
|
||||
|
||||
lua_pushcfunction(L, luaGetEntityName);
|
||||
lua_setfield(L, -2, "get_entity_name");
|
||||
|
||||
// Hierarchy
|
||||
lua_pushcfunction(L, luaGetParent);
|
||||
lua_setfield(L, -2, "parent");
|
||||
|
||||
lua_pushcfunction(L, luaGetChildren);
|
||||
lua_setfield(L, -2, "children");
|
||||
|
||||
// Set the global
|
||||
lua_setglobal(L, "ecs");
|
||||
}
|
||||
|
||||
} // namespace editScene
|
||||
126
src/features/editScene/lua/LuaEntityApi.hpp
Normal file
126
src/features/editScene/lua/LuaEntityApi.hpp
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifndef EDITSCENE_LUA_ENTITY_API_HPP
|
||||
#define EDITSCENE_LUA_ENTITY_API_HPP
|
||||
#pragma once
|
||||
|
||||
#include <flecs.h>
|
||||
#include <lua.hpp>
|
||||
#include <Ogre.h>
|
||||
#include <unordered_map>
|
||||
|
||||
/**
|
||||
* @file LuaEntityApi.hpp
|
||||
* @brief Lua API for entity creation, destruction, and ID mapping.
|
||||
*
|
||||
* Provides a bidirectional mapping between Lua integer IDs and
|
||||
* Flecs entity handles. Lua scripts reference entities by integer
|
||||
* IDs rather than raw Flecs handles for safety and simplicity.
|
||||
*
|
||||
* Exposed Lua globals:
|
||||
* ecs.create_entity() -> int (entity ID)
|
||||
* ecs.destroy_entity(id) -> nil
|
||||
* ecs.entity_exists(id) -> bool
|
||||
* ecs.get_player_entity() -> int (entity ID)
|
||||
* ecs.get_entity_by_name(name) -> int (entity ID) or nil
|
||||
* ecs.set_entity_name(id, name)-> nil
|
||||
* ecs.get_entity_name(id) -> string or nil
|
||||
* ecs.parent(id) -> int (parent ID) or nil
|
||||
* ecs.children(id) -> table of child IDs
|
||||
*/
|
||||
|
||||
namespace editScene
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Global bidirectional mapping between Lua integer IDs and Flecs entities.
|
||||
*
|
||||
* This is a singleton-like global so that all Lua API functions can
|
||||
* access it without needing to pass it through every closure.
|
||||
*/
|
||||
struct LuaEntityIdMap {
|
||||
std::unordered_map<int, flecs::entity> id2entity;
|
||||
std::unordered_map<flecs::entity_t, int> entity2id;
|
||||
int nextId = 0;
|
||||
|
||||
/** @brief Get the next available integer ID. */
|
||||
int getNextId()
|
||||
{
|
||||
nextId++;
|
||||
return nextId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add an entity to the map, returning its integer ID.
|
||||
* If the entity is already mapped, returns the existing ID.
|
||||
*/
|
||||
int addEntity(flecs::entity e)
|
||||
{
|
||||
if (entity2id.find(e.id()) != entity2id.end())
|
||||
return entity2id[e.id()];
|
||||
int id = getNextId();
|
||||
id2entity[id] = e;
|
||||
entity2id[e.id()] = id;
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the Flecs entity for an integer ID.
|
||||
* Asserts if the ID is not found or the entity is invalid.
|
||||
*/
|
||||
flecs::entity getEntity(int id)
|
||||
{
|
||||
auto it = id2entity.find(id);
|
||||
OgreAssert(it != id2entity.end(), "Invalid entity ID");
|
||||
OgreAssert(it->second.is_valid(), "Entity is no longer valid");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove an entity from the map.
|
||||
*/
|
||||
void removeEntity(flecs::entity e)
|
||||
{
|
||||
auto it = entity2id.find(e.id());
|
||||
if (it != entity2id.end()) {
|
||||
id2entity.erase(it->second);
|
||||
entity2id.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if an integer ID is valid.
|
||||
*/
|
||||
bool hasId(int id) const
|
||||
{
|
||||
auto it = id2entity.find(id);
|
||||
return it != id2entity.end() && it->second.is_valid();
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Global entity ID map instance. */
|
||||
extern LuaEntityIdMap g_luaEntityIdMap;
|
||||
|
||||
/**
|
||||
* @brief Convert a Flecs entity to a Lua integer ID.
|
||||
* @return The integer ID, or -1 if the entity is invalid.
|
||||
*/
|
||||
int luaEntityToId(flecs::entity e);
|
||||
|
||||
/**
|
||||
* @brief Convert a Lua integer ID to a Flecs entity.
|
||||
* Asserts if the ID is invalid.
|
||||
*/
|
||||
flecs::entity luaIdToEntity(int id);
|
||||
|
||||
/**
|
||||
* @brief Register all entity-related Lua API functions into the global table.
|
||||
*
|
||||
* Creates the "ecs" global table (or adds to it) with entity management
|
||||
* functions. Must be called after LuaState is constructed.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
*/
|
||||
void registerLuaEntityApi(lua_State *L);
|
||||
|
||||
} // namespace editScene
|
||||
|
||||
#endif // EDITSCENE_LUA_ENTITY_API_HPP
|
||||
320
src/features/editScene/lua/LuaEventApi.cpp
Normal file
320
src/features/editScene/lua/LuaEventApi.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
#include "LuaEventApi.hpp"
|
||||
#include "LuaEntityApi.hpp"
|
||||
#include "../systems/EventBus.hpp"
|
||||
#include "../components/GoapBlackboard.hpp"
|
||||
#include <OgreLogManager.h>
|
||||
#include <OgreVector3.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace editScene
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Internal: subscription ID tracking for Lua-managed subscriptions
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Map from Lua subscription IDs to EventBus ListenerIds.
|
||||
*
|
||||
* When Lua subscribes to an event, we store the mapping so that
|
||||
* unsubscribe_event() can remove the correct listener.
|
||||
*/
|
||||
static std::unordered_map<int, EventBus::ListenerId> s_luaSubscriptions;
|
||||
static int s_nextLuaSubId = 1;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helper: push a GoapBlackboard as a Lua table
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Push a GoapBlackboard as a Lua table with named fields.
|
||||
*
|
||||
* The resulting table has:
|
||||
* .bits -> integer
|
||||
* .mask -> integer
|
||||
* .values -> {string -> int}
|
||||
* .floatValues -> {string -> float}
|
||||
* .vec3Values -> {string -> {x, y, z}}
|
||||
* .stringValues -> {string -> string}
|
||||
*
|
||||
* @param L Lua state.
|
||||
* @param bb The GoapBlackboard to convert.
|
||||
*/
|
||||
static void pushGoapBlackboard(lua_State *L, const GoapBlackboard &bb)
|
||||
{
|
||||
lua_newtable(L);
|
||||
|
||||
// bits and mask
|
||||
lua_pushinteger(L, (lua_Integer)bb.bits);
|
||||
lua_setfield(L, -2, "bits");
|
||||
|
||||
lua_pushinteger(L, (lua_Integer)bb.mask);
|
||||
lua_setfield(L, -2, "mask");
|
||||
|
||||
// values (int map)
|
||||
lua_newtable(L);
|
||||
for (auto &kv : bb.values) {
|
||||
lua_pushinteger(L, kv.second);
|
||||
lua_setfield(L, -2, kv.first.c_str());
|
||||
}
|
||||
lua_setfield(L, -2, "values");
|
||||
|
||||
// floatValues
|
||||
lua_newtable(L);
|
||||
for (auto &kv : bb.floatValues) {
|
||||
lua_pushnumber(L, kv.second);
|
||||
lua_setfield(L, -2, kv.first.c_str());
|
||||
}
|
||||
lua_setfield(L, -2, "floatValues");
|
||||
|
||||
// vec3Values
|
||||
lua_newtable(L);
|
||||
for (auto &kv : bb.vec3Values) {
|
||||
lua_newtable(L);
|
||||
lua_pushnumber(L, kv.second.x);
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushnumber(L, kv.second.y);
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_pushnumber(L, kv.second.z);
|
||||
lua_rawseti(L, -2, 3);
|
||||
lua_setfield(L, -2, kv.first.c_str());
|
||||
}
|
||||
lua_setfield(L, -2, "vec3Values");
|
||||
|
||||
// stringValues
|
||||
lua_newtable(L);
|
||||
for (auto &kv : bb.stringValues) {
|
||||
lua_pushstring(L, kv.second.c_str());
|
||||
lua_setfield(L, -2, kv.first.c_str());
|
||||
}
|
||||
lua_setfield(L, -2, "stringValues");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a Lua table at the given index as a GoapBlackboard.
|
||||
*
|
||||
* Expects the same format as pushGoapBlackboard produces.
|
||||
*
|
||||
* @param L Lua state.
|
||||
* @param idx Stack index of the table.
|
||||
* @return GoapBlackboard populated from the table.
|
||||
*/
|
||||
static GoapBlackboard readGoapBlackboard(lua_State *L, int idx)
|
||||
{
|
||||
GoapBlackboard bb;
|
||||
|
||||
// bits
|
||||
lua_getfield(L, idx, "bits");
|
||||
if (lua_isnumber(L, -1))
|
||||
bb.bits = (uint64_t)lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
// mask
|
||||
lua_getfield(L, idx, "mask");
|
||||
if (lua_isnumber(L, -1))
|
||||
bb.mask = (uint64_t)lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
// values (int map)
|
||||
lua_getfield(L, idx, "values");
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
if (lua_isstring(L, -2) && lua_isnumber(L, -1))
|
||||
bb.values[lua_tostring(L, -2)] =
|
||||
(int)lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
// floatValues
|
||||
lua_getfield(L, idx, "floatValues");
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
if (lua_isstring(L, -2) && lua_isnumber(L, -1))
|
||||
bb.floatValues[lua_tostring(L, -2)] =
|
||||
(float)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
// vec3Values
|
||||
lua_getfield(L, idx, "vec3Values");
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
if (lua_isstring(L, -2) && lua_istable(L, -1)) {
|
||||
Ogre::Vector3 v;
|
||||
lua_rawgeti(L, -1, 1);
|
||||
v.x = (float)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
lua_rawgeti(L, -1, 2);
|
||||
v.y = (float)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
lua_rawgeti(L, -1, 3);
|
||||
v.z = (float)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
bb.vec3Values[lua_tostring(L, -2)] = v;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
// stringValues
|
||||
lua_getfield(L, idx, "stringValues");
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0) {
|
||||
if (lua_isstring(L, -2) && lua_isstring(L, -1))
|
||||
bb.stringValues[lua_tostring(L, -2)] =
|
||||
lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.send_event("eventName", [params_table])
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Lua: ecs.send_event("eventName", [params_table]) -> nil
|
||||
*
|
||||
* Sends an event through the global EventBus. The optional params table
|
||||
* is converted to a GoapBlackboard payload.
|
||||
*
|
||||
* Usage:
|
||||
* ecs.send_event("collision")
|
||||
* ecs.send_event("collision", { entity_id = 42, damage = 10 })
|
||||
*/
|
||||
static int luaSendEvent(lua_State *L)
|
||||
{
|
||||
const char *eventName = luaL_checkstring(L, 1);
|
||||
|
||||
GoapBlackboard params;
|
||||
if (lua_gettop(L) >= 2 && lua_istable(L, 2)) {
|
||||
params = readGoapBlackboard(L, 2);
|
||||
}
|
||||
|
||||
EventBus::getInstance().send(eventName, params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.subscribe_event("eventName", callback_fn) -> int (subscription id)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Lua: ecs.subscribe_event("eventName", callback_fn) -> int
|
||||
*
|
||||
* Subscribes a Lua function to an event. The callback receives:
|
||||
* function(event_name, params_table)
|
||||
*
|
||||
* Returns a subscription ID that can be used with unsubscribe_event().
|
||||
*
|
||||
* Usage:
|
||||
* local sub_id = ecs.subscribe_event("collision", function(event, params)
|
||||
* print("Collision event received!")
|
||||
* print("entity_id: " .. params.values.entity_id)
|
||||
* end)
|
||||
*/
|
||||
static int luaSubscribeEvent(lua_State *L)
|
||||
{
|
||||
const char *eventName = luaL_checkstring(L, 1);
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||
|
||||
// Create a reference to the Lua callback function
|
||||
lua_pushvalue(L, 2);
|
||||
int callbackRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Subscribe to the EventBus with a C++ lambda that calls the Lua function
|
||||
EventBus::ListenerId listenerId = EventBus::getInstance().subscribe(
|
||||
eventName, [L, callbackRef](const Ogre::String &eventName,
|
||||
const GoapBlackboard ¶ms) {
|
||||
// Push the Lua callback function
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, callbackRef);
|
||||
|
||||
// Push event name
|
||||
lua_pushstring(L, eventName.c_str());
|
||||
|
||||
// Push params as a Lua table
|
||||
pushGoapBlackboard(L, params);
|
||||
|
||||
// Call the Lua function (2 args, 0 results)
|
||||
if (lua_pcall(L, 2, 0, 0) != LUA_OK) {
|
||||
Ogre::LogManager::getSingleton().stream()
|
||||
<< "Lua event callback error: "
|
||||
<< lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
});
|
||||
|
||||
// Store the mapping from Lua subscription ID to EventBus listener ID
|
||||
int luaSubId = s_nextLuaSubId++;
|
||||
s_luaSubscriptions[luaSubId] = listenerId;
|
||||
|
||||
lua_pushinteger(L, luaSubId);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lua: ecs.unsubscribe_event(subscription_id) -> nil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Lua: ecs.unsubscribe_event(subscription_id) -> nil
|
||||
*
|
||||
* Unsubscribes a previously registered event subscription.
|
||||
*
|
||||
* Usage:
|
||||
* ecs.unsubscribe_event(sub_id)
|
||||
*/
|
||||
static int luaUnsubscribeEvent(lua_State *L)
|
||||
{
|
||||
int luaSubId = (int)luaL_checkinteger(L, 1);
|
||||
|
||||
auto it = s_luaSubscriptions.find(luaSubId);
|
||||
if (it != s_luaSubscriptions.end()) {
|
||||
EventBus::getInstance().unsubscribe(it->second);
|
||||
s_luaSubscriptions.erase(it);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Public registration function
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void registerLuaEventApi(lua_State *L)
|
||||
{
|
||||
// Get or create the "ecs" global table
|
||||
lua_getglobal(L, "ecs");
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_newtable(L);
|
||||
lua_setglobal(L, "ecs");
|
||||
lua_getglobal(L, "ecs");
|
||||
}
|
||||
|
||||
// Register event functions
|
||||
lua_pushcfunction(L, luaSendEvent);
|
||||
lua_setfield(L, -2, "send_event");
|
||||
|
||||
lua_pushcfunction(L, luaSubscribeEvent);
|
||||
lua_setfield(L, -2, "subscribe_event");
|
||||
|
||||
lua_pushcfunction(L, luaUnsubscribeEvent);
|
||||
lua_setfield(L, -2, "unsubscribe_event");
|
||||
|
||||
// Pop the ecs table
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
} // namespace editScene
|
||||
55
src/features/editScene/lua/LuaEventApi.hpp
Normal file
55
src/features/editScene/lua/LuaEventApi.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef EDITSCENE_LUA_EVENT_API_HPP
|
||||
#define EDITSCENE_LUA_EVENT_API_HPP
|
||||
#pragma once
|
||||
|
||||
#include <lua.hpp>
|
||||
|
||||
/**
|
||||
* @file LuaEventApi.hpp
|
||||
* @brief Lua API for the EventBus system.
|
||||
*
|
||||
* Provides Lua bindings for the global EventBus singleton, allowing
|
||||
* Lua scripts to subscribe to events, send events, and manage
|
||||
* event subscriptions.
|
||||
*
|
||||
* The EventBus is a synchronous publish/subscribe system. Events are
|
||||
* identified by name strings. Payloads use GoapBlackboard, which
|
||||
* supports int, float, Vector3, and string values.
|
||||
*
|
||||
* Exposed Lua globals (in the "ecs" table):
|
||||
* ecs.send_event("eventName") -> nil
|
||||
* ecs.send_event("eventName", {key=value, ...}) -> nil
|
||||
* ecs.subscribe_event("eventName", callback_fn) -> int (subscription id)
|
||||
* ecs.unsubscribe_event(subscription_id) -> nil
|
||||
*
|
||||
* The callback function receives (event_name, params_table):
|
||||
* ecs.subscribe_event("collision", function(event, params)
|
||||
* print(event .. " occurred")
|
||||
* print("entity_id: " .. params.entity_id)
|
||||
* end)
|
||||
*
|
||||
* The params table contains the GoapBlackboard fields:
|
||||
* params.bits -> integer (bitfield)
|
||||
* params.mask -> integer (bitmask)
|
||||
* params.values -> table {string -> int}
|
||||
* params.floatValues -> table {string -> float}
|
||||
* params.vec3Values -> table {string -> {x, y, z}}
|
||||
* params.stringValues -> table {string -> string}
|
||||
*/
|
||||
|
||||
namespace editScene
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Register all event-related Lua API functions into the "ecs" table.
|
||||
*
|
||||
* Adds functions for event subscription, unsubscription, and sending.
|
||||
* Must be called after LuaState is constructed and the "ecs" table exists.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
*/
|
||||
void registerLuaEventApi(lua_State *L);
|
||||
|
||||
} // namespace editScene
|
||||
|
||||
#endif // EDITSCENE_LUA_EVENT_API_HPP
|
||||
187
src/features/editScene/lua/LuaState.cpp
Normal file
187
src/features/editScene/lua/LuaState.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
#include "LuaState.hpp"
|
||||
#include <OgreResourceGroupManager.h>
|
||||
#include <OgreLogManager.h>
|
||||
#include <OgreDataStream.h>
|
||||
#include <iostream>
|
||||
|
||||
extern "C" {
|
||||
int luaopen_lpeg(lua_State *L);
|
||||
}
|
||||
|
||||
namespace editScene
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Custom library loader: loads .lua files from OGRE resource groups
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int LuaState::luaLibraryLoader(lua_State *L)
|
||||
{
|
||||
if (!lua_isstring(L, 1)) {
|
||||
luaL_error(
|
||||
L,
|
||||
"luaLibraryLoader: Expected string for first parameter");
|
||||
}
|
||||
|
||||
std::string libraryFile = lua_tostring(L, 1);
|
||||
|
||||
// Translate '.' to '/' for OGRE resource path compatibility
|
||||
while (libraryFile.find('.') != std::string::npos)
|
||||
libraryFile.replace(libraryFile.find('.'), 1, "/");
|
||||
|
||||
libraryFile += ".lua";
|
||||
|
||||
Ogre::DataStreamPtr stream =
|
||||
Ogre::ResourceGroupManager::getSingleton().openResource(
|
||||
libraryFile, "LuaScripts");
|
||||
Ogre::String script = stream->getAsString();
|
||||
if (luaL_loadbuffer(L, script.c_str(), script.length(),
|
||||
libraryFile.c_str())) {
|
||||
luaL_error(
|
||||
L,
|
||||
"Error loading library '%s' from resource archive.\n%s",
|
||||
libraryFile.c_str(), lua_tostring(L, -1));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Install the custom loader into package.searchers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void LuaState::installLibraryLoader()
|
||||
{
|
||||
lua_getglobal(L, "table");
|
||||
lua_getfield(L, -1, "insert");
|
||||
lua_remove(L, -2); // table
|
||||
lua_getglobal(L, "package");
|
||||
lua_getfield(L, -1, "searchers");
|
||||
lua_remove(L, -2); // package
|
||||
lua_pushnumber(L, 1); // insert at position 1 (highest priority)
|
||||
lua_pushcfunction(L, luaLibraryLoader);
|
||||
if (lua_pcall(L, 3, 0, 0))
|
||||
Ogre::LogManager::getSingleton().stream() << lua_tostring(L, 1);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constructor: create Lua state and open standard libraries
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
LuaState::LuaState()
|
||||
: L(luaL_newstate())
|
||||
{
|
||||
luaopen_base(L);
|
||||
luaopen_table(L);
|
||||
luaopen_package(L);
|
||||
luaL_requiref(L, "table", luaopen_table, 1);
|
||||
lua_pop(L, 1);
|
||||
luaL_requiref(L, "math", luaopen_math, 1);
|
||||
lua_pop(L, 1);
|
||||
luaL_requiref(L, "package", luaopen_package, 1);
|
||||
lua_pop(L, 1);
|
||||
luaL_requiref(L, "string", luaopen_string, 1);
|
||||
lua_pop(L, 1);
|
||||
luaL_requiref(L, "io", luaopen_io, 1);
|
||||
lua_pop(L, 1);
|
||||
luaL_requiref(L, "lpeg", luaopen_lpeg, 1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
installLibraryLoader();
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Destructor
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
LuaState::~LuaState()
|
||||
{
|
||||
lua_close(L);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Handler registration
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int LuaState::setupHandler()
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
lua_pushvalue(L, 1);
|
||||
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
setupHandlers.push_back(ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Call all handlers with an event name (no entities)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int LuaState::callHandler(const Ogre::String &event)
|
||||
{
|
||||
for (int ref : setupHandlers) {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
lua_pushstring(L, event.c_str());
|
||||
lua_pushinteger(L, -1);
|
||||
lua_pushinteger(L, -1);
|
||||
if (lua_pcall(L, 3, 0, 0) != LUA_OK) {
|
||||
Ogre::LogManager::getSingleton().stream()
|
||||
<< lua_tostring(L, -1);
|
||||
OgreAssert(false, "Lua error");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Call all handlers with an event name and two entities
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int LuaState::callHandler(const Ogre::String &event, flecs::entity e1,
|
||||
flecs::entity e2)
|
||||
{
|
||||
// Entity IDs are mapped through the global idmap (see LuaEntityApi.cpp)
|
||||
extern int luaEntityToId(flecs::entity e);
|
||||
extern flecs::entity luaIdToEntity(int id);
|
||||
|
||||
for (int ref : setupHandlers) {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||
lua_pushstring(L, event.c_str());
|
||||
lua_pushinteger(L, luaEntityToId(e1));
|
||||
lua_pushinteger(L, luaEntityToId(e2));
|
||||
if (lua_pcall(L, 3, 0, 0) != LUA_OK) {
|
||||
Ogre::LogManager::getSingleton().stream()
|
||||
<< lua_tostring(L, -1);
|
||||
OgreAssert(false, "Lua error");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Late setup: load data.lua and run initialisation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void LuaState::lateSetup()
|
||||
{
|
||||
Ogre::DataStreamPtr stream =
|
||||
Ogre::ResourceGroupManager::getSingleton().openResource(
|
||||
"data.lua", "LuaScripts");
|
||||
std::cout << "stream: " << stream->getAsString() << "\n";
|
||||
if (luaL_dostring(L, stream->getAsString().c_str()) != LUA_OK) {
|
||||
std::cout << "error: " << lua_tostring(L, -1) << "\n";
|
||||
OgreAssert(false, "Script failure");
|
||||
}
|
||||
|
||||
const char *lua_code = "\n\
|
||||
function stuff()\n\
|
||||
return 4\n\
|
||||
end\n\
|
||||
x = stuff()\n\
|
||||
";
|
||||
luaL_dostring(L, lua_code);
|
||||
lua_getglobal(L, "x");
|
||||
int x = lua_tonumber(L, 1);
|
||||
std::cout << "lua: " << x << "\n";
|
||||
}
|
||||
|
||||
} // namespace editScene
|
||||
137
src/features/editScene/lua/LuaState.hpp
Normal file
137
src/features/editScene/lua/LuaState.hpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#ifndef EDITSCENE_LUA_STATE_HPP
|
||||
#define EDITSCENE_LUA_STATE_HPP
|
||||
#pragma once
|
||||
|
||||
#include <Ogre.h>
|
||||
#include <lua.hpp>
|
||||
#include <flecs.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @file LuaState.hpp
|
||||
* @brief Lua state management for the editScene editor.
|
||||
*
|
||||
* Manages the Lua virtual machine instance, library loading,
|
||||
* script loading from OGRE resource groups, and the custom
|
||||
* package.searchers entry that loads Lua modules from
|
||||
* the "LuaScripts" resource group.
|
||||
*
|
||||
* Usage:
|
||||
* LuaState lua;
|
||||
* lua.installLibraryLoader(); // Register custom searcher
|
||||
* lua.lateSetup(); // Load data.lua and run startup
|
||||
* lua.callHandler("event_name", e1, e2);
|
||||
*/
|
||||
|
||||
namespace editScene
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Manages a single lua_State instance.
|
||||
*
|
||||
* Opens standard Lua libraries (base, table, math, package, string, io)
|
||||
* plus LPEG. Installs a custom package.searchers entry that loads
|
||||
* .lua files from OGRE's "LuaScripts" resource group.
|
||||
*
|
||||
* Provides a handler/callback system: Lua scripts can register
|
||||
* callback functions via setup_handler(), and C++ code can invoke
|
||||
* them with event names and optional entity parameters.
|
||||
*/
|
||||
class LuaState {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Lua state.
|
||||
*
|
||||
* Opens all standard libraries and installs the custom
|
||||
* library loader for OGRE resource-based Lua modules.
|
||||
*/
|
||||
LuaState();
|
||||
|
||||
/**
|
||||
* @brief Destroy the Lua state and close the VM.
|
||||
*/
|
||||
~LuaState();
|
||||
|
||||
/**
|
||||
* @brief Get the underlying lua_State pointer.
|
||||
*/
|
||||
lua_State *getState() const
|
||||
{
|
||||
return L;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Install the custom library loader into package.searchers.
|
||||
*
|
||||
* Inserts luaLibraryLoader at position 1 of the searchers table
|
||||
* so it takes precedence over the default file-system loader.
|
||||
* This allows Lua's require() to load modules from OGRE resource
|
||||
* archives.
|
||||
*/
|
||||
void installLibraryLoader();
|
||||
|
||||
/**
|
||||
* @brief Late setup: load data.lua and run initialisation.
|
||||
*
|
||||
* Opens "data.lua" from the "LuaScripts" resource group and
|
||||
* executes it. Also runs a simple inline Lua test snippet.
|
||||
* Called once after the ECS world is fully initialised.
|
||||
*/
|
||||
void lateSetup();
|
||||
|
||||
/**
|
||||
* @brief Register a Lua callback function for event handling.
|
||||
*
|
||||
* Expects a Lua function on the stack (at index 1).
|
||||
* Stores a reference to it in the registry so it can be
|
||||
* called later via callHandler().
|
||||
*
|
||||
* @return int Reference index (stored internally).
|
||||
*/
|
||||
int setupHandler();
|
||||
|
||||
/**
|
||||
* @brief Call all registered handlers with an event name.
|
||||
*
|
||||
* @param event The event name string.
|
||||
* @return int 0 on success.
|
||||
*/
|
||||
int callHandler(const Ogre::String &event);
|
||||
|
||||
/**
|
||||
* @brief Call all registered handlers with an event name and
|
||||
* two entity IDs.
|
||||
*
|
||||
* Entity IDs are mapped through the global idmap (see LuaEntityApi).
|
||||
*
|
||||
* @param event The event name string.
|
||||
* @param e1 First entity (e.g. subject).
|
||||
* @param e2 Second entity (e.g. object).
|
||||
* @return int 0 on success.
|
||||
*/
|
||||
int callHandler(const Ogre::String &event, flecs::entity e1,
|
||||
flecs::entity e2);
|
||||
|
||||
private:
|
||||
lua_State *L;
|
||||
|
||||
/** Registry references for registered Lua callback functions. */
|
||||
std::vector<int> setupHandlers;
|
||||
|
||||
/**
|
||||
* @brief Custom Lua loader function for OGRE resource-based modules.
|
||||
*
|
||||
* Registered in package.searchers. Translates dots to path
|
||||
* separators, appends ".lua", and loads the file from the
|
||||
* "LuaScripts" OGRE resource group.
|
||||
*
|
||||
* @param L Lua state.
|
||||
* @return int 1 (pushes loaded chunk onto stack) or error.
|
||||
*/
|
||||
static int luaLibraryLoader(lua_State *L);
|
||||
};
|
||||
|
||||
} // namespace editScene
|
||||
|
||||
#endif // EDITSCENE_LUA_STATE_HPP
|
||||
Reference in New Issue
Block a user