Map exec
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
module('platform')
|
||||
module('input')
|
||||
module('scene')
|
||||
module('map')
|
||||
|
||||
-- Default Input bindings.
|
||||
if PLATFORM == "psp" then
|
||||
@@ -37,4 +38,5 @@ else
|
||||
end
|
||||
end
|
||||
|
||||
sceneSet('map')
|
||||
sceneSet('map')
|
||||
mapLoad('map/testmap/testmap.dmf')
|
||||
@@ -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)
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"mapName": "Test"
|
||||
}
|
||||
7
assets/map/testmap/CMakeLists.txt
Normal file
7
assets/map/testmap/CMakeLists.txt
Normal 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)
|
||||
3
assets/map/testmap/testmap.json
Normal file
3
assets/map/testmap/testmap.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "Test"
|
||||
}
|
||||
1
assets/map/testmap/testmap.lua
Normal file
1
assets/map/testmap/testmap.lua
Normal file
@@ -0,0 +1 @@
|
||||
print('Test Map Script Run')
|
||||
@@ -1 +1 @@
|
||||
print('map')
|
||||
-- Map Scene
|
||||
@@ -89,5 +89,5 @@ static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
||||
.header = "DSF",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||
.custom = assetScriptHandler
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
49
src/script/module/modulemap.h
Normal file
49
src/script/module/modulemap.h
Normal 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);
|
||||
}
|
||||
@@ -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 ( \
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
|
||||
# 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'])
|
||||
# Map file
|
||||
outBuffer = bytearray()
|
||||
outBuffer.extend(b'DMF')
|
||||
outBuffer.extend(len(chunkFiles).to_bytes(4, 'little'))
|
||||
|
||||
# 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)
|
||||
@@ -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()
|
||||
|
||||
@@ -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,11 +130,17 @@ 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():
|
||||
if chunk.isDirty():
|
||||
|
||||
Reference in New Issue
Block a user