Map exec
Some checks failed
Build Dusk / build-linux (push) Successful in 1m40s
Build Dusk / build-psp (push) Failing after 1m38s

This commit is contained in:
2025-12-26 20:38:24 +10:00
parent 7940f4c487
commit 726233e55f
29 changed files with 152 additions and 33 deletions

View File

@@ -1,6 +1,7 @@
module('platform')
module('input')
module('scene')
module('map')
-- Default Input bindings.
if PLATFORM == "psp" then
@@ -38,3 +39,4 @@ else
end
sceneSet('map')
mapLoad('map/testmap/testmap.dmf')

View File

@@ -3,4 +3,4 @@
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
add_asset(MAP map.json)
add_subdirectory(testmap)

View File

@@ -1,3 +0,0 @@
{
"mapName": "Test"
}

View File

@@ -0,0 +1,7 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
add_asset(MAP testmap.json)
add_asset(SCRIPT testmap.lua)

View File

@@ -0,0 +1,3 @@
{
"name": "Test"
}

View File

@@ -0,0 +1 @@
print('Test Map Script Run')

View File

@@ -1 +1 @@
print('map')
-- Map Scene

View File

@@ -89,5 +89,5 @@ static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
.header = "DSF",
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
.custom = assetScriptHandler
}
},
};

View File

@@ -11,6 +11,7 @@
#include "asset/asset.h"
#include "rpg/entity/entity.h"
#include "util/string.h"
#include "script/scriptcontext.h"
map_t MAP;
@@ -44,6 +45,19 @@ errorret_t mapLoad(const char_t *path, const chunkpos_t position) {
// 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
// Reset map position
MAP.chunkPosition = position;
@@ -64,6 +78,18 @@ errorret_t mapLoad(const char_t *path, const chunkpos_t position) {
}
// Execute map script.
char_t scriptPath[MAP_FILE_PATH_MAX + 16];
stringFormat(
scriptPath, sizeof(scriptPath), "%s/%s.dsf",
MAP.dirPath, MAP.fileName
);
if(assetFileExists(scriptPath)) {
scriptcontext_t ctx;
errorChain(scriptContextInit(&ctx));
errorChain(scriptContextExecFile(&ctx, scriptPath));
scriptContextDispose(&ctx);
}
errorOk();
}
@@ -183,8 +209,8 @@ errorret_t mapChunkLoad(chunk_t* chunk) {
memorySet(chunk->entities, 0xFF, sizeof(chunk->entities));
// Get chunk filepath.
snprintf(buffer, sizeof(buffer), "%s/%d_%d_%d.dcf",
MAP.filePath,
snprintf(buffer, sizeof(buffer), "%s/chunks/%d_%d_%d.dcf",
MAP.dirPath,
chunk->position.x,
chunk->position.y,
chunk->position.z

View File

@@ -12,6 +12,9 @@
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];
chunk_t chunks[MAP_CHUNK_COUNT];
chunk_t *chunkOrder[MAP_CHUNK_COUNT];
chunkpos_t chunkPosition;

View File

@@ -0,0 +1,49 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/scriptcontext.h"
#include "debug/debug.h"
#include "assert/assert.h"
#include "rpg/world/map.h"
int32_t moduleMapLoad(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
if(!lua_isstring(L, 1)) {
luaL_error(L, "Expected string map filename");
return 0;
}
// Potentially provide up to 3 params
chunkpos_t initial = { .x = 0, .y = 0, .z = 0 };
if(lua_isnumber(L, 2)) {
initial.x = (chunkunit_t)luaL_checkinteger(L, 2);
}
if(lua_isnumber(L, 3)) {
initial.y = (chunkunit_t)luaL_checkinteger(L, 3);
}
if(lua_isnumber(L, 4)) {
initial.z = (chunkunit_t)luaL_checkinteger(L, 4);
}
// Load the map.
errorret_t ret = mapLoad(luaL_checkstring(L, 1), initial);
if(ret.code != ERROR_OK) {
luaL_error(L, "Failed to load map");
errorCatch(errorPrint(ret));
return 0;
}
return 0;
}
void moduleMapSystem(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL");
scriptContextRegFunc(context, "mapLoad", moduleMapLoad);
}

View File

@@ -10,12 +10,14 @@
#include "script/module/moduleinput.h"
#include "script/module/moduleplatform.h"
#include "script/module/modulescene.h"
#include "script/module/modulemap.h"
const scriptmodule_t SCRIPT_MODULE_LIST[] = {
{ .name = "system", .callback = moduleSystem },
{ .name = "input", .callback = moduleInput },
{ .name = "platform", .callback = modulePlatform },
{ .name = "scene", .callback = moduleScene },
{ .name = "map", .callback = moduleMapSystem },
};
#define SCRIPT_MODULE_COUNT ( \

View File

@@ -57,6 +57,17 @@ char_t * stringToken(char_t *str, const char_t *delim) {
return strtok(str, delim);
}
char_t * stringFindLastChar(const char_t *str, const char_t c) {
assertNotNull(str, "str must not be NULL");
char_t *last = NULL;
for(const char_t *p = str; *p != '\0'; p++) {
if(*p == c) {
last = (char_t *)p;
}
}
return last;
}
int32_t stringFormat(
char_t *dest,
const size_t destSize,

View File

@@ -64,6 +64,16 @@ void stringTrim(char_t *str);
*/
char_t * stringToken(char_t *str, const char_t *delim);
/**
* Finds the last occurrence of a character in a string.
*
* @param str The string to search.
* @param c The character to find.
* @return A pointer to the last occurrence of the character in the string, or
* NULL if not found.
*/
char_t * stringFindLastChar(const char_t *str, const char_t c);
/**
* Formats a string.
*

View File

@@ -111,11 +111,11 @@ def processMap(asset):
map = Map(None)
map.load(asset['path'])
dir = map.getMapDirectory()
chunksDir = map.getChunkDirectory()
files = os.listdir(dir)
files = os.listdir(chunksDir)
if len(files) == 0:
print(f"Error: No chunk files found in map directory {dir}.")
print(f"Error: No chunk files found in {chunksDir}.")
sys.exit(1)
chunkFiles = []
@@ -133,21 +133,22 @@ def processMap(asset):
result = processChunk(chunk)
chunkFiles.extend(result['files'])
outMap = {
'files': chunkFiles
}
return assetCache(asset['path'], outMap)
# Map file
outBuffer = bytearray()
outBuffer.extend(b'DMF')
outBuffer.extend(len(chunkFiles).to_bytes(4, 'little'))
# List files
chunkFiles = []
for fileName in os.listdir(asset['path']):
if not fileName.endswith('.json'):
continue
result = processChunk(os.path.join(asset['path'], fileName))
chunkFiles.extend(result['files'])
# DMF (Dusk Map file)
fileRelative = getAssetRelativePath(asset['path'])
fileNameWithoutExt = os.path.splitext(os.path.basename(fileRelative))[0]
outputMapRelative = os.path.join(os.path.dirname(fileRelative), f"{fileNameWithoutExt}.dmf")
outputMapPath = os.path.join(args.output_assets, outputMapRelative)
os.makedirs(os.path.dirname(outputMapPath), exist_ok=True)
with open(outputMapPath, "wb") as f:
f.write(outBuffer)
outMap = {
'files': chunkFiles
}
outMap['files'].append(outputMapPath)
return assetCache(asset['path'], outMap)

View File

@@ -131,12 +131,12 @@ class Chunk:
return self.dirty
def getFilename(self):
if not self.map or not hasattr(self.map, 'getMapDirectory'):
if not self.map or not hasattr(self.map, 'getChunkDirectory'):
return None
dir_path = self.map.getMapDirectory()
if dir_path is None:
dirPath = self.map.getChunkDirectory()
if dirPath is None:
return None
return f"{dir_path}/{self.x}_{self.y}_{self.z}.json"
return f"{dirPath}/{self.x}_{self.y}_{self.z}.json"
def draw(self):
self.vertexBuffer.draw()

View File

@@ -1,4 +1,5 @@
import json
import sys
from dusk.event import Event
from PyQt5.QtWidgets import QFileDialog, QMessageBox
from PyQt5.QtCore import QTimer
@@ -129,10 +130,16 @@ class Map:
return self.mapFileName if self.mapFileName and os.path.exists(self.mapFileName) else None
def getMapDirectory(self):
fname = self.getMapFilename()
if not fname or not fname.endswith('.json'):
if self.mapFileName is None:
return None
return fname[:-5] # Remove '.json' extension
dirname = os.path.dirname(self.mapFileName)
return dirname
def getChunkDirectory(self):
dirName = self.getMapDirectory()
if dirName is None:
return None
return os.path.join(dirName, 'chunks')
def anyChunksDirty(self):
for chunk in self.chunks.values():