Working on some script modules

This commit is contained in:
2026-05-05 16:22:04 -05:00
parent 6edcf75a0c
commit bb29c0edef
28 changed files with 712 additions and 229 deletions
-1
View File
@@ -4,7 +4,6 @@
# https://opensource.org/licenses/MIT
add_subdirectory(dusk)
add_subdirectory(duskrpg)
if(DUSK_TARGET_SYSTEM STREQUAL "linux" OR DUSK_TARGET_SYSTEM STREQUAL "knulli")
add_subdirectory(dusklinux)
+2
View File
@@ -56,6 +56,8 @@ target_sources(${DUSK_BINARY_TARGET_NAME}
# Subdirs
add_subdirectory(assert)
add_subdirectory(asset)
add_subdirectory(item)
add_subdirectory(story)
add_subdirectory(console)
add_subdirectory(display)
add_subdirectory(log)
+2 -4
View File
@@ -18,11 +18,11 @@
#include "assert/assert.h"
#include "entity/entitymanager.h"
#include "entity/component/physics/entityphysics.h"
#include "game/game.h"
#include "physics/physicsmanager.h"
#include "network/network.h"
#include "system/system.h"
#include "console/console.h"
#include "item/backpack.h"
double jerry_port_current_time(void) {
dusktimeepoch_t epoch = timeGetEpoch();
@@ -54,9 +54,9 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
errorChain(uiInit());
errorChain(sceneInit());
entityManagerInit();
backpackInit();
physicsManagerInit();
errorChain(networkInit());
errorChain(gameInit());
/* Run the init script. */
consolePrint("Engine initialized");
@@ -73,7 +73,6 @@ errorret_t engineUpdate(void) {
consoleUpdate();
uiUpdate();
physicsManagerUpdate();
errorChain(gameUpdate());
errorChain(displayUpdate());
if(inputPressed(INPUT_ACTION_RAGEQUIT)) ENGINE.running = false;
@@ -91,7 +90,6 @@ void engineExit(void) {
errorret_t engineDispose(void) {
sceneDispose();
errorChain(gameDispose());
errorChain(networkDispose());
entityManagerDispose();
localeManagerDispose();
+1 -102
View File
@@ -7,11 +7,6 @@
#include "entitymesh.h"
#include "entity/entitymanager.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "display/mesh/cube.h"
#include "display/mesh/plane.h"
#include "display/mesh/capsule.h"
void entityMeshInit(
const entityid_t entityId,
@@ -20,9 +15,7 @@ void entityMeshInit(
entitymesh_t *comp = componentGetData(
entityId, componentId, COMPONENT_TYPE_MESH
);
comp->mesh = &CUBE_MESH_SIMPLE;
comp->ownedVertices = NULL;
comp->ownsData = false;
comp->mesh = NULL;
}
mesh_t * entityMeshGetMesh(
@@ -50,98 +43,4 @@ void entityMeshDispose(
const entityid_t entityId,
const componentid_t componentId
) {
entitymesh_t *comp = componentGetData(
entityId, componentId, COMPONENT_TYPE_MESH
);
if(!comp->ownsData) return;
(void)meshDispose(&comp->ownedMesh);
memoryFree(comp->ownedVertices);
comp->ownedVertices = NULL;
comp->ownsData = false;
comp->mesh = NULL;
}
errorret_t entityMeshGeneratePlane(
const entityid_t entityId,
const componentid_t componentId,
const float_t width,
const float_t height
) {
entitymesh_t *comp = componentGetData(
entityId, componentId, COMPONENT_TYPE_MESH
);
entityMeshDispose(entityId, componentId);
comp->ownedVertices = memoryAllocate(
PLANE_VERTEX_COUNT * sizeof(meshvertex_t)
);
assertNotNull(comp->ownedVertices, "Failed to allocate plane vertices");
vec3 min = { -width * 0.5f, 0.0f, -height * 0.5f };
vec3 max = { width * 0.5f, 0.0f, height * 0.5f };
vec2 uvMin = { 0.0f, 0.0f };
vec2 uvMax = { 1.0f, 1.0f };
planeBuffer(
comp->ownedVertices,
PLANE_AXIS_XZ,
min,
max
#if MESH_ENABLE_COLOR
, COLOR_WHITE_4B
#endif
, uvMin,
uvMax
);
errorChain(meshInit(
&comp->ownedMesh,
PLANE_PRIMITIVE_TYPE,
PLANE_VERTEX_COUNT,
comp->ownedVertices
));
comp->mesh = &comp->ownedMesh;
comp->ownsData = true;
errorOk();
}
errorret_t entityMeshGenerateCapsule(
const entityid_t entityId,
const componentid_t componentId,
const float_t radius,
const float_t halfHeight
) {
entitymesh_t *comp = componentGetData(
entityId, componentId, COMPONENT_TYPE_MESH
);
entityMeshDispose(entityId, componentId);
comp->ownedVertices = memoryAllocate(
CAPSULE_VERTEX_COUNT * sizeof(meshvertex_t)
);
assertNotNull(comp->ownedVertices, "Failed to allocate capsule vertices");
vec3 center = { 0.0f, 0.0f, 0.0f };
capsuleBuffer(
comp->ownedVertices,
center,
radius,
halfHeight,
CAPSULE_CAP_RINGS,
CAPSULE_SECTORS
#if MESH_ENABLE_COLOR
, COLOR_WHITE_4B
#endif
);
errorChain(meshInit(
&comp->ownedMesh,
CAPSULE_PRIMITIVE_TYPE,
CAPSULE_VERTEX_COUNT,
comp->ownedVertices
));
comp->mesh = &comp->ownedMesh;
comp->ownsData = true;
errorOk();
}
+1 -36
View File
@@ -11,9 +11,6 @@
typedef struct {
mesh_t *mesh;
mesh_t ownedMesh;
meshvertex_t *ownedVertices;
bool_t ownsData;
} entitymesh_t;
/**
@@ -53,7 +50,7 @@ void entityMeshSetMesh(
);
/**
* Disposes the entity mesh component, freeing any owned mesh data.
* Disposes the entity mesh component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
@@ -62,35 +59,3 @@ void entityMeshDispose(
const entityid_t entityId,
const componentid_t componentId
);
/**
* Generates an XZ-aligned plane mesh owned by the component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param width Width of the plane along the X axis.
* @param height Height of the plane along the Z axis.
* @return Error return value.
*/
errorret_t entityMeshGeneratePlane(
const entityid_t entityId,
const componentid_t componentId,
const float_t width,
const float_t height
);
/**
* Generates a Y-axis capsule mesh owned by the component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param radius Radius of the cylinder and hemisphere caps.
* @param halfHeight Half-height of the cylindrical section.
* @return Error return value.
*/
errorret_t entityMeshGenerateCapsule(
const entityid_t entityId,
const componentid_t componentId,
const float_t radius,
const float_t halfHeight
);
+452
View File
@@ -0,0 +1,452 @@
/**
* 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 "script/scriptproto.h"
#include "script/module/math/modulevec3ref.h"
#include "display/mesh/mesh.h"
#include "display/mesh/cube.h"
#include "display/mesh/quad.h"
#include "display/mesh/sphere.h"
#include "display/mesh/plane.h"
#include "display/mesh/capsule.h"
#include "display/mesh/triprism.h"
typedef struct {
mesh_t mesh;
meshvertex_t *vertices;
int32_t vertexCount;
bool_t initialized;
} meshscript_t;
typedef struct {
meshvertex_t *vertex;
} meshvertexscript_t;
static scriptproto_t MODULE_MESH_PROTO;
static scriptproto_t MODULE_MESH_VERTEX_PROTO;
static inline meshscript_t * moduleMeshGet(
const jerry_call_info_t *callInfo
) {
return (meshscript_t*)scriptProtoGetValue(
&MODULE_MESH_PROTO, callInfo->this_value
);
}
static inline meshscript_t * moduleMeshFrom(const jerry_value_t val) {
return (meshscript_t*)scriptProtoGetValue(&MODULE_MESH_PROTO, val);
}
static void moduleMeshFreeData(
void *ptr,
jerry_object_native_info_t *info
) {
(void)info;
meshscript_t *ms = (meshscript_t*)ptr;
if(ms->initialized) (void)meshDispose(&ms->mesh);
if(ms->vertices) memoryFree(ms->vertices);
memoryFree(ptr);
}
// Creates a new JS Mesh object from an already-filled heap-allocated meshscript_t.
static jerry_value_t moduleMeshWrapNew(meshscript_t *ms) {
jerry_value_t obj = jerry_object();
jerry_object_set_native_ptr(obj, &MODULE_MESH_PROTO.info, ms);
jerry_object_set_proto(obj, MODULE_MESH_PROTO.prototype);
jerry_value_t arr = jerry_array((jerry_length_t)ms->vertexCount);
for(int32_t i = 0; i < ms->vertexCount; i++) {
meshvertexscript_t mv = { .vertex = &ms->vertices[i] };
jerry_value_t vobj = scriptProtoCreateValue(&MODULE_MESH_VERTEX_PROTO, &mv);
jerry_value_t res = jerry_object_set_index(arr, (uint32_t)i, vobj);
jerry_value_free(res);
jerry_value_free(vobj);
}
jerry_value_t key = jerry_string_sz("_verts");
jerry_object_set(obj, key, arr);
jerry_value_free(key);
jerry_value_free(arr);
return obj;
}
// Allocates a meshscript_t for the given vertex count and buffers it.
// Caller is responsible for populating ms->vertices before calling meshInit.
static meshscript_t * moduleMeshAlloc(const int32_t vertexCount) {
meshscript_t *ms = (meshscript_t*)memoryAllocate(sizeof(meshscript_t));
memoryZero(ms, sizeof(meshscript_t));
ms->vertices = (meshvertex_t*)memoryAllocate(
(size_t)vertexCount * sizeof(meshvertex_t)
);
memoryZero(ms->vertices, (size_t)vertexCount * sizeof(meshvertex_t));
ms->vertexCount = vertexCount;
return ms;
}
// Finalizes a meshscript_t: uploads to GPU and wraps in a JS object.
static jerry_value_t moduleMeshFinalize(
meshscript_t *ms,
const meshprimitivetype_t type
) {
(void)meshInit(&ms->mesh, type, ms->vertexCount, ms->vertices);
ms->initialized = true;
return moduleMeshWrapNew(ms);
}
// ---- MeshVertex ----
moduleBaseFunction(moduleMeshVertexGetPosition) {
meshvertexscript_t *mv = (meshvertexscript_t*)scriptProtoGetValue(
&MODULE_MESH_VERTEX_PROTO, callInfo->this_value
);
if(!mv) return jerry_undefined();
return moduleVec3RefPush(mv->vertex->pos, NULL, NULL);
}
moduleBaseFunction(moduleMeshVertexSetPosition) {
if(argc < 1) return moduleBaseThrow("Expected position argument");
meshvertexscript_t *mv = (meshvertexscript_t*)scriptProtoGetValue(
&MODULE_MESH_VERTEX_PROTO, callInfo->this_value
);
if(!mv) return jerry_undefined();
vec3 v;
if(!moduleVec3AnyCheck(args[0], v)) return moduleBaseThrow("Expected Vec3");
glm_vec3_copy(v, mv->vertex->pos);
return jerry_undefined();
}
// ---- Mesh instance ----
moduleBaseFunction(moduleMeshConstructor) {
if(argc < 1) return moduleBaseThrow("Expected vertex count");
moduleBaseRequireNumber(0);
int32_t vertexCount = (int32_t)jerry_value_as_number(args[0]);
if(vertexCount <= 0) return moduleBaseThrow("Vertex count must be > 0");
meshscript_t *ms = moduleMeshAlloc(vertexCount);
jerry_object_set_native_ptr(
callInfo->this_value, &MODULE_MESH_PROTO.info, ms
);
jerry_value_t arr = jerry_array((jerry_length_t)vertexCount);
for(int32_t i = 0; i < vertexCount; i++) {
meshvertexscript_t mv = { .vertex = &ms->vertices[i] };
jerry_value_t vobj = scriptProtoCreateValue(&MODULE_MESH_VERTEX_PROTO, &mv);
jerry_value_t res = jerry_object_set_index(arr, (uint32_t)i, vobj);
jerry_value_free(res);
jerry_value_free(vobj);
}
jerry_value_t key = jerry_string_sz("_verts");
jerry_object_set(callInfo->this_value, key, arr);
jerry_value_free(key);
jerry_value_free(arr);
return jerry_undefined();
}
moduleBaseFunction(moduleMeshGetVertices) {
jerry_value_t key = jerry_string_sz("_verts");
jerry_value_t arr = jerry_object_get(callInfo->this_value, key);
jerry_value_free(key);
return arr;
}
moduleBaseFunction(moduleMeshGetVertexCount) {
meshscript_t *ms = moduleMeshGet(callInfo);
if(!ms) return jerry_undefined();
return jerry_number((double)ms->vertexCount);
}
moduleBaseFunction(moduleMeshFlush) {
meshscript_t *ms = moduleMeshGet(callInfo);
if(!ms) return jerry_undefined();
if(!ms->initialized) {
(void)meshInit(
&ms->mesh,
MESH_PRIMITIVE_TYPE_TRIANGLES,
ms->vertexCount,
ms->vertices
);
ms->initialized = true;
} else {
(void)meshFlush(&ms->mesh, 0, -1);
}
return jerry_undefined();
}
moduleBaseFunction(moduleMeshDispose) {
meshscript_t *ms = moduleMeshGet(callInfo);
if(!ms) return jerry_undefined();
if(ms->initialized) {
(void)meshDispose(&ms->mesh);
ms->initialized = false;
}
if(ms->vertices) {
memoryFree(ms->vertices);
ms->vertices = NULL;
}
return jerry_undefined();
}
moduleBaseFunction(moduleMeshToString) {
meshscript_t *ms = moduleMeshGet(callInfo);
if(!ms) return jerry_string_sz("Mesh(?)");
char_t buf[64];
stringFormat(buf, sizeof(buf), "Mesh(%d)", ms->vertexCount);
return jerry_string_sz(buf);
}
// ---- Static defaults (engine-owned, not GC'd) ----
moduleBaseFunction(moduleMeshDefaultCube) {
return moduleBaseWrapPointer(&CUBE_MESH_SIMPLE);
}
moduleBaseFunction(moduleMeshDefaultQuad) {
return moduleBaseWrapPointer(&QUAD_MESH_SIMPLE);
}
moduleBaseFunction(moduleMeshDefaultSphere) {
return moduleBaseWrapPointer(&SPHERE_MESH_SIMPLE);
}
moduleBaseFunction(moduleMeshDefaultPlane) {
return moduleBaseWrapPointer(&PLANE_MESH_SIMPLE);
}
moduleBaseFunction(moduleMeshDefaultCapsule) {
return moduleBaseWrapPointer(&CAPSULE_MESH_SIMPLE);
}
moduleBaseFunction(moduleMeshDefaultTriPrism) {
return moduleBaseWrapPointer(&TRIPRISM_MESH_SIMPLE);
}
// ---- Static factory methods ----
// Mesh.createCube(min?, max?) — defaults to (-0.5,-0.5,-0.5)..(0.5,0.5,0.5)
moduleBaseFunction(moduleMeshCreateCube) {
vec3 min = { -0.5f, -0.5f, -0.5f };
vec3 max = { 0.5f, 0.5f, 0.5f };
if(argc >= 2) {
if(!moduleVec3AnyCheck(args[0], min)) {
return moduleBaseThrow("Mesh.createCube: expected Vec3 min");
}
if(!moduleVec3AnyCheck(args[1], max)) {
return moduleBaseThrow("Mesh.createCube: expected Vec3 max");
}
}
meshscript_t *ms = moduleMeshAlloc(CUBE_VERTEX_COUNT);
cubeBuffer(
ms->vertices, min, max
#if MESH_ENABLE_COLOR
, COLOR_WHITE_4B
#endif
);
return moduleMeshFinalize(ms, CUBE_PRIMITIVE_TYPE);
}
// Mesh.createQuad(minX, minY, maxX, maxY) — 2D XY quad, u0-u1=0-1 v0-v1=0-1
moduleBaseFunction(moduleMeshCreateQuad) {
float_t minX = -0.5f, minY = -0.5f, maxX = 0.5f, maxY = 0.5f;
if(argc >= 4) {
if(!jerry_value_is_number(args[0]) || !jerry_value_is_number(args[1]) ||
!jerry_value_is_number(args[2]) || !jerry_value_is_number(args[3])) {
return moduleBaseThrow("Mesh.createQuad: expected (minX, minY, maxX, maxY)");
}
minX = (float_t)jerry_value_as_number(args[0]);
minY = (float_t)jerry_value_as_number(args[1]);
maxX = (float_t)jerry_value_as_number(args[2]);
maxY = (float_t)jerry_value_as_number(args[3]);
}
meshscript_t *ms = moduleMeshAlloc(QUAD_VERTEX_COUNT);
quadBuffer(
ms->vertices,
minX, minY, maxX, maxY,
0.0f, 0.0f, 1.0f, 1.0f
#if MESH_ENABLE_COLOR
, COLOR_WHITE_4B
#endif
);
return moduleMeshFinalize(ms, QUAD_PRIMITIVE_TYPE);
}
// Mesh.createSphere(radius?, stacks?, sectors?)
moduleBaseFunction(moduleMeshCreateSphere) {
float_t radius = 0.5f;
int32_t stacks = SPHERE_STACKS;
int32_t sectors = SPHERE_SECTORS;
if(argc >= 1 && jerry_value_is_number(args[0])) {
radius = (float_t)jerry_value_as_number(args[0]);
}
if(argc >= 2 && jerry_value_is_number(args[1])) {
stacks = (int32_t)jerry_value_as_number(args[1]);
}
if(argc >= 3 && jerry_value_is_number(args[2])) {
sectors = (int32_t)jerry_value_as_number(args[2]);
}
int32_t vertexCount = stacks * sectors * 6;
vec3 center = { 0.0f, 0.0f, 0.0f };
meshscript_t *ms = moduleMeshAlloc(vertexCount);
sphereBuffer(
ms->vertices, center, radius, stacks, sectors
#if MESH_ENABLE_COLOR
, COLOR_WHITE_4B
#endif
);
return moduleMeshFinalize(ms, SPHERE_PRIMITIVE_TYPE);
}
// Mesh.createPlane(width?, height?) — XZ-aligned, centered at origin
moduleBaseFunction(moduleMeshCreatePlane) {
float_t width = 1.0f, height = 1.0f;
if(argc >= 1 && jerry_value_is_number(args[0])) {
width = (float_t)jerry_value_as_number(args[0]);
}
if(argc >= 2 && jerry_value_is_number(args[1])) {
height = (float_t)jerry_value_as_number(args[1]);
}
vec3 min = { -width * 0.5f, 0.0f, -height * 0.5f };
vec3 max = { width * 0.5f, 0.0f, height * 0.5f };
vec2 uvMin = { 0.0f, 0.0f };
vec2 uvMax = { 1.0f, 1.0f };
meshscript_t *ms = moduleMeshAlloc(PLANE_VERTEX_COUNT);
planeBuffer(
ms->vertices, PLANE_AXIS_XZ, min, max
#if MESH_ENABLE_COLOR
, COLOR_WHITE_4B
#endif
, uvMin, uvMax
);
return moduleMeshFinalize(ms, PLANE_PRIMITIVE_TYPE);
}
// Mesh.createCapsule(radius?, halfHeight?, capRings?, sectors?)
moduleBaseFunction(moduleMeshCreateCapsule) {
float_t radius = 0.5f;
float_t halfHeight = 0.5f;
int32_t capRings = CAPSULE_CAP_RINGS;
int32_t sectors = CAPSULE_SECTORS;
if(argc >= 1 && jerry_value_is_number(args[0])) {
radius = (float_t)jerry_value_as_number(args[0]);
}
if(argc >= 2 && jerry_value_is_number(args[1])) {
halfHeight = (float_t)jerry_value_as_number(args[1]);
}
if(argc >= 3 && jerry_value_is_number(args[2])) {
capRings = (int32_t)jerry_value_as_number(args[2]);
}
if(argc >= 4 && jerry_value_is_number(args[3])) {
sectors = (int32_t)jerry_value_as_number(args[3]);
}
int32_t vertexCount = (2 * capRings + 1) * sectors * 6;
vec3 center = { 0.0f, 0.0f, 0.0f };
meshscript_t *ms = moduleMeshAlloc(vertexCount);
capsuleBuffer(
ms->vertices, center, radius, halfHeight, capRings, sectors
#if MESH_ENABLE_COLOR
, COLOR_WHITE_4B
#endif
);
return moduleMeshFinalize(ms, CAPSULE_PRIMITIVE_TYPE);
}
// Mesh.createTriPrism(x0, y0, x1, y1, x2, y2, minZ, maxZ)
moduleBaseFunction(moduleMeshCreateTriPrism) {
if(argc < 8) {
return moduleBaseThrow(
"Mesh.createTriPrism: expected (x0,y0, x1,y1, x2,y2, minZ, maxZ)"
);
}
float_t x0 = (float_t)jerry_value_as_number(args[0]);
float_t y0 = (float_t)jerry_value_as_number(args[1]);
float_t x1 = (float_t)jerry_value_as_number(args[2]);
float_t y1 = (float_t)jerry_value_as_number(args[3]);
float_t x2 = (float_t)jerry_value_as_number(args[4]);
float_t y2 = (float_t)jerry_value_as_number(args[5]);
float_t minZ = (float_t)jerry_value_as_number(args[6]);
float_t maxZ = (float_t)jerry_value_as_number(args[7]);
meshscript_t *ms = moduleMeshAlloc(TRIPRISM_VERTEX_COUNT);
triPrismBuffer(
ms->vertices, x0, y0, x1, y1, x2, y2, minZ, maxZ
#if MESH_ENABLE_COLOR
, COLOR_WHITE_4B
#endif
);
return moduleMeshFinalize(ms, TRIPRISM_PRIMITIVE_TYPE);
}
// ---- Registration ----
static void moduleMesh(void) {
// MeshVertex - internal type, no global constructor
scriptProtoInit(
&MODULE_MESH_VERTEX_PROTO, NULL,
sizeof(meshvertexscript_t), NULL
);
scriptProtoDefineProp(
&MODULE_MESH_VERTEX_PROTO, "position",
moduleMeshVertexGetPosition, moduleMeshVertexSetPosition
);
// Mesh - global constructor: new Mesh(vertexCount)
scriptProtoInit(
&MODULE_MESH_PROTO, "Mesh",
sizeof(meshscript_t), moduleMeshConstructor
);
MODULE_MESH_PROTO.info.free_cb = moduleMeshFreeData;
scriptProtoDefineToString(&MODULE_MESH_PROTO, moduleMeshToString);
scriptProtoDefineProp(
&MODULE_MESH_PROTO, "vertices",
moduleMeshGetVertices, NULL
);
scriptProtoDefineProp(
&MODULE_MESH_PROTO, "vertexCount",
moduleMeshGetVertexCount, NULL
);
scriptProtoDefineFunc(&MODULE_MESH_PROTO, "flush", moduleMeshFlush);
scriptProtoDefineFunc(&MODULE_MESH_PROTO, "dispose", moduleMeshDispose);
// Static default mesh references
scriptProtoDefineStaticProp(
&MODULE_MESH_PROTO, "DEFAULT_CUBE", moduleMeshDefaultCube, NULL
);
scriptProtoDefineStaticProp(
&MODULE_MESH_PROTO, "DEFAULT_QUAD", moduleMeshDefaultQuad, NULL
);
scriptProtoDefineStaticProp(
&MODULE_MESH_PROTO, "DEFAULT_SPHERE", moduleMeshDefaultSphere, NULL
);
scriptProtoDefineStaticProp(
&MODULE_MESH_PROTO, "DEFAULT_PLANE", moduleMeshDefaultPlane, NULL
);
scriptProtoDefineStaticProp(
&MODULE_MESH_PROTO, "DEFAULT_CAPSULE", moduleMeshDefaultCapsule, NULL
);
scriptProtoDefineStaticProp(
&MODULE_MESH_PROTO, "DEFAULT_TRIPRISM", moduleMeshDefaultTriPrism, NULL
);
// Static factory methods
scriptProtoDefineStaticFunc(
&MODULE_MESH_PROTO, "createCube", moduleMeshCreateCube
);
scriptProtoDefineStaticFunc(
&MODULE_MESH_PROTO, "createQuad", moduleMeshCreateQuad
);
scriptProtoDefineStaticFunc(
&MODULE_MESH_PROTO, "createSphere", moduleMeshCreateSphere
);
scriptProtoDefineStaticFunc(
&MODULE_MESH_PROTO, "createPlane", moduleMeshCreatePlane
);
scriptProtoDefineStaticFunc(
&MODULE_MESH_PROTO, "createCapsule", moduleMeshCreateCapsule
);
scriptProtoDefineStaticFunc(
&MODULE_MESH_PROTO, "createTriPrism", moduleMeshCreateTriPrism
);
}
@@ -8,6 +8,7 @@
#pragma once
#include "script/module/modulebase.h"
#include "script/scriptproto.h"
#include "script/module/display/modulemesh.h"
#include "entity/entity.h"
#include "entity/component/display/entitymesh.h"
#include "moduleentityposition.h"
@@ -24,16 +25,32 @@ static entitymesh_t * moduleEntityMeshGet(
return (entitymesh_t*)componentGetData(h->eid, h->cid, COMPONENT_TYPE_MESH);
}
moduleBaseFunction(moduleEntityMeshAdd) {
if(argc < 1) {
return moduleBaseThrow("Expected at least 1 argument");
moduleBaseFunction(moduleEntityMeshGetMesh) {
entitymesh_t *comp = moduleEntityMeshGet(callInfo);
if(!comp || !comp->mesh) return jerry_undefined();
return moduleBaseWrapPointer(comp->mesh);
}
moduleBaseFunction(moduleEntityMeshSetMesh) {
if(argc < 1) return moduleBaseThrow("Expected a Mesh argument");
entitymesh_t *comp = moduleEntityMeshGet(callInfo);
if(!comp) return jerry_undefined();
// User-created Mesh JS object (meshscript_t)
meshscript_t *ms = moduleMeshFrom(args[0]);
if(ms) {
comp->mesh = &ms->mesh;
return jerry_undefined();
}
moduleBaseRequireNumber(0);
entityid_t id = (entityid_t)jerry_value_as_number(args[0]);
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_MESH);
componenthandle_t h = { .eid = id, .cid = comp };
return scriptProtoCreateValue(&MODULE_ENTITY_MESH_PROTO, &h);
// Engine-owned default mesh (Mesh.DEFAULT_CUBE etc.) — raw mesh_t*
mesh_t *raw = (mesh_t*)moduleBaseUnwrapPointer(args[0]);
if(raw) {
comp->mesh = raw;
return jerry_undefined();
}
return moduleBaseThrow("Expected a Mesh object or mesh constant");
}
static void moduleEntityMESH(void) {
@@ -41,4 +58,8 @@ static void moduleEntityMESH(void) {
&MODULE_ENTITY_MESH_PROTO, NULL,
sizeof(componenthandle_t), NULL
);
scriptProtoDefineProp(
&MODULE_ENTITY_MESH_PROTO, "mesh",
moduleEntityMeshGetMesh, moduleEntityMeshSetMesh
);
}
+152
View File
@@ -0,0 +1,152 @@
/**
* 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 "script/scriptproto.h"
#include "item/inventory.h"
#include "item/backpack.h"
#include "item/item.h"
typedef struct {
inventory_t *inventory;
} inventoryscript_t;
static scriptproto_t MODULE_INVENTORY_PROTO;
static inline inventory_t * moduleInventoryGet(
const jerry_call_info_t *callInfo
) {
inventoryscript_t *h = (inventoryscript_t*)scriptProtoGetValue(
&MODULE_INVENTORY_PROTO, callInfo->this_value
);
return h ? h->inventory : NULL;
}
// inventory.add(itemId, quantity)
moduleBaseFunction(moduleInventoryAdd) {
if(argc < 2) return moduleBaseThrow("Expected (itemId, quantity)");
moduleBaseRequireNumber(0);
moduleBaseRequireNumber(1);
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
inventoryAdd(
inv,
(itemid_t)jerry_value_as_number(args[0]),
(uint8_t)jerry_value_as_number(args[1])
);
return jerry_undefined();
}
// inventory.remove(itemId)
moduleBaseFunction(moduleInventoryRemove) {
if(argc < 1) return moduleBaseThrow("Expected itemId");
moduleBaseRequireNumber(0);
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
inventoryRemove(inv, (itemid_t)jerry_value_as_number(args[0]));
return jerry_undefined();
}
// inventory.set(itemId, quantity)
moduleBaseFunction(moduleInventorySet) {
if(argc < 2) return moduleBaseThrow("Expected (itemId, quantity)");
moduleBaseRequireNumber(0);
moduleBaseRequireNumber(1);
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
inventorySet(
inv,
(itemid_t)jerry_value_as_number(args[0]),
(uint8_t)jerry_value_as_number(args[1])
);
return jerry_undefined();
}
// inventory.count(itemId) → number
moduleBaseFunction(moduleInventoryCount) {
if(argc < 1) return moduleBaseThrow("Expected itemId");
moduleBaseRequireNumber(0);
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
return jerry_number(
(double)inventoryGetCount(inv, (itemid_t)jerry_value_as_number(args[0]))
);
}
// inventory.has(itemId) → boolean
moduleBaseFunction(moduleInventoryHas) {
if(argc < 1) return moduleBaseThrow("Expected itemId");
moduleBaseRequireNumber(0);
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
return jerry_boolean(
inventoryItemExists(inv, (itemid_t)jerry_value_as_number(args[0]))
);
}
// inventory.isItemFull(itemId) → boolean
moduleBaseFunction(moduleInventoryIsItemFull) {
if(argc < 1) return moduleBaseThrow("Expected itemId");
moduleBaseRequireNumber(0);
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
return jerry_boolean(
inventoryItemFull(inv, (itemid_t)jerry_value_as_number(args[0]))
);
}
// inventory.sort(sortBy, reverse?)
moduleBaseFunction(moduleInventorySort) {
if(argc < 1) return moduleBaseThrow("Expected sortBy");
moduleBaseRequireNumber(0);
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
inventorysort_t sortBy = (inventorysort_t)jerry_value_as_number(args[0]);
bool_t reverse = (argc >= 2 && jerry_value_is_true(args[1]));
inventorySort(inv, sortBy, reverse);
return jerry_undefined();
}
// inventory.full → boolean (read-only property)
moduleBaseFunction(moduleInventoryGetFull) {
inventory_t *inv = moduleInventoryGet(callInfo);
if(!inv) return jerry_undefined();
return jerry_boolean(inventoryIsFull(inv));
}
static void moduleItem(void) {
// ITEM_ID_* and ITEM_TYPE_* numeric constants
moduleBaseEval(ITEM_SCRIPT);
// Sort constants
moduleBaseSetInt("INVENTORY_SORT_BY_ID", INVENTORY_SORT_BY_ID);
moduleBaseSetInt("INVENTORY_SORT_BY_TYPE", INVENTORY_SORT_BY_TYPE);
// Inventory prototype — not a public constructor, only used via singletons
scriptProtoInit(
&MODULE_INVENTORY_PROTO, NULL,
sizeof(inventoryscript_t), NULL
);
scriptProtoDefineProp(
&MODULE_INVENTORY_PROTO, "full",
moduleInventoryGetFull, NULL
);
scriptProtoDefineFunc(&MODULE_INVENTORY_PROTO, "add", moduleInventoryAdd);
scriptProtoDefineFunc(&MODULE_INVENTORY_PROTO, "remove", moduleInventoryRemove);
scriptProtoDefineFunc(&MODULE_INVENTORY_PROTO, "set", moduleInventorySet);
scriptProtoDefineFunc(&MODULE_INVENTORY_PROTO, "count", moduleInventoryCount);
scriptProtoDefineFunc(&MODULE_INVENTORY_PROTO, "has", moduleInventoryHas);
scriptProtoDefineFunc(&MODULE_INVENTORY_PROTO, "isItemFull", moduleInventoryIsItemFull);
scriptProtoDefineFunc(&MODULE_INVENTORY_PROTO, "sort", moduleInventorySort);
// Backpack — global singleton Inventory wrapping the engine BACKPACK
inventoryscript_t h = { .inventory = &BACKPACK };
jerry_value_t backpackObj = scriptProtoCreateValue(&MODULE_INVENTORY_PROTO, &h);
moduleBaseSetValue("Backpack", backpackObj);
jerry_value_free(backpackObj);
}
+6
View File
@@ -13,16 +13,20 @@
#include "script/module/moduleplatform.h"
#include "script/module/time/moduletime.h"
#include "script/module/display/modulecolor.h"
#include "script/module/display/modulemesh.h"
#include "script/module/display/modulescreen.h"
#include "script/module/display/modulespritebatch.h"
#include "script/module/display/moduletext.h"
#include "script/module/scene/modulescene.h"
#include "script/module/console/moduleconsole.h"
#include "script/module/engine/moduleengine.h"
#include "script/module/item/moduleitem.h"
#include "script/module/story/modulestory.h"
static void moduleRegister(void) {
moduleInclude();
moduleMath();
moduleMesh();
moduleEntity();
moduleInput();
modulePlatform();
@@ -34,4 +38,6 @@ static void moduleRegister(void) {
moduleScene();
moduleConsole();
moduleEngine();
moduleItem();
moduleStory();
}
@@ -0,0 +1,54 @@
/**
* 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 "script/scriptproto.h"
#include "story/storyflag.h"
static scriptproto_t MODULE_STORY_FLAG_PROTO;
// StoryFlag.get(flagId) → number
moduleBaseFunction(moduleStoryFlagGet) {
if(argc < 1) return moduleBaseThrow("Expected flagId");
moduleBaseRequireNumber(0);
storyflag_t flag = (storyflag_t)jerry_value_as_number(args[0]);
if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) {
return moduleBaseThrow("StoryFlag.get: invalid flag ID");
}
return jerry_number((double)storyFlagGet(flag));
}
// StoryFlag.set(flagId, value)
moduleBaseFunction(moduleStoryFlagSet) {
if(argc < 2) return moduleBaseThrow("Expected (flagId, value)");
moduleBaseRequireNumber(0);
moduleBaseRequireNumber(1);
storyflag_t flag = (storyflag_t)jerry_value_as_number(args[0]);
if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) {
return moduleBaseThrow("StoryFlag.set: invalid flag ID");
}
storyFlagSet(flag, (storyflagvalue_t)jerry_value_as_number(args[1]));
return jerry_undefined();
}
static void moduleStory(void) {
// STORY_FLAG_* numeric constants
moduleBaseEval(STORY_FLAG_SCRIPT);
// StoryFlag — global static namespace, no instances
scriptProtoInit(
&MODULE_STORY_FLAG_PROTO, "StoryFlag",
sizeof(uint8_t), NULL
);
scriptProtoDefineStaticFunc(
&MODULE_STORY_FLAG_PROTO, "get", moduleStoryFlagGet
);
scriptProtoDefineStaticFunc(
&MODULE_STORY_FLAG_PROTO, "set", moduleStoryFlagSet
);
}
-15
View File
@@ -1,15 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Includes
target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
# Subdirs
add_subdirectory(game)
add_subdirectory(item)
add_subdirectory(story)
-10
View File
@@ -1,10 +0,0 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
game.c
)
-20
View File
@@ -1,20 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "game.h"
errorret_t gameInit(void) {
errorOk();
}
errorret_t gameUpdate(void) {
errorOk();
}
errorret_t gameDispose(void) {
errorOk();
}
-30
View File
@@ -1,30 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
/**
* Initializes the game systems and loads the initial game state.
*
* @return An error code indicating success or failure.
*/
errorret_t gameInit(void);
/**
* Updates the game state. This should be called every frame.
*
* @return An error code indicating success or failure.
*/
errorret_t gameUpdate(void);
/**
* Disposes of game resources and shuts down the game systems.
*
* @return An error code indicating success or failure.
*/
errorret_t gameDispose(void);