diff --git a/assets/entities/cube.lua b/assets/entities/cube.lua new file mode 100644 index 00000000..86132f47 --- /dev/null +++ b/assets/entities/cube.lua @@ -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 diff --git a/assets/entities/plane.lua b/assets/entities/plane.lua deleted file mode 100644 index 04c23272..00000000 --- a/assets/entities/plane.lua +++ /dev/null @@ -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 diff --git a/assets/entities/player.lua b/assets/entities/player.lua deleted file mode 100644 index c3e5a07b..00000000 --- a/assets/entities/player.lua +++ /dev/null @@ -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 diff --git a/assets/init.lua b/assets/init.lua index 2a71c265..34303093 100644 --- a/assets/init.lua +++ b/assets/init.lua @@ -72,6 +72,4 @@ else print("Unknown platform, no default input bindings set.") end - -local test = 'test' -Scene.set('test/scene.lua') \ No newline at end of file +Scene.set('scenes/cube.lua') \ No newline at end of file diff --git a/assets/scenes/cube.lua b/assets/scenes/cube.lua new file mode 100644 index 00000000..ef137caa --- /dev/null +++ b/assets/scenes/cube.lua @@ -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 diff --git a/src/dusk/entity/component/script/CMakeLists.txt b/src/dusk/entity/component/script/CMakeLists.txt index bd179301..5fa29add 100644 --- a/src/dusk/entity/component/script/CMakeLists.txt +++ b/src/dusk/entity/component/script/CMakeLists.txt @@ -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 -) + + diff --git a/src/dusk/entity/component/script/entityscript.c b/src/dusk/entity/component/script/entityscript.c deleted file mode 100644 index ebbd7323..00000000 --- a/src/dusk/entity/component/script/entityscript.c +++ /dev/null @@ -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); -} diff --git a/src/dusk/entity/component/script/entityscript.h b/src/dusk/entity/component/script/entityscript.h deleted file mode 100644 index c133899c..00000000 --- a/src/dusk/entity/component/script/entityscript.h +++ /dev/null @@ -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 -); diff --git a/src/dusk/entity/componentlist.h b/src/dusk/entity/componentlist.h index 939f3514..6fda2fea 100644 --- a/src/dusk/entity/componentlist.h +++ b/src/dusk/entity/componentlist.h @@ -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) \ No newline at end of file +X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose) \ No newline at end of file diff --git a/src/dusk/scene/scene.c b/src/dusk/scene/scene.c index 21b756e6..5e62fc04 100644 --- a/src/dusk/scene/scene.c +++ b/src/dusk/scene/scene.c @@ -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; -} \ No newline at end of file +} diff --git a/src/dusk/scene/scene.h b/src/dusk/scene/scene.h index d1b77935..62528e9d 100644 --- a/src/dusk/scene/scene.h +++ b/src/dusk/scene/scene.h @@ -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); \ No newline at end of file +int sceneSetLua(lua_State *L); diff --git a/src/dusk/script/module/entity/display/moduleentitycamera.h b/src/dusk/script/module/entity/display/moduleentitycamera.h deleted file mode 100644 index 85cca377..00000000 --- a/src/dusk/script/module/entity/display/moduleentitycamera.h +++ /dev/null @@ -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); -} diff --git a/src/dusk/script/module/entity/display/moduleentitymaterial.h b/src/dusk/script/module/entity/display/moduleentitymaterial.h deleted file mode 100644 index bd183f22..00000000 --- a/src/dusk/script/module/entity/display/moduleentitymaterial.h +++ /dev/null @@ -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); -} diff --git a/src/dusk/script/module/entity/display/moduleentitymesh.h b/src/dusk/script/module/entity/display/moduleentitymesh.h deleted file mode 100644 index 6a227ca9..00000000 --- a/src/dusk/script/module/entity/display/moduleentitymesh.h +++ /dev/null @@ -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); -} diff --git a/src/dusk/script/module/entity/display/moduleentityposition.h b/src/dusk/script/module/entity/display/moduleentityposition.h deleted file mode 100644 index fef8900e..00000000 --- a/src/dusk/script/module/entity/display/moduleentityposition.h +++ /dev/null @@ -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); -} diff --git a/src/dusk/script/module/entity/moduleentity.h b/src/dusk/script/module/entity/moduleentity.h index e393a8a6..51725449 100644 --- a/src/dusk/script/module/entity/moduleentity.h +++ b/src/dusk/script/module/entity/moduleentity.h @@ -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); } diff --git a/src/dusk/script/module/entity/physics/moduleentityphysics.h b/src/dusk/script/module/entity/physics/moduleentityphysics.h deleted file mode 100644 index 56599f66..00000000 --- a/src/dusk/script/module/entity/physics/moduleentityphysics.h +++ /dev/null @@ -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); -} diff --git a/src/dusk/script/module/entity/script/moduleentityscript.h b/src/dusk/script/module/entity/script/moduleentityscript.h deleted file mode 100644 index abbaa3ed..00000000 --- a/src/dusk/script/module/entity/script/moduleentityscript.h +++ /dev/null @@ -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); -} diff --git a/src/dusk/script/module/script/modulescript.h b/src/dusk/script/module/script/modulescript.h index 82c5a113..2207ae23 100644 --- a/src/dusk/script/module/script/modulescript.h +++ b/src/dusk/script/module/script/modulescript.h @@ -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) {