Map exec
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
module('platform')
|
module('platform')
|
||||||
module('input')
|
module('input')
|
||||||
module('scene')
|
module('scene')
|
||||||
|
module('map')
|
||||||
|
|
||||||
-- Default Input bindings.
|
-- Default Input bindings.
|
||||||
if PLATFORM == "psp" then
|
if PLATFORM == "psp" then
|
||||||
@@ -38,3 +39,4 @@ else
|
|||||||
end
|
end
|
||||||
|
|
||||||
sceneSet('map')
|
sceneSet('map')
|
||||||
|
mapLoad('map/testmap/testmap.dmf')
|
||||||
@@ -3,4 +3,4 @@
|
|||||||
# This software is released under the MIT License.
|
# This software is released under the MIT License.
|
||||||
# https://opensource.org/licenses/MIT
|
# 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",
|
.header = "DSF",
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||||
.custom = assetScriptHandler
|
.custom = assetScriptHandler
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "rpg/entity/entity.h"
|
#include "rpg/entity/entity.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
#include "script/scriptcontext.h"
|
||||||
|
|
||||||
map_t MAP;
|
map_t MAP;
|
||||||
|
|
||||||
@@ -44,6 +45,19 @@ errorret_t mapLoad(const char_t *path, const chunkpos_t position) {
|
|||||||
// Store the map file path
|
// Store the map file path
|
||||||
stringCopy(MAP.filePath, path, MAP_FILE_PATH_MAX);
|
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
|
// Reset map position
|
||||||
MAP.chunkPosition = position;
|
MAP.chunkPosition = position;
|
||||||
|
|
||||||
@@ -64,6 +78,18 @@ errorret_t mapLoad(const char_t *path, const chunkpos_t position) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute map script.
|
// 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();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,8 +209,8 @@ errorret_t mapChunkLoad(chunk_t* chunk) {
|
|||||||
memorySet(chunk->entities, 0xFF, sizeof(chunk->entities));
|
memorySet(chunk->entities, 0xFF, sizeof(chunk->entities));
|
||||||
|
|
||||||
// Get chunk filepath.
|
// Get chunk filepath.
|
||||||
snprintf(buffer, sizeof(buffer), "%s/%d_%d_%d.dcf",
|
snprintf(buffer, sizeof(buffer), "%s/chunks/%d_%d_%d.dcf",
|
||||||
MAP.filePath,
|
MAP.dirPath,
|
||||||
chunk->position.x,
|
chunk->position.x,
|
||||||
chunk->position.y,
|
chunk->position.y,
|
||||||
chunk->position.z
|
chunk->position.z
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
|
|
||||||
typedef struct map_s {
|
typedef struct map_s {
|
||||||
char_t filePath[MAP_FILE_PATH_MAX];
|
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 chunks[MAP_CHUNK_COUNT];
|
||||||
chunk_t *chunkOrder[MAP_CHUNK_COUNT];
|
chunk_t *chunkOrder[MAP_CHUNK_COUNT];
|
||||||
chunkpos_t chunkPosition;
|
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/moduleinput.h"
|
||||||
#include "script/module/moduleplatform.h"
|
#include "script/module/moduleplatform.h"
|
||||||
#include "script/module/modulescene.h"
|
#include "script/module/modulescene.h"
|
||||||
|
#include "script/module/modulemap.h"
|
||||||
|
|
||||||
const scriptmodule_t SCRIPT_MODULE_LIST[] = {
|
const scriptmodule_t SCRIPT_MODULE_LIST[] = {
|
||||||
{ .name = "system", .callback = moduleSystem },
|
{ .name = "system", .callback = moduleSystem },
|
||||||
{ .name = "input", .callback = moduleInput },
|
{ .name = "input", .callback = moduleInput },
|
||||||
{ .name = "platform", .callback = modulePlatform },
|
{ .name = "platform", .callback = modulePlatform },
|
||||||
{ .name = "scene", .callback = moduleScene },
|
{ .name = "scene", .callback = moduleScene },
|
||||||
|
{ .name = "map", .callback = moduleMapSystem },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCRIPT_MODULE_COUNT ( \
|
#define SCRIPT_MODULE_COUNT ( \
|
||||||
|
|||||||
@@ -57,6 +57,17 @@ char_t * stringToken(char_t *str, const char_t *delim) {
|
|||||||
return strtok(str, 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(
|
int32_t stringFormat(
|
||||||
char_t *dest,
|
char_t *dest,
|
||||||
const size_t destSize,
|
const size_t destSize,
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ void stringTrim(char_t *str);
|
|||||||
*/
|
*/
|
||||||
char_t * stringToken(char_t *str, const char_t *delim);
|
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.
|
* Formats a string.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -111,11 +111,11 @@ def processMap(asset):
|
|||||||
|
|
||||||
map = Map(None)
|
map = Map(None)
|
||||||
map.load(asset['path'])
|
map.load(asset['path'])
|
||||||
dir = map.getMapDirectory()
|
chunksDir = map.getChunkDirectory()
|
||||||
|
|
||||||
files = os.listdir(dir)
|
files = os.listdir(chunksDir)
|
||||||
if len(files) == 0:
|
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)
|
sys.exit(1)
|
||||||
|
|
||||||
chunkFiles = []
|
chunkFiles = []
|
||||||
@@ -133,21 +133,22 @@ def processMap(asset):
|
|||||||
result = processChunk(chunk)
|
result = processChunk(chunk)
|
||||||
chunkFiles.extend(result['files'])
|
chunkFiles.extend(result['files'])
|
||||||
|
|
||||||
outMap = {
|
# Map file
|
||||||
'files': chunkFiles
|
outBuffer = bytearray()
|
||||||
}
|
outBuffer.extend(b'DMF')
|
||||||
return assetCache(asset['path'], outMap)
|
outBuffer.extend(len(chunkFiles).to_bytes(4, 'little'))
|
||||||
|
|
||||||
# List files
|
# DMF (Dusk Map file)
|
||||||
chunkFiles = []
|
fileRelative = getAssetRelativePath(asset['path'])
|
||||||
for fileName in os.listdir(asset['path']):
|
fileNameWithoutExt = os.path.splitext(os.path.basename(fileRelative))[0]
|
||||||
if not fileName.endswith('.json'):
|
outputMapRelative = os.path.join(os.path.dirname(fileRelative), f"{fileNameWithoutExt}.dmf")
|
||||||
continue
|
outputMapPath = os.path.join(args.output_assets, outputMapRelative)
|
||||||
result = processChunk(os.path.join(asset['path'], fileName))
|
os.makedirs(os.path.dirname(outputMapPath), exist_ok=True)
|
||||||
chunkFiles.extend(result['files'])
|
with open(outputMapPath, "wb") as f:
|
||||||
|
f.write(outBuffer)
|
||||||
|
|
||||||
outMap = {
|
outMap = {
|
||||||
'files': chunkFiles
|
'files': chunkFiles
|
||||||
}
|
}
|
||||||
|
outMap['files'].append(outputMapPath)
|
||||||
return assetCache(asset['path'], outMap)
|
return assetCache(asset['path'], outMap)
|
||||||
@@ -131,12 +131,12 @@ class Chunk:
|
|||||||
return self.dirty
|
return self.dirty
|
||||||
|
|
||||||
def getFilename(self):
|
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
|
return None
|
||||||
dir_path = self.map.getMapDirectory()
|
dirPath = self.map.getChunkDirectory()
|
||||||
if dir_path is None:
|
if dirPath is None:
|
||||||
return 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):
|
def draw(self):
|
||||||
self.vertexBuffer.draw()
|
self.vertexBuffer.draw()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
import sys
|
||||||
from dusk.event import Event
|
from dusk.event import Event
|
||||||
from PyQt5.QtWidgets import QFileDialog, QMessageBox
|
from PyQt5.QtWidgets import QFileDialog, QMessageBox
|
||||||
from PyQt5.QtCore import QTimer
|
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
|
return self.mapFileName if self.mapFileName and os.path.exists(self.mapFileName) else None
|
||||||
|
|
||||||
def getMapDirectory(self):
|
def getMapDirectory(self):
|
||||||
fname = self.getMapFilename()
|
if self.mapFileName is None:
|
||||||
if not fname or not fname.endswith('.json'):
|
|
||||||
return 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):
|
def anyChunksDirty(self):
|
||||||
for chunk in self.chunks.values():
|
for chunk in self.chunks.values():
|
||||||
|
|||||||
Reference in New Issue
Block a user