From 0392dd0e7f032abf3ba8dc20542bde5f8a47361b Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Mon, 26 Jan 2026 08:37:36 -0600 Subject: [PATCH] Added csv_to_array tool --- assets/CMakeLists.txt | 1 + assets/input/CMakeLists.txt | 6 ++ assets/input/input.csv | 8 ++ assets/item/CMakeLists.txt | 16 +--- src/input/inputaction.h | 27 ++----- src/item/item.h | 5 ++ tools/CMakeLists.txt | 3 + tools/csv_to_array/CMakeLists.txt | 23 ++++++ tools/csv_to_array/__main__.py | 117 ++++++++++++++++++++++++++++++ tools/csv_to_enum/__main__.py | 8 +- tools/input/CMakeLists.txt | 29 ++++++++ tools/item/CMakeLists.txt | 37 ++++++++++ 12 files changed, 239 insertions(+), 41 deletions(-) create mode 100644 assets/input/CMakeLists.txt create mode 100644 assets/input/input.csv create mode 100644 tools/csv_to_array/CMakeLists.txt create mode 100644 tools/csv_to_array/__main__.py create mode 100644 tools/input/CMakeLists.txt create mode 100644 tools/item/CMakeLists.txt diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt index 37ce0c1..0083360 100644 --- a/assets/CMakeLists.txt +++ b/assets/CMakeLists.txt @@ -15,6 +15,7 @@ add_subdirectory(locale) add_asset(SCRIPT init.lua) # Subdirs +add_subdirectory(input) add_subdirectory(item) add_subdirectory(entity) add_subdirectory(map) diff --git a/assets/input/CMakeLists.txt b/assets/input/CMakeLists.txt new file mode 100644 index 0000000..0c09b54 --- /dev/null +++ b/assets/input/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2026 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +dusk_input_csv(${CMAKE_CURRENT_LIST_DIR}/input.csv) \ No newline at end of file diff --git a/assets/input/input.csv b/assets/input/input.csv new file mode 100644 index 0000000..eabbe95 --- /dev/null +++ b/assets/input/input.csv @@ -0,0 +1,8 @@ +id, +UP, +DOWN, +LEFT, +RIGHT, +ACCEPT, +CANCEL, +RAGEQUIT \ No newline at end of file diff --git a/assets/item/CMakeLists.txt b/assets/item/CMakeLists.txt index 91e0942..a7a9f47 100644 --- a/assets/item/CMakeLists.txt +++ b/assets/item/CMakeLists.txt @@ -3,18 +3,4 @@ # This software is released under the MIT License. # https://opensource.org/licenses/MIT -dusk_csv_to_enum( - ${CMAKE_CURRENT_LIST_DIR}/items.csv - item/itemtype.h - itemtype_t - ITEM_TYPE - type -) - -dusk_csv_to_enum( - ${CMAKE_CURRENT_LIST_DIR}/items.csv - item/itemid.h - itemid_t - ITEM_ID - id -) \ No newline at end of file +dusk_item_csv(${CMAKE_CURRENT_LIST_DIR}/items.csv) \ No newline at end of file diff --git a/src/input/inputaction.h b/src/input/inputaction.h index 55f61fe..2b4de70 100644 --- a/src/input/inputaction.h +++ b/src/input/inputaction.h @@ -8,18 +8,11 @@ #pragma once #include "time/time.h" -typedef enum { - INPUT_ACTION_NULL, - INPUT_ACTION_UP, - INPUT_ACTION_DOWN, - INPUT_ACTION_LEFT, - INPUT_ACTION_RIGHT, - INPUT_ACTION_ACCEPT, - INPUT_ACTION_CANCEL, - INPUT_ACTION_RAGEQUIT, - - INPUT_ACTION_COUNT -} inputaction_t; +#ifndef INPUT_CSV_GENERATED + #error "Input CSV has not been generated. Run dusk_input_csv in CMake." +#endif +#include "input/inputactiontype.h" +#include "input/inputactionname.h" typedef struct { inputaction_t action; @@ -32,16 +25,6 @@ typedef struct { #endif } inputactiondata_t; -static const char_t* INPUT_ACTION_NAMES[INPUT_ACTION_COUNT] = { - [INPUT_ACTION_UP] = "UP", - [INPUT_ACTION_DOWN] = "DOWN", - [INPUT_ACTION_LEFT] = "LEFT", - [INPUT_ACTION_RIGHT] = "RIGHT", - [INPUT_ACTION_ACCEPT] = "ACCEPT", - [INPUT_ACTION_CANCEL] = "CANCEL", - [INPUT_ACTION_RAGEQUIT] = "RAGEQUIT", -}; - /** * Gets an input action by its name. * diff --git a/src/item/item.h b/src/item/item.h index 8a99b68..f89de77 100644 --- a/src/item/item.h +++ b/src/item/item.h @@ -6,6 +6,11 @@ */ #pragma once + +#ifndef ITEM_CSV_GENERATED +#error "Item CSV has not been generated. Ensure dusk_item_csv is run in CMake." +#endif + #include "item/itemtype.h" #include "item/itemid.h" diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 913325b..3822177 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -6,6 +6,9 @@ add_subdirectory(run_python) add_subdirectory(env_to_h) add_subdirectory(csv_to_enum) +add_subdirectory(csv_to_array) +add_subdirectory(item) +add_subdirectory(input) # Function that adds an asset to be compiled function(add_asset ASSET_TYPE ASSET_PATH) diff --git a/tools/csv_to_array/CMakeLists.txt b/tools/csv_to_array/CMakeLists.txt new file mode 100644 index 0000000..b142555 --- /dev/null +++ b/tools/csv_to_array/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) 2026 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +function(dusk_csv_to_array INPUT_PATH OUTPUT_NAME_RELATIVE VARIABLE INDEX_INCLUDE_PATH INDEX_PREFIX INDEX_COLUMN DATA_COLUMN) + set(DUSK_DEFS_TARGET_NAME "DUSK_DEFS_${OUTPUT_NAME_RELATIVE}") + string(REPLACE "." "_" DUSK_DEFS_TARGET_NAME ${DUSK_DEFS_TARGET_NAME}) + string(REPLACE "/" "_" DUSK_DEFS_TARGET_NAME ${DUSK_DEFS_TARGET_NAME}) + + dusk_run_python( + ${DUSK_DEFS_TARGET_NAME} + tools.csv_to_array + --csv ${INPUT_PATH} + --output ${DUSK_GENERATED_HEADERS_DIR}/${OUTPUT_NAME_RELATIVE} + --variable ${VARIABLE} + --index-include-path ${INDEX_INCLUDE_PATH} + --index-prefix ${INDEX_PREFIX} + --index-column ${INDEX_COLUMN} + --data-column ${DATA_COLUMN} + ) + add_dependencies(${DUSK_LIBRARY_TARGET_NAME} ${DUSK_DEFS_TARGET_NAME}) +endfunction() \ No newline at end of file diff --git a/tools/csv_to_array/__main__.py b/tools/csv_to_array/__main__.py new file mode 100644 index 0000000..8fe455f --- /dev/null +++ b/tools/csv_to_array/__main__.py @@ -0,0 +1,117 @@ +import argparse +import os +import csv + +parser = argparse.ArgumentParser(description="Convert CSV to .h defines") +parser.add_argument("--csv", required=True, help="Path to CSV file") +parser.add_argument("--output", required=True, help="Path to output .h file") +parser.add_argument("--variable", required=True, help="Name of generated array variable") +parser.add_argument('--index-include-path', required=False, default='', help="Include path for index defines") +parser.add_argument('--index-prefix', required=False, default='', help="Prefix for index defines") +parser.add_argument('--index-column', required=True, help="Column name for index values") +parser.add_argument('--data-column', required=True, help="Column name for data values") +args = parser.parse_args() + +# Start Header +outHeader = "#pragma once\n" +outHeader += "#include \"dusk.h\"\n" +if args.index_include_path: + outHeader += f'#include "{args.index_include_path}"\n' +outHeader += "\n" + +# Read CSV file +with open(args.csv, newline='') as csvfile: + reader = csv.reader(csvfile) + headers = next(reader) + + # Ensure both index and data columns exist. + if args.index_column not in headers: + raise ValueError(f"Index column '{args.index_column}' not found in CSV headers") + if args.data_column not in headers: + raise ValueError(f"Data column '{args.data_column}' not found in CSV headers") + + # Create key-value pairs from CSV rows. + index_col_idx = headers.index(args.index_column) + data_col_idx = headers.index(args.data_column) + keyValuePairs = {} + for row in reader: + key = row[index_col_idx] + value = row[data_col_idx] + + # Don't allow duplicate keys. + if key in keyValuePairs: + raise ValueError(f"Duplicate key '{key}' found in CSV") + keyValuePairs[key] = value + + # Determine type. Can be float, int, bool, or string. + isFloat = False + isInt = False + isBool = False + isString = False + + # If there's no entries, assume string type. + if len(keyValuePairs) == 0: + isString = True + else: + allInts = True + allFloats = True + + # Check if ALL values can be parsed as int or float. + for value in keyValuePairs.values(): + if allInts: + try: + int(value) + except: + allInts = False + if allFloats: + try: + float(value) + except: + allFloats = False + + if not allInts and not allFloats: + break + + if allInts: + isInt = True + elif allFloats: + isFloat = True + else: + # Not all floats/ints, probably string or bool, check first entry + firstValue = next(iter(keyValuePairs.values())) + if firstValue.lower() in ['true', 'false']: + isBool = True + else: + isString = True + + typeString = "" + if isFloat: + typeString = "float" + elif isInt: + typeString = "int" + elif isBool: + typeString = "bool" + elif isString: + typeString = "char*" + + # Now begin generating header. + outHeader += f"static const {typeString} {args.variable}[] = {{\n" + for key in keyValuePairs: + outHeader += f" [{args.index_prefix}{key}] = " + value = keyValuePairs[key] + if isFloat: + outHeader += str(float(value)) + elif isInt: + outHeader += str(int(value)) + elif isBool: + asBool = 'true' if value.lower() == 'true' else 'false' + outHeader += asBool + elif isString: + escaped = value.replace('\\', '\\\\').replace('"', '\\"') + outHeader += f'"{escaped}"' + outHeader += ",\n" + outHeader += "};\n\n" + +# Write to output file +with open(args.output, 'w') as outFile: + outFile.write(outHeader) \ No newline at end of file diff --git a/tools/csv_to_enum/__main__.py b/tools/csv_to_enum/__main__.py index 5ba7a82..d49ce43 100644 --- a/tools/csv_to_enum/__main__.py +++ b/tools/csv_to_enum/__main__.py @@ -12,7 +12,7 @@ parser.add_argument("--null-entry", default=None, help="Optional name for a NULL parser.add_argument("--count-entry", default=None, help="Optional name for a COUNT entry") args = parser.parse_args() -outHeader = "" +outHeader = "#pragma once\n" outHeader += "#include \"dusk.h\"\n\n" with open(args.csv, newline='') as csvfile: reader = csv.reader(csvfile) @@ -34,13 +34,13 @@ with open(args.csv, newline='') as csvfile: # Gen enum. outHeader += f"typedef enum {{\n" if args.null_entry == "TRUE": - outHeader += f" {args.prefix}_NULL = 0,\n\n" + outHeader += f" {args.prefix}NULL = 0,\n\n" for entry in entries: - outHeader += f" {args.prefix}_{entry},\n" + outHeader += f" {args.prefix}{entry},\n" if args.count_entry == "TRUE": - outHeader += f"\n {args.prefix}_COUNT,\n" + outHeader += f"\n {args.prefix}COUNT,\n" outHeader += f"}} {args.typedef};\n\n" diff --git a/tools/input/CMakeLists.txt b/tools/input/CMakeLists.txt new file mode 100644 index 0000000..72fc008 --- /dev/null +++ b/tools/input/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) 2026 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +function(dusk_input_csv CSV_FILE) + dusk_csv_to_enum( + ${CSV_FILE} + input/inputactiontype.h + inputaction_t + INPUT_ACTION_ + id + ) + + dusk_csv_to_array( + ${CSV_FILE} + input/inputactionname.h + INPUT_ACTION_NAMES + input/inputactiontype.h + INPUT_ACTION_ + id + id + ) + + target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} + PUBLIC + INPUT_CSV_GENERATED=1 + ) +endfunction() \ No newline at end of file diff --git a/tools/item/CMakeLists.txt b/tools/item/CMakeLists.txt new file mode 100644 index 0000000..3854d35 --- /dev/null +++ b/tools/item/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (c) 2026 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +function(dusk_item_csv CSV_FILE) + dusk_csv_to_enum( + ${CSV_FILE} + item/itemtype.h + itemtype_t + ITEM_TYPE_ + type + ) + + dusk_csv_to_enum( + ${CSV_FILE} + item/itemid.h + itemid_t + ITEM_ID_ + id + ) + + dusk_csv_to_array( + ${CSV_FILE} + item/itemname.h + ITEM_NAMES + item/itemid.h + ITEM_ID_ + id + id + ) + + target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} + PUBLIC + ITEM_CSV_GENERATED=1 + ) +endfunction() \ No newline at end of file