prog
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
id,type,
|
id,type,weight
|
||||||
POTION,MEDICINE,
|
POTION,MEDICINE,1.0
|
||||||
POTATO,FOOD,
|
POTATO,FOOD,0.5
|
||||||
APPLE,FOOD,
|
APPLE,FOOD,0.3
|
||||||
|
@@ -15,8 +15,10 @@
|
|||||||
#include "item/itemid.h"
|
#include "item/itemid.h"
|
||||||
#include "item/itemname.h"
|
#include "item/itemname.h"
|
||||||
|
|
||||||
|
// test.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
itemtype_t type;
|
const char_t *name;
|
||||||
|
const itemtype_t type;
|
||||||
} item_t;
|
} item_t;
|
||||||
|
|
||||||
extern const item_t ITEMS[];
|
extern const item_t ITEMS[];
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
|
from tools.util.type import detectType, stringToCType, typeToCType
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="Convert CSV to .h defines")
|
parser = argparse.ArgumentParser(description="Convert CSV to .h defines")
|
||||||
parser.add_argument("--csv", required=True, help="Path to CSV file")
|
parser.add_argument("--csv", required=True, help="Path to CSV file")
|
||||||
@@ -34,6 +35,7 @@ with open(args.csv, newline='') as csvfile:
|
|||||||
index_col_idx = headers.index(args.index_column)
|
index_col_idx = headers.index(args.index_column)
|
||||||
data_col_idx = headers.index(args.data_column)
|
data_col_idx = headers.index(args.data_column)
|
||||||
keyValuePairs = {}
|
keyValuePairs = {}
|
||||||
|
valType = None
|
||||||
for row in reader:
|
for row in reader:
|
||||||
key = row[index_col_idx]
|
key = row[index_col_idx]
|
||||||
value = row[data_col_idx]
|
value = row[data_col_idx]
|
||||||
@@ -42,73 +44,19 @@ with open(args.csv, newline='') as csvfile:
|
|||||||
if key in keyValuePairs:
|
if key in keyValuePairs:
|
||||||
raise ValueError(f"Duplicate key '{key}' found in CSV")
|
raise ValueError(f"Duplicate key '{key}' found in CSV")
|
||||||
keyValuePairs[key] = value
|
keyValuePairs[key] = value
|
||||||
|
if valType is None:
|
||||||
|
valType = detectType(value)
|
||||||
|
|
||||||
# Determine type. Can be float, int, bool, or string.
|
if valType is None:
|
||||||
isFloat = False
|
valType = 'String'
|
||||||
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.
|
# Now begin generating header.
|
||||||
outHeader += f"static const {typeString} {args.variable}[] = {{\n"
|
cType = typeToCType(valType)
|
||||||
|
outHeader += f"static const {cType} {args.variable}[] = {{\n"
|
||||||
for key in keyValuePairs:
|
for key in keyValuePairs:
|
||||||
outHeader += f" [{args.index_prefix}{key}] = "
|
outHeader += f" [{args.index_prefix}{key}] = "
|
||||||
value = keyValuePairs[key]
|
value = keyValuePairs[key]
|
||||||
if isFloat:
|
outHeader += stringToCType(value)
|
||||||
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"
|
||||||
outHeader += "};\n\n"
|
outHeader += "};\n\n"
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1 @@
|
|||||||
# Copyright (c) 2026 Dominic Masters
|
add_subdirectory(csv)
|
||||||
#
|
|
||||||
# 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()
|
|
||||||
45
tools/item/csv/CMakeLists.txt
Normal file
45
tools/item/csv/CMakeLists.txt
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# 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
|
||||||
|
)
|
||||||
|
|
||||||
|
dusk_run_python(
|
||||||
|
dusk_item_csv_defs
|
||||||
|
tools.item.csv
|
||||||
|
--csv ${CSV_FILE}
|
||||||
|
--output ${DUSK_GENERATED_HEADERS_DIR}/item/itemdefs.h
|
||||||
|
)
|
||||||
|
add_dependencies(${DUSK_LIBRARY_TARGET_NAME} dusk_item_csv_defs)
|
||||||
|
endfunction()
|
||||||
19
tools/item/csv/__main__.py
Normal file
19
tools/item/csv/__main__.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import csv
|
||||||
|
from tools.util.type import detectType, stringToCType, typeToCType
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Item CSV to .h defines")
|
||||||
|
parser.add_argument("--csv", required=True, help="Path to item CSV file")
|
||||||
|
parser.add_argument("--output", required=True, help="Path to output .h file")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Load up CSV file.
|
||||||
|
outHeader = "#pragma once\n"
|
||||||
|
outHeader += "#include \"item/item.h\"\n\n"
|
||||||
|
with open(args.csv, newline="", encoding="utf-8") as csvfile:
|
||||||
|
reader = csv.DictReader(csvfile)
|
||||||
|
|
||||||
|
# CSV must have id and type columns.
|
||||||
|
if "id" not in reader.fieldnames or "type" not in reader.fieldnames:
|
||||||
|
raise Exception("CSV file must have 'id' and 'type' columns")
|
||||||
44
tools/util/type.py
Normal file
44
tools/util/type.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
def detectType(value: str) -> str:
|
||||||
|
val = value.strip()
|
||||||
|
# Boolean check
|
||||||
|
if val.lower() in {'true', 'false'}:
|
||||||
|
return 'Boolean'
|
||||||
|
|
||||||
|
# Int check
|
||||||
|
try:
|
||||||
|
int(val)
|
||||||
|
return 'Int'
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Float check
|
||||||
|
try:
|
||||||
|
float(val)
|
||||||
|
return 'Float'
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Default to String
|
||||||
|
return 'String'
|
||||||
|
|
||||||
|
def typeToCType(valType: str) -> str:
|
||||||
|
if valType == 'Int':
|
||||||
|
return 'int'
|
||||||
|
elif valType == 'Float':
|
||||||
|
return 'float'
|
||||||
|
elif valType == 'Boolean':
|
||||||
|
return 'bool'
|
||||||
|
else:
|
||||||
|
return 'char_t*'
|
||||||
|
|
||||||
|
def stringToCType(value: str) -> str:
|
||||||
|
valType = detectType(value)
|
||||||
|
if valType == 'Int':
|
||||||
|
return str(int(value))
|
||||||
|
elif valType == 'Float':
|
||||||
|
return str(float(value))
|
||||||
|
elif valType == 'Boolean':
|
||||||
|
return 'true' if value.lower() == 'true' else 'false'
|
||||||
|
else:
|
||||||
|
escaped = value.replace('\\', '\\\\').replace('"', '\\"')
|
||||||
|
return f'"{escaped}"'
|
||||||
Reference in New Issue
Block a user