Test loading asset data.
This commit is contained in:
@ -34,9 +34,6 @@ project(Dawn
|
|||||||
# Add tools
|
# Add tools
|
||||||
add_subdirectory(tools)
|
add_subdirectory(tools)
|
||||||
|
|
||||||
# Add assets
|
|
||||||
add_subdirectory(assets)
|
|
||||||
|
|
||||||
# Add Libraries
|
# Add Libraries
|
||||||
add_subdirectory(lib)
|
add_subdirectory(lib)
|
||||||
|
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
# Copyright (c) 2024 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
tool_copy(
|
|
||||||
testmap
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/testmap.json
|
|
||||||
testmap.json
|
|
||||||
)
|
|
@ -4,10 +4,10 @@
|
|||||||
"layers": [
|
"layers": [
|
||||||
{
|
{
|
||||||
"tiles": [
|
"tiles": [
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
1, 1, 1, 2, 1, 1, 1, 1, 1, 1,
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
1, 1, 1, 2, 1, 1, 1, 1, 1, 1,
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
1, 1, 1, 2, 1, 1, 1, 1, 1, 1,
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
1, 1, 1, 2, 1, 1, 1, 1, 1, 1,
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
@ -30,4 +30,6 @@ target_sources(${DAWN_TARGET_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Assets
|
# Assets
|
||||||
add_dependencies(${DAWN_TARGET_NAME} dawnassets)
|
tool_copy(testmap testmap.json)
|
||||||
|
|
||||||
|
add_dependencies(${DAWN_TARGET_NAME} dawnassets)
|
||||||
|
@ -8,4 +8,6 @@ target_sources(${DAWN_TARGET_NAME}
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
asset.c
|
asset.c
|
||||||
assetarchive.c
|
assetarchive.c
|
||||||
|
assetjson.c
|
||||||
|
assetmap.c
|
||||||
)
|
)
|
@ -93,16 +93,17 @@ size_t assetGetSize() {
|
|||||||
|
|
||||||
size_t n = archive_entry_size(ASSET_ENTRY);
|
size_t n = archive_entry_size(ASSET_ENTRY);
|
||||||
|
|
||||||
char_t path[2048];
|
// Remnant when get size was doing some incorrect stuff.
|
||||||
sprintf(
|
// char_t path[2048];
|
||||||
path, "/home/yourwishes/htdocs/dusk/build/assets/%s", ASSET_PATH_CURRENT
|
// sprintf(
|
||||||
);
|
// path, "/home/yourwishes/htdocs/dusk/build/assets/%s", ASSET_PATH_CURRENT
|
||||||
FILE *temp = fopen(path, "rb");
|
// );
|
||||||
assertNotNull(temp, "assetGetSize: Failed to open temp file!");
|
// FILE *temp = fopen(path, "rb");
|
||||||
fseek(temp, 0, SEEK_END);
|
// assertNotNull(temp, "assetGetSize: Failed to open temp file!");
|
||||||
size_t size = ftell(temp);
|
// fseek(temp, 0, SEEK_END);
|
||||||
assertTrue(size == n, "assetGetSize: Size is not equal!");
|
// size_t size = ftell(temp);
|
||||||
fclose(temp);
|
// assertTrue(size == n, "assetGetSize: Size is not equal!");
|
||||||
|
// fclose(temp);
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
551
src/dawn/asset/assetjson.c
Normal file
551
src/dawn/asset/assetjson.c
Normal file
@ -0,0 +1,551 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2024 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "assetjson.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
size_t assetJsonParse(const char_t *json, assetjson_t **out) {
|
||||||
|
size_t offset = assetJsonParseSub(json, out);
|
||||||
|
|
||||||
|
// We only expect whitespace or EOF here
|
||||||
|
char_t c;
|
||||||
|
do {
|
||||||
|
c = json[offset];
|
||||||
|
if(c == '\0') break;
|
||||||
|
if(c == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||||
|
offset++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assertUnreachable("Unexpected character found after JSON data.");
|
||||||
|
} while(true);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t assetJsonParseSub(
|
||||||
|
const char_t *json,
|
||||||
|
assetjson_t **out
|
||||||
|
) {
|
||||||
|
size_t offset = 0;
|
||||||
|
char_t c;
|
||||||
|
|
||||||
|
// Skip whitespace
|
||||||
|
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||||
|
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read first character
|
||||||
|
c = json[offset];
|
||||||
|
|
||||||
|
switch(c) {
|
||||||
|
case '{':
|
||||||
|
offset += assetJsonParseAsObject(json + offset, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
offset += assetJsonParseAsArray(json + offset, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
offset += assetJsonParseAsString(json + offset, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
case '0' ... '9':
|
||||||
|
case '.':
|
||||||
|
offset += assetJsonParseAsNumber(json + offset, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
case 'f':
|
||||||
|
offset += assetJsonParseAsBoolean(json + offset, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
offset += assetJsonParseAsNull(json + offset, out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assertUnreachable("Invalid JSON data type found.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t assetJsonParseAsNull(
|
||||||
|
const char_t *json,
|
||||||
|
assetjson_t **out
|
||||||
|
) {
|
||||||
|
assetjson_t *obj = malloc(sizeof(assetjson_t));
|
||||||
|
// Read "null"
|
||||||
|
assertTrue(json[0] == 'n', "Expected NULL data type. (n0)");
|
||||||
|
assertTrue(json[1] == 'u', "Expected NULL data type. (u0)");
|
||||||
|
assertTrue(json[2] == 'l', "Expected NULL data type. (l0)");
|
||||||
|
assertTrue(json[3] == 'l', "Expected NULL data type. (l1)");
|
||||||
|
|
||||||
|
obj->type = ASSET_JSON_DATA_TYPE_NULL;
|
||||||
|
|
||||||
|
*out = obj;
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t assetJsonParseAsBoolean(
|
||||||
|
const char_t *json,
|
||||||
|
assetjson_t **out
|
||||||
|
) {
|
||||||
|
assetjson_t *obj = malloc(sizeof(assetjson_t));
|
||||||
|
|
||||||
|
obj->type = ASSET_JSON_DATA_TYPE_BOOLEAN;
|
||||||
|
*out = obj;
|
||||||
|
|
||||||
|
if(json[0] == 't') {
|
||||||
|
// Read "true"
|
||||||
|
assertTrue(json[0] == 't', "Expected TRUE data type. (t0)");
|
||||||
|
assertTrue(json[1] == 'r', "Expected TRUE data type. (r0)");
|
||||||
|
assertTrue(json[2] == 'u', "Expected TRUE data type. (u0)");
|
||||||
|
assertTrue(json[3] == 'e', "Expected TRUE data type. (e0)");
|
||||||
|
obj->boolean = true;
|
||||||
|
return 4;
|
||||||
|
} else {
|
||||||
|
// Read "false"
|
||||||
|
assertTrue(json[0] == 'f', "Expected FALSE data type. (f0)");
|
||||||
|
assertTrue(json[1] == 'a', "Expected FALSE data type. (a0)");
|
||||||
|
assertTrue(json[2] == 'l', "Expected FALSE data type. (l0)");
|
||||||
|
assertTrue(json[3] == 's', "Expected FALSE data type. (s0)");
|
||||||
|
assertTrue(json[4] == 'e', "Expected FALSE data type. (e0)");
|
||||||
|
obj->boolean = false;
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t assetJsonParseAsString(
|
||||||
|
const char_t *json,
|
||||||
|
assetjson_t **out
|
||||||
|
) {
|
||||||
|
assetjson_t *obj = malloc(sizeof(assetjson_t));
|
||||||
|
|
||||||
|
obj->type = ASSET_JSON_DATA_TYPE_STRING;
|
||||||
|
|
||||||
|
// For each char
|
||||||
|
size_t offset = 1;// Skip opening quote
|
||||||
|
size_t outOffset = 0;
|
||||||
|
char c;
|
||||||
|
bool_t inEscape = false;
|
||||||
|
size_t bufferSize = 2;
|
||||||
|
char_t *string = (char_t*)malloc(bufferSize * sizeof(char_t));
|
||||||
|
while(true) {
|
||||||
|
c = json[offset];
|
||||||
|
if(c == '\0') assertUnreachable("Unexpected end of string.");
|
||||||
|
if(inEscape) {
|
||||||
|
inEscape = false;
|
||||||
|
switch(c) {
|
||||||
|
case 'n':
|
||||||
|
c = '\n';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
c = '\r';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
c = '\t';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
c = '\b';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
c = '\f';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
assertUnreachable("Unicode escape sequences are not supported.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(outOffset >= bufferSize) {
|
||||||
|
bufferSize *= 2;
|
||||||
|
string = realloc(string, bufferSize * sizeof(char_t));
|
||||||
|
}
|
||||||
|
string[outOffset] = c;
|
||||||
|
offset++;
|
||||||
|
outOffset++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(c == '\\') {
|
||||||
|
inEscape = true;
|
||||||
|
offset++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(c == '"') break;
|
||||||
|
if(outOffset >= bufferSize) {
|
||||||
|
bufferSize *= 2;
|
||||||
|
string = realloc(string, bufferSize * sizeof(char_t));
|
||||||
|
}
|
||||||
|
string[outOffset] = c;
|
||||||
|
offset++;
|
||||||
|
outOffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[outOffset] = '\0';
|
||||||
|
outOffset++;
|
||||||
|
|
||||||
|
*out = obj;
|
||||||
|
obj->string = string;
|
||||||
|
return offset + 1;// For closing string quote
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t assetJsonParseAsObject(
|
||||||
|
const char_t *json,
|
||||||
|
assetjson_t **out
|
||||||
|
) {
|
||||||
|
assetjson_t *obj = malloc(sizeof(assetjson_t));
|
||||||
|
|
||||||
|
obj->type = ASSET_JSON_DATA_TYPE_OBJECT;
|
||||||
|
|
||||||
|
size_t bufferSize = 2;
|
||||||
|
char_t **keys = malloc(bufferSize * sizeof(char_t*));
|
||||||
|
assetjson_t **values = malloc(bufferSize * sizeof(assetjson_t*));
|
||||||
|
size_t length = 0;
|
||||||
|
|
||||||
|
// Skip whitespace
|
||||||
|
size_t offset = 1;// Skip opening bracket
|
||||||
|
char_t c;
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||||
|
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only expect opening string or closing brace
|
||||||
|
if(c == '}') break;
|
||||||
|
|
||||||
|
assertTrue(c == '"', "Expected opening string for JSON object key.");
|
||||||
|
char_t *bufferKey;
|
||||||
|
|
||||||
|
// Skip "
|
||||||
|
offset++;
|
||||||
|
offset += assetJsonReadString(json + offset, &bufferKey);
|
||||||
|
|
||||||
|
// Skip whitespace
|
||||||
|
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||||
|
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only expect colon
|
||||||
|
assertTrue(c == ':', "Expected colon after JSON object key.");
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
// Skip whitespace
|
||||||
|
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||||
|
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse sub
|
||||||
|
assetjson_t *value;
|
||||||
|
offset += assetJsonParseSub(json + offset, &value);
|
||||||
|
|
||||||
|
// Need to resize?
|
||||||
|
if(length >= bufferSize) {
|
||||||
|
bufferSize *= 2;
|
||||||
|
keys = realloc(keys, bufferSize * sizeof(char_t*));
|
||||||
|
values = realloc(values, bufferSize * sizeof(assetjson_t*));
|
||||||
|
}
|
||||||
|
|
||||||
|
keys[length] = bufferKey;
|
||||||
|
values[length] = value;
|
||||||
|
length++;
|
||||||
|
|
||||||
|
// Skip whitespace
|
||||||
|
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||||
|
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expect either comma or closing bracket
|
||||||
|
assertTrue(c == ',' || c == '}', "Expected comma or closing bracket after JSON object value.");
|
||||||
|
if(c == '}') break;
|
||||||
|
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->object.keys = keys;
|
||||||
|
obj->object.values = values;
|
||||||
|
obj->object.length = length;
|
||||||
|
|
||||||
|
*out = obj;
|
||||||
|
return offset + 1;// Skip closing bracket
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t assetJsonParseAsArray(
|
||||||
|
const char_t *json,
|
||||||
|
assetjson_t **out
|
||||||
|
) {
|
||||||
|
assetjson_t *obj = malloc(sizeof(assetjson_t));
|
||||||
|
|
||||||
|
obj->type = ASSET_JSON_DATA_TYPE_ARRAY;
|
||||||
|
|
||||||
|
size_t offset = 1;// Skip opening bracket
|
||||||
|
char_t c;
|
||||||
|
|
||||||
|
// Create array
|
||||||
|
size_t arraySize = 2;
|
||||||
|
obj->array.value = malloc(arraySize * sizeof(assetjson_t*));
|
||||||
|
obj->array.length = 0;
|
||||||
|
|
||||||
|
// Until closing bracket
|
||||||
|
while(true) {
|
||||||
|
c = json[offset];
|
||||||
|
|
||||||
|
if(c == '\0') assertUnreachable("Unexpected end of JSON array.");
|
||||||
|
|
||||||
|
if(c == ']') break;
|
||||||
|
|
||||||
|
// Skip whitespace ONLY
|
||||||
|
if(c == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||||
|
offset++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to expand?
|
||||||
|
if(obj->array.length >= arraySize) {
|
||||||
|
arraySize *= 2;
|
||||||
|
obj->array.value = realloc(
|
||||||
|
obj->array.value, arraySize * sizeof(assetjson_t*)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse sub
|
||||||
|
offset += assetJsonParseSub(
|
||||||
|
json + offset,
|
||||||
|
&obj->array.value[obj->array.length++]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Skip whitespace ONLY
|
||||||
|
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
||||||
|
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If comma, continue
|
||||||
|
if(c == ',') {
|
||||||
|
offset++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If closing bracket, break
|
||||||
|
if(c == ']') break;
|
||||||
|
|
||||||
|
// Else, error
|
||||||
|
assertUnreachable("Unexpected character found in JSON array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of array
|
||||||
|
*out = obj;
|
||||||
|
return offset + 1;// Skip closing bracket
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t assetJsonParseAsNumber(
|
||||||
|
const char_t *json,
|
||||||
|
assetjson_t **out
|
||||||
|
) {
|
||||||
|
assetjson_t *obj = malloc(sizeof(assetjson_t));
|
||||||
|
|
||||||
|
obj->type = ASSET_JSON_DATA_TYPE_NUMBER;
|
||||||
|
|
||||||
|
// For each char
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t outOffset = 0;
|
||||||
|
char_t c;
|
||||||
|
size_t bufferSize = 2;
|
||||||
|
char_t *buffer = (char_t*)malloc(bufferSize * sizeof(char_t));
|
||||||
|
bool_t hasDecimal = false;
|
||||||
|
bool_t hasNumber = false;
|
||||||
|
|
||||||
|
// Read number
|
||||||
|
while(true) {
|
||||||
|
c = json[offset];
|
||||||
|
if(c == '\0') assertUnreachable("Unexpected end of number.");
|
||||||
|
|
||||||
|
if(c == '-') {
|
||||||
|
// only accepted on first input
|
||||||
|
assertTrue(outOffset == 0, "Unexpected - after first digit");
|
||||||
|
} else if(c == '.') {
|
||||||
|
// only accepted once
|
||||||
|
assertTrue(!hasDecimal, "Unexpected . after first decimal");
|
||||||
|
hasDecimal = true;
|
||||||
|
|
||||||
|
if(!hasNumber) {
|
||||||
|
// If no number before decimal, add a 0
|
||||||
|
if(outOffset >= bufferSize) {
|
||||||
|
bufferSize *= 2;
|
||||||
|
buffer = realloc(buffer, bufferSize * sizeof(char_t));
|
||||||
|
}
|
||||||
|
buffer[outOffset] = '0';
|
||||||
|
outOffset++;
|
||||||
|
}
|
||||||
|
} else if(c >= '0' && c <= '9') {
|
||||||
|
hasNumber = true;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to expand?
|
||||||
|
if(outOffset >= bufferSize) {
|
||||||
|
bufferSize *= 2;
|
||||||
|
buffer = realloc(buffer, bufferSize * sizeof(char_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[outOffset] = c;
|
||||||
|
offset++;
|
||||||
|
outOffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seal the buffer, parse and cleanup
|
||||||
|
buffer[outOffset] = '\0';
|
||||||
|
obj->number = strtod(buffer, NULL);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
*out = obj;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t assetJsonReadString(
|
||||||
|
const char_t *json,
|
||||||
|
char_t **buffer
|
||||||
|
) {
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t outOffset = 0;
|
||||||
|
char_t c;
|
||||||
|
size_t bufferSize = 32;
|
||||||
|
char_t *string = (char_t*)malloc(sizeof(char_t) * bufferSize);
|
||||||
|
bool_t inEscape = false;
|
||||||
|
|
||||||
|
// For each char
|
||||||
|
while(true) {
|
||||||
|
c = json[offset];
|
||||||
|
if(c == '\0') assertUnreachable("Unexpected end of string.");
|
||||||
|
|
||||||
|
if(inEscape) {
|
||||||
|
inEscape = false;
|
||||||
|
switch(c) {
|
||||||
|
case 'n':
|
||||||
|
c = '\n';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
c = '\r';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
c = '\t';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
c = '\b';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
c = '\f';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
assertUnreachable("Unicode escape sequences are not supported.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(outOffset >= bufferSize) {
|
||||||
|
bufferSize *= 2;
|
||||||
|
string = realloc(string, bufferSize);
|
||||||
|
}
|
||||||
|
string[outOffset] = c;
|
||||||
|
offset++;
|
||||||
|
outOffset++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c == '\\') {
|
||||||
|
inEscape = true;
|
||||||
|
offset++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c == '"') break;
|
||||||
|
|
||||||
|
if(outOffset >= bufferSize) {
|
||||||
|
bufferSize *= 2;
|
||||||
|
string = realloc(string, bufferSize);
|
||||||
|
}
|
||||||
|
string[outOffset] = c;
|
||||||
|
offset++;
|
||||||
|
outOffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[outOffset] = '\0';
|
||||||
|
outOffset++;
|
||||||
|
*buffer = string;
|
||||||
|
return offset + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assetjson_t * assetJsonGetObjectValue(assetjson_t *json, const char_t *key) {
|
||||||
|
assertTrue(json->type == ASSET_JSON_DATA_TYPE_OBJECT, "Expected JSON object.");
|
||||||
|
|
||||||
|
for(size_t i = 0; i < json->object.length; i++) {
|
||||||
|
if(strcmp(json->object.keys[i], key) == 0) {
|
||||||
|
return json->object.values[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assetJsonDispose(assetjson_t *json) {
|
||||||
|
switch(json->type) {
|
||||||
|
case ASSET_JSON_DATA_TYPE_OBJECT:
|
||||||
|
for(size_t i = 0; i < json->object.length; i++) {
|
||||||
|
free(json->object.keys[i]);
|
||||||
|
assetJsonDispose(json->object.values[i]);
|
||||||
|
}
|
||||||
|
free(json->object.keys);
|
||||||
|
free(json->object.values);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASSET_JSON_DATA_TYPE_ARRAY:
|
||||||
|
for(size_t i = 0; i < json->array.length; i++) {
|
||||||
|
assetJsonDispose(json->array.value[i]);
|
||||||
|
}
|
||||||
|
free(json->array.value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASSET_JSON_DATA_TYPE_STRING:
|
||||||
|
free(json->string);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASSET_JSON_DATA_TYPE_NUMBER:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASSET_JSON_DATA_TYPE_BOOLEAN:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASSET_JSON_DATA_TYPE_NULL:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(json);
|
||||||
|
}
|
140
src/dawn/asset/assetjson.h
Normal file
140
src/dawn/asset/assetjson.h
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2024 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dawn.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ASSET_JSON_DATA_TYPE_OBJECT,
|
||||||
|
ASSET_JSON_DATA_TYPE_ARRAY,
|
||||||
|
ASSET_JSON_DATA_TYPE_STRING,
|
||||||
|
ASSET_JSON_DATA_TYPE_NUMBER,
|
||||||
|
ASSET_JSON_DATA_TYPE_BOOLEAN,
|
||||||
|
ASSET_JSON_DATA_TYPE_NULL
|
||||||
|
} assetjsondatatype_t;
|
||||||
|
|
||||||
|
typedef struct _assetjson_t assetjson_t;
|
||||||
|
|
||||||
|
typedef struct _assetjson_t {
|
||||||
|
assetjsondatatype_t type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
char_t **keys;
|
||||||
|
assetjson_t **values;
|
||||||
|
size_t length;
|
||||||
|
} object;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
assetjson_t **value;
|
||||||
|
size_t length;
|
||||||
|
} array;
|
||||||
|
|
||||||
|
double_t number;
|
||||||
|
char_t *string;
|
||||||
|
bool_t boolean;
|
||||||
|
};
|
||||||
|
} assetjson_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
size_t assetJsonParse(const char_t *json, assetjson_t **out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string as a sub-object.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
size_t assetJsonParseSub(const char_t *json, assetjson_t **out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string as a NULL value.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
size_t assetJsonParseAsNull(const char_t *json, assetjson_t **out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string as a boolean value.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
size_t assetJsonParseAsBoolean(const char_t *json, assetjson_t **out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string as an object.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
size_t assetJsonParseAsObject(const char_t *json, assetjson_t **out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string as an array.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
size_t assetJsonParseAsArray(const char_t *json, assetjson_t **out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string as a string.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
size_t assetJsonParseAsString(const char_t *json, assetjson_t **out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string as a number.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
size_t assetJsonParseAsNumber(const char_t *json, assetjson_t **out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string as a string.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
size_t assetJsonReadString(const char_t *json, char_t **out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string as a number.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
assetjson_t *assetJsonGetObjectValue(assetjson_t *object, const char_t *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a JSON string as a number.
|
||||||
|
*
|
||||||
|
* @param json JSON string to parse.
|
||||||
|
* @param out Pointer to store the parsed JSON object.
|
||||||
|
* @return The number of characters parsed.
|
||||||
|
*/
|
||||||
|
void assetJsonDispose(assetjson_t *json);
|
102
src/dawn/asset/assetmap.c
Normal file
102
src/dawn/asset/assetmap.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2024 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "assetmap.h"
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "asset/assetjson.h"
|
||||||
|
|
||||||
|
void assetMapLoad(
|
||||||
|
const char_t *path,
|
||||||
|
map_t *map
|
||||||
|
) {
|
||||||
|
assertNotNull(map, "assetMapLoad: Map is NULL!");
|
||||||
|
|
||||||
|
// Read in the string data.
|
||||||
|
assetOpen(path);
|
||||||
|
size_t length = assetGetSize();
|
||||||
|
char_t *buffer = malloc(sizeof(char_t) * (length + 1));
|
||||||
|
size_t read = assetRead((uint8_t*)buffer, length);
|
||||||
|
assertTrue(read == length, "assetMapLoad: Failed to read map data!");
|
||||||
|
assetClose();
|
||||||
|
|
||||||
|
// Begin parsing JSON data.
|
||||||
|
assetjson_t *json;
|
||||||
|
read = assetJsonParse(buffer, &json);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
json->type == ASSET_JSON_DATA_TYPE_OBJECT,
|
||||||
|
"assetMapLoad: Map data is not an object!"
|
||||||
|
);
|
||||||
|
|
||||||
|
int32_t width = (int32_t)assetJsonGetObjectValue(json, "width")->number;
|
||||||
|
int32_t height = (int32_t)assetJsonGetObjectValue(json, "height")->number;
|
||||||
|
|
||||||
|
assetjson_t *layers = assetJsonGetObjectValue(json, "layers");
|
||||||
|
assertTrue(
|
||||||
|
layers->type == ASSET_JSON_DATA_TYPE_ARRAY,
|
||||||
|
"assetMapLoad: Layers is not an array!"
|
||||||
|
);
|
||||||
|
|
||||||
|
int32_t layerCount = layers->array.length;
|
||||||
|
assertTrue(layerCount == MAP_LAYERS_MAX, "assetMapLoad: No layers found!");
|
||||||
|
|
||||||
|
mapInit(map, width, height, layerCount);
|
||||||
|
|
||||||
|
// Load tile data.
|
||||||
|
for(int32_t i = 0; i < layerCount; i++) {
|
||||||
|
assetjson_t *layer = layers->array.value[i];
|
||||||
|
assertTrue(
|
||||||
|
layer->type == ASSET_JSON_DATA_TYPE_OBJECT,
|
||||||
|
"assetMapLoad: Layer is not an object!"
|
||||||
|
);
|
||||||
|
|
||||||
|
assetjson_t *tiles = assetJsonGetObjectValue(layer, "tiles");
|
||||||
|
assertTrue(
|
||||||
|
tiles->type == ASSET_JSON_DATA_TYPE_ARRAY,
|
||||||
|
"assetMapLoad: Tiles is not an array!"
|
||||||
|
);
|
||||||
|
assertTrue(
|
||||||
|
tiles->array.length == width * height,
|
||||||
|
"assetMapLoad: Tile count does not match map size!"
|
||||||
|
);
|
||||||
|
|
||||||
|
for(int32_t j = 0; j < width * height; j++) {
|
||||||
|
map->tiles[j] = (tile_t){
|
||||||
|
.id = (uint16_t)tiles->array.value[j]->number
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load entity data
|
||||||
|
assetjson_t *entities = assetJsonGetObjectValue(json, "entities");
|
||||||
|
assertTrue(
|
||||||
|
entities->type == ASSET_JSON_DATA_TYPE_ARRAY,
|
||||||
|
"assetMapLoad: Entities is not an array!"
|
||||||
|
);
|
||||||
|
|
||||||
|
for(int32_t i = 0; i < entities->array.length; i++) {
|
||||||
|
assetjson_t *jsonEntity = entities->array.value[i];
|
||||||
|
assertTrue(
|
||||||
|
jsonEntity->type == ASSET_JSON_DATA_TYPE_OBJECT,
|
||||||
|
"assetMapLoad: Entity is not an object!"
|
||||||
|
);
|
||||||
|
|
||||||
|
int32_t x = (int32_t)assetJsonGetObjectValue(jsonEntity, "x")->number;
|
||||||
|
int32_t y = (int32_t)assetJsonGetObjectValue(jsonEntity, "y")->number;
|
||||||
|
uint8_t type = (uint8_t)assetJsonGetObjectValue(jsonEntity, "type")->number;
|
||||||
|
|
||||||
|
entity_t *ent = mapEntityAdd(map);
|
||||||
|
entityInit(ent, type, map);
|
||||||
|
entityPositionSet(ent, x, y);
|
||||||
|
|
||||||
|
// TODO: Parse any extra data.
|
||||||
|
}
|
||||||
|
|
||||||
|
assetJsonDispose(json);
|
||||||
|
}
|
14
src/dawn/asset/assetmap.h
Normal file
14
src/dawn/asset/assetmap.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2024 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "rpg/world/map.h"
|
||||||
|
|
||||||
|
void assetMapLoad(
|
||||||
|
const char_t *path,
|
||||||
|
map_t *map
|
||||||
|
);
|
@ -12,6 +12,7 @@
|
|||||||
#include "rpg/world/maps/testmap.h"
|
#include "rpg/world/maps/testmap.h"
|
||||||
#include "ui/textbox.h"
|
#include "ui/textbox.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
|
#include "asset/assetmap.h"
|
||||||
|
|
||||||
map_t MAP;
|
map_t MAP;
|
||||||
game_t GAME;
|
game_t GAME;
|
||||||
@ -24,8 +25,10 @@ void gameInit() {
|
|||||||
displayInit();
|
displayInit();
|
||||||
assetInit();
|
assetInit();
|
||||||
textboxInit();
|
textboxInit();
|
||||||
|
|
||||||
testMapInit(&MAP);
|
assetMapLoad("testmap.json", &MAP);
|
||||||
|
// testMapInit(&MAP);
|
||||||
|
|
||||||
gameSetMap(&MAP);
|
gameSetMap(&MAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
# 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
|
||||||
|
|
||||||
function(tool_copy target input output)
|
function(tool_copy target file)
|
||||||
add_custom_target(${target}
|
add_custom_target(${target}
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${input} ${output}
|
COMMAND ${CMAKE_COMMAND} -E copy ${DAWN_ASSETS_SOURCE_DIR}/${file} ${DAWN_ASSETS_BUILD_DIR}/${file}
|
||||||
)
|
)
|
||||||
add_dependencies(dawnassets ${target})
|
add_dependencies(dawnassets ${target})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
Reference in New Issue
Block a user