This commit is contained in:
2026-04-24 21:22:11 -05:00
parent 565c530469
commit c9d949f759
19 changed files with 379 additions and 1141 deletions
+21
View File
@@ -0,0 +1,21 @@
local Cube = {}
Cube.__index = Cube
function Cube.new()
local self = setmetatable({}, Cube)
self.id = entityAdd()
local pos = entityPositionAdd(self.id)
pos.x = 0
pos.y = 0
pos.z = 0
entityMeshAdd(self.id)
local mat = entityMaterialAdd(self.id)
mat.color = colorWhite()
return self
end
function Cube:dispose()
entityRemove(self.id)
end
return Cube
-20
View File
@@ -1,20 +0,0 @@
module('entity')
module('math')
module('color')
function entityInit()
entityPositionAdd(ENTITY_ID)
local phys = entityPhysicsAdd(ENTITY_ID)
phys.bodyType = PHYSICS_BODY_STATIC
phys:setShapePlane(vec3(0, 1, 0), 0)
local mesh = entityMeshAdd(ENTITY_ID)
mesh:generatePlane(20, 20)
local mat = entityMaterialAdd(ENTITY_ID)
mat.color = colorBlack()
end
function entityDispose()
end
-48
View File
@@ -1,48 +0,0 @@
module('entity')
module('input')
module('color')
module('math')
module('scene')
module('event')
module('entitycamera')
local phys
local updateSub
local SPEED = 4.0
local mat
function entityInit()
local pos = entityPositionAdd(ENTITY_ID)
pos.x = 0
pos.y = 1
pos.z = 0
phys = entityPhysicsAdd(ENTITY_ID)
phys:setShapeCapsule(0.3, 0.9)
local mesh = entityMeshAdd(ENTITY_ID)
mesh:generateCapsule(0.3, 0.9)
mat = entityMaterialAdd(ENTITY_ID)
updateSub = eventSubscribe(SCENE_EVENT_UPDATE, onUpdate)
end
function onUpdate()
local moveX = inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT)
local moveZ = inputAxis(INPUT_ACTION_DOWN, INPUT_ACTION_UP)
mat.color = colorRainbow()
local cam = entityCameraGetCurrent()
local fwd = cam:getForward()
local right = cam:getRight()
local vy = phys.velocityY
phys.velocityX = (moveX * right.x + moveZ * fwd.x) * SPEED
phys.velocityZ = (moveX * right.y + moveZ * fwd.y) * SPEED
end
function entityDispose()
eventUnsubscribe(SCENE_EVENT_UPDATE, updateSub)
end
+1 -3
View File
@@ -72,6 +72,4 @@ else
print("Unknown platform, no default input bindings set.")
end
local test = 'test'
Scene.set('test/scene.lua')
Scene.set('scenes/cube.lua')
+26
View File
@@ -0,0 +1,26 @@
local Cube = include('entities/cube.lua')
local cam
local cube
function Scene:init()
print("Scene init")
local camId = entityAdd()
local pos = entityPositionAdd(camId)
pos.x = 3
pos.y = 3
pos.z = 3
pos:lookAt(0, 0, 0)
entityCameraAdd(camId)
cam = camId
cube = Cube.new()
end
function Scene:update()
end
function Scene:dispose()
cube:dispose()
entityRemove(cam)
end
@@ -3,7 +3,5 @@
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
entityscript.c
)
@@ -1,115 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entityscript.h"
#include "entity/entitymanager.h"
#include "assert/assert.h"
#include "util/memory.h"
void entityScriptInit(
const entityid_t entityId,
const componentid_t compId
) {
entityscript_t *data = componentGetData(
entityId, compId, COMPONENT_TYPE_ENTITYSCRIPT
);
memoryZero(data, sizeof(entityscript_t));
}
void entityScriptUnload(
const entityid_t entityId,
const componentid_t compId
) {
entityscript_t *data = componentGetData(
entityId, compId, COMPONENT_TYPE_ENTITYSCRIPT
);
if(!data->active) return;
lua_getglobal(data->context.luaState, "entityDispose");
if(lua_isfunction(data->context.luaState, -1)) {
if(lua_pcall(data->context.luaState, 0, 0, 0) != LUA_OK) {
lua_pop(data->context.luaState, 1);
}
} else {
lua_pop(data->context.luaState, 1);
}
scriptContextDispose(&data->context);
data->active = false;
}
errorret_t entityScriptSetScript(
const entityid_t entityId,
const componentid_t compId,
const char_t *filename
) {
assertNotNull(filename, "Entity script filename cannot be NULL");
entityScriptUnload(entityId, compId);
entityscript_t *data = componentGetData(
entityId, compId, COMPONENT_TYPE_ENTITYSCRIPT
);
errorChain(scriptContextInit(&data->context));
data->active = true;
// Expose entity identity to the script as globals
lua_pushnumber(data->context.luaState, (lua_Number)entityId);
lua_setglobal(data->context.luaState, "ENTITY_ID");
lua_pushnumber(data->context.luaState, (lua_Number)compId);
lua_setglobal(data->context.luaState, "ENTITY_COMPONENT_ID");
errorChain(scriptContextExecFile(&data->context, filename));
lua_getglobal(data->context.luaState, "entityInit");
if(lua_isfunction(data->context.luaState, -1)) {
if(lua_pcall(data->context.luaState, 0, 0, 0) != LUA_OK) {
errorThrow(
"Failed to call entityInit: %s",
lua_tostring(data->context.luaState, -1)
);
}
} else {
lua_pop(data->context.luaState, 1);
}
errorOk();
}
errorret_t entityScriptUpdate(
const entityid_t entityId,
const componentid_t compId
) {
entityscript_t *data = componentGetData(
entityId, compId, COMPONENT_TYPE_ENTITYSCRIPT
);
if(!data->active) errorOk();
lua_getglobal(data->context.luaState, "entityUpdate");
if(lua_isfunction(data->context.luaState, -1)) {
if(lua_pcall(data->context.luaState, 0, 0, 0) != LUA_OK) {
errorThrow(
"Failed to call entityUpdate: %s",
lua_tostring(data->context.luaState, -1)
);
}
} else {
lua_pop(data->context.luaState, 1);
}
errorOk();
}
void entityScriptDispose(
const entityid_t entityId,
const componentid_t compId
) {
entityScriptUnload(entityId, compId);
}
@@ -1,77 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
#include "script/scriptcontext.h"
typedef struct {
scriptcontext_t context;
bool_t active;
} entityscript_t;
/**
* Initializes the entity script component (empty context, not yet loaded).
*
* @param entityId The entity ID.
* @param compId The component ID.
*/
void entityScriptInit(
const entityid_t entityId,
const componentid_t compId
);
/**
* Unloads the currently active script: calls entityDispose if defined and
* disposes the context. No-op if no script is loaded.
*
* @param entityId The entity ID.
* @param compId The component ID.
*/
void entityScriptUnload(
const entityid_t entityId,
const componentid_t compId
);
/**
* Sets the script for this component. If a script is already loaded it is
* unloaded first. Then loads and executes the new file, sets entityId and
* entityScriptId as Lua globals, and calls entityInit if defined.
*
* @param entityId The entity ID.
* @param compId The component ID.
* @param filename The script file to load.
* @return The error return value.
*/
errorret_t entityScriptSetScript(
const entityid_t entityId,
const componentid_t compId,
const char_t *filename
);
/**
* Calls the entityUpdate Lua function in the entity script context, if defined.
*
* @param entityId The entity ID.
* @param compId The component ID.
* @return The error return value.
*/
errorret_t entityScriptUpdate(
const entityid_t entityId,
const componentid_t compId
);
/**
* Unloads the script if one is active, then disposes the component.
*
* @param entityId The entity ID.
* @param compId The component ID.
*/
void entityScriptDispose(
const entityid_t entityId,
const componentid_t compId
);
+1 -3
View File
@@ -10,11 +10,9 @@
#include "entity/component/display/entitymesh.h"
#include "entity/component/display/entitymaterial.h"
#include "entity/component/physics/entityphysics.h"
#include "entity/component/script/entityscript.h"
X(POSITION, entityposition_t, position, entityPositionInit, NULL)
X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL)
X(MESH, entitymesh_t, mesh, entityMeshInit, entityMeshDispose)
X(MATERIAL, entitymaterial_t, material, entityMaterialInit, NULL)
X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose)
X(ENTITYSCRIPT, entityscript_t, entityscript, entityScriptInit, entityScriptDispose)
X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose)
+53 -65
View File
@@ -1,5 +1,5 @@
// Copyright (c) 2026 Dominic Masters
//
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
@@ -21,29 +21,37 @@
scene_t SCENE;
errorret_t sceneInit(void) {
memoryZero(&SCENE, sizeof(scene_t));
errorChain(scriptContextExec(
&SCRIPT_MANAGER.mainContext,
"SceneBase = {}\n"
"function SceneBase:callTest()\n"
" print('SceneBase:callTest called with: ' .. tostring(self.test))\n"
"end\n"
"Scene = {}\n"
"Scene.__index = Scene\n"
"setmetatable(Scene, { __index = SceneBase })\n"
"Scene.current = nil\n"
));
// Rebuilds the Scene global to a clean table with only Scene.set bound.
static void sceneReset(void) {
lua_State *L = SCRIPT_MANAGER.mainContext.luaState;
lua_getglobal(L, "Scene");
assertTrue(lua_istable(L, -1), "Scene must be a table");
lua_newtable(L);
lua_pushcfunction(L, sceneSetLua);
lua_setfield(L, -2, "set");
lua_setglobal(L, "Scene");
}
lua_pop(L, 1);
// Calls Scene:method() if it exists. Returns an error if the call fails.
static errorret_t sceneCall(const char_t *method) {
lua_State *L = SCRIPT_MANAGER.mainContext.luaState;
lua_getglobal(L, "Scene");
lua_getfield(L, -1, method);
if(!lua_isfunction(L, -1)) {
lua_pop(L, 2);
errorOk();
}
lua_pushvalue(L, -2); // self
if(lua_pcall(L, 1, 0, 0) != LUA_OK) {
const char_t *err = lua_tostring(L, -1);
lua_pop(L, 2);
errorThrow("Scene:%s failed: %s", method, err);
}
lua_pop(L, 1); // pop Scene
errorOk();
}
errorret_t sceneInit(void) {
memoryZero(&SCENE, sizeof(scene_t));
sceneReset();
errorOk();
}
@@ -54,26 +62,14 @@ errorret_t sceneUpdate(void) {
}
#endif
// Call scene update on active scene
if(SCENE.scriptActive) {
errorChain(scriptContextExec(
&SCRIPT_MANAGER.mainContext,
"if Scene.current ~= nil and Scene.current.update ~= nil then\n"
" Scene.current:update()\n"
"end\n"
));
}
// Is the scene changing?
if(stringCompare(SCENE.sceneNext, SCENE.sceneCurrent) != 0) {
errorChain(sceneSetImmediate(SCENE.sceneNext));
}
// Call scene update function if script loaded
if(!SCENE.scriptActive) {
errorOk();
if(SCENE.scriptActive) {
errorChain(sceneCall("update"));
}
errorOk();
}
@@ -184,58 +180,50 @@ errorret_t sceneRender(void) {
errorOk();
}
errorret_t sceneSetImmediate(const char_t *script) {
// Update the next scene name (shouldn't really happen but its for safety).
if(script != SCENE.sceneNext) {
errorret_t sceneSetImmediate(const char_t *scene) {
if(scene != SCENE.sceneNext) {
stringCopy(
SCENE.sceneNext,
script == NULL ? "" : script,
scene == NULL ? "" : scene,
ASSET_FILE_PATH_MAX
);
}
// If there's currently a scene active, dispose of it first.
if(SCENE.scriptActive) {
// Unload script context. I do this with Lua code but I can probably make
// it optimized in future and call from C.
errorChain(scriptContextExec(
&SCRIPT_MANAGER.mainContext,
"if Scene.current ~= nil and Scene.current.dispose ~= nil then\n"
" Scene.current:dispose()\n"
"end\n"
"Scene.current = nil\n"
));
errorChain(sceneCall("dispose"));
SCENE.scriptActive = false;
}
// At this point the existing scene is unloaded, update the current scene.
// Wipe Scene back to a clean table before loading the next file so custom
// methods from the previous scene (e.g. Scene.doThing) cannot bleed through.
sceneReset();
stringCopy(
SCENE.sceneCurrent,
script == NULL ? "" : script,
scene == NULL ? "" : scene,
ASSET_FILE_PATH_MAX
);
// If we have a new scene, execute it.
if(script != NULL) {
SCENE.scriptActive = true;
errorChain(scriptContextExecFile(&SCRIPT_MANAGER.mainContext, script));
if(scene != NULL) {
lua_State *L = SCRIPT_MANAGER.mainContext.luaState;
int32_t stackBase = lua_gettop(L);
// Call the init function.
errorChain(scriptContextExec(
&SCRIPT_MANAGER.mainContext,
"Scene.current = Scene.new()\n"
));
errorChain(scriptContextExecFile(&SCRIPT_MANAGER.mainContext, scene));
// Discard any return values — we access Scene via the global.
lua_settop(L, stackBase);
errorChain(sceneCall("init"));
SCENE.scriptActive = true;
}
errorOk();
}
void sceneSet(const char_t *script) {
// Tell the scene that next update it needs to change scenes. This will always
// occur on the NEXT frame.
void sceneSet(const char_t *scene) {
stringCopy(
SCENE.sceneNext,
script == NULL ? "" : script,
scene == NULL ? "" : scene,
ASSET_FILE_PATH_MAX
);
}
@@ -255,4 +243,4 @@ int sceneSetLua(lua_State *L) {
sceneSet(lua_tostring(L, 1));
return 0;
}
}
+4 -45
View File
@@ -1,6 +1,6 @@
/**
* Copyright (c) 2026 Dominic Masters
*
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
@@ -20,51 +20,10 @@ typedef struct {
extern scene_t SCENE;
/**
* Initialize the scene subsystem.
*
* @return The error return value.
*/
errorret_t sceneInit(void);
/**
* Update the current scene.
*
* @return The error return value.
*/
errorret_t sceneUpdate(void);
/**
* Render the current scene.
*
* @return The error return value.
*/
errorret_t sceneRender(void);
/**
* Internal only method, immediately sets the scene. This will basically crash
* Lua if called from its tree.
*/
errorret_t sceneSetImmediate(const char_t *script);
/**
* Set the current scene by script name.
*
* @param script The script name of the scene to set.
* @return The error return value.
*/
void sceneSet(const char_t *script);
/**
* Dispose of the scene subsystem.
*
* @return The error return value.
*/
errorret_t sceneSetImmediate(const char_t *scene);
void sceneSet(const char_t *scene);
errorret_t sceneDispose(void);
/**
* Lua method for setting the scene.
* @param L The Lua state.
* @return The number of return values on the Lua stack.
*/
int sceneSetLua(lua_State *L);
int sceneSetLua(lua_State *L);
@@ -1,133 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/module/modulebase.h"
#include "entity/entity.h"
#include "entity/component/display/entitycamera.h"
#include "script/module/math/modulevec2.h"
typedef struct {
entityid_t entityId;
componentid_t compId;
} entitycamera_handle_t;
static void pushEntityCameraHandle(
lua_State *L,
entityid_t entityId,
componentid_t compId
) {
entitycamera_handle_t *h = lua_newuserdata(
L, sizeof(entitycamera_handle_t)
);
h->entityId = entityId;
h->compId = compId;
luaL_getmetatable(L, "entitycamera_mt");
lua_setmetatable(L, -2);
}
static int entityCameraIndex(lua_State *L) {
entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt");
assertNotNull(h, "EntityCamera handle cannot be NULL");
const char *key = luaL_checkstring(L, 2);
if(stringCompare(key, "zNear") == 0) {
lua_pushnumber(
L, (lua_Number)entityCameraGetZNear(h->entityId, h->compId)
);
return 1;
} else if(stringCompare(key, "zFar") == 0) {
lua_pushnumber(
L, (lua_Number)entityCameraGetZFar(h->entityId, h->compId)
);
return 1;
}
lua_getmetatable(L, 1);
lua_getfield(L, -1, key);
return 1;
}
static int entityCameraNewindex(lua_State *L) {
entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt");
assertNotNull(h, "EntityCamera handle cannot be NULL");
const char *key = luaL_checkstring(L, 2);
if(stringCompare(key, "zNear") == 0) {
entityCameraSetZNear(
h->entityId, h->compId, (float_t)luaL_checknumber(L, 3)
);
return 0;
} else if(stringCompare(key, "zFar") == 0) {
entityCameraSetZFar(
h->entityId, h->compId, (float_t)luaL_checknumber(L, 3)
);
return 0;
}
luaL_error(L, "entitycamera: unknown property '%s'", key);
return 0;
}
static int entityCameraGetForwardMethod(lua_State *L) {
entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt");
assertNotNull(h, "EntityCamera handle cannot be NULL");
vec2 fwd;
entityCameraGetForward(h->entityId, fwd);
luaVec2Push(L, fwd);
return 1;
}
static int entityCameraGetRightMethod(lua_State *L) {
entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt");
assertNotNull(h, "EntityCamera handle cannot be NULL");
vec2 right;
entityCameraGetRight(h->entityId, right);
luaVec2Push(L, right);
return 1;
}
static int entityCameraAdd(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
entityid_t entityId = (entityid_t)luaL_checknumber(L, 1);
componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_CAMERA);
pushEntityCameraHandle(L, entityId, compId);
return 1;
}
static int entityCameraGetCurrentGlobal(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
entityid_t camEnts[ENTITY_COUNT_MAX];
componentid_t camComps[ENTITY_COUNT_MAX];
entityid_t count = componentGetEntitiesWithComponent(
COMPONENT_TYPE_CAMERA, camEnts, camComps
);
if(count == 0) {
lua_pushnil(L);
return 1;
}
pushEntityCameraHandle(L, camEnts[0], camComps[0]);
return 1;
}
static void moduleEntityCamera(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
luaL_newmetatable(L, "entitycamera_mt");
lua_pushcfunction(L, entityCameraIndex);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, entityCameraNewindex);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, entityCameraGetForwardMethod);
lua_setfield(L, -2, "getForward");
lua_pushcfunction(L, entityCameraGetRightMethod);
lua_setfield(L, -2, "getRight");
lua_pop(L, 1);
lua_register(L, "entityCameraAdd", entityCameraAdd);
lua_register(L, "entityCameraGetCurrent", entityCameraGetCurrentGlobal);
}
@@ -1,72 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/module/modulebase.h"
#include "entity/entity.h"
#include "entity/component/display/entitymaterial.h"
typedef struct {
entityid_t entityId;
componentid_t compId;
} entitymaterial_handle_t;
static void pushEntityMaterialHandle(
lua_State *L,
entityid_t entityId,
componentid_t compId
) {
entitymaterial_handle_t *h = lua_newuserdata(
L, sizeof(entitymaterial_handle_t)
);
h->entityId = entityId;
h->compId = compId;
luaL_getmetatable(L, "entitymaterial_mt");
lua_setmetatable(L, -2);
}
static int entityMaterialIndex(lua_State *L) {
lua_getmetatable(L, 1);
lua_getfield(L, -1, luaL_checkstring(L, 2));
return 1;
}
static int entityMaterialNewindex(lua_State *L) {
entitymaterial_handle_t *h = luaL_checkudata(L, 1, "entitymaterial_mt");
assertNotNull(h, "EntityMaterial handle cannot be NULL");
const char *key = luaL_checkstring(L, 2);
if(stringCompare(key, "color") == 0) {
const color_t *col = (const color_t *)luaL_checkudata(L, 3, "color_mt");
entityMaterialSetColor(h->entityId, h->compId, *col);
return 0;
}
luaL_error(L, "entitymaterial: unknown property '%s'", key);
return 0;
}
static int entityMaterialAdd(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
entityid_t entityId = (entityid_t)luaL_checknumber(L, 1);
componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_MATERIAL);
pushEntityMaterialHandle(L, entityId, compId);
return 1;
}
static void moduleEntityMaterial(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
luaL_newmetatable(L, "entitymaterial_mt");
lua_pushcfunction(L, entityMaterialIndex);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, entityMaterialNewindex);
lua_setfield(L, -2, "__newindex");
lua_pop(L, 1);
lua_register(L, "entityMaterialAdd", entityMaterialAdd);
}
@@ -1,83 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/module/modulebase.h"
#include "entity/entity.h"
#include "entity/component/display/entitymesh.h"
typedef struct {
entityid_t entityId;
componentid_t compId;
} entitymesh_handle_t;
static void pushEntityMeshHandle(
lua_State *L,
entityid_t entityId,
componentid_t compId
) {
entitymesh_handle_t *h = lua_newuserdata(L, sizeof(entitymesh_handle_t));
h->entityId = entityId;
h->compId = compId;
luaL_getmetatable(L, "entitymesh_mt");
lua_setmetatable(L, -2);
}
static int entityMeshIndex(lua_State *L) {
lua_getmetatable(L, 1);
lua_getfield(L, -1, luaL_checkstring(L, 2));
return 1;
}
static int entityMeshGeneratePlaneMethod(lua_State *L) {
entitymesh_handle_t *h = luaL_checkudata(L, 1, "entitymesh_mt");
assertNotNull(h, "EntityMesh handle cannot be NULL");
float_t width = (float_t)luaL_checknumber(L, 2);
float_t height = (float_t)luaL_checknumber(L, 3);
errorret_t err = entityMeshGeneratePlane(h->entityId, h->compId, width, height);
if(err.code != ERROR_OK) {
luaL_error(L, "Failed to generate plane mesh");
}
return 0;
}
static int entityMeshGenerateCapsuleMethod(lua_State *L) {
entitymesh_handle_t *h = luaL_checkudata(L, 1, "entitymesh_mt");
assertNotNull(h, "EntityMesh handle cannot be NULL");
float_t radius = (float_t)luaL_checknumber(L, 2);
float_t halfHeight = (float_t)luaL_checknumber(L, 3);
errorret_t err = entityMeshGenerateCapsule(
h->entityId, h->compId, radius, halfHeight
);
if(err.code != ERROR_OK) {
luaL_error(L, "Failed to generate capsule mesh");
}
return 0;
}
static int entityMeshAdd(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
entityid_t entityId = (entityid_t)luaL_checknumber(L, 1);
componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_MESH);
pushEntityMeshHandle(L, entityId, compId);
return 1;
}
static void moduleEntityMesh(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
luaL_newmetatable(L, "entitymesh_mt");
lua_pushcfunction(L, entityMeshIndex);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, entityMeshGeneratePlaneMethod);
lua_setfield(L, -2, "generatePlane");
lua_pushcfunction(L, entityMeshGenerateCapsuleMethod);
lua_setfield(L, -2, "generateCapsule");
lua_pop(L, 1);
lua_register(L, "entityMeshAdd", entityMeshAdd);
}
@@ -1,169 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/module/modulebase.h"
#include "entity/entity.h"
#include "entity/component/display/entityposition.h"
#include "script/module/math/modulevec3.h"
typedef struct {
entityid_t entityId;
componentid_t compId;
} entityposition_handle_t;
static void pushEntityPositionHandle(
lua_State *L,
entityid_t entityId,
componentid_t compId
) {
entityposition_handle_t *h = lua_newuserdata(
L, sizeof(entityposition_handle_t)
);
h->entityId = entityId;
h->compId = compId;
luaL_getmetatable(L, "entityposition_mt");
lua_setmetatable(L, -2);
}
static int entityPositionIndex(lua_State *L) {
entityposition_handle_t *h = luaL_checkudata(L, 1, "entityposition_mt");
assertNotNull(h, "EntityPosition handle cannot be NULL");
const char *key = luaL_checkstring(L, 2);
if(stringCompare(key, "x") == 0) {
vec3 v; entityPositionGetPosition(h->entityId, h->compId, v);
lua_pushnumber(L, v[0]); return 1;
} else if(stringCompare(key, "y") == 0) {
vec3 v; entityPositionGetPosition(h->entityId, h->compId, v);
lua_pushnumber(L, v[1]); return 1;
} else if(stringCompare(key, "z") == 0) {
vec3 v; entityPositionGetPosition(h->entityId, h->compId, v);
lua_pushnumber(L, v[2]); return 1;
} else if(stringCompare(key, "rotX") == 0) {
vec3 v; entityPositionGetRotation(h->entityId, h->compId, v);
lua_pushnumber(L, v[0]); return 1;
} else if(stringCompare(key, "rotY") == 0) {
vec3 v; entityPositionGetRotation(h->entityId, h->compId, v);
lua_pushnumber(L, v[1]); return 1;
} else if(stringCompare(key, "rotZ") == 0) {
vec3 v; entityPositionGetRotation(h->entityId, h->compId, v);
lua_pushnumber(L, v[2]); return 1;
} else if(stringCompare(key, "scaleX") == 0) {
vec3 v; entityPositionGetScale(h->entityId, h->compId, v);
lua_pushnumber(L, v[0]); return 1;
} else if(stringCompare(key, "scaleY") == 0) {
vec3 v; entityPositionGetScale(h->entityId, h->compId, v);
lua_pushnumber(L, v[1]); return 1;
} else if(stringCompare(key, "scaleZ") == 0) {
vec3 v; entityPositionGetScale(h->entityId, h->compId, v);
lua_pushnumber(L, v[2]); return 1;
} else if(stringCompare(key, "position") == 0) {
vec3 v; entityPositionGetPosition(h->entityId, h->compId, v);
luaVec3Push(L, v); return 1;
} else if(stringCompare(key, "rotation") == 0) {
vec3 v; entityPositionGetRotation(h->entityId, h->compId, v);
luaVec3Push(L, v); return 1;
} else if(stringCompare(key, "scale") == 0) {
vec3 v; entityPositionGetScale(h->entityId, h->compId, v);
luaVec3Push(L, v); return 1;
}
lua_getmetatable(L, 1);
lua_getfield(L, -1, key);
return 1;
}
static int entityPositionNewindex(lua_State *L) {
entityposition_handle_t *h = luaL_checkudata(L, 1, "entityposition_mt");
assertNotNull(h, "EntityPosition handle cannot be NULL");
const char *key = luaL_checkstring(L, 2);
if(stringCompare(key, "x") == 0) {
vec3 v; entityPositionGetPosition(h->entityId, h->compId, v);
v[0] = (float_t)luaL_checknumber(L, 3);
entityPositionSetPosition(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "y") == 0) {
vec3 v; entityPositionGetPosition(h->entityId, h->compId, v);
v[1] = (float_t)luaL_checknumber(L, 3);
entityPositionSetPosition(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "z") == 0) {
vec3 v; entityPositionGetPosition(h->entityId, h->compId, v);
v[2] = (float_t)luaL_checknumber(L, 3);
entityPositionSetPosition(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "rotX") == 0) {
vec3 v; entityPositionGetRotation(h->entityId, h->compId, v);
v[0] = (float_t)luaL_checknumber(L, 3);
entityPositionSetRotation(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "rotY") == 0) {
vec3 v; entityPositionGetRotation(h->entityId, h->compId, v);
v[1] = (float_t)luaL_checknumber(L, 3);
entityPositionSetRotation(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "rotZ") == 0) {
vec3 v; entityPositionGetRotation(h->entityId, h->compId, v);
v[2] = (float_t)luaL_checknumber(L, 3);
entityPositionSetRotation(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "scaleX") == 0) {
vec3 v; entityPositionGetScale(h->entityId, h->compId, v);
v[0] = (float_t)luaL_checknumber(L, 3);
entityPositionSetScale(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "scaleY") == 0) {
vec3 v; entityPositionGetScale(h->entityId, h->compId, v);
v[1] = (float_t)luaL_checknumber(L, 3);
entityPositionSetScale(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "scaleZ") == 0) {
vec3 v; entityPositionGetScale(h->entityId, h->compId, v);
v[2] = (float_t)luaL_checknumber(L, 3);
entityPositionSetScale(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "position") == 0) {
vec3 v; luaVec3Check(L, 3, v);
entityPositionSetPosition(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "rotation") == 0) {
vec3 v; luaVec3Check(L, 3, v);
entityPositionSetRotation(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "scale") == 0) {
vec3 v; luaVec3Check(L, 3, v);
entityPositionSetScale(h->entityId, h->compId, v); return 0;
}
luaL_error(L, "entityposition: unknown property '%s'", key);
return 0;
}
static int entityPositionLookAtMethod(lua_State *L) {
entityposition_handle_t *h = luaL_checkudata(L, 1, "entityposition_mt");
assertNotNull(h, "EntityPosition handle cannot be NULL");
vec3 target, up, eye;
luaVec3Check(L, 2, target);
luaVec3Check(L, 3, up);
luaVec3Check(L, 4, eye);
entityPositionLookAt(h->entityId, h->compId, target, up, eye);
return 0;
}
static int entityPositionAdd(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
entityid_t entityId = (entityid_t)luaL_checknumber(L, 1);
componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_POSITION);
pushEntityPositionHandle(L, entityId, compId);
return 1;
}
static void moduleEntityPosition(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
luaL_newmetatable(L, "entityposition_mt");
lua_pushcfunction(L, entityPositionIndex);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, entityPositionNewindex);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, entityPositionLookAtMethod);
lua_setfield(L, -2, "lookAt");
lua_pop(L, 1);
lua_register(L, "entityPositionAdd", entityPositionAdd);
}
+267 -28
View File
@@ -7,46 +7,285 @@
#pragma once
#include "script/module/modulebase.h"
#include "entity/entitymanager.h"
#include "entity/entity.h"
#include "display/moduleentityposition.h"
#include "display/moduleentitycamera.h"
#include "display/moduleentitymesh.h"
#include "display/moduleentitymaterial.h"
#include "physics/moduleentityphysics.h"
#include "script/moduleentityscript.h"
#include "entity/entitymanager.h"
#include "entity/component/display/entityposition.h"
#include "entity/component/display/entitycamera.h"
#include "entity/component/display/entitymesh.h"
#include "entity/component/display/entitymaterial.h"
static int moduleEntityAdd(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
// ============================================================================
// Handles
// ============================================================================
entityid_t id = entityManagerAdd();
lua_pushnumber(L, (lua_Number)id);
typedef struct { entityid_t entityId; componentid_t compId; } entitypos_handle_t;
typedef struct { entityid_t entityId; componentid_t compId; } entitycam_handle_t;
typedef struct { entityid_t entityId; componentid_t compId; } entitymesh_handle_t;
typedef struct { entityid_t entityId; componentid_t compId; } entitymat_handle_t;
// ============================================================================
// entityPosition
// ============================================================================
static int _posIndex(lua_State *L) {
entitypos_handle_t *h = luaL_checkudata(L, 1, "entitypos_mt");
const char *k = luaL_checkstring(L, 2);
vec3 v;
if(stringCompare(k, "x") == 0) {
entityPositionGetPosition(h->entityId, h->compId, v);
lua_pushnumber(L, v[0]); return 1;
} else if(stringCompare(k, "y") == 0) {
entityPositionGetPosition(h->entityId, h->compId, v);
lua_pushnumber(L, v[1]); return 1;
} else if(stringCompare(k, "z") == 0) {
entityPositionGetPosition(h->entityId, h->compId, v);
lua_pushnumber(L, v[2]); return 1;
} else if(stringCompare(k, "rotX") == 0) {
entityPositionGetRotation(h->entityId, h->compId, v);
lua_pushnumber(L, v[0]); return 1;
} else if(stringCompare(k, "rotY") == 0) {
entityPositionGetRotation(h->entityId, h->compId, v);
lua_pushnumber(L, v[1]); return 1;
} else if(stringCompare(k, "rotZ") == 0) {
entityPositionGetRotation(h->entityId, h->compId, v);
lua_pushnumber(L, v[2]); return 1;
} else if(stringCompare(k, "scaleX") == 0) {
entityPositionGetScale(h->entityId, h->compId, v);
lua_pushnumber(L, v[0]); return 1;
} else if(stringCompare(k, "scaleY") == 0) {
entityPositionGetScale(h->entityId, h->compId, v);
lua_pushnumber(L, v[1]); return 1;
} else if(stringCompare(k, "scaleZ") == 0) {
entityPositionGetScale(h->entityId, h->compId, v);
lua_pushnumber(L, v[2]); return 1;
}
lua_getmetatable(L, 1);
lua_getfield(L, -1, k);
return 1;
}
static int moduleEntityRemove(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
if(!lua_isnumber(L, 1)) {
luaL_error(L, "entityRemove requires a number entity ID");
return 0;
static int _posNewindex(lua_State *L) {
entitypos_handle_t *h = luaL_checkudata(L, 1, "entitypos_mt");
const char *k = luaL_checkstring(L, 2);
vec3 v;
if(stringCompare(k, "x") == 0) {
entityPositionGetPosition(h->entityId, h->compId, v);
v[0] = (float_t)luaL_checknumber(L, 3);
entityPositionSetPosition(h->entityId, h->compId, v); return 0;
} else if(stringCompare(k, "y") == 0) {
entityPositionGetPosition(h->entityId, h->compId, v);
v[1] = (float_t)luaL_checknumber(L, 3);
entityPositionSetPosition(h->entityId, h->compId, v); return 0;
} else if(stringCompare(k, "z") == 0) {
entityPositionGetPosition(h->entityId, h->compId, v);
v[2] = (float_t)luaL_checknumber(L, 3);
entityPositionSetPosition(h->entityId, h->compId, v); return 0;
} else if(stringCompare(k, "rotX") == 0) {
entityPositionGetRotation(h->entityId, h->compId, v);
v[0] = (float_t)luaL_checknumber(L, 3);
entityPositionSetRotation(h->entityId, h->compId, v); return 0;
} else if(stringCompare(k, "rotY") == 0) {
entityPositionGetRotation(h->entityId, h->compId, v);
v[1] = (float_t)luaL_checknumber(L, 3);
entityPositionSetRotation(h->entityId, h->compId, v); return 0;
} else if(stringCompare(k, "rotZ") == 0) {
entityPositionGetRotation(h->entityId, h->compId, v);
v[2] = (float_t)luaL_checknumber(L, 3);
entityPositionSetRotation(h->entityId, h->compId, v); return 0;
} else if(stringCompare(k, "scaleX") == 0) {
entityPositionGetScale(h->entityId, h->compId, v);
v[0] = (float_t)luaL_checknumber(L, 3);
entityPositionSetScale(h->entityId, h->compId, v); return 0;
} else if(stringCompare(k, "scaleY") == 0) {
entityPositionGetScale(h->entityId, h->compId, v);
v[1] = (float_t)luaL_checknumber(L, 3);
entityPositionSetScale(h->entityId, h->compId, v); return 0;
} else if(stringCompare(k, "scaleZ") == 0) {
entityPositionGetScale(h->entityId, h->compId, v);
v[2] = (float_t)luaL_checknumber(L, 3);
entityPositionSetScale(h->entityId, h->compId, v); return 0;
}
entityid_t id = (entityid_t)luaL_checknumber(L, 1);
entityDispose(id);
luaL_error(L, "entitypos: unknown property '%s'", k);
return 0;
}
static int _posLookAt(lua_State *L) {
entitypos_handle_t *h = luaL_checkudata(L, 1, "entitypos_mt");
vec3 target = {
(float_t)luaL_checknumber(L, 2),
(float_t)luaL_checknumber(L, 3),
(float_t)luaL_checknumber(L, 4)
};
vec3 up = { 0.0f, 1.0f, 0.0f };
if(lua_gettop(L) >= 7) {
up[0] = (float_t)luaL_checknumber(L, 5);
up[1] = (float_t)luaL_checknumber(L, 6);
up[2] = (float_t)luaL_checknumber(L, 7);
}
vec3 eye;
entityPositionGetPosition(h->entityId, h->compId, eye);
entityPositionLookAt(h->entityId, h->compId, target, up, eye);
return 0;
}
static int _entityPositionAdd(lua_State *L) {
entityid_t id = (entityid_t)luaL_checknumber(L, 1);
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_POSITION);
entitypos_handle_t *h = lua_newuserdata(L, sizeof(entitypos_handle_t));
h->entityId = id;
h->compId = comp;
luaL_getmetatable(L, "entitypos_mt");
lua_setmetatable(L, -2);
return 1;
}
// ============================================================================
// entityCamera
// ============================================================================
static int _camIndex(lua_State *L) {
entitycam_handle_t *h = luaL_checkudata(L, 1, "entitycam_mt");
const char *k = luaL_checkstring(L, 2);
if(stringCompare(k, "zNear") == 0) {
lua_pushnumber(L, entityCameraGetZNear(h->entityId, h->compId)); return 1;
} else if(stringCompare(k, "zFar") == 0) {
lua_pushnumber(L, entityCameraGetZFar(h->entityId, h->compId)); return 1;
}
lua_getmetatable(L, 1); lua_getfield(L, -1, k); return 1;
}
static int _camNewindex(lua_State *L) {
entitycam_handle_t *h = luaL_checkudata(L, 1, "entitycam_mt");
const char *k = luaL_checkstring(L, 2);
if(stringCompare(k, "zNear") == 0) {
entityCameraSetZNear(h->entityId, h->compId, (float_t)luaL_checknumber(L, 3));
return 0;
} else if(stringCompare(k, "zFar") == 0) {
entityCameraSetZFar(h->entityId, h->compId, (float_t)luaL_checknumber(L, 3));
return 0;
}
luaL_error(L, "entitycam: unknown property '%s'", k); return 0;
}
static int _entityCameraAdd(lua_State *L) {
entityid_t id = (entityid_t)luaL_checknumber(L, 1);
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_CAMERA);
entitycam_handle_t *h = lua_newuserdata(L, sizeof(entitycam_handle_t));
h->entityId = id; h->compId = comp;
luaL_getmetatable(L, "entitycam_mt"); lua_setmetatable(L, -2);
return 1;
}
// ============================================================================
// entityMesh
// ============================================================================
static int _meshIndex(lua_State *L) {
lua_getmetatable(L, 1); lua_getfield(L, -1, luaL_checkstring(L, 2)); return 1;
}
static int _meshGeneratePlane(lua_State *L) {
entitymesh_handle_t *h = luaL_checkudata(L, 1, "entitymesh_mt");
float_t w = (float_t)luaL_checknumber(L, 2);
float_t d = (float_t)luaL_checknumber(L, 3);
errorret_t err = entityMeshGeneratePlane(h->entityId, h->compId, w, d);
if(err.code != ERROR_OK) luaL_error(L, "entityMesh: generatePlane failed");
return 0;
}
static int _meshGenerateCapsule(lua_State *L) {
entitymesh_handle_t *h = luaL_checkudata(L, 1, "entitymesh_mt");
float_t r = (float_t)luaL_checknumber(L, 2);
float_t hh = (float_t)luaL_checknumber(L, 3);
errorret_t err = entityMeshGenerateCapsule(h->entityId, h->compId, r, hh);
if(err.code != ERROR_OK) luaL_error(L, "entityMesh: generateCapsule failed");
return 0;
}
static int _entityMeshAdd(lua_State *L) {
entityid_t id = (entityid_t)luaL_checknumber(L, 1);
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_MESH);
entitymesh_handle_t *h = lua_newuserdata(L, sizeof(entitymesh_handle_t));
h->entityId = id; h->compId = comp;
luaL_getmetatable(L, "entitymesh_mt"); lua_setmetatable(L, -2);
return 1;
}
// ============================================================================
// entityMaterial
// ============================================================================
static int _matIndex(lua_State *L) {
lua_getmetatable(L, 1); lua_getfield(L, -1, luaL_checkstring(L, 2)); return 1;
}
static int _matNewindex(lua_State *L) {
entitymat_handle_t *h = luaL_checkudata(L, 1, "entitymat_mt");
const char *k = luaL_checkstring(L, 2);
if(stringCompare(k, "color") == 0) {
const color_t *col = (const color_t *)luaL_checkudata(L, 3, "color_mt");
entityMaterialSetColor(h->entityId, h->compId, *col);
return 0;
}
luaL_error(L, "entitymat: unknown property '%s'", k); return 0;
}
static int _entityMaterialAdd(lua_State *L) {
entityid_t id = (entityid_t)luaL_checknumber(L, 1);
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_MATERIAL);
entitymat_handle_t *h = lua_newuserdata(L, sizeof(entitymat_handle_t));
h->entityId = id; h->compId = comp;
luaL_getmetatable(L, "entitymat_mt"); lua_setmetatable(L, -2);
return 1;
}
// ============================================================================
// entityAdd / entityRemove
// ============================================================================
static int _entityAdd(lua_State *L) {
lua_pushnumber(L, (lua_Number)entityManagerAdd());
return 1;
}
static int _entityRemove(lua_State *L) {
entityDispose((entityid_t)luaL_checknumber(L, 1));
return 0;
}
// ============================================================================
// Register
// ============================================================================
static void moduleEntity(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
lua_register(L, "entityAdd", moduleEntityAdd);
lua_register(L, "entityRemove", moduleEntityRemove);
luaL_newmetatable(L, "entitypos_mt");
lua_pushcfunction(L, _posIndex); lua_setfield(L, -2, "__index");
lua_pushcfunction(L, _posNewindex); lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, _posLookAt); lua_setfield(L, -2, "lookAt");
lua_pop(L, 1);
moduleEntityPosition(L);
moduleEntityCamera(L);
moduleEntityMesh(L);
moduleEntityMaterial(L);
moduleEntityPhysics(L);
moduleEntityScript(L);
luaL_newmetatable(L, "entitycam_mt");
lua_pushcfunction(L, _camIndex); lua_setfield(L, -2, "__index");
lua_pushcfunction(L, _camNewindex); lua_setfield(L, -2, "__newindex");
lua_pop(L, 1);
luaL_newmetatable(L, "entitymesh_mt");
lua_pushcfunction(L, _meshIndex); lua_setfield(L, -2, "__index");
lua_pushcfunction(L, _meshGeneratePlane); lua_setfield(L, -2, "generatePlane");
lua_pushcfunction(L, _meshGenerateCapsule); lua_setfield(L, -2, "generateCapsule");
lua_pop(L, 1);
luaL_newmetatable(L, "entitymat_mt");
lua_pushcfunction(L, _matIndex); lua_setfield(L, -2, "__index");
lua_pushcfunction(L, _matNewindex); lua_setfield(L, -2, "__newindex");
lua_pop(L, 1);
lua_register(L, "entityAdd", _entityAdd);
lua_register(L, "entityRemove", _entityRemove);
lua_register(L, "entityPositionAdd", _entityPositionAdd);
lua_register(L, "entityCameraAdd", _entityCameraAdd);
lua_register(L, "entityMeshAdd", _entityMeshAdd);
lua_register(L, "entityMaterialAdd", _entityMaterialAdd);
}
@@ -1,191 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/module/modulebase.h"
#include "entity/entity.h"
#include "entity/component/physics/entityphysics.h"
#include "physics/physicsbodytype.h"
#include "script/module/math/modulevec3.h"
typedef struct {
entityid_t entityId;
componentid_t compId;
} entityphysics_handle_t;
static void pushEntityPhysicsHandle(
lua_State *L,
entityid_t entityId,
componentid_t compId
) {
entityphysics_handle_t *h = lua_newuserdata(
L, sizeof(entityphysics_handle_t)
);
h->entityId = entityId;
h->compId = compId;
luaL_getmetatable(L, "entityphysics_mt");
lua_setmetatable(L, -2);
}
static int entityPhysicsIndex(lua_State *L) {
entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt");
assertNotNull(h, "EntityPhysics handle cannot be NULL");
const char *key = luaL_checkstring(L, 2);
if(stringCompare(key, "bodyType") == 0) {
lua_pushnumber(
L, (lua_Number)entityPhysicsGetBodyType(h->entityId, h->compId)
);
return 1;
} else if(stringCompare(key, "velocityX") == 0) {
vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v);
lua_pushnumber(L, v[0]); return 1;
} else if(stringCompare(key, "velocityY") == 0) {
vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v);
lua_pushnumber(L, v[1]); return 1;
} else if(stringCompare(key, "velocityZ") == 0) {
vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v);
lua_pushnumber(L, v[2]); return 1;
} else if(stringCompare(key, "velocity") == 0) {
vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v);
luaVec3Push(L, v); return 1;
} else if(stringCompare(key, "onGround") == 0) {
lua_pushboolean(
L, (int)entityPhysicsIsOnGround(h->entityId, h->compId)
);
return 1;
}
lua_getmetatable(L, 1);
lua_getfield(L, -1, key);
return 1;
}
static int entityPhysicsNewindex(lua_State *L) {
entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt");
assertNotNull(h, "EntityPhysics handle cannot be NULL");
const char *key = luaL_checkstring(L, 2);
if(stringCompare(key, "bodyType") == 0) {
physicsbodytype_t t = (physicsbodytype_t)luaL_checknumber(L, 3);
entityPhysicsSetBodyType(h->entityId, h->compId, t);
return 0;
} else if(stringCompare(key, "velocityX") == 0) {
vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v);
v[0] = (float_t)luaL_checknumber(L, 3);
entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "velocityY") == 0) {
vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v);
v[1] = (float_t)luaL_checknumber(L, 3);
entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "velocityZ") == 0) {
vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v);
v[2] = (float_t)luaL_checknumber(L, 3);
entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0;
} else if(stringCompare(key, "velocity") == 0) {
vec3 v; luaVec3Check(L, 3, v);
entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0;
}
luaL_error(L, "entityphysics: unknown property '%s'", key);
return 0;
}
static int entityPhysicsSetShapeCapsuleMethod(lua_State *L) {
entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt");
assertNotNull(h, "EntityPhysics handle cannot be NULL");
physicsshape_t shape;
shape.type = PHYSICS_SHAPE_CAPSULE;
shape.data.capsule.radius = (float_t)luaL_checknumber(L, 2);
shape.data.capsule.halfHeight = (float_t)luaL_checknumber(L, 3);
entityPhysicsSetShape(h->entityId, h->compId, shape);
return 0;
}
static int entityPhysicsSetShapePlaneMethod(lua_State *L) {
entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt");
assertNotNull(h, "EntityPhysics handle cannot be NULL");
physicsshape_t shape;
shape.type = PHYSICS_SHAPE_PLANE;
vec3 normal; luaVec3Check(L, 2, normal);
shape.data.plane.normal[0] = normal[0];
shape.data.plane.normal[1] = normal[1];
shape.data.plane.normal[2] = normal[2];
shape.data.plane.distance = (float_t)luaL_checknumber(L, 3);
entityPhysicsSetShape(h->entityId, h->compId, shape);
return 0;
}
static int entityPhysicsSetShapeSphereMethod(lua_State *L) {
entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt");
assertNotNull(h, "EntityPhysics handle cannot be NULL");
physicsshape_t shape;
shape.type = PHYSICS_SHAPE_SPHERE;
shape.data.sphere.radius = (float_t)luaL_checknumber(L, 2);
entityPhysicsSetShape(h->entityId, h->compId, shape);
return 0;
}
static int entityPhysicsSetShapeCubeMethod(lua_State *L) {
entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt");
assertNotNull(h, "EntityPhysics handle cannot be NULL");
physicsshape_t shape;
shape.type = PHYSICS_SHAPE_CUBE;
vec3 half; luaVec3Check(L, 2, half);
shape.data.cube.halfExtents[0] = half[0];
shape.data.cube.halfExtents[1] = half[1];
shape.data.cube.halfExtents[2] = half[2];
entityPhysicsSetShape(h->entityId, h->compId, shape);
return 0;
}
static int entityPhysicsApplyImpulseMethod(lua_State *L) {
entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt");
assertNotNull(h, "EntityPhysics handle cannot be NULL");
vec3 impulse; luaVec3Check(L, 2, impulse);
entityPhysicsApplyImpulse(h->entityId, h->compId, impulse);
return 0;
}
static int entityPhysicsAdd(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
entityid_t entityId = (entityid_t)luaL_checknumber(L, 1);
componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_PHYSICS);
pushEntityPhysicsHandle(L, entityId, compId);
return 1;
}
static void moduleEntityPhysics(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
#define SET(name, val) \
lua_pushnumber(L, (lua_Number)(val)); \
lua_setglobal(L, name)
SET("PHYSICS_BODY_STATIC", PHYSICS_BODY_STATIC);
SET("PHYSICS_BODY_DYNAMIC", PHYSICS_BODY_DYNAMIC);
SET("PHYSICS_BODY_KINEMATIC", PHYSICS_BODY_KINEMATIC);
#undef SET
luaL_newmetatable(L, "entityphysics_mt");
lua_pushcfunction(L, entityPhysicsIndex);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, entityPhysicsNewindex);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, entityPhysicsSetShapeCapsuleMethod);
lua_setfield(L, -2, "setShapeCapsule");
lua_pushcfunction(L, entityPhysicsSetShapePlaneMethod);
lua_setfield(L, -2, "setShapePlane");
lua_pushcfunction(L, entityPhysicsSetShapeSphereMethod);
lua_setfield(L, -2, "setShapeSphere");
lua_pushcfunction(L, entityPhysicsSetShapeCubeMethod);
lua_setfield(L, -2, "setShapeCube");
lua_pushcfunction(L, entityPhysicsApplyImpulseMethod);
lua_setfield(L, -2, "applyImpulse");
lua_pop(L, 1);
lua_register(L, "entityPhysicsAdd", entityPhysicsAdd);
}
@@ -1,83 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/module/modulebase.h"
#include "entity/entity.h"
#include "entity/entitymanager.h"
#include "entity/component/script/entityscript.h"
static int moduleEntityScriptAdd(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
entityid_t entityId = (entityid_t)luaL_checknumber(L, 1);
componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_ENTITYSCRIPT);
lua_pushnumber(L, (lua_Number)compId);
return 1;
}
static int moduleEntityScriptSetScript(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
entityid_t entityId = (entityid_t)luaL_checknumber(L, 1);
componentid_t compId = (componentid_t)luaL_checknumber(L, 2);
const char_t *filename = luaL_checkstring(L, 3);
errorret_t err = entityScriptSetScript(entityId, compId, filename);
if(err.code != ERROR_OK) {
luaL_error(L, "Failed to set entity script: %s", filename);
errorCatch(errorPrint(err));
return 0;
}
return 0;
}
static int moduleEntityAddScripted(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
const char_t *filename = luaL_checkstring(L, 1);
entityid_t entityId = entityManagerAdd();
componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_ENTITYSCRIPT);
errorret_t err = entityScriptSetScript(entityId, compId, filename);
if(err.code != ERROR_OK) {
luaL_error(L, "Failed to set entity script: %s", filename);
errorCatch(errorPrint(err));
return 0;
}
lua_pushnumber(L, (lua_Number)entityId);
lua_pushnumber(L, (lua_Number)compId);
return 2;
}
static int moduleEntityScriptUpdate(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
entityid_t entityId = (entityid_t)luaL_checknumber(L, 1);
componentid_t compId = (componentid_t)luaL_checknumber(L, 2);
errorret_t err = entityScriptUpdate(entityId, compId);
if(err.code != ERROR_OK) {
luaL_error(L, "Failed to update entity script");
errorCatch(errorPrint(err));
return 0;
}
return 0;
}
static void moduleEntityScript(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
lua_register(L, "entityScriptAdd", moduleEntityScriptAdd);
lua_register(L, "entityScriptSetScript", moduleEntityScriptSetScript);
lua_register(L, "entityScriptUpdate", moduleEntityScriptUpdate);
lua_register(L, "entityAddScripted", moduleEntityAddScripted);
}
+4 -2
View File
@@ -62,14 +62,16 @@ static int moduleScriptInclude(lua_State *L) {
stringCopy(&buffer[len], ".lua", 5);
}
int32_t stackBase = lua_gettop(L);
errorret_t err = scriptContextExecFile(ctx, buffer);
if(err.code != ERROR_OK) {
luaL_error(L, "Failed to include script file");
luaL_error(L, "Failed to include script file: %s", buffer);
errorCatch(errorPrint(err));
return 0;
}
return 0;
return lua_gettop(L) - stackBase;
}
static void moduleScript(lua_State *L) {