ECS
This commit is contained in:
@@ -74,5 +74,3 @@ elseif LINUX then
|
||||
else
|
||||
print("Unknown platform, no default input bindings set.")
|
||||
end
|
||||
|
||||
sceneSet('scene/main_menu/main_menu.lua')
|
||||
@@ -1,46 +0,0 @@
|
||||
module('spritebatch')
|
||||
module('camera')
|
||||
module('color')
|
||||
module('ui')
|
||||
module('screen')
|
||||
module('time')
|
||||
module('text')
|
||||
module('tileset')
|
||||
module('texture')
|
||||
module('input')
|
||||
module('shader')
|
||||
module('locale')
|
||||
|
||||
screenSetBackground(colorCornflowerBlue())
|
||||
camera = cameraCreate(CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC)
|
||||
|
||||
text = localeGetText('cart.item_count', 52, 2)
|
||||
|
||||
function sceneDispose()
|
||||
end
|
||||
|
||||
function sceneUpdate()
|
||||
end
|
||||
|
||||
function sceneRender()
|
||||
-- Update camera
|
||||
camera.top = screenGetHeight()
|
||||
camera.right = screenGetWidth()
|
||||
|
||||
shaderBind(SHADER_UNLIT)
|
||||
proj = cameraGetProjectionMatrix(camera)
|
||||
shaderSetMatrix(SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj)
|
||||
view = cameraGetViewMatrix(camera)
|
||||
shaderSetMatrix(SHADER_UNLIT, SHADER_UNLIT_VIEW, view)
|
||||
|
||||
-- shaderSetTexture(SHADER_UNLIT, SHADER_UNLIT_TEXTURE, nil)
|
||||
-- spriteBatchPush(
|
||||
-- 32, 32,
|
||||
-- 64, 64,
|
||||
-- colorWhite()
|
||||
-- )
|
||||
-- spriteBatchFlush()
|
||||
|
||||
textDraw(10, 10, text, colorWhite())
|
||||
spriteBatchFlush()
|
||||
end
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "Dominic",
|
||||
"age": 31,
|
||||
"likes": [
|
||||
"thing1",
|
||||
"thing2"
|
||||
],
|
||||
"options": {
|
||||
"someParam": true,
|
||||
"someSubObject": {
|
||||
"someSubSubParam": 52
|
||||
},
|
||||
"someArray": [
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -4,8 +4,7 @@
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_subdirectory(dusk)
|
||||
# add_subdirectory(duskrpg)
|
||||
add_subdirectory(dusktrivia)
|
||||
add_subdirectory(duskrpg)
|
||||
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux" OR DUSK_TARGET_SYSTEM STREQUAL "knulli")
|
||||
add_subdirectory(dusklinux)
|
||||
|
||||
@@ -67,6 +67,7 @@ add_subdirectory(asset)
|
||||
add_subdirectory(log)
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(engine)
|
||||
add_subdirectory(entity)
|
||||
add_subdirectory(error)
|
||||
add_subdirectory(event)
|
||||
add_subdirectory(input)
|
||||
|
||||
@@ -23,24 +23,6 @@
|
||||
#include "script/module/display/moduleshader.h"
|
||||
|
||||
display_t DISPLAY = { 0 };
|
||||
mesh_t mesh;
|
||||
meshvertex_t vertices[3] = {
|
||||
{
|
||||
.color = { 255, 0, 0, 255 },
|
||||
.uv = { 0.0f, 0.0f },
|
||||
.pos = { 0.0f, 0.5f, 0.0f }
|
||||
},
|
||||
{
|
||||
.color = { 0, 255, 0, 255 },
|
||||
.uv = { 0.5f, 1.0f },
|
||||
.pos = { -0.5f, -0.5f, 0.0f }
|
||||
},
|
||||
{
|
||||
.color = { 0, 0, 255, 255 },
|
||||
.uv = { 1.0f, 0.0f },
|
||||
.pos = { 0.5f, -0.5f, 0.0f }
|
||||
}
|
||||
};
|
||||
|
||||
errorret_t displayInit(void) {
|
||||
memoryZero(&DISPLAY, sizeof(DISPLAY));
|
||||
@@ -68,8 +50,6 @@ errorret_t displayInit(void) {
|
||||
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, mat));
|
||||
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, NULL));
|
||||
|
||||
errorChain(meshInit(&mesh, MESH_PRIMITIVE_TYPE_TRIANGLES, 3, vertices));
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
#include "ui/ui.h"
|
||||
#include "script/scriptmanager.h"
|
||||
#include "assert/assert.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "game/game.h"
|
||||
|
||||
#include "asset/loader/json/assetjsonloader.h"
|
||||
#include "entity/component/display/entityposition.h"
|
||||
#include "entity/component/display/entitycamera.h"
|
||||
|
||||
engine_t ENGINE;
|
||||
|
||||
@@ -37,9 +39,17 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
errorChain(displayInit());
|
||||
errorChain(uiInit());
|
||||
errorChain(sceneInit());
|
||||
entityManagerInit();
|
||||
errorChain(gameInit());
|
||||
|
||||
// Run the initial script.
|
||||
entityid_t ent0 = entityAdd();
|
||||
entityAddComponent(ent0, ENTITY_POSITION_DATA);
|
||||
entityAddComponent(ent0, ENTITY_CAMERA_DATA);
|
||||
|
||||
entityid_t ent1 = entityAdd();
|
||||
entityAddComponent(ent0, ENTITY_POSITION_DATA);
|
||||
|
||||
// Run the init script.
|
||||
scriptcontext_t ctx;
|
||||
errorChain(scriptContextInit(&ctx));
|
||||
errorChain(scriptContextExecFile(&ctx, "init.lua"));
|
||||
@@ -69,6 +79,7 @@ void engineExit(void) {
|
||||
errorret_t engineDispose(void) {
|
||||
sceneDispose();
|
||||
errorChain(gameDispose());
|
||||
entityManagerDispose();
|
||||
localeManagerDispose();
|
||||
uiDispose();
|
||||
errorChain(displayDispose());
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
entity.c
|
||||
entitycomponent.c
|
||||
entitymanager.c
|
||||
)
|
||||
|
||||
# Subdirectories
|
||||
add_subdirectory(component)
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
@@ -6,8 +6,7 @@
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
mapchunk.c
|
||||
map.c
|
||||
worldpos.c
|
||||
maptile.c
|
||||
)
|
||||
|
||||
# Subdirectories
|
||||
add_subdirectory(display)
|
||||
+3
-1
@@ -6,5 +6,7 @@
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
modulemap.c
|
||||
entityposition.c
|
||||
)
|
||||
|
||||
# Subdirectories
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entitycamera.h"
|
||||
|
||||
ENTITY_COMPONENT_DEFINE(entitycamera_t, entityCameraInit, NULL)
|
||||
|
||||
void entityCameraInit(const entityandentitycomponentid_t id) {
|
||||
entityid_t entityId =
|
||||
|
||||
// Default to perspective camera with default values.
|
||||
data->projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE;
|
||||
data->perspective.fov = glm_rad(45.0f);
|
||||
data->nearClip = 0.1f;
|
||||
data->farClip = 10000.0f;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity/entitymanager.h"
|
||||
#include "display/camera/camera.h"
|
||||
|
||||
#define ENTITY_CAMERA_COUNT_MAX 2
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
float_t fov;
|
||||
} perspective;
|
||||
|
||||
struct {
|
||||
float_t left;
|
||||
float_t right;
|
||||
float_t top;
|
||||
float_t bottom;
|
||||
} orthographic;
|
||||
};
|
||||
|
||||
float_t nearClip;
|
||||
float_t farClip;
|
||||
|
||||
cameraprojectiontype_t projType;
|
||||
} entitycamera_t;
|
||||
|
||||
/**
|
||||
* Initializes the camera component for an entity.
|
||||
*
|
||||
* @param id The component entity id.
|
||||
*/
|
||||
void entityCameraInit(const entityandentitycomponentid_t id);
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entityposition.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
entityposition_t ENTITY_POSITION_DATA[ENTITY_COUNT_MAX];
|
||||
|
||||
void entityPositionInit(const entityid_t id, entityposition_t *data) {
|
||||
memoryZero(data, sizeof(entityposition_t));
|
||||
|
||||
glm_mat4_identity(data->transform);
|
||||
}
|
||||
|
||||
void entityPositionLookAt(
|
||||
const entityid_t id,
|
||||
const vec3 target,
|
||||
const vec3 up,
|
||||
const vec3 eye
|
||||
) {
|
||||
glm_lookat(eye, target, up, ENTITY_POSITION_DATA[id].transform);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity/entity.h"
|
||||
|
||||
typedef struct {
|
||||
mat4 transform;
|
||||
} entityposition_t;
|
||||
|
||||
/**
|
||||
* Initializes the position component for an entity.
|
||||
*
|
||||
* @param id The component entity id.
|
||||
*/
|
||||
void entityPositionInit(const entityandentitycomponentid_t id);
|
||||
|
||||
/**
|
||||
* Sets the position component of an entity to look at a target point.
|
||||
*
|
||||
* @param id The component entity id.
|
||||
* @param target The target point to look at.
|
||||
* @param up The up vector to use for the look at calculation.
|
||||
* @param eye The eye position to use for the look at calculation.
|
||||
*/
|
||||
void entityPositionLookAt(
|
||||
const entityandentitycomponentid_t id,
|
||||
const vec3 target,
|
||||
const vec3 up,
|
||||
const vec3 eye
|
||||
);
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entitymanager.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
entityid_t entityAdd() {
|
||||
entityid_t id = 0xFF;
|
||||
|
||||
// Quick search for an available slot.
|
||||
for(uint8_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if(id >= ENTITY_COUNT_MAX) {
|
||||
assertUnreachable("No available entity slots.");
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
// Init the entity.
|
||||
entity_t *entity = &ENTITY_MANAGER.entities[id];
|
||||
memoryZero(entity, sizeof(entity_t));
|
||||
entity->state |= ENTITY_STATE_ACTIVE;
|
||||
return id;
|
||||
}
|
||||
|
||||
entitycomponentid_t entityAddComponent(
|
||||
const entityid_t id,
|
||||
void *componentData
|
||||
) {
|
||||
entitycomponentid_t compId = entityComponentGetByData(componentData);
|
||||
assertTrue(compId != 0xFF, "Component not found in entity manager.");
|
||||
|
||||
// Find empty entity slot.
|
||||
entitycomponent_t *comp = &ENTITY_MANAGER.components[compId];
|
||||
uint8_t x = 0xFF;// Entity slot within the component
|
||||
for(uint8_t i = 0; i < comp->entityMax; i++) {
|
||||
if(comp->entities[i] != 0xFF) {
|
||||
continue;
|
||||
}
|
||||
x = i;
|
||||
break;
|
||||
}
|
||||
assertTrue(x != 0xFF, "No available component entity slots.");
|
||||
|
||||
// Set the entity id.
|
||||
entity_t *entity = &ENTITY_MANAGER.entities[id];
|
||||
assertTrue(
|
||||
entity->componentCount < ENTITY_COMPONENT_COUNT_MAX,
|
||||
"Entity has too many components."
|
||||
);
|
||||
comp->entities[x] = id;
|
||||
entity->components[entity->componentCount++] = compId;
|
||||
|
||||
if(comp->init != NULL) {
|
||||
void *data = (uint8_t *)comp->data + (comp->dataSize * x);
|
||||
comp->init(id, data);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void entityRemove(const entityid_t id) {
|
||||
assertTrue(id < ENTITY_COUNT_MAX, "Invalid entity ID.");
|
||||
|
||||
entity_t *entity = &ENTITY_MANAGER.entities[id];
|
||||
entity->state &= ~ENTITY_STATE_ACTIVE;
|
||||
|
||||
// Remove components.
|
||||
for(uint8_t i = 0; i < entity->componentCount; i++) {
|
||||
entitycomponentid_t compId = entity->components[i];
|
||||
entitycomponent_t *comp = &ENTITY_MANAGER.components[compId];
|
||||
|
||||
// Find the component slot for this entity.
|
||||
uint8_t x = 0xFF;
|
||||
for(uint8_t j = 0; j < comp->entityMax; j++) {
|
||||
if(comp->entities[j] == id) {
|
||||
x = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(x != 0xFF, "Entity does not have this component.");
|
||||
|
||||
// Clear the component slot.
|
||||
comp->entities[x] = 0xFF;
|
||||
|
||||
// Dispose
|
||||
if(comp->dispose != NULL) {
|
||||
void *data = (uint8_t *)comp->data + (comp->dataSize * x);
|
||||
comp->dispose(id, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entityid_t entityGetId(const entityandentitycomponentid_t id) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entitybase.h"
|
||||
|
||||
#define ENTITY_STATE_ACTIVE (1 << 0)
|
||||
|
||||
typedef struct {
|
||||
entitycomponentid_t components[ENTITY_COMPONENT_COUNT_MAX];
|
||||
uint8_t componentCount;
|
||||
uint8_t state;
|
||||
} entity_t;
|
||||
|
||||
/**
|
||||
* Adds an entity to the entity manager and initializes it.
|
||||
*
|
||||
* @return The ID of the added entity.
|
||||
*/
|
||||
entityid_t entityAdd();
|
||||
|
||||
/**
|
||||
* Adds a component to an entity.
|
||||
*
|
||||
* @param id The ID of the entity to add the component to.
|
||||
* @param componentData The data of the component to add.
|
||||
* @return The ID of the added component.
|
||||
*/
|
||||
entitycomponentid_t entityAddComponent(
|
||||
const entityid_t id,
|
||||
void *componentData
|
||||
);
|
||||
|
||||
/**
|
||||
* Disposes of an entity with the given ID, this will dispose of its components.
|
||||
*
|
||||
* @param id The ID of the entity to dispose.
|
||||
*/
|
||||
void entityRemove(const entityid_t id);
|
||||
|
||||
/**
|
||||
* Gets an entity id by the entity and entity component id provided.
|
||||
*
|
||||
* @param id Id to get the entity id for.
|
||||
* @return The entity id.
|
||||
*/
|
||||
entityid_t entityGetId(const entityandentitycomponentid_t id);
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
#define ENTITY_COUNT_MAX 256
|
||||
#define ENTITY_COMPONENT_COUNT_MAX 16
|
||||
#define ENTITY_MANAGER_COMPONENT_COUNT_MAX 64
|
||||
|
||||
typedef uint8_t entityid_t;
|
||||
typedef uint8_t entitycomponentid_t;
|
||||
typedef uint16_t entityandentitycomponentid_t;
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
|
||||
#include "entitymanager.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
entitycomponentid_t entityComponentInit(
|
||||
void *data,
|
||||
const size_t dataSize,
|
||||
const uint8_t entityCountMax,
|
||||
void (*init)(const entityid_t id, void *data),
|
||||
void (*dispose)(const entityid_t id, void *data)
|
||||
) {
|
||||
assertNotNull(data, "Component data cannot be null.");
|
||||
assertTrue(dataSize > 0, "Component data size must be greater than 0.");
|
||||
assertTrue(entityCountMax > 0, "Component entity count max be at least 1");
|
||||
|
||||
// Get next available component slot.
|
||||
entitycomponentid_t componentIndex = 0xFF;
|
||||
for(uint8_t i = 0; i <ENTITY_MANAGER_COMPONENT_COUNT_MAX ; i++) {
|
||||
if(ENTITY_MANAGER.components[i].data != NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
componentIndex = i;
|
||||
break;
|
||||
}
|
||||
assertTrue(
|
||||
componentIndex < ENTITY_MANAGER_COMPONENT_COUNT_MAX,
|
||||
"No available component slots."
|
||||
);
|
||||
|
||||
entitycomponent_t *component = &ENTITY_MANAGER.components[componentIndex];
|
||||
memoryZero(component, sizeof(entitycomponent_t));
|
||||
component->data = data;
|
||||
component->dataSize = dataSize;
|
||||
component->entityMax = entityCountMax;
|
||||
component->init = init;
|
||||
component->dispose = dispose;
|
||||
|
||||
// Fill with 0xFF
|
||||
memorySet(component->entities, 0xFF, sizeof(entityid_t) * ENTITY_COUNT_MAX);
|
||||
|
||||
return componentIndex;
|
||||
}
|
||||
|
||||
entitycomponentid_t entityComponentGetByData(const void *data) {
|
||||
assertNotNull(data, "Component data cannot be null.");
|
||||
|
||||
for(uint8_t i = 0; i < ENTITY_MANAGER_COMPONENT_COUNT_MAX; i++) {
|
||||
if(ENTITY_MANAGER.components[i].data == data) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void * entityComponentGetData(
|
||||
const entitycomponentid_t componentId,
|
||||
const entityid_t entityId
|
||||
) {
|
||||
assertTrue(
|
||||
componentId < ENTITY_MANAGER_COMPONENT_COUNT_MAX,
|
||||
"Component ID is out of bounds."
|
||||
);
|
||||
assertTrue(
|
||||
entityId < ENTITY_COUNT_MAX,
|
||||
"Entity ID is out of bounds."
|
||||
);
|
||||
entitycomponent_t *comp = &ENTITY_MANAGER.components[componentId];
|
||||
for(uint8_t i = 0; i < comp->entityMax; i++) {
|
||||
if(comp->entities[i] == entityId) {
|
||||
return (uint8_t *)comp->data + (comp->dataSize * i);
|
||||
}
|
||||
}
|
||||
assertUnreachable("Entity does not have the component.");
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entitybase.h"
|
||||
|
||||
typedef struct {
|
||||
size_t dataSize;
|
||||
entityid_t entities[ENTITY_COUNT_MAX];
|
||||
uint8_t entityMax;
|
||||
|
||||
void (*init)(const entityid_t id, void *data);
|
||||
void (*dispose)(const entityid_t id, void *data);
|
||||
} entitycomponent_t;
|
||||
|
||||
#define ENTITY_COMPONENT_DEFINE(name, stc, init, dispose) \
|
||||
static const entitycomponent_t name = { \
|
||||
.dataSize = sizeof(*stc), \
|
||||
.entities = {0}, \
|
||||
.entityMax = ENTITY_COUNT_MAX, \
|
||||
.init = init, \
|
||||
.dispose = dispose \
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a component to the entity manager / Initializes a component slot.
|
||||
*
|
||||
* @param data The data of the component.
|
||||
* @param dataSize The size of the component data.
|
||||
* @param entityCountMax The maximum number of entities that can have this component.
|
||||
* @param init The function to initialize the component for an entity.
|
||||
* @param dispose The function to dispose of the component for an entity.
|
||||
* @return The ID of the added component.
|
||||
*/
|
||||
entitycomponentid_t entityComponentInit(
|
||||
void *data,
|
||||
const size_t dataSize,
|
||||
const uint8_t entityCountMax,
|
||||
void (*init)(const entityid_t id, void *data),
|
||||
void (*dispose)(const entityid_t id, void *data)
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the component ID of a component by its data pointer.
|
||||
*
|
||||
* @param data The data pointer of the component.
|
||||
* @return The ID of the component, or 0xFF if not found.
|
||||
*/
|
||||
entitycomponentid_t entityComponentGetByData(const void *data);
|
||||
|
||||
/**
|
||||
* Gets the component data for a given component and entity ID.
|
||||
*
|
||||
* @param componentId The ID of the component.
|
||||
* @param entityId The ID of the entity.
|
||||
* @return The component data.
|
||||
*/
|
||||
void * entityComponentGetData(
|
||||
const entitycomponentid_t componentId,
|
||||
const entityid_t entityId
|
||||
);
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entitymanager.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
#include "entity/component/display/entityposition.h"
|
||||
#include "entity/component/display/entitycamera.h"
|
||||
|
||||
entitymanager_t ENTITY_MANAGER;
|
||||
|
||||
void entityManagerInit(void) {
|
||||
memoryZero(&ENTITY_MANAGER, sizeof(entitymanager_t));
|
||||
|
||||
// Init components.
|
||||
entityComponentInit(
|
||||
ENTITY_POSITION_DATA,
|
||||
sizeof(entityposition_t),
|
||||
ENTITY_COUNT_MAX,
|
||||
NULL, NULL
|
||||
);
|
||||
|
||||
entityComponentInit(
|
||||
ENTITY_CAMERA_DATA,
|
||||
sizeof(entitycamera_t),
|
||||
ENTITY_CAMERA_COUNT_MAX,
|
||||
entityCameraInit, NULL
|
||||
);
|
||||
}
|
||||
|
||||
void entityManagerDispose(void) {
|
||||
for(uint8_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entityRemove(i);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity.h"
|
||||
#include "entitycomponent.h"
|
||||
|
||||
typedef struct {
|
||||
entity_t entities[ENTITY_COUNT_MAX];
|
||||
entitycomponent_t components[ENTITY_MANAGER_COMPONENT_COUNT_MAX];
|
||||
} entitymanager_t;
|
||||
|
||||
extern entitymanager_t ENTITY_MANAGER;
|
||||
|
||||
/**
|
||||
* Initializes the entity manager.
|
||||
*/
|
||||
void entityManagerInit(void);
|
||||
|
||||
/**
|
||||
* Disposes of the entity manager, this will dispose active entities.
|
||||
*/
|
||||
void entityManagerDispose(void);
|
||||
+1
-50
@@ -16,7 +16,6 @@ scene_t SCENE;
|
||||
errorret_t sceneInit(void) {
|
||||
memoryZero(&SCENE, sizeof(scene_t));
|
||||
|
||||
errorChain(scriptContextInit(&SCENE.scriptContext));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -27,68 +26,20 @@ errorret_t sceneUpdate(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
lua_getglobal(SCENE.scriptContext.luaState, "sceneUpdate");
|
||||
if(!lua_isfunction(SCENE.scriptContext.luaState, -1)) {
|
||||
lua_pop(SCENE.scriptContext.luaState, 1);
|
||||
errorOk();
|
||||
}
|
||||
|
||||
if(lua_pcall(SCENE.scriptContext.luaState, 0, 0, 0) != LUA_OK) {
|
||||
const char_t *strErr = lua_tostring(SCENE.scriptContext.luaState, -1);
|
||||
lua_pop(SCENE.scriptContext.luaState, 1);
|
||||
errorThrow("Failed to call function '%s': %s", "sceneUpdate", strErr);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t sceneRender(void) {
|
||||
lua_getglobal(SCENE.scriptContext.luaState, "sceneRender");
|
||||
if(!lua_isfunction(SCENE.scriptContext.luaState, -1)) {
|
||||
lua_pop(SCENE.scriptContext.luaState, 1);
|
||||
errorOk();
|
||||
}
|
||||
// For each camera
|
||||
|
||||
if(lua_pcall(SCENE.scriptContext.luaState, 0, 0, 0) != LUA_OK) {
|
||||
const char_t *strErr = lua_tostring(SCENE.scriptContext.luaState, -1);
|
||||
lua_pop(SCENE.scriptContext.luaState, 1);
|
||||
errorThrow("Failed to call function '%s': %s", "sceneRender", strErr);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t sceneSet(const char_t *script) {
|
||||
// Cleanup old script context.
|
||||
lua_getglobal(SCENE.scriptContext.luaState, "sceneDispose");
|
||||
if(lua_isfunction(SCENE.scriptContext.luaState, -1)) {
|
||||
if(lua_pcall(SCENE.scriptContext.luaState, 0, 0, 0) != LUA_OK) {
|
||||
const char_t *strErr = lua_tostring(SCENE.scriptContext.luaState, -1);
|
||||
lua_pop(SCENE.scriptContext.luaState, 1);
|
||||
errorThrow("Failed to call function '%s': %s", "sceneDispose", strErr);
|
||||
}
|
||||
} else {
|
||||
lua_pop(SCENE.scriptContext.luaState, 1);
|
||||
}
|
||||
scriptContextDispose(&SCENE.scriptContext);
|
||||
|
||||
// Create a new script context.
|
||||
errorChain(scriptContextInit(&SCENE.scriptContext));
|
||||
errorChain(scriptContextExecFile(&SCENE.scriptContext, script));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void sceneDispose(void) {
|
||||
lua_getglobal(SCENE.scriptContext.luaState, "sceneDispose");
|
||||
if(lua_isfunction(SCENE.scriptContext.luaState, -1)) {
|
||||
if(lua_pcall(SCENE.scriptContext.luaState, 0, 0, 0) != LUA_OK) {
|
||||
const char_t *strErr = lua_tostring(SCENE.scriptContext.luaState, -1);
|
||||
lua_pop(SCENE.scriptContext.luaState, 1);
|
||||
logDebug("Failed to call function '%s': %s\n", "sceneDispose", strErr);
|
||||
}
|
||||
} else {
|
||||
lua_pop(SCENE.scriptContext.luaState, 1);
|
||||
}
|
||||
|
||||
scriptContextDispose(&SCENE.scriptContext);
|
||||
}
|
||||
@@ -6,10 +6,10 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptcontext.h"
|
||||
#include "error/error.h"
|
||||
|
||||
typedef struct {
|
||||
scriptcontext_t scriptContext;
|
||||
void *nothing;
|
||||
} scene_t;
|
||||
|
||||
extern scene_t SCENE;
|
||||
|
||||
@@ -30,6 +30,10 @@ void moduleTexture(scriptcontext_t *ctx) {
|
||||
lua_setfield(l, -2, "__gc");
|
||||
}
|
||||
|
||||
// Texture formats
|
||||
lua_pushnumber(l, TEXTURE_FORMAT_RGBA);
|
||||
lua_setglobal(l, "TEXTURE_FORMAT_RGBA");
|
||||
|
||||
lua_register(ctx->luaState, "textureLoad", moduleTextureLoad);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "display/texture/tileset.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "asset/loader/display/assettilesetloader.h"
|
||||
|
||||
void moduleTileset(scriptcontext_t *ctx) {
|
||||
assertNotNull(ctx, "Script context cannot be NULL");
|
||||
@@ -24,7 +25,7 @@ void moduleTileset(scriptcontext_t *ctx) {
|
||||
}
|
||||
lua_pop(ctx->luaState, 1); // Pop the metatable
|
||||
|
||||
// lua_register(ctx->luaState, "tilesetGetByName", moduleTilesetGetByName);
|
||||
lua_register(ctx->luaState, "tilesetLoad", moduleTilesetLoad);
|
||||
lua_register(ctx->luaState, "tilesetTileGetUV", moduleTilesetTileGetUV);
|
||||
lua_register(
|
||||
ctx->luaState, "tilesetPositionGetUV", moduleTilesetPositionGetUV
|
||||
@@ -71,34 +72,6 @@ int moduleTilesetToString(lua_State *l) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// int moduleTilesetGetByName(lua_State *l) {
|
||||
// assertNotNull(l, "Lua state cannot be NULL.");
|
||||
|
||||
// if(!lua_isstring(l, 1)) {
|
||||
// lua_pushnil(l);
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
// const char_t *name = lua_tostring(l, 1);
|
||||
// if(name == NULL || name[0] == '\0') {
|
||||
// luaL_error(l, "Invalid tileset name.");
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
// const tileset_t *ts = tilesetGetByName(name);
|
||||
// if(ts == NULL) {
|
||||
// lua_pushnil(l);
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
// // Lua does not own this reference
|
||||
// lua_pushlightuserdata(l, (void *)ts);
|
||||
// luaL_getmetatable(l, "tileset_mt");
|
||||
// lua_setmetatable(l, -2);
|
||||
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
int moduleTilesetTileGetUV(lua_State *l) {
|
||||
assertNotNull(l, "Lua state cannot be NULL.");
|
||||
|
||||
@@ -158,3 +131,34 @@ int moduleTilesetPositionGetUV(lua_State *l) {
|
||||
lua_setmetatable(l, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int moduleTilesetLoad(lua_State *l) {
|
||||
assertNotNull(l, "Lua state cannot be NULL.");
|
||||
|
||||
if(!lua_isstring(l, 1)) {
|
||||
luaL_error(l, "First argument must be a string filename.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char_t *filename = lua_tostring(l, 1);
|
||||
assertNotNull(filename, "Filename cannot be NULL.");
|
||||
assertStrLenMin(filename, 1, "Filename cannot be empty.");
|
||||
|
||||
// Create texture owned to lua
|
||||
tileset_t *tileset = (tileset_t *)lua_newuserdata(l, sizeof(tileset_t));
|
||||
memoryZero(tileset, sizeof(tileset_t));
|
||||
|
||||
errorret_t ret = assetTilesetLoad(filename, tileset);
|
||||
if(ret.code != ERROR_OK) {
|
||||
errorCatch(errorPrint(ret));
|
||||
luaL_error(l, "Failed to load tileset asset: %s", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set metatable
|
||||
luaL_getmetatable(l, "tileset_mt");
|
||||
lua_setmetatable(l, -2);
|
||||
|
||||
// Return the tileset
|
||||
return 1;
|
||||
}
|
||||
@@ -31,14 +31,6 @@ int moduleTilesetIndex(lua_State *l);
|
||||
*/
|
||||
int moduleTilesetToString(lua_State *l);
|
||||
|
||||
/**
|
||||
* Lua function to get a tileset by name.
|
||||
*
|
||||
* @param l The Lua state.
|
||||
* @return The number of return values on the Lua stack.
|
||||
*/
|
||||
int moduleTilesetGetByName(lua_State *l);
|
||||
|
||||
/**
|
||||
* Lua function to get the UV coordinates for a tile index in a tileset.
|
||||
*
|
||||
@@ -54,3 +46,11 @@ int moduleTilesetTileGetUV(lua_State *l);
|
||||
* @return The number of return values on the Lua stack.
|
||||
*/
|
||||
int moduleTilesetPositionGetUV(lua_State *l);
|
||||
|
||||
/**
|
||||
* Lua function to load a tileset from a texture and tile dimensions.
|
||||
*
|
||||
* @param l The Lua state.
|
||||
* @return The number of return values on the Lua stack.
|
||||
*/
|
||||
int moduleTilesetLoad(lua_State *l);
|
||||
@@ -10,7 +10,7 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(game)
|
||||
add_subdirectory(item)
|
||||
add_subdirectory(map)
|
||||
add_subdirectory(story)
|
||||
add_subdirectory(script)
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
@@ -9,21 +9,21 @@
|
||||
#include "error/error.h"
|
||||
|
||||
/**
|
||||
* Initializes the game.
|
||||
* 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. Should be called every frame.
|
||||
* 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. Should be called when the game is shutting down.
|
||||
* Disposes of game resources and shuts down the game systems.
|
||||
*
|
||||
* @return An error code indicating success or failure.
|
||||
*/
|
||||
@@ -1,272 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "map.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
#include "asset/asset.h"
|
||||
#include "display/texture/texture.h"
|
||||
// #include "entity/entity.h"
|
||||
#include "util/string.h"
|
||||
#include "time/time.h"
|
||||
|
||||
map_t MAP;
|
||||
|
||||
errorret_t mapInit() {
|
||||
memoryZero(&MAP, sizeof(map_t));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
bool_t mapIsLoaded() {
|
||||
return MAP.filePath[0] != '\0';
|
||||
}
|
||||
|
||||
errorret_t mapLoad(const char_t *path, const chunkpos_t position) {
|
||||
assertStrLenMin(path, 1, "Map file path cannot be empty");
|
||||
assertStrLenMax(path, MAP_FILE_PATH_MAX - 1, "Map file path too long");
|
||||
|
||||
if(stringCompare(MAP.filePath, path) == 0) {
|
||||
// Same map, no need to reload
|
||||
errorChain(mapPositionSet(position));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
chunkindex_t i;
|
||||
|
||||
// Unload all loaded chunks
|
||||
if(mapIsLoaded()) {
|
||||
for(i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||
mapChunkUnload(&MAP.chunks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Store the map file path
|
||||
stringCopy(MAP.filePath, path, MAP_FILE_PATH_MAX);
|
||||
|
||||
// Determine directory path (it is dirname)
|
||||
stringCopy(MAP.dirPath, path, MAP_FILE_PATH_MAX);
|
||||
char_t *last = stringFindLastChar(MAP.dirPath, '/');
|
||||
if(last == NULL) errorThrow("Invalid map file path");
|
||||
|
||||
// Store filename, sans extension
|
||||
stringCopy(MAP.fileName, last + 1, MAP_FILE_PATH_MAX);
|
||||
*last = '\0'; // Terminate to get directory path
|
||||
|
||||
last = stringFindLastChar(MAP.fileName, '.');
|
||||
if(last == NULL) errorThrow("Map file name has no extension");
|
||||
*last = '\0'; // Terminate to remove extension
|
||||
|
||||
// Load map itself
|
||||
errorChain(assetLoad(MAP.filePath, &MAP));
|
||||
|
||||
// Reset map position
|
||||
MAP.chunkPosition = position;
|
||||
|
||||
// Perform "initial load"
|
||||
i = 0;
|
||||
for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) {
|
||||
for(chunkunit_t y = 0; y < MAP_CHUNK_HEIGHT; y++) {
|
||||
for(chunkunit_t x = 0; x < MAP_CHUNK_WIDTH; x++) {
|
||||
mapchunk_t *chunk = &MAP.chunks[i];
|
||||
chunk->position.x = x + position.x;
|
||||
chunk->position.y = y + position.y;
|
||||
chunk->position.z = z + position.z;
|
||||
MAP.chunkOrder[i] = chunk;
|
||||
errorChain(mapChunkLoad(chunk));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t mapPositionSet(const chunkpos_t newPos) {
|
||||
if(!mapIsLoaded()) errorThrow("No map loaded");
|
||||
|
||||
const chunkpos_t curPos = MAP.chunkPosition;
|
||||
if(mapChunkPositionIsEqual(curPos, newPos)) {
|
||||
errorOk();
|
||||
}
|
||||
|
||||
// Determine which chunks remain loaded
|
||||
chunkindex_t chunksRemaining[MAP_CHUNK_COUNT] = {0};
|
||||
chunkindex_t chunksFreed[MAP_CHUNK_COUNT] = {0};
|
||||
|
||||
uint32_t remainingCount = 0;
|
||||
uint32_t freedCount = 0;
|
||||
|
||||
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||
// Will this chunk remain loaded?
|
||||
mapchunk_t *chunk = &MAP.chunks[i];
|
||||
if(
|
||||
chunk->position.x >= newPos.x &&
|
||||
chunk->position.x < newPos.x + MAP_CHUNK_WIDTH &&
|
||||
|
||||
chunk->position.y >= newPos.y &&
|
||||
chunk->position.y < newPos.y + MAP_CHUNK_HEIGHT &&
|
||||
|
||||
chunk->position.z >= newPos.z &&
|
||||
chunk->position.z < newPos.z + MAP_CHUNK_DEPTH
|
||||
) {
|
||||
// Stays loaded
|
||||
chunksRemaining[remainingCount++] = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not remaining loaded
|
||||
chunksFreed[freedCount++] = i;
|
||||
}
|
||||
|
||||
// Unload the freed chunks
|
||||
for(chunkindex_t i = 0; i < freedCount; i++) {
|
||||
mapchunk_t *chunk = &MAP.chunks[chunksFreed[i]];
|
||||
mapChunkUnload(chunk);
|
||||
}
|
||||
|
||||
// This can probably be optimized later, for now we check each chunk and see
|
||||
// if it needs loading or not, and update the chunk order
|
||||
chunkindex_t orderIndex = 0;
|
||||
for(chunkunit_t zOff = 0; zOff < MAP_CHUNK_DEPTH; zOff++) {
|
||||
for(chunkunit_t yOff = 0; yOff < MAP_CHUNK_HEIGHT; yOff++) {
|
||||
for(chunkunit_t xOff = 0; xOff < MAP_CHUNK_WIDTH; xOff++) {
|
||||
const chunkpos_t newChunkPos = {
|
||||
newPos.x + xOff, newPos.y + yOff, newPos.z + zOff
|
||||
};
|
||||
|
||||
// Is this chunk already loaded (was not unloaded earlier)?
|
||||
chunkindex_t chunkIndex = -1;
|
||||
for(chunkindex_t i = 0; i < remainingCount; i++) {
|
||||
mapchunk_t *chunk = &MAP.chunks[chunksRemaining[i]];
|
||||
if(!mapChunkPositionIsEqual(chunk->position, newChunkPos)) continue;
|
||||
chunkIndex = chunksRemaining[i];
|
||||
break;
|
||||
}
|
||||
|
||||
// Need to load this chunk
|
||||
if(chunkIndex == -1) {
|
||||
// Find a freed chunk to reuse
|
||||
chunkIndex = chunksFreed[--freedCount];
|
||||
mapchunk_t *chunk = &MAP.chunks[chunkIndex];
|
||||
chunk->position = newChunkPos;
|
||||
errorChain(mapChunkLoad(chunk));
|
||||
}
|
||||
|
||||
MAP.chunkOrder[orderIndex++] = &MAP.chunks[chunkIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update map position
|
||||
MAP.chunkPosition = newPos;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void mapUpdate() {
|
||||
#ifdef DUSK_TIME_DYNAMIC
|
||||
if(!TIME.dynamicUpdate) return;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mapRender() {
|
||||
if(!mapIsLoaded()) return;
|
||||
|
||||
// textureBind(NULL);
|
||||
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||
mapChunkRender(&MAP.chunks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void mapDispose() {
|
||||
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||
mapChunkUnload(&MAP.chunks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void mapChunkUnload(mapchunk_t* chunk) {
|
||||
// for(uint8_t i = 0; i < CHUNK_ENTITY_COUNT_MAX; i++) {
|
||||
// if(chunk->entities[i] == 0xFF) break;
|
||||
// entity_t *entity = &ENTITIES[chunk->entities[i]];
|
||||
// entity->type = ENTITY_TYPE_NULL;
|
||||
// }
|
||||
|
||||
for(uint8_t i = 0; i < chunk->meshCount; i++) {
|
||||
// if(chunk->meshes[i].vertexCount == 0) continue;
|
||||
// meshDispose(&chunk->meshes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
errorret_t mapChunkLoad(mapchunk_t* chunk) {
|
||||
if(!mapIsLoaded()) errorThrow("No map loaded");
|
||||
|
||||
char_t buffer[160];
|
||||
|
||||
// TODO: Can probably move this to asset load logic?
|
||||
chunk->meshCount = 0;
|
||||
memoryZero(chunk->meshes, sizeof(chunk->meshes));
|
||||
memorySet(chunk->entities, 0xFF, sizeof(chunk->entities));
|
||||
|
||||
// Get chunk filepath.
|
||||
snprintf(buffer, sizeof(buffer), "%s/chunks/%d_%d_%d.dmc",
|
||||
MAP.dirPath,
|
||||
chunk->position.x,
|
||||
chunk->position.y,
|
||||
chunk->position.z
|
||||
);
|
||||
|
||||
// Chunk available?
|
||||
if(!assetFileExists(buffer)) {
|
||||
memoryZero(chunk->tiles, sizeof(chunk->tiles));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
// Load.
|
||||
errorChain(assetLoad(buffer, chunk));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
chunkindex_t mapGetChunkIndexAt(const chunkpos_t position) {
|
||||
if(!mapIsLoaded()) return -1;
|
||||
|
||||
chunkpos_t relPos = {
|
||||
position.x - MAP.chunkPosition.x,
|
||||
position.y - MAP.chunkPosition.y,
|
||||
position.z - MAP.chunkPosition.z
|
||||
};
|
||||
|
||||
if(
|
||||
relPos.x < 0 || relPos.y < 0 || relPos.z < 0 ||
|
||||
relPos.x >= MAP_CHUNK_WIDTH ||
|
||||
relPos.y >= MAP_CHUNK_HEIGHT ||
|
||||
relPos.z >= MAP_CHUNK_DEPTH
|
||||
) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return chunkPosToIndex(&relPos);
|
||||
}
|
||||
|
||||
mapchunk_t* mapGetChunk(const uint8_t index) {
|
||||
if(index >= MAP_CHUNK_COUNT) return NULL;
|
||||
if(!mapIsLoaded()) return NULL;
|
||||
return MAP.chunkOrder[index];
|
||||
}
|
||||
|
||||
maptile_t mapGetTile(const worldpos_t position) {
|
||||
if(!mapIsLoaded()) return TILE_SHAPE_NULL;
|
||||
|
||||
chunkpos_t chunkPos;
|
||||
worldPosToChunkPos(&position, &chunkPos);
|
||||
chunkindex_t chunkIndex = mapGetChunkIndexAt(chunkPos);
|
||||
if(chunkIndex == -1) return TILE_SHAPE_NULL;
|
||||
|
||||
mapchunk_t *chunk = mapGetChunk(chunkIndex);
|
||||
assertNotNull(chunk, "Chunk pointer cannot be NULL");
|
||||
chunktileindex_t tileIndex = worldPosToChunkTileIndex(&position);
|
||||
return chunk->tiles[tileIndex];
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "mapchunk.h"
|
||||
|
||||
#define MAP_FILE_PATH_MAX 128
|
||||
|
||||
typedef struct map_s {
|
||||
char_t filePath[MAP_FILE_PATH_MAX];
|
||||
char_t dirPath[MAP_FILE_PATH_MAX];
|
||||
char_t fileName[MAP_FILE_PATH_MAX];
|
||||
|
||||
mapchunk_t chunks[MAP_CHUNK_COUNT];
|
||||
mapchunk_t *chunkOrder[MAP_CHUNK_COUNT];
|
||||
chunkpos_t chunkPosition;
|
||||
} map_t;
|
||||
|
||||
extern map_t MAP;
|
||||
|
||||
/**
|
||||
* Initializes the map.
|
||||
*
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t mapInit();
|
||||
|
||||
/**
|
||||
* Checks if a map is loaded.
|
||||
*
|
||||
* @return true if a map is loaded, false otherwise.
|
||||
*/
|
||||
bool_t mapIsLoaded();
|
||||
|
||||
/**
|
||||
* Loads a map from the given file path.
|
||||
*
|
||||
* @param path The file path.
|
||||
* @param position The initial chunk position.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t mapLoad(const char_t *path, const chunkpos_t position);
|
||||
|
||||
/**
|
||||
* Updates the map.
|
||||
*/
|
||||
void mapUpdate();
|
||||
|
||||
/**
|
||||
* Renders the map.
|
||||
*/
|
||||
void mapRender();
|
||||
|
||||
/**
|
||||
* Disposes of the map.
|
||||
*/
|
||||
void mapDispose();
|
||||
|
||||
/**
|
||||
* Sets the map position and updates chunks accordingly.
|
||||
*
|
||||
* @param newPos The new chunk position.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t mapPositionSet(const chunkpos_t newPos);
|
||||
|
||||
/**
|
||||
* Unloads a chunk.
|
||||
*
|
||||
* @param chunk The chunk to unload.
|
||||
*/
|
||||
void mapChunkUnload(mapchunk_t* chunk);
|
||||
|
||||
/**
|
||||
* Loads a chunk.
|
||||
*
|
||||
* @param chunk The chunk to load.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t mapChunkLoad(mapchunk_t* chunk);
|
||||
|
||||
/**
|
||||
* Gets the index of a chunk, within the world, at the given position.
|
||||
*
|
||||
* @param position The chunk position.
|
||||
* @return The index of the chunk, or -1 if out of bounds.
|
||||
*/
|
||||
chunkindex_t mapGetChunkIndexAt(const chunkpos_t position);
|
||||
|
||||
/**
|
||||
* Gets a chunk by its index.
|
||||
*
|
||||
* @param chunkIndex The index of the chunk.
|
||||
* @return A pointer to the chunk.
|
||||
*/
|
||||
mapchunk_t * mapGetChunk(const uint8_t chunkIndex);
|
||||
|
||||
/**
|
||||
* Gets the tile at the given world position.
|
||||
*
|
||||
* @param position The world position.
|
||||
* @return The tile at that position, or TILE_NULL if the chunk is unloaded.
|
||||
*/
|
||||
maptile_t mapGetTile(const worldpos_t position);
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "mapchunk.h"
|
||||
|
||||
uint32_t mapChunkGetTileindex(const chunkpos_t position) {
|
||||
return (
|
||||
(position.z * CHUNK_WIDTH * CHUNK_HEIGHT) +
|
||||
(position.y * CHUNK_WIDTH) +
|
||||
position.x
|
||||
);
|
||||
}
|
||||
|
||||
bool_t mapChunkPositionIsEqual(const chunkpos_t a, const chunkpos_t b) {
|
||||
return (a.x == b.x) && (a.y == b.y) && (a.z == b.z);
|
||||
}
|
||||
|
||||
void mapChunkRender(const mapchunk_t *chunk) {
|
||||
for(uint8_t i = 0; i < chunk->meshCount; i++) {
|
||||
meshDraw(&chunk->meshes[i], 0, -1);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "maptile.h"
|
||||
#include "worldpos.h"
|
||||
#include "display/mesh/quad.h"
|
||||
|
||||
typedef struct chunk_s {
|
||||
chunkpos_t position;
|
||||
maptile_t tiles[CHUNK_TILE_COUNT];
|
||||
|
||||
uint8_t meshCount;
|
||||
meshvertex_t vertices[CHUNK_VERTEX_COUNT_MAX];
|
||||
mesh_t meshes[CHUNK_MESH_COUNT_MAX];
|
||||
uint8_t entities[CHUNK_ENTITY_COUNT_MAX];
|
||||
} mapchunk_t;
|
||||
|
||||
/**
|
||||
* Gets the tile index for a tile position within a chunk.
|
||||
*
|
||||
* @param position The position within the chunk.
|
||||
* @return The tile index within the chunk.
|
||||
*/
|
||||
uint32_t mapChunkGetTileindex(const chunkpos_t position);
|
||||
|
||||
/**
|
||||
* Checks if two chunk positions are equal.
|
||||
*
|
||||
* @param a The first chunk position.
|
||||
* @param b The second chunk position.
|
||||
* @return true if equal, false otherwise.
|
||||
*/
|
||||
bool_t mapChunkPositionIsEqual(const chunkpos_t a, const chunkpos_t b);
|
||||
|
||||
/**
|
||||
* Renders the given map chunk.
|
||||
*
|
||||
* @param chunk The map chunk to render.
|
||||
*/
|
||||
void mapChunkRender(const mapchunk_t *chunk);
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "maptile.h"
|
||||
|
||||
bool_t mapTileIsWalkable(const maptile_t tile) {
|
||||
switch(tile) {
|
||||
case TILE_SHAPE_NULL:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool_t mapTileIsRamp(const maptile_t tile) {
|
||||
switch(tile) {
|
||||
case TILE_SHAPE_RAMP_NORTH:
|
||||
case TILE_SHAPE_RAMP_SOUTH:
|
||||
case TILE_SHAPE_RAMP_EAST:
|
||||
case TILE_SHAPE_RAMP_WEST:
|
||||
case TILE_SHAPE_RAMP_NORTHEAST:
|
||||
case TILE_SHAPE_RAMP_NORTHWEST:
|
||||
case TILE_SHAPE_RAMP_SOUTHEAST:
|
||||
case TILE_SHAPE_RAMP_SOUTHWEST:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "duskdefs.h"
|
||||
// #include "rpg/entity/entitydir.h"
|
||||
|
||||
typedef uint8_t maptile_t;
|
||||
|
||||
/**
|
||||
* Returns whether or not the given tile is walkable.
|
||||
*
|
||||
* @param tile The tile to check.
|
||||
* @return bool_t True if walkable, false if not.
|
||||
*/
|
||||
bool_t mapTileIsWalkable(const maptile_t tile);
|
||||
|
||||
/**
|
||||
* Returns whether or not the given tile is a ramp tile.
|
||||
*
|
||||
* @param tile The tile to check.
|
||||
* @return bool_t True if ramp, false if not.
|
||||
*/
|
||||
bool_t mapTileIsRamp(const maptile_t tile);
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "worldpos.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
bool_t worldPosIsEqual(const worldpos_t a, const worldpos_t b) {
|
||||
return a.x == b.x && a.y == b.y && a.z == b.z;
|
||||
}
|
||||
|
||||
void chunkPosToWorldPos(const chunkpos_t* chunkPos, worldpos_t* out) {
|
||||
assertNotNull(chunkPos, "Chunk position pointer cannot be NULL");
|
||||
assertNotNull(out, "Output world position pointer cannot be NULL");
|
||||
|
||||
out->x = (worldunit_t)(chunkPos->x * CHUNK_WIDTH);
|
||||
out->y = (worldunit_t)(chunkPos->y * CHUNK_HEIGHT);
|
||||
out->z = (worldunit_t)(chunkPos->z * CHUNK_DEPTH);
|
||||
}
|
||||
|
||||
void worldPosToChunkPos(const worldpos_t* worldPos, chunkpos_t* out) {
|
||||
assertNotNull(worldPos, "World position pointer cannot be NULL");
|
||||
assertNotNull(out, "Output chunk position pointer cannot be NULL");
|
||||
|
||||
if(worldPos->x < 0) {
|
||||
out->x = (chunkunit_t)((worldPos->x - (CHUNK_WIDTH - 1)) / CHUNK_WIDTH);
|
||||
} else {
|
||||
out->x = (chunkunit_t)(worldPos->x / CHUNK_WIDTH);
|
||||
}
|
||||
|
||||
if(worldPos->y < 0) {
|
||||
out->y = (chunkunit_t)((worldPos->y - (CHUNK_HEIGHT - 1)) / CHUNK_HEIGHT);
|
||||
} else {
|
||||
out->y = (chunkunit_t)(worldPos->y / CHUNK_HEIGHT);
|
||||
}
|
||||
|
||||
if(worldPos->z < 0) {
|
||||
out->z = (chunkunit_t)((worldPos->z - (CHUNK_DEPTH - 1)) / CHUNK_DEPTH);
|
||||
} else {
|
||||
out->z = (chunkunit_t)(worldPos->z / CHUNK_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
chunktileindex_t worldPosToChunkTileIndex(const worldpos_t* worldPos) {
|
||||
assertNotNull(worldPos, "World position pointer cannot be NULL");
|
||||
|
||||
uint8_t localX, localY, localZ;
|
||||
if(worldPos->x < 0) {
|
||||
localX = (uint8_t)(
|
||||
(CHUNK_WIDTH - 1) - ((-worldPos->x - 1) % CHUNK_WIDTH)
|
||||
);
|
||||
} else {
|
||||
localX = (uint8_t)(worldPos->x % CHUNK_WIDTH);
|
||||
}
|
||||
|
||||
if(worldPos->y < 0) {
|
||||
localY = (uint8_t)(
|
||||
(CHUNK_HEIGHT - 1) - ((-worldPos->y - 1) % CHUNK_HEIGHT)
|
||||
);
|
||||
} else {
|
||||
localY = (uint8_t)(worldPos->y % CHUNK_HEIGHT);
|
||||
}
|
||||
|
||||
if(worldPos->z < 0) {
|
||||
localZ = (uint8_t)(
|
||||
(CHUNK_DEPTH - 1) - ((-worldPos->z - 1) % CHUNK_DEPTH)
|
||||
);
|
||||
} else {
|
||||
localZ = (uint8_t)(worldPos->z % CHUNK_DEPTH);
|
||||
}
|
||||
|
||||
chunktileindex_t chunkTileIndex = (chunktileindex_t)(
|
||||
(localZ * CHUNK_WIDTH * CHUNK_HEIGHT) +
|
||||
(localY * CHUNK_WIDTH) +
|
||||
localX
|
||||
);
|
||||
assertTrue(
|
||||
chunkTileIndex < CHUNK_TILE_COUNT,
|
||||
"Calculated chunk tile index is out of bounds"
|
||||
);
|
||||
return chunkTileIndex;
|
||||
}
|
||||
|
||||
chunkindex_t chunkPosToIndex(const chunkpos_t* pos) {
|
||||
assertNotNull(pos, "Chunk position pointer cannot be NULL");
|
||||
|
||||
chunkindex_t chunkIndex = (chunkindex_t)(
|
||||
(pos->z * MAP_CHUNK_WIDTH * MAP_CHUNK_HEIGHT) +
|
||||
(pos->y * MAP_CHUNK_WIDTH) +
|
||||
pos->x
|
||||
);
|
||||
|
||||
return chunkIndex;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "duskdefs.h"
|
||||
|
||||
#define CHUNK_TILE_COUNT (CHUNK_WIDTH * CHUNK_HEIGHT * CHUNK_DEPTH)
|
||||
|
||||
#define MAP_CHUNK_WIDTH 3
|
||||
#define MAP_CHUNK_HEIGHT 3
|
||||
#define MAP_CHUNK_DEPTH 3
|
||||
#define MAP_CHUNK_COUNT (MAP_CHUNK_WIDTH * MAP_CHUNK_HEIGHT * MAP_CHUNK_DEPTH)
|
||||
|
||||
typedef int16_t worldunit_t;
|
||||
typedef int16_t chunkunit_t;
|
||||
typedef int16_t chunkindex_t;
|
||||
typedef uint32_t chunktileindex_t;
|
||||
|
||||
typedef int32_t worldunits_t;
|
||||
typedef int32_t chunkunits_t;
|
||||
|
||||
typedef struct worldpos_s {
|
||||
worldunit_t x, y, z;
|
||||
} worldpos_t;
|
||||
|
||||
typedef struct chunkpos_t {
|
||||
chunkunit_t x, y, z;
|
||||
} chunkpos_t;
|
||||
|
||||
/**
|
||||
* Compares two world positions for equality.
|
||||
*
|
||||
* @param a The first world position.
|
||||
* @param b The second world position.
|
||||
* @return true if equal, false otherwise.
|
||||
*/
|
||||
bool_t worldPosIsEqual(const worldpos_t a, const worldpos_t b);
|
||||
|
||||
/**
|
||||
* Converts a world position to a chunk position.
|
||||
*
|
||||
* @param worldPos The world position.
|
||||
* @param out The output chunk position.
|
||||
*/
|
||||
void chunkPosToWorldPos(const chunkpos_t* chunkPos, worldpos_t* out);
|
||||
|
||||
/**
|
||||
* Converts a chunk position to a world position.
|
||||
*
|
||||
* @param worldPos The world position.
|
||||
* @param out The output chunk position.
|
||||
*/
|
||||
void worldPosToChunkPos(const worldpos_t* worldPos, chunkpos_t* out);
|
||||
|
||||
/**
|
||||
* Converts a position in world-space to an index inside a chunk that the tile
|
||||
* resides in.
|
||||
*
|
||||
* @param worldPos The world position.
|
||||
* @return The tile index within the chunk.
|
||||
*/
|
||||
chunktileindex_t worldPosToChunkTileIndex(const worldpos_t* worldPos);
|
||||
|
||||
/**
|
||||
* Converts a chunk position to a world position.
|
||||
*
|
||||
* @param worldPos The world position.
|
||||
* @param out The output chunk position.
|
||||
*/
|
||||
chunkindex_t chunkPosToIndex(const chunkpos_t* pos);
|
||||
@@ -5,5 +5,4 @@
|
||||
|
||||
# Subdirectories
|
||||
add_subdirectory(item)
|
||||
add_subdirectory(map)
|
||||
add_subdirectory(story)
|
||||
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "modulemap.h"
|
||||
#include "assert/assert.h"
|
||||
#include "map/map.h"
|
||||
|
||||
void moduleMap(scriptcontext_t *ctx) {
|
||||
assertNotNull(ctx, "Script context cannot be NULL");
|
||||
|
||||
// Register map functions
|
||||
lua_register(ctx->luaState, "mapIsLoaded", moduleMapIsLoaded);
|
||||
lua_register(ctx->luaState, "mapGetTile", moduleMapGetTile);
|
||||
lua_register(ctx->luaState, "mapRender", moduleMapRender);
|
||||
lua_register(ctx->luaState, "mapLoad", moduleMapLoad);
|
||||
}
|
||||
|
||||
int moduleMapIsLoaded(lua_State *L) {
|
||||
assertNotNull(L, "Lua state cannot be NULL.");
|
||||
lua_pushboolean(L, mapIsLoaded());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int moduleMapGetTile(lua_State *L) {
|
||||
assertNotNull(L, "Lua state cannot be NULL.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int moduleMapRender(lua_State *L) {
|
||||
assertNotNull(L, "Lua state cannot be NULL.");
|
||||
mapRender();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int moduleMapLoad(lua_State *L) {
|
||||
assertNotNull(L, "Lua state cannot be NULL.");
|
||||
|
||||
if(!lua_isstring(L, 1)) {
|
||||
luaL_error(L, "Expected string as first argument (file path).");
|
||||
return 0;
|
||||
}
|
||||
const char_t *path = lua_tostring(L, 1);
|
||||
|
||||
|
||||
// Optional position.
|
||||
chunkpos_t position = {0, 0, 0};
|
||||
|
||||
errorret_t err = mapLoad(path, position);
|
||||
if(err.code != ERROR_OK) {
|
||||
errorCatch(errorPrint(err));
|
||||
luaL_error(L, "Failed to load map!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/scriptcontext.h"
|
||||
|
||||
/**
|
||||
* Register map functions to the given script context.
|
||||
*
|
||||
* @param context The script context to register map functions to.
|
||||
*/
|
||||
void moduleMap(scriptcontext_t *context);
|
||||
|
||||
/**
|
||||
* Script function to check if a map is loaded.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
* @return Number of return values on the Lua stack.
|
||||
*/
|
||||
int moduleMapIsLoaded(lua_State *L);
|
||||
|
||||
/**
|
||||
* Script function to get the tile at a given world position.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
* @return Number of return values on the Lua stack.
|
||||
*/
|
||||
int moduleMapGetTile(lua_State *L);
|
||||
|
||||
/**
|
||||
* Script function to render the map.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
* @return Number of return values on the Lua stack.
|
||||
*/
|
||||
int moduleMapRender(lua_State *L);
|
||||
|
||||
/**
|
||||
* Script function to load a map from a given file path.
|
||||
*
|
||||
* @param L The Lua state.
|
||||
* @return Number of return values on the Lua stack.
|
||||
*/
|
||||
int moduleMapLoad(lua_State *L);
|
||||
@@ -8,9 +8,7 @@
|
||||
#pragma once
|
||||
#include "script/module/item/moduleitem.h"
|
||||
#include "script/module/story/modulestoryflag.h"
|
||||
#include "script/module/map/modulemap.h"
|
||||
|
||||
#define SCRIPT_GAME_LIST \
|
||||
{ .name = "item", .callback = moduleItem }, \
|
||||
{ .name = "storyflag", .callback = moduleStoryFlag }, \
|
||||
{ .name = "map", .callback = moduleMap },
|
||||
{ .name = "storyflag", .callback = moduleStoryFlag },
|
||||
@@ -1,14 +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(script)
|
||||
@@ -1,7 +0,0 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(module)
|
||||
@@ -1,6 +0,0 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Subdirectories
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
Reference in New Issue
Block a user