prog
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import argparse
|
||||
import os
|
||||
import csv
|
||||
from tools.util.type import detectType, stringToCType, typeToCType
|
||||
|
||||
parser = argparse.ArgumentParser(description="Convert CSV to .h defines")
|
||||
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)
|
||||
data_col_idx = headers.index(args.data_column)
|
||||
keyValuePairs = {}
|
||||
valType = None
|
||||
for row in reader:
|
||||
key = row[index_col_idx]
|
||||
value = row[data_col_idx]
|
||||
@@ -42,73 +44,19 @@ with open(args.csv, newline='') as csvfile:
|
||||
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*"
|
||||
if valType is None:
|
||||
valType = detectType(value)
|
||||
|
||||
if valType is None:
|
||||
valType = 'String'
|
||||
|
||||
# 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:
|
||||
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 += stringToCType(value)
|
||||
outHeader += ",\n"
|
||||
outHeader += "};\n\n"
|
||||
|
||||
|
||||
@@ -1,37 +1 @@
|
||||
# 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()
|
||||
add_subdirectory(csv)
|
||||
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