Add exec command

This commit is contained in:
2025-09-07 23:24:21 -05:00
parent 3f37b7cdb5
commit e32d1f0900
16 changed files with 249 additions and 18 deletions

View File

@@ -6,5 +6,7 @@
add_asset(PALETTE first.palette.png)
add_asset(IMAGE font_minogram.png type=ALPHA)
add_asset(IMAGE entities.png type=PALETTIZED)
add_asset(CONFIG init.dcf)
add_asset(CONFIG test.dcf)
# add_asset(TILESET entities.tsx)

View File

@@ -1 +0,0 @@
bind w up;

3
assets/init.dcf Normal file
View File

@@ -0,0 +1,3 @@
echo "test1";
echo "test2";
exec "test";

1
assets/test.dcf Normal file
View File

@@ -0,0 +1 @@
echo "test file"

View File

@@ -15,9 +15,12 @@ assetdef_t ASSET_DEFINITIONS[ASSET_TYPE_COUNT] = {
[ASSET_TYPE_PALETTE_IMAGE] = {
"DPI", assetPaletteImageLoad, assetPaletteImageDispose
},
[ASSET_TYPE_ALPHA_IMAGE] = {
[ASSET_TYPE_ALPHA_IMAGE] = {
"DAI", assetAlphaImageLoad, assetAlphaImageDispose
},
[ASSET_TYPE_CONFIG] = {
"DCF", assetConfigLoad, assetConfigDispose
}
};
errorret_t assetInit(asset_t *asset, const char_t *filename) {
@@ -42,8 +45,6 @@ errorret_t assetInit(asset_t *asset, const char_t *filename) {
if(asset->file == NULL) errorThrow("Failed to open asset file: %s", filename);
zip_fclose(asset->file);
asset->file = NULL;
consolePrint("Initialized asset: %s", filename);
errorOk();
}

View File

@@ -12,6 +12,7 @@
#include "asset/type/assetpaletteimage.h"
#include "asset/type/assetalphaimage.h"
#include "asset/type/assetconfig.h"
#define ASSET_HEADER_SIZE 3
#define ASSET_REFERENCE_COUNT_MAX 8
@@ -31,6 +32,7 @@ typedef enum {
ASSET_TYPE_UNKNOWN,
ASSET_TYPE_PALETTE_IMAGE,
ASSET_TYPE_ALPHA_IMAGE,
ASSET_TYPE_CONFIG,
ASSET_TYPE_COUNT
} assettype_t;
@@ -46,6 +48,7 @@ typedef struct asset_s {
union {
assetpaletteimage_t paletteImage;
assetalphaimager_t alphaImage;
assetconfig_t config;
};
} asset_t;

View File

@@ -33,7 +33,6 @@ errorret_t assetManagerInit(void) {
// Try open
ASSET_MANAGER.zip = zip_open(searchPath, ZIP_RDONLY, NULL);
if(ASSET_MANAGER.zip == NULL) continue;
consolePrint("Opened asset file: %s", searchPath);
break;
}
@@ -51,7 +50,6 @@ void assetManagerUpdate(void) {
// Check if the asset is loaded
if(asset->file != NULL) {
asset->state = ASSET_STATE_LOADED;
consolePrint("Asset loaded: %s", asset->filename);
}
}
++asset;

View File

@@ -7,5 +7,6 @@
target_sources(${DUSK_TARGET_NAME}
PRIVATE
assetalphaimage.c
assetconfig.c
assetpaletteimage.c
)

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset/asset.h"
#include "console/console.h"
#include "assert/assert.h"
errorret_t assetConfigLoad(asset_t *asset) {
char_t buffer[CONSOLE_LINE_MAX + 1];
// Read byte by byte.
zip_int64_t bytesRead = 0;
zip_int64_t totalBytesRead = 0;
char_t c;
while(1) {
bytesRead = zip_fread(
asset->file,
&c,
1
);
if(bytesRead < 0) errorThrow("Failed to read from config asset file");
// Is byte execute?
if(c != ';' && c != '\n' && c != '\r' && bytesRead == 1) {
// Not execute, add to buffer.
buffer[totalBytesRead] = c;
if(++totalBytesRead >= CONSOLE_LINE_MAX) {
errorThrow("Config line too long!");
}
continue;
}
// Execute buffer.
buffer[totalBytesRead] = '\0';
consoleExec(buffer);
totalBytesRead = 0;
if(bytesRead == 0) break;
}
if(totalBytesRead > 0) {
// Execute remaining buffer.
buffer[totalBytesRead] = '\0';
consoleExec(buffer);
}
errorOk();
}
errorret_t assetConfigExecute(asset_t *asset) {
errorOk();
}
errorret_t assetConfigDispose(asset_t *asset) {
errorOk();
}

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
typedef struct asset_s asset_t;
typedef struct {
zip_int64_t pos;
zip_int64_t size;
} assetconfig_t;
/**
* Loads a config asset from the given asset structure. The asset must be of
* type ASSET_TYPE_CONFIG and must be loaded.
*
* @param asset The asset to load the config from.
* @return An error code.
*/
errorret_t assetConfigLoad(asset_t *asset);
/**
* Executes the config commands in the given asset. The asset must be of type
* ASSET_TYPE_CONFIG and must be loaded.
*
* @param asset The asset to execute the config from.
* @return An error code.
*/
errorret_t assetConfigExecute(asset_t *asset);
/**
* Disposes of a config asset, freeing any allocated resources.
*
* @param asset The asset to dispose of.
* @return An error code.
*/
errorret_t assetConfigDispose(asset_t *asset);

View File

@@ -9,10 +9,10 @@
#include "console/console.h"
void cmdEcho(const consolecmdexec_t *exec) {
assertTrue(
exec->argc >= 1,
"echo command requires 1 argument."
);
if(exec->argc < 1) {
consolePrint("Expected 1 argument: <message>");
return;
}
consolePrint("%s", exec->argv[0]);
}

50
src/console/cmd/cmdexec.h Normal file
View File

@@ -0,0 +1,50 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "console/console.h"
#include "asset/assetmanager.h"
void cmdExec(const consolecmdexec_t *exec) {
if(exec->argc < 1) {
consolePrint("Expected 1 argument: <filename>");
return;
}
char_t file[FILENAME_MAX];
stringCopy(file, exec->argv[0], FILENAME_MAX);
if(!stringEndsWith(file, ".dcf")) {
sprintf(
file,
"%s.dcf",
exec->argv[0]
);
}
ref_t ref;
asset_t asset;
errorret_t ret = assetInit(&asset, file);
if(ret.code != ERROR_OK) {
errorPrint(ret);
consolePrint("Failed to load asset %s", file);
return;
}
ret = assetLoad(&asset);
if(asset.type != ASSET_TYPE_CONFIG) {
consolePrint("Asset is not a config: %s", file);
assetDispose(&asset);
return;
}
assetDispose(&asset);
if(ret.code != ERROR_OK) {
errorPrint(ret);
consolePrint("Failed to load asset %s", file);
return;
}
}

View File

@@ -13,6 +13,7 @@
#include "console/cmd/cmdecho.h"
#include "console/cmd/cmdset.h"
#include "console/cmd/cmdget.h"
#include "console/cmd/cmdexec.h"
#include "input/input.h"
console_t CONSOLE;
@@ -25,6 +26,7 @@ void consoleInit() {
CONSOLE.cmdSet = consoleRegCmd("set", cmdSet);
consoleRegCmd("quit", cmdQuit);
consoleRegCmd("echo", cmdEcho);
consoleRegCmd("exec", cmdExec);
consolePrint(" = Dawn Console = ");
@@ -316,19 +318,36 @@ void consoleUpdate() {
CONSOLE.visible = !CONSOLE.visible;
}
// Exec pending buffer.
for(uint32_t i = 0; i < CONSOLE.execBufferCount; i++) {
consolecmdexec_t *exec = &CONSOLE.execBuffer[i];
assertNotNull(exec->cmd, "Command execution has no command.");
exec->cmd->function(exec);
// Anything to exec?
if(CONSOLE.execBufferCount == 0) {
#if CONSOLE_POSIX
threadMutexUnlock(&CONSOLE.execMutex);
#endif
return;
}
// Clear the exec buffer
CONSOLE.execBufferCount = 0;
// Copy the exec buffer, this allows exec command to work
consolecmdexec_t execBuffer[CONSOLE_EXEC_BUFFER_MAX];
uint32_t execBufferCount = CONSOLE.execBufferCount;
memoryCopy(
execBuffer,
CONSOLE.execBuffer,
sizeof(consolecmdexec_t) * execBufferCount
);
// Clear the exec buffer and unlock so new commands can be added while we
// process the current ones.
CONSOLE.execBufferCount = 0;
#if CONSOLE_POSIX
threadMutexUnlock(&CONSOLE.execMutex);
#endif
// Exec pending buffer.
for(uint32_t i = 0; i < execBufferCount; i++) {
consolecmdexec_t *exec = &execBuffer[i];
assertNotNull(exec->cmd, "Command execution has no command.");
exec->cmd->function(exec);
}
}
void consoleDispose(void) {

View File

@@ -16,6 +16,8 @@
engine_t ENGINE;
asset_t *outAsset;
ref_t outRef;
errorret_t engineInit(void) {
memoryZero(&ENGINE, sizeof(engine_t));
@@ -23,12 +25,14 @@ errorret_t engineInit(void) {
// Init systems. Order is important.
timeInit();
inputInit();
consoleInit();
inputInit();
errorChain(assetManagerInit());
errorChain(displayInit());
rpgInit();
consoleExec("exec init.dcf");
errorOk();
}

View File

@@ -2,6 +2,7 @@ import sys
# from processtileset import processTileset
from processimage import processImage
from processpalette import processPalette
from processconfig import processConfig
processedAssets = []
@@ -17,6 +18,8 @@ def processAsset(asset):
return processPalette(asset)
elif t == 'image':
return processImage(asset)
elif t == 'config':
return processConfig(asset)
# elif t == 'tileset':
# return processTileset(asset)
else:

View File

@@ -0,0 +1,44 @@
import os
import sys
from args import args
from assethelpers import getAssetRelativePath
def processConfig(asset):
assetPath = asset['path']
print(f"Processing config: {assetPath}")
# Takes each line, seperates it by either semicolon or newline,
# trims whitespace. Then outputs it to a file.
with open(assetPath, "r") as f:
lines = f.read().replace('\r', '').split('\n')
commands = []
for line in lines:
lineCommands = line.split(';')
for command in lineCommands:
command = command.strip()
if command != '':
commands.append(command)
data = bytearray()
data.extend(b"DCF") # Dusk Config File
for command in commands:
# Convert to string and seperate each command with semicolon
data.extend(command.encode('utf-8'))
data.append(0x3B) # Semicolon
if len(commands) > 0:
data.pop() # Remove last semicolon
relative = getAssetRelativePath(assetPath)
fileNameWithoutExt = os.path.splitext(os.path.basename(assetPath))[0]
outputFileRelative = os.path.join(os.path.dirname(relative), f"{fileNameWithoutExt}.dcf")
outputFilePath = os.path.join(args.output_assets, outputFileRelative)
os.makedirs(os.path.dirname(outputFilePath), exist_ok=True)
with open(outputFilePath, "wb") as f:
f.write(data)
outConfig = {
"files": [ outputFilePath ],
}
return outConfig