From 24eab84f4fabf68706bc4f5783ec57a2d2a828ad Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Mon, 23 Jun 2025 22:23:18 -0500 Subject: [PATCH] Update parsers to use more real C data. --- data/map project.tiled-project | 15 +++++++++++++++ data/map project.tiled-session | 2 +- data/map.tmj | 4 ++-- data/overworld.tsx | 2 +- src/dusk/entity/entity.c | 26 +++++++++++++++++--------- src/dusk/entity/entity.h | 8 ++++---- src/dusk/entity/npc.c | 6 ++++-- src/dusk/entity/npc.h | 3 ++- src/dusk/entity/player.c | 18 +++++++++++------- src/dusk/entity/player.h | 7 ++++--- src/dusk/world/chunk.c | 13 +++---------- src/dusk/world/chunkdata.h | 9 +-------- tools/mapcompile/entityParser.py | 5 +++-- tools/mapcompile/helper.py | 2 +- tools/mapcompile/mapParser.py | 4 ++++ tools/mapcompile/mapcompile.py | 9 ++++++--- tools/tilecompile/tilecompile.py | 9 ++++++--- 17 files changed, 85 insertions(+), 57 deletions(-) diff --git a/data/map project.tiled-project b/data/map project.tiled-project index 597da78..bf2dde3 100644 --- a/data/map project.tiled-project +++ b/data/map project.tiled-project @@ -22,6 +22,21 @@ "NPC_INTERACT_TYPE_EVENT" ], "valuesAsFlags": false + }, + { + "id": 2, + "name": "tileSolidType", + "storageType": "string", + "type": "enum", + "values": [ + "TILE_SOLID_NONE", + "TILE_SOLID_FULL", + "TILE_SOLID_TRIANGLE_TOP_RIGHT", + "TILE_SOLID_TRIANGLE_TOP_LEFT", + "TILE_SOLID_TRIANGLE_BOTTOM_RIGHT", + "TILE_SOLID_TRIANGLE_BOTTOM_LEFT" + ], + "valuesAsFlags": false } ] } diff --git a/data/map project.tiled-session b/data/map project.tiled-session index 91a7991..d145a65 100644 --- a/data/map project.tiled-session +++ b/data/map project.tiled-session @@ -36,7 +36,7 @@ "map.tmj" ], "project": "map project.tiled-project", - "property.type": "string", + "property.type": "tileSolidType", "recentFiles": [ "map.tmj", "minogram.tsx", diff --git a/data/map.tmj b/data/map.tmj index 27e0de4..9a48a55 100644 --- a/data/map.tmj +++ b/data/map.tmj @@ -437,8 +437,8 @@ "value":"NPC_INTERACT_TYPE_TEXT" }], "template":"templates\/NPC.tx", - "x":6575, - "y":6837.33333333333 + "x":6575.625, + "y":6816.33333333333 }], "opacity":1, "type":"objectgroup", diff --git a/data/overworld.tsx b/data/overworld.tsx index eb6d93e..4ddc6bb 100644 --- a/data/overworld.tsx +++ b/data/overworld.tsx @@ -13,7 +13,7 @@ - + diff --git a/src/dusk/entity/entity.c b/src/dusk/entity/entity.c index f4eed01..16d3d9b 100644 --- a/src/dusk/entity/entity.c +++ b/src/dusk/entity/entity.c @@ -17,29 +17,37 @@ entity_t ENTITIES[ENTITY_COUNT_MAX] = {0}; entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT] = { {NULL}, // ENTITY_TYPE_NULL { - .init = playerNPCInit, - .update = playerNPCUpdate, + .load = playerEntityLoad, + .update = playerEntityUpdate, }, { - .init = npcInit, + .load = npcLoad, .update = npcUpdate, .interact = npcInteract, }, }; -void entityInit(entity_t *entity, const entitytype_t type) { +void entityLoad(entity_t *entity, const entity_t *source) { assertNotNull(entity, "Entity pointer cannot be NULL"); - assertTrue(type != ENTITY_TYPE_NULL, "Entity type NULL"); - assertTrue(type < ENTITY_TYPE_COUNT, "Entity type out of bounds"); + assertNotNull(source, "Source entity pointer cannot be NULL"); + assertTrue(source->type != ENTITY_TYPE_NULL, "Source entity type NULL"); + assertTrue(source->type < ENTITY_TYPE_COUNT, "Source entity type bad"); assertNotNull( - ENTITY_CALLBACKS[type].init, + ENTITY_CALLBACKS[source->type].load, "Entity type has no i nit callback" ); memoryZero(entity, sizeof(entity_t)); - entity->type = type; - ENTITY_CALLBACKS[type].init(entity); + entity->type = source->type; + entity->x = source->x; + entity->y = source->y; + entity->vx = source->vx; + entity->vy = source->vy; + entity->dir = source->dir; + entity->id = source->id; + + ENTITY_CALLBACKS[entity->type].load(entity, source); } void entityUpdate(entity_t *entity) { diff --git a/src/dusk/entity/entity.h b/src/dusk/entity/entity.h index 28ba757..a9d2ffc 100644 --- a/src/dusk/entity/entity.h +++ b/src/dusk/entity/entity.h @@ -45,7 +45,7 @@ typedef struct _entity_t { } entity_t; typedef struct { - void (*init) (entity_t *entity); + void (*load) (entity_t *entity, const entity_t *source); void (*update) (entity_t *entity); void (*interact)(entity_t *player, entity_t *self); } entitycallback_t; @@ -54,12 +54,12 @@ extern entity_t ENTITIES[ENTITY_COUNT_MAX]; extern entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT]; /** - * Initializes an entity with the given type. + * Loads an entity from the generated entity data. * * @param entity Pointer to the entity to initialize. - * @param type The type of the entity to initialize. + * @param source Pointer to the source entity data. */ -void entityInit(entity_t *entity, const entitytype_t type); +void entityLoad(entity_t *entity, const entity_t *source); /** * Updates the entity's state. diff --git a/src/dusk/entity/npc.c b/src/dusk/entity/npc.c index 88f32a2..ccb8ac0 100644 --- a/src/dusk/entity/npc.c +++ b/src/dusk/entity/npc.c @@ -10,8 +10,10 @@ #include "locale/language.h" #include "assert/assert.h" -void npcInit(entity_t *entity) { - +void npcLoad(entity_t *entity, const entity_t *source) { + assertNotNull(entity, "Entity pointer cannot be NULL"); + assertNotNull(source, "Source entity pointer cannot be NULL"); + assertTrue(source->type == ENTITY_TYPE_NPC, "Source entity type must be NPC"); } void npcUpdate(entity_t *entity) { diff --git a/src/dusk/entity/npc.h b/src/dusk/entity/npc.h index cbc22de..0bb41a7 100644 --- a/src/dusk/entity/npc.h +++ b/src/dusk/entity/npc.h @@ -25,8 +25,9 @@ typedef struct { * Initializes the NPC entity. * * @param entity The entity to initialize. + * @param source The source entity to copy data from. */ -void npcInit(entity_t *entity); +void npcLoad(entity_t *entity, const entity_t *source); /** * Updates the NPC entity. diff --git a/src/dusk/entity/player.c b/src/dusk/entity/player.c index e79654f..b5c59be 100644 --- a/src/dusk/entity/player.c +++ b/src/dusk/entity/player.c @@ -19,21 +19,25 @@ inventory_t PLAYER_INVENTORY; void playerInit() { entity_t *ent = &ENTITIES[0]; - entityInit(ent, ENTITY_TYPE_PLAYER); - ent->id = PLAYER_ENTITY_ID; - - ent->x = WORLD_PLAYER_SPAWN_X; - ent->y = WORLD_PLAYER_SPAWN_Y; + entity_t playerEntityData = { + .id = PLAYER_ENTITY_ID, + .type = ENTITY_TYPE_PLAYER, + .x = WORLD_PLAYER_SPAWN_X, + .y = WORLD_PLAYER_SPAWN_Y, + }; + entityLoad(ent, &playerEntityData); inventoryInit(&PLAYER_INVENTORY, INVENTORY_SIZE_MAX); } -void playerNPCInit(entity_t *entity) { +void playerEntityLoad(entity_t *entity, const entity_t *source) { assertNotNull(entity, "Entity pointer cannot be NULL"); + assertNotNull(source, "Source entity pointer cannot be NULL"); assertTrue(entity->type == ENTITY_TYPE_PLAYER, "Entity type must be PLAYER"); + assertTrue(source->type == entity->type, "Source/Entity type mismatch"); } -void playerNPCUpdate(entity_t *entity) { +void playerEntityUpdate(entity_t *entity) { assertNotNull(entity, "Entity pointer cannot be NULL"); assertTrue(entity->type == ENTITY_TYPE_PLAYER, "Entity type must be PLAYER"); diff --git a/src/dusk/entity/player.h b/src/dusk/entity/player.h index b416bf4..2f30ced 100644 --- a/src/dusk/entity/player.h +++ b/src/dusk/entity/player.h @@ -32,15 +32,16 @@ extern inventory_t PLAYER_INVENTORY; void playerInit(void); /** - * Initializes the player entity. + * Loads the player entity. * * @param entity The entity to initialize. + * @param source The source entity to copy data from. */ -void playerNPCInit(entity_t *entity); +void playerEntityLoad(entity_t *entity, const entity_t *source); /** * Updates the player entity. * * @param entity The entity to update. */ -void playerNPCUpdate(entity_t *entity); \ No newline at end of file +void playerEntityUpdate(entity_t *entity); \ No newline at end of file diff --git a/src/dusk/world/chunk.c b/src/dusk/world/chunk.c index 4bf7e6b..47abf71 100644 --- a/src/dusk/world/chunk.c +++ b/src/dusk/world/chunk.c @@ -222,7 +222,7 @@ void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) { ); // Load chunk entities - const chunkentity_t *data; + const entity_t *data; entity_t *entity; data = chunkData->entities; while(data < chunkData->entities + CHUNK_ENTITY_COUNT_MAX) { @@ -257,15 +257,8 @@ void chunkLoad(chunk_t *chunk, const uint16_t x, const uint16_t y) { entity++; }; - // Initialize this entity. - entityInit(entity, data->type); - entity->id = data->id; - - // Positions are chunk-relative. - entity->x = fx248Fromu32((chunk->x * CHUNK_WIDTH * TILE_WIDTH_HEIGHT) + data->x); - entity->y = fx248Fromu32((chunk->y * CHUNK_HEIGHT * TILE_WIDTH_HEIGHT)+data->y); - - // Next entity + // Load this entity. + entityLoad(entity, data); data++; } } diff --git a/src/dusk/world/chunkdata.h b/src/dusk/world/chunkdata.h index 42b054c..ecd2c31 100644 --- a/src/dusk/world/chunkdata.h +++ b/src/dusk/world/chunkdata.h @@ -9,15 +9,8 @@ #include "chunk.h" #include "entity/entity.h" -typedef struct { - uint32_t id; - entitytype_t type; - uint8_t x, y; - entitydir_t dir; -} chunkentity_t; - typedef struct { uint8_t layerBase[CHUNK_TILE_COUNT]; uint8_t layerBaseOverlay[CHUNK_TILE_COUNT]; - chunkentity_t entities[CHUNK_ENTITY_COUNT_MAX]; + entity_t entities[CHUNK_ENTITY_COUNT_MAX]; } chunkdata_t; \ No newline at end of file diff --git a/tools/mapcompile/entityParser.py b/tools/mapcompile/entityParser.py index 9124811..749fa9c 100644 --- a/tools/mapcompile/entityParser.py +++ b/tools/mapcompile/entityParser.py @@ -1,11 +1,12 @@ from constants import TILE_WIDTH_HEIGHT, ENTITY_TYPE_MAP +from helper import floatToFixed248 def parseEntity(obj, chunkData): if 'type' in obj and obj['type'] not in ENTITY_TYPE_MAP: return None - obj['localX'] = round(obj['x'] - (chunkData['topLeftTileX'] * TILE_WIDTH_HEIGHT)) - obj['localY'] = round(obj['y'] - (chunkData['topLeftTileY'] * TILE_WIDTH_HEIGHT)) + obj['localX'] = obj['x'] - (chunkData['topLeftTileX'] * TILE_WIDTH_HEIGHT) + obj['localY'] = obj['y'] - (chunkData['topLeftTileY'] * TILE_WIDTH_HEIGHT) obj['dir'] = 'ENTITY_DIR_SOUTH' obj['type'] = 'ENTITY_TYPE_NPC' diff --git a/tools/mapcompile/helper.py b/tools/mapcompile/helper.py index dcffc6a..be93631 100644 --- a/tools/mapcompile/helper.py +++ b/tools/mapcompile/helper.py @@ -2,4 +2,4 @@ def floatToFixed248(value): # Converts a float to the fixed248_t used internally. high24 = int(value) & 0xFFFFFF low8 = int((value * 256.0 - high24) * 256.0) & 0xFF - return (high24 << 8) | low8 \ No newline at end of file + return f'((fixed248_t){(high24 << 8) | low8})' \ No newline at end of file diff --git a/tools/mapcompile/mapParser.py b/tools/mapcompile/mapParser.py index 069b86f..d074d78 100644 --- a/tools/mapcompile/mapParser.py +++ b/tools/mapcompile/mapParser.py @@ -121,6 +121,10 @@ def parseMap(data): print(f"Error: Object in object layer does not contain 'x' or 'y' key.") sys.exit(1) + if 'id' not in ob: + print(f"Error: Object in object layer does not contain 'id' key.") + sys.exit(1) + ob['x'] -= mapData['inputMapLowestX'] * TILE_WIDTH_HEIGHT ob['y'] -= mapData['inputMapLowestY'] * TILE_WIDTH_HEIGHT diff --git a/tools/mapcompile/mapcompile.py b/tools/mapcompile/mapcompile.py index 87f98b2..c6817f2 100644 --- a/tools/mapcompile/mapcompile.py +++ b/tools/mapcompile/mapcompile.py @@ -83,9 +83,12 @@ for chunkY in range(mapData['mapHeightInRealChunks']): f.write(" {\n") f.write(f" .id = {entity['id']},\n") f.write(f" .type = {entity['type']},\n") - f.write(f" .x = {entity['localX']},\n") - f.write(f" .y = {entity['localY']},\n") - f.write(f" .dir = {entity['dir']},\n") + f.write(f" .x = {floatToFixed248(entity['x'])},\n") + f.write(f" .y = {floatToFixed248(entity['y'])},\n") + + if 'dir' in entity: + f.write(f" .dir = {entity['dir']},\n") + f.write(" },\n") f.write(f" }},\n") diff --git a/tools/tilecompile/tilecompile.py b/tools/tilecompile/tilecompile.py index e614210..01270ed 100644 --- a/tools/tilecompile/tilecompile.py +++ b/tools/tilecompile/tilecompile.py @@ -91,14 +91,17 @@ with open(headerFile, 'w') as f: def findProp(name, expectedType=''): for prop in properties.findall('property'): if prop.get('name') == name: - if len(expectedType) > 0 and prop.get('type') != expectedType: - continue + if len(expectedType) > 0: + if 'type' in prop.attrib and prop.get('type') != expectedType: + continue + if 'propertytype' in prop.attrib and prop.get('propertytype') != expectedType: + continue return prop.get('value', '') return None f.write(f" {{\n") - propSolid = findProp('solid', 'int') + propSolid = findProp('solidType', 'tileSolidType') if propSolid is not None: f.write(f" .solidType = {propSolid},\n")