Add some script modules

This commit is contained in:
2026-06-02 12:55:32 -05:00
parent 0f8b629e20
commit 82c300b077
12 changed files with 1189 additions and 0 deletions
@@ -0,0 +1,145 @@
/**
* 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/entity/modulecomponent.h"
#include "entity/component/overworld/entityinteractable.h"
#include <stdlib.h>
static scriptproto_t MODULE_INTERACTABLE_PROTO;
moduleBaseFunction(moduleInteractableCtor) {
(void)callInfo; (void)args; (void)argc;
return moduleBaseThrow("Interactable cannot be instantiated with new");
}
static inline jscomponent_t *moduleInteractableSelf(
const jerry_call_info_t *callInfo
) {
return (jscomponent_t *)scriptProtoGetValue(
&MODULE_INTERACTABLE_PROTO, callInfo->this_value
);
}
static void moduleInteractableCb(
const entityid_t entityId,
const componentid_t componentId,
void *user
) {
(void)entityId; (void)componentId;
jerry_value_t fn = *((jerry_value_t *)user);
jerry_value_t ret = jerry_call(fn, jerry_undefined(), NULL, 0);
jerry_value_free(ret);
}
moduleBaseFunction(moduleInteractableGetEntity) {
jscomponent_t *c = moduleInteractableSelf(callInfo);
if(!c) return jerry_undefined();
return jerry_number((double)c->entityId);
}
moduleBaseFunction(moduleInteractableGetId) {
jscomponent_t *c = moduleInteractableSelf(callInfo);
if(!c) return jerry_undefined();
return jerry_number((double)c->componentId);
}
/*
* onInteract getter — reads back the pinned JS function stored on this._cb.
*/
moduleBaseFunction(moduleInteractableGetOnInteract) {
(void)args; (void)argc;
jerry_value_t key = jerry_string_sz("_cb");
jerry_value_t val = jerry_object_get(callInfo->this_value, key);
jerry_value_free(key);
return val;
}
/*
* onInteract setter — pins the JS function on this._cb for GC safety, and
* registers a C trampoline that calls it when the player interacts.
* Passing null/undefined clears the callback.
*/
moduleBaseFunction(moduleInteractableSetOnInteract) {
jscomponent_t *c = moduleInteractableSelf(callInfo);
if(!c) return jerry_undefined();
entityinteractable_t *d = entityInteractableGet(c->entityId, c->componentId);
if(!d) return jerry_undefined();
/* Free previously stored JS reference */
if(d->user) {
jerry_value_free(*((jerry_value_t *)d->user));
free(d->user);
d->user = NULL;
}
jerry_value_t pin = (argc > 0) ? args[0] : jerry_undefined();
jerry_value_t pinKey = jerry_string_sz("_cb");
if(jerry_value_is_function(pin)) {
jerry_value_t *stored = (jerry_value_t *)malloc(sizeof(jerry_value_t));
*stored = jerry_value_copy(pin);
entityInteractableSetCallback(
c->entityId, c->componentId, moduleInteractableCb, stored
);
jerry_object_set(callInfo->this_value, pinKey, pin);
} else {
entityInteractableSetCallback(c->entityId, c->componentId, NULL, NULL);
jerry_value_t undef = jerry_undefined();
jerry_object_set(callInfo->this_value, pinKey, undef);
jerry_value_free(undef);
}
jerry_value_free(pinKey);
return jerry_undefined();
}
moduleBaseFunction(moduleInteractableTrigger) {
(void)args; (void)argc;
jscomponent_t *c = moduleInteractableSelf(callInfo);
if(!c) return jerry_undefined();
entityInteractableTrigger(c->entityId, c->componentId);
return jerry_undefined();
}
moduleBaseFunction(moduleInteractableToString) {
jscomponent_t *c = moduleInteractableSelf(callInfo);
if(!c) return jerry_string_sz("Interactable:invalid");
char_t buf[32];
snprintf(buf, sizeof(buf), "Interactable(%u)", (unsigned)c->componentId);
return jerry_string_sz(buf);
}
static void moduleInteractableInit(void) {
scriptProtoInit(
&MODULE_INTERACTABLE_PROTO, "Interactable",
sizeof(jscomponent_t), moduleInteractableCtor
);
scriptProtoDefineProp(
&MODULE_INTERACTABLE_PROTO, "entity", moduleInteractableGetEntity, NULL
);
scriptProtoDefineProp(
&MODULE_INTERACTABLE_PROTO, "id", moduleInteractableGetId, NULL
);
scriptProtoDefineProp(
&MODULE_INTERACTABLE_PROTO, "onInteract",
moduleInteractableGetOnInteract, moduleInteractableSetOnInteract
);
scriptProtoDefineFunc(
&MODULE_INTERACTABLE_PROTO, "trigger", moduleInteractableTrigger
);
scriptProtoDefineToString(
&MODULE_INTERACTABLE_PROTO, moduleInteractableToString
);
}
static void moduleInteractableDispose(void) {
scriptProtoDispose(&MODULE_INTERACTABLE_PROTO);
}
@@ -8,7 +8,12 @@
#pragma once
#include "script/module/entity/modulecomponent.h"
#include "camera/modulecamera.h"
#include "interactable/moduleinteractable.h"
#include "overworld/moduleoverworld.h"
#include "overworldcamera/moduleoverworldcamera.h"
#include "overworldtrigger/moduleoverworldtrigger.h"
#include "physics/modulephysics.h"
#include "player/moduleplayer.h"
#include "position/moduleposition.h"
#include "renderable/modulerenderable.h"
#include "trigger/moduletrigger.h"
@@ -24,8 +29,18 @@ static jerry_value_t moduleComponentListCreateInstance(
switch(type) {
case COMPONENT_TYPE_CAMERA:
return scriptProtoCreateValue(&MODULE_CAMERA_PROTO, comp);
case COMPONENT_TYPE_INTERACTABLE:
return scriptProtoCreateValue(&MODULE_INTERACTABLE_PROTO, comp);
case COMPONENT_TYPE_OVERWORLD:
return scriptProtoCreateValue(&MODULE_OVERWORLD_PROTO, comp);
case COMPONENT_TYPE_OVERWORLD_CAMERA:
return scriptProtoCreateValue(&MODULE_OVERWORLD_CAMERA_PROTO, comp);
case COMPONENT_TYPE_OVERWORLD_TRIGGER:
return scriptProtoCreateValue(&MODULE_OVERWORLD_TRIGGER_PROTO, comp);
case COMPONENT_TYPE_PHYSICS:
return scriptProtoCreateValue(&MODULE_PHYSICS_PROTO, comp);
case COMPONENT_TYPE_PLAYER:
return scriptProtoCreateValue(&MODULE_PLAYER_PROTO, comp);
case COMPONENT_TYPE_POSITION:
return scriptProtoCreateValue(&MODULE_POSITION_PROTO, comp);
case COMPONENT_TYPE_RENDERABLE:
@@ -39,7 +54,12 @@ static jerry_value_t moduleComponentListCreateInstance(
static void moduleComponentListInit(void) {
moduleCameraInit();
moduleInteractableInit();
moduleOverworldInit();
moduleOverworldCameraInit();
moduleOverworldTriggerInit();
modulePhysicsInit();
modulePlayerInit();
modulePositionInit();
moduleRenderableInit();
moduleTriggerInit();
@@ -49,6 +69,11 @@ static void moduleComponentListDispose(void) {
moduleTriggerDispose();
moduleRenderableDispose();
modulePositionDispose();
modulePlayerDispose();
modulePhysicsDispose();
moduleOverworldTriggerDispose();
moduleOverworldCameraDispose();
moduleOverworldDispose();
moduleInteractableDispose();
moduleCameraDispose();
}
@@ -0,0 +1,168 @@
/**
* 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/entity/modulecomponent.h"
#include "entity/component/overworld/entityoverworld.h"
#include "overworld/facingdir.h"
static scriptproto_t MODULE_OVERWORLD_PROTO;
moduleBaseFunction(moduleOverworldCtor) {
(void)callInfo; (void)args; (void)argc;
return moduleBaseThrow("Overworld cannot be instantiated with new");
}
static inline jscomponent_t *moduleOverworldSelf(
const jerry_call_info_t *callInfo
) {
return (jscomponent_t *)scriptProtoGetValue(
&MODULE_OVERWORLD_PROTO, callInfo->this_value
);
}
moduleBaseFunction(moduleOverworldGetEntity) {
jscomponent_t *c = moduleOverworldSelf(callInfo);
if(!c) return jerry_undefined();
return jerry_number((double)c->entityId);
}
moduleBaseFunction(moduleOverworldGetId) {
jscomponent_t *c = moduleOverworldSelf(callInfo);
if(!c) return jerry_undefined();
return jerry_number((double)c->componentId);
}
moduleBaseFunction(moduleOverworldGetType) {
jscomponent_t *c = moduleOverworldSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworld_t *o = entityOverworldGet(c->entityId, c->componentId);
if(!o) return jerry_undefined();
return jerry_number((double)o->type);
}
moduleBaseFunction(moduleOverworldSetType) {
moduleBaseRequireArgs(1);
jscomponent_t *c = moduleOverworldSelf(callInfo);
if(!c) return jerry_undefined();
entityOverworldSetType(
c->entityId, c->componentId,
(entityoverworldtype_t)moduleBaseArgInt(0)
);
return jerry_undefined();
}
moduleBaseFunction(moduleOverworldGetFacing) {
jscomponent_t *c = moduleOverworldSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworld_t *o = entityOverworldGet(c->entityId, c->componentId);
if(!o) return jerry_undefined();
return jerry_number((double)o->facing);
}
moduleBaseFunction(moduleOverworldSetFacing) {
moduleBaseRequireArgs(1);
jscomponent_t *c = moduleOverworldSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworld_t *o = entityOverworldGet(c->entityId, c->componentId);
if(!o) return jerry_undefined();
o->facing = (facingdir_t)moduleBaseArgInt(0);
return jerry_undefined();
}
moduleBaseFunction(moduleOverworldGetRenderCompId) {
jscomponent_t *c = moduleOverworldSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworld_t *o = entityOverworldGet(c->entityId, c->componentId);
if(!o) return jerry_undefined();
return jerry_number((double)o->renderCompId);
}
moduleBaseFunction(moduleOverworldGetPhysCompId) {
jscomponent_t *c = moduleOverworldSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworld_t *o = entityOverworldGet(c->entityId, c->componentId);
if(!o) return jerry_undefined();
return jerry_number((double)o->physCompId);
}
moduleBaseFunction(moduleOverworldToString) {
jscomponent_t *c = moduleOverworldSelf(callInfo);
if(!c) return jerry_string_sz("Overworld:invalid");
char_t buf[32];
snprintf(buf, sizeof(buf), "Overworld(%u)", (unsigned)c->componentId);
return jerry_string_sz(buf);
}
static void moduleOverworldInit(void) {
scriptProtoInit(
&MODULE_OVERWORLD_PROTO, "Overworld",
sizeof(jscomponent_t), moduleOverworldCtor
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_PROTO, "entity", moduleOverworldGetEntity, NULL
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_PROTO, "id", moduleOverworldGetId, NULL
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_PROTO, "type",
moduleOverworldGetType, moduleOverworldSetType
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_PROTO, "facing",
moduleOverworldGetFacing, moduleOverworldSetFacing
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_PROTO, "renderComponentId",
moduleOverworldGetRenderCompId, NULL
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_PROTO, "physicsComponentId",
moduleOverworldGetPhysCompId, NULL
);
scriptProtoDefineToString(&MODULE_OVERWORLD_PROTO, moduleOverworldToString);
jerry_value_t ctor = MODULE_OVERWORLD_PROTO.constructor;
struct { const char_t *name; int val; } types[] = {
{ "PLAYER", OVERWORLD_ENTITY_TYPE_PLAYER },
{ "NPC", OVERWORLD_ENTITY_TYPE_NPC },
};
for(int i = 0; i < 2; i++) {
jerry_value_t k = jerry_string_sz(types[i].name);
jerry_value_t v = jerry_number((double)types[i].val);
jerry_object_set(ctor, k, v);
jerry_value_free(v);
jerry_value_free(k);
}
struct { const char_t *name; int val; } dirs[] = {
{ "FACING_DOWN", FACING_DIR_DOWN },
{ "FACING_UP", FACING_DIR_UP },
{ "FACING_LEFT", FACING_DIR_LEFT },
{ "FACING_RIGHT", FACING_DIR_RIGHT },
{ "FACING_SOUTH", FACING_DIR_SOUTH },
{ "FACING_NORTH", FACING_DIR_NORTH },
{ "FACING_WEST", FACING_DIR_WEST },
{ "FACING_EAST", FACING_DIR_EAST },
};
for(int i = 0; i < 8; i++) {
jerry_value_t k = jerry_string_sz(dirs[i].name);
jerry_value_t v = jerry_number((double)dirs[i].val);
jerry_object_set(ctor, k, v);
jerry_value_free(v);
jerry_value_free(k);
}
}
static void moduleOverworldDispose(void) {
scriptProtoDispose(&MODULE_OVERWORLD_PROTO);
}
@@ -0,0 +1,201 @@
/**
* 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/modulevec3.h"
#include "script/module/entity/modulecomponent.h"
#include "entity/component/overworld/entityoverworldcamera.h"
static scriptproto_t MODULE_OVERWORLD_CAMERA_PROTO;
moduleBaseFunction(moduleOverworldCameraCtor) {
(void)callInfo; (void)args; (void)argc;
return moduleBaseThrow("OverworldCamera cannot be instantiated with new");
}
static inline jscomponent_t *moduleOverworldCameraSelf(
const jerry_call_info_t *callInfo
) {
return (jscomponent_t *)scriptProtoGetValue(
&MODULE_OVERWORLD_CAMERA_PROTO, callInfo->this_value
);
}
moduleBaseFunction(moduleOverworldCameraGetEntity) {
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
return jerry_number((double)c->entityId);
}
moduleBaseFunction(moduleOverworldCameraGetId) {
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
return jerry_number((double)c->componentId);
}
moduleBaseFunction(moduleOverworldCameraGetTargetEntity) {
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
if(!cam) return jerry_undefined();
return jerry_number((double)cam->targetEntityId);
}
moduleBaseFunction(moduleOverworldCameraSetTargetEntity) {
moduleBaseRequireArgs(1);
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
if(!cam) return jerry_undefined();
cam->targetEntityId = (entityid_t)moduleBaseArgInt(0);
return jerry_undefined();
}
moduleBaseFunction(moduleOverworldCameraGetTargetPosComp) {
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
if(!cam) return jerry_undefined();
return jerry_number((double)cam->targetPosCompId);
}
moduleBaseFunction(moduleOverworldCameraSetTargetPosComp) {
moduleBaseRequireArgs(1);
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
if(!cam) return jerry_undefined();
cam->targetPosCompId = (componentid_t)moduleBaseArgInt(0);
return jerry_undefined();
}
moduleBaseFunction(moduleOverworldCameraGetTargetOffset) {
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
if(!cam) return jerry_undefined();
return moduleVec3Push(cam->targetOffset);
}
moduleBaseFunction(moduleOverworldCameraSetTargetOffset) {
moduleBaseRequireArgs(1);
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
float_t *v = moduleVec3From(args[0]);
if(!v) return moduleBaseThrow("OverworldCamera.targetOffset: expected Vec3");
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
if(!cam) return jerry_undefined();
glm_vec3_copy(v, cam->targetOffset);
return jerry_undefined();
}
moduleBaseFunction(moduleOverworldCameraGetEyeOffset) {
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
if(!cam) return jerry_undefined();
return moduleVec3Push(cam->eyeOffset);
}
moduleBaseFunction(moduleOverworldCameraSetEyeOffset) {
moduleBaseRequireArgs(1);
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
float_t *v = moduleVec3From(args[0]);
if(!v) return moduleBaseThrow("OverworldCamera.eyeOffset: expected Vec3");
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
if(!cam) return jerry_undefined();
glm_vec3_copy(v, cam->eyeOffset);
return jerry_undefined();
}
moduleBaseFunction(moduleOverworldCameraGetScale) {
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
if(!cam) return jerry_undefined();
return jerry_number((double)cam->scale);
}
moduleBaseFunction(moduleOverworldCameraSetScale) {
moduleBaseRequireArgs(1);
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldcamera_t *cam = entityOverworldCameraGet(c->entityId, c->componentId);
if(!cam) return jerry_undefined();
cam->scale = moduleBaseArgFloat(0);
return jerry_undefined();
}
moduleBaseFunction(moduleOverworldCameraSetTarget) {
moduleBaseRequireArgs(2);
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_undefined();
entityOverworldCameraSetTarget(
c->entityId, c->componentId,
(entityid_t)moduleBaseArgInt(0),
(componentid_t)moduleBaseArgInt(1)
);
return jerry_undefined();
}
moduleBaseFunction(moduleOverworldCameraToString) {
jscomponent_t *c = moduleOverworldCameraSelf(callInfo);
if(!c) return jerry_string_sz("OverworldCamera:invalid");
char_t buf[32];
snprintf(buf, sizeof(buf), "OverworldCamera(%u)", (unsigned)c->componentId);
return jerry_string_sz(buf);
}
static void moduleOverworldCameraInit(void) {
scriptProtoInit(
&MODULE_OVERWORLD_CAMERA_PROTO, "OverworldCamera",
sizeof(jscomponent_t), moduleOverworldCameraCtor
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_CAMERA_PROTO, "entity",
moduleOverworldCameraGetEntity, NULL
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_CAMERA_PROTO, "id",
moduleOverworldCameraGetId, NULL
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_CAMERA_PROTO, "targetEntity",
moduleOverworldCameraGetTargetEntity, moduleOverworldCameraSetTargetEntity
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_CAMERA_PROTO, "targetPositionComponent",
moduleOverworldCameraGetTargetPosComp, moduleOverworldCameraSetTargetPosComp
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_CAMERA_PROTO, "targetOffset",
moduleOverworldCameraGetTargetOffset, moduleOverworldCameraSetTargetOffset
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_CAMERA_PROTO, "eyeOffset",
moduleOverworldCameraGetEyeOffset, moduleOverworldCameraSetEyeOffset
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_CAMERA_PROTO, "scale",
moduleOverworldCameraGetScale, moduleOverworldCameraSetScale
);
scriptProtoDefineFunc(
&MODULE_OVERWORLD_CAMERA_PROTO, "setTarget",
moduleOverworldCameraSetTarget
);
scriptProtoDefineToString(
&MODULE_OVERWORLD_CAMERA_PROTO, moduleOverworldCameraToString
);
}
static void moduleOverworldCameraDispose(void) {
scriptProtoDispose(&MODULE_OVERWORLD_CAMERA_PROTO);
}
@@ -0,0 +1,374 @@
/**
* 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/modulevec3.h"
#include "script/module/entity/modulecomponent.h"
#include "entity/component/overworld/entityoverworldtrigger.h"
#include <stdlib.h>
static scriptproto_t MODULE_OVERWORLD_TRIGGER_PROTO;
/**
* Heap-allocated struct stored in entityoverworldtrigger_t.user.
* Holds jerry_value_t copies of the four JS callback functions.
*/
typedef struct {
jerry_value_t onEnter;
jerry_value_t onExit;
jerry_value_t onStay;
jerry_value_t onOutside;
} jsoverworldtriggercbs_t;
moduleBaseFunction(moduleOverworldTriggerCtor) {
(void)callInfo; (void)args; (void)argc;
return moduleBaseThrow("OverworldTrigger cannot be instantiated with new");
}
static inline jscomponent_t *moduleOverworldTriggerSelf(
const jerry_call_info_t *callInfo
) {
return (jscomponent_t *)scriptProtoGetValue(
&MODULE_OVERWORLD_TRIGGER_PROTO, callInfo->this_value
);
}
/** Lazily allocates the callback struct and stores it in the trigger's user. */
static jsoverworldtriggercbs_t *moduleOverworldTriggerGetCbs(
entityoverworldtrigger_t *t
) {
if(t->user) return (jsoverworldtriggercbs_t *)t->user;
jsoverworldtriggercbs_t *cbs = (jsoverworldtriggercbs_t *)malloc(
sizeof(jsoverworldtriggercbs_t)
);
cbs->onEnter = jerry_undefined();
cbs->onExit = jerry_undefined();
cbs->onStay = jerry_undefined();
cbs->onOutside = jerry_undefined();
t->user = (void *)cbs;
return cbs;
}
static void moduleOverworldTriggerOnEnterCb(
const entityid_t entityId,
const componentid_t componentId,
void *user
) {
(void)entityId; (void)componentId;
jsoverworldtriggercbs_t *cbs = (jsoverworldtriggercbs_t *)user;
if(!jerry_value_is_function(cbs->onEnter)) return;
jerry_value_t ret = jerry_call(cbs->onEnter, jerry_undefined(), NULL, 0);
jerry_value_free(ret);
}
static void moduleOverworldTriggerOnExitCb(
const entityid_t entityId,
const componentid_t componentId,
void *user
) {
(void)entityId; (void)componentId;
jsoverworldtriggercbs_t *cbs = (jsoverworldtriggercbs_t *)user;
if(!jerry_value_is_function(cbs->onExit)) return;
jerry_value_t ret = jerry_call(cbs->onExit, jerry_undefined(), NULL, 0);
jerry_value_free(ret);
}
static void moduleOverworldTriggerOnStayCb(
const entityid_t entityId,
const componentid_t componentId,
void *user
) {
(void)entityId; (void)componentId;
jsoverworldtriggercbs_t *cbs = (jsoverworldtriggercbs_t *)user;
if(!jerry_value_is_function(cbs->onStay)) return;
jerry_value_t ret = jerry_call(cbs->onStay, jerry_undefined(), NULL, 0);
jerry_value_free(ret);
}
static void moduleOverworldTriggerOnOutsideCb(
const entityid_t entityId,
const componentid_t componentId,
void *user
) {
(void)entityId; (void)componentId;
jsoverworldtriggercbs_t *cbs = (jsoverworldtriggercbs_t *)user;
if(!jerry_value_is_function(cbs->onOutside)) return;
jerry_value_t ret = jerry_call(cbs->onOutside, jerry_undefined(), NULL, 0);
jerry_value_free(ret);
}
// ---- entity / id ----
moduleBaseFunction(moduleOverworldTriggerGetEntity) {
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
return jerry_number((double)c->entityId);
}
moduleBaseFunction(moduleOverworldTriggerGetId) {
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
return jerry_number((double)c->componentId);
}
// ---- min / max ----
moduleBaseFunction(moduleOverworldTriggerGetMin) {
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
if(!t) return jerry_undefined();
return moduleVec3Push(t->min);
}
moduleBaseFunction(moduleOverworldTriggerSetMin) {
moduleBaseRequireArgs(1);
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
float_t *v = moduleVec3From(args[0]);
if(!v) return moduleBaseThrow("OverworldTrigger.min: expected Vec3");
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
if(!t) return jerry_undefined();
glm_vec3_copy(v, t->min);
return jerry_undefined();
}
moduleBaseFunction(moduleOverworldTriggerGetMax) {
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
if(!t) return jerry_undefined();
return moduleVec3Push(t->max);
}
moduleBaseFunction(moduleOverworldTriggerSetMax) {
moduleBaseRequireArgs(1);
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
float_t *v = moduleVec3From(args[0]);
if(!v) return moduleBaseThrow("OverworldTrigger.max: expected Vec3");
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
if(!t) return jerry_undefined();
glm_vec3_copy(v, t->max);
return jerry_undefined();
}
// ---- playerInside ----
moduleBaseFunction(moduleOverworldTriggerGetPlayerInside) {
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
if(!t) return jerry_undefined();
return jerry_boolean(t->playerInside);
}
// ---- setBounds ----
moduleBaseFunction(moduleOverworldTriggerSetBounds) {
moduleBaseRequireArgs(2);
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
float_t *minV = moduleVec3From(args[0]);
float_t *maxV = moduleVec3From(args[1]);
if(!minV) return moduleBaseThrow("OverworldTrigger.setBounds: expected Vec3 for min");
if(!maxV) return moduleBaseThrow("OverworldTrigger.setBounds: expected Vec3 for max");
entityOverworldTriggerSetBounds(c->entityId, c->componentId, minV, maxV);
return jerry_undefined();
}
// ---- callback helpers ----
/*
* Pins the JS function on this._onXxx for GC safety, stores a copied
* jerry_value_t reference in the cbs struct for the C trampoline, and
* wires up the C callback pointer. Passing null/undefined clears it.
*/
static void moduleOverworldTriggerSetCb(
const jerry_call_info_t *callInfo,
const jerry_value_t *newArgs,
const jerry_length_t newArgc,
jerry_value_t *slot,
entityoverworldtriggercallback_t *cslot,
entityoverworldtriggercallback_t trampolineFn,
const char_t *pinKey
) {
jerry_value_free(*slot);
jerry_value_t pin = (newArgc > 0) ? newArgs[0] : jerry_undefined();
jerry_value_t keyVal = jerry_string_sz(pinKey);
if(jerry_value_is_function(pin)) {
*slot = jerry_value_copy(pin);
*cslot = trampolineFn;
jerry_object_set(callInfo->this_value, keyVal, pin);
} else {
*slot = jerry_undefined();
*cslot = NULL;
jerry_value_t undef = jerry_undefined();
jerry_object_set(callInfo->this_value, keyVal, undef);
jerry_value_free(undef);
}
jerry_value_free(keyVal);
}
static jerry_value_t moduleOverworldTriggerGetPinnedCb(
const jerry_call_info_t *callInfo,
const char_t *pinKey
) {
jerry_value_t key = jerry_string_sz(pinKey);
jerry_value_t val = jerry_object_get(callInfo->this_value, key);
jerry_value_free(key);
return val;
}
// ---- onEnter ----
moduleBaseFunction(moduleOverworldTriggerGetOnEnter) {
(void)args; (void)argc;
return moduleOverworldTriggerGetPinnedCb(callInfo, "_onEnter");
}
moduleBaseFunction(moduleOverworldTriggerSetOnEnter) {
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
if(!t) return jerry_undefined();
jsoverworldtriggercbs_t *cbs = moduleOverworldTriggerGetCbs(t);
moduleOverworldTriggerSetCb(
callInfo, args, argc,
&cbs->onEnter, &t->onEnter,
moduleOverworldTriggerOnEnterCb, "_onEnter"
);
return jerry_undefined();
}
// ---- onExit ----
moduleBaseFunction(moduleOverworldTriggerGetOnExit) {
(void)args; (void)argc;
return moduleOverworldTriggerGetPinnedCb(callInfo, "_onExit");
}
moduleBaseFunction(moduleOverworldTriggerSetOnExit) {
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
if(!t) return jerry_undefined();
jsoverworldtriggercbs_t *cbs = moduleOverworldTriggerGetCbs(t);
moduleOverworldTriggerSetCb(
callInfo, args, argc,
&cbs->onExit, &t->onExit,
moduleOverworldTriggerOnExitCb, "_onExit"
);
return jerry_undefined();
}
// ---- onStay ----
moduleBaseFunction(moduleOverworldTriggerGetOnStay) {
(void)args; (void)argc;
return moduleOverworldTriggerGetPinnedCb(callInfo, "_onStay");
}
moduleBaseFunction(moduleOverworldTriggerSetOnStay) {
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
if(!t) return jerry_undefined();
jsoverworldtriggercbs_t *cbs = moduleOverworldTriggerGetCbs(t);
moduleOverworldTriggerSetCb(
callInfo, args, argc,
&cbs->onStay, &t->onStay,
moduleOverworldTriggerOnStayCb, "_onStay"
);
return jerry_undefined();
}
// ---- onOutside ----
moduleBaseFunction(moduleOverworldTriggerGetOnOutside) {
(void)args; (void)argc;
return moduleOverworldTriggerGetPinnedCb(callInfo, "_onOutside");
}
moduleBaseFunction(moduleOverworldTriggerSetOnOutside) {
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_undefined();
entityoverworldtrigger_t *t = entityOverworldTriggerGet(c->entityId, c->componentId);
if(!t) return jerry_undefined();
jsoverworldtriggercbs_t *cbs = moduleOverworldTriggerGetCbs(t);
moduleOverworldTriggerSetCb(
callInfo, args, argc,
&cbs->onOutside, &t->onOutside,
moduleOverworldTriggerOnOutsideCb, "_onOutside"
);
return jerry_undefined();
}
moduleBaseFunction(moduleOverworldTriggerToString) {
jscomponent_t *c = moduleOverworldTriggerSelf(callInfo);
if(!c) return jerry_string_sz("OverworldTrigger:invalid");
char_t buf[32];
snprintf(buf, sizeof(buf), "OverworldTrigger(%u)", (unsigned)c->componentId);
return jerry_string_sz(buf);
}
static void moduleOverworldTriggerInit(void) {
scriptProtoInit(
&MODULE_OVERWORLD_TRIGGER_PROTO, "OverworldTrigger",
sizeof(jscomponent_t), moduleOverworldTriggerCtor
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_TRIGGER_PROTO, "entity",
moduleOverworldTriggerGetEntity, NULL
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_TRIGGER_PROTO, "id",
moduleOverworldTriggerGetId, NULL
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_TRIGGER_PROTO, "min",
moduleOverworldTriggerGetMin, moduleOverworldTriggerSetMin
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_TRIGGER_PROTO, "max",
moduleOverworldTriggerGetMax, moduleOverworldTriggerSetMax
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_TRIGGER_PROTO, "playerInside",
moduleOverworldTriggerGetPlayerInside, NULL
);
scriptProtoDefineFunc(
&MODULE_OVERWORLD_TRIGGER_PROTO, "setBounds",
moduleOverworldTriggerSetBounds
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_TRIGGER_PROTO, "onEnter",
moduleOverworldTriggerGetOnEnter, moduleOverworldTriggerSetOnEnter
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_TRIGGER_PROTO, "onExit",
moduleOverworldTriggerGetOnExit, moduleOverworldTriggerSetOnExit
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_TRIGGER_PROTO, "onStay",
moduleOverworldTriggerGetOnStay, moduleOverworldTriggerSetOnStay
);
scriptProtoDefineProp(
&MODULE_OVERWORLD_TRIGGER_PROTO, "onOutside",
moduleOverworldTriggerGetOnOutside, moduleOverworldTriggerSetOnOutside
);
scriptProtoDefineToString(
&MODULE_OVERWORLD_TRIGGER_PROTO, moduleOverworldTriggerToString
);
}
static void moduleOverworldTriggerDispose(void) {
scriptProtoDispose(&MODULE_OVERWORLD_TRIGGER_PROTO);
}
@@ -0,0 +1,110 @@
/**
* 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/entity/modulecomponent.h"
#include "entity/component/overworld/entityplayer.h"
static scriptproto_t MODULE_PLAYER_PROTO;
moduleBaseFunction(modulePlayerCtor) {
(void)callInfo; (void)args; (void)argc;
return moduleBaseThrow("Player cannot be instantiated with new");
}
static inline jscomponent_t *modulePlayerSelf(
const jerry_call_info_t *callInfo
) {
return (jscomponent_t *)scriptProtoGetValue(
&MODULE_PLAYER_PROTO, callInfo->this_value
);
}
moduleBaseFunction(modulePlayerGetEntity) {
jscomponent_t *c = modulePlayerSelf(callInfo);
if(!c) return jerry_undefined();
return jerry_number((double)c->entityId);
}
moduleBaseFunction(modulePlayerGetId) {
jscomponent_t *c = modulePlayerSelf(callInfo);
if(!c) return jerry_undefined();
return jerry_number((double)c->componentId);
}
moduleBaseFunction(modulePlayerGetSpeed) {
jscomponent_t *c = modulePlayerSelf(callInfo);
if(!c) return jerry_undefined();
entityplayer_t *p = entityPlayerGet(c->entityId, c->componentId);
if(!p) return jerry_undefined();
return jerry_number((double)p->speed);
}
moduleBaseFunction(modulePlayerSetSpeed) {
moduleBaseRequireArgs(1);
jscomponent_t *c = modulePlayerSelf(callInfo);
if(!c) return jerry_undefined();
entityplayer_t *p = entityPlayerGet(c->entityId, c->componentId);
if(!p) return jerry_undefined();
p->speed = moduleBaseArgFloat(0);
return jerry_undefined();
}
moduleBaseFunction(modulePlayerGetRunSpeed) {
jscomponent_t *c = modulePlayerSelf(callInfo);
if(!c) return jerry_undefined();
entityplayer_t *p = entityPlayerGet(c->entityId, c->componentId);
if(!p) return jerry_undefined();
return jerry_number((double)p->runSpeed);
}
moduleBaseFunction(modulePlayerSetRunSpeed) {
moduleBaseRequireArgs(1);
jscomponent_t *c = modulePlayerSelf(callInfo);
if(!c) return jerry_undefined();
entityplayer_t *p = entityPlayerGet(c->entityId, c->componentId);
if(!p) return jerry_undefined();
p->runSpeed = moduleBaseArgFloat(0);
return jerry_undefined();
}
moduleBaseFunction(modulePlayerToString) {
jscomponent_t *c = modulePlayerSelf(callInfo);
if(!c) return jerry_string_sz("Player:invalid");
char_t buf[32];
snprintf(buf, sizeof(buf), "Player(%u)", (unsigned)c->componentId);
return jerry_string_sz(buf);
}
static void modulePlayerInit(void) {
scriptProtoInit(
&MODULE_PLAYER_PROTO, "Player",
sizeof(jscomponent_t), modulePlayerCtor
);
scriptProtoDefineProp(
&MODULE_PLAYER_PROTO, "entity", modulePlayerGetEntity, NULL
);
scriptProtoDefineProp(
&MODULE_PLAYER_PROTO, "id", modulePlayerGetId, NULL
);
scriptProtoDefineProp(
&MODULE_PLAYER_PROTO, "speed",
modulePlayerGetSpeed, modulePlayerSetSpeed
);
scriptProtoDefineProp(
&MODULE_PLAYER_PROTO, "runSpeed",
modulePlayerGetRunSpeed, modulePlayerSetRunSpeed
);
scriptProtoDefineToString(&MODULE_PLAYER_PROTO, modulePlayerToString);
}
static void modulePlayerDispose(void) {
scriptProtoDispose(&MODULE_PLAYER_PROTO);
}