CObject Properties

- Added property members to CObjects via `PROPERTY` macro
`PROPERTY(name, get, set)`
  - `name`: property name
  - `get`: `fun(self): value`
  - `set`: `fun(self, value)`
- Prettified `LuaObjectField` struct with unions for function/property value types
- Added properties to `struct ModAudio`
  - `position`
  - `looping`
  - `frequency`
  - `volume`
    - NOTE: only work with streams- the audio reform will come later
This commit is contained in:
Cooliokid956 2025-12-30 20:52:53 -06:00
parent 39d351d753
commit a549c729ab
11 changed files with 156 additions and 122 deletions

View file

@ -97,7 +97,7 @@ WINDOWS_AUTO_BUILDER ?= 0
# Setup extra cflags
EXTRA_CFLAGS ?=
EXTRA_CPP_FLAGS ?=
EXTRA_CFLAGS += -Wno-format-security -Wno-trigraphs
EXTRA_CFLAGS += -Wno-format-security -Wno-trigraphs -Wno-missing-braces
dev:; @$(MAKE) DEVELOPMENT=1

View file

@ -6,6 +6,7 @@ usf_types = ['u8', 'u16', 'u32', 'u64', 's8', 's16', 's32', 's64', 'f32', 'f64']
vec_types = list(VEC_TYPES.keys())
typedef_pointers = ['BehaviorScript', 'ObjectAnimPointer', 'Collision', 'LevelScript', 'Trajectory', 'Texture']
cobject_function_identifier = 'FUNCTION'
cobject_property_identifier = 'PROPERTY'
type_mappings = {
'char': 's8',
@ -149,14 +150,10 @@ def translate_type_to_lvt(ptype, allowArrays=False):
if ptype == cobject_function_identifier:
return "LVT_FUNCTION"
if "struct" in ptype:
if pointerLvl > 1:
return "LVT_???"
if pointerLvl == 1:
return "LVT_COBJECT_P"
return "LVT_COBJECT"
if ptype == cobject_property_identifier:
return "LVT_PROPERTY"
if ptype in override_types:
if "struct" in ptype or ptype in override_types:
if pointerLvl > 1:
return "LVT_???"
if pointerLvl == 1:
@ -174,16 +171,8 @@ def translate_type_to_lot(ptype, allowArrays=True):
pointerLvl = 0
lvt = translate_type_to_lvt(ptype, allowArrays=allowArrays)
if ptype == 'void':
return 'LOT_NONE'
if ptype == 'const char*':
return 'LOT_NONE'
if ptype == 'ByteString':
return 'LOT_NONE'
if 'unsigned' not in ptype and (ptype == 'char*' or ('char' in ptype and '[' in ptype)):
if ptype == ('void', 'const char*', 'ByteString') \
or 'unsigned' not in ptype and (ptype == 'char*' or ('char' in ptype and '[' in ptype)):
return 'LOT_NONE'
# Remove array symbols so they can be identified
@ -199,13 +188,7 @@ def translate_type_to_lot(ptype, allowArrays=True):
if '[' in ptype or '{' in ptype:
return 'LOT_???'
if 'enum ' in ptype:
return 'LOT_NONE'
if ptype in usf_types:
return 'LOT_NONE'
if extract_integer_datatype(ptype):
if 'enum ' in ptype or ptype in usf_types or extract_integer_datatype(ptype):
return 'LOT_NONE'
# Strip out our pointer stars to get the true type.
@ -214,22 +197,10 @@ def translate_type_to_lot(ptype, allowArrays=True):
pointerLvl = ptype.count("*")
ptype = ptype.replace("*", "").strip()
if ptype == 'bool':
return 'LOT_NONE'
if ptype in vec_types:
return 'LOT_' + ptype.upper()
if ptype == 'float':
return 'LOT_NONE'
if ptype == 'LuaFunction':
return 'LOT_NONE'
if ptype == 'LuaTable':
return 'LOT_NONE'
if ptype == cobject_function_identifier:
if ptype in ('bool', 'float', 'LuaFunction', 'LuaTable', cobject_function_identifier, cobject_property_identifier):
return 'LOT_NONE'
if ptype in override_types:
@ -291,22 +262,10 @@ def translate_type_to_lua(ptype):
return '`number`', None
return '`integer`', None
if ptype == 'char':
if ptype in ('char', 'int', 'lua_Integer'):
return '`integer`', None
if ptype == 'int':
return '`integer`', None
if ptype == 'lua_Integer':
return '`integer`', None
if ptype == 'float':
return '`number`', None
if ptype == 'lua_Number':
return '`number`', None
if ptype == 'double':
if ptype in ('float', 'lua_Number', 'double'):
return '`number`', None
if ptype == 'bool':
@ -324,6 +283,9 @@ def translate_type_to_lua(ptype):
if ptype == cobject_function_identifier:
return cobject_function_identifier, None
if ptype == cobject_property_identifier:
return cobject_property_identifier, None
if ptype.count('*') == 1 and '???' not in translate_type_to_lvt(ptype):
ptype = ptype.replace('const', '').replace('*', '').strip()
s = '`Pointer` <`%s`>' % translate_type_to_lua(ptype)[0].replace('`', '').strip()

View file

@ -264,10 +264,17 @@ def table_to_string(table):
for row in table:
for i in range(columns):
if '#' in row[i]:
if '#' in row[i] or row[i][-1] == '\\':
continue
if len(row[i]) > column_width[i]:
column_width[i] = len(row[i])
for row in table:
for i in range(columns):
if row[i][-1] == '\\':
row[i] = row[i][:-1]
row[i+1] = row[i][column_width[i]:] + row[i+1]
row[i] = row[i][:column_width[i]]
s = ''
for row in table:
@ -327,12 +334,21 @@ def parse_struct(struct_str, sortFields = False):
# handle function members
if field['type'].startswith(cobject_function_identifier):
field_function = field['identifier']
field_type, field_id = field['type'].split()
field_function = field['identifier']
field['type'] = field_type.strip()
field['identifier'] = field_id.strip('"').strip()
field['identifier'] = field_id.strip()
field['function'] = field_function.strip()
# handle property members
if field['type'].startswith(cobject_property_identifier):
field_type, field_id, field_get = field['type'].split()
field_set = field['identifier']
field['type'] = field_type.strip()
field['identifier'] = field_id.strip()
field['get'] = field_get.strip()
field['set'] = field_set.strip()
struct['fields'].append(field)
if identifier == 'Object':
@ -496,9 +512,6 @@ def get_struct_field_info(struct, field):
if fid in override_field_mutable[sid] or '*' in override_field_mutable[sid]:
fimmutable = 'false'
if ftype == cobject_function_identifier:
fimmutable = 'true'
if not ('char' in ftype and '[' in ftype and 'unsigned' not in ftype):
array_match = re.search(r'\[([^\]]+)\]', ftype)
if array_match:
@ -549,27 +562,24 @@ def build_struct(struct):
startStr += '#ifndef ' + override_field_version_excludes[fid] + '\n'
endStr += '\n#endif'
startStr += ' { '
if ftype == cobject_function_identifier:
row.append(startStr )
row.append('"%s", ' % fid )
row.append('%s, ' % lvt )
row.append('(size_t) "%s", ' % field['function'])
row.append('%s, ' % fimmutable )
row.append('%s, ' % lot )
row.append('%s, ' % size )
row.append('sizeof(const char *)' )
row.append(endStr )
field_functions.append(field['function'])
row.append(startStr)
row.append('"%s", ' % fid)
row.append('%s, ' % lvt)
if field.get('function'):
row.append('.function = "%s"\\' % field['function'])
elif field.get('get'):
row.append('.get = "%s", ' % field['get'])
row.append('.set = "%s"\\' % field['set'])
else:
row.append(startStr )
row.append('"%s", ' % fid )
row.append('%s, ' % lvt )
row.append('offsetof(%s%s, %s), ' % (struct_str, name, field['identifier']))
row.append('%s, ' % fimmutable )
row.append('%s, ' % lot )
row.append('%s, ' % size )
row.append('sizeof(%s)' % ftype )
row.append(endStr )
row.append('%s, ' % fimmutable)
row.append('%s, ' % lot )
row.append('%s, ' % size )
row.append('sizeof(%s)' % ftype )
row.extend(['\\'] * (8 - len(row)))
row.append(endStr)
if field.get('function'):
field_functions.append(field['function'])
field_table.append(row)
field_table_str, field_count = table_to_string(field_table)
@ -726,6 +736,10 @@ def doc_struct_field(struct, field):
flink = doc_find_function_link(field['function'])
return '| %s | [`%s`](%s) |\n' % (fid, field['function'], flink), True
if ftype == cobject_property_identifier:
ftype = get_function_signature(field['get'])
ftype = f"`{ftype[ftype.rfind(':')+2:]}`"
restrictions = ('', 'read-only')[fimmutable == 'true']
global total_fields
@ -854,6 +868,9 @@ def def_struct(struct):
# try to get the function signature
if ftype == cobject_function_identifier:
ftype = get_function_signature(field['function'])
elif ftype == cobject_property_identifier:
ftype = get_function_signature(field['get'])
ftype = f"{ftype[ftype.rfind(':')+2:]}"
else:
ftype = translate_to_def(ftype)

View file

@ -1,7 +1,7 @@
import os
import re
import sys
from common import cobject_function_identifier
from common import cobject_function_identifier, cobject_property_identifier
def extract_structs(filename):
with open(filename) as file:
@ -38,7 +38,10 @@ def extract_structs(filename):
txt = txt.replace(' ', ' ')
# handle function members (NOT function pointers)
txt = re.sub(f'{cobject_function_identifier}\\((.*),(.*)\\)', f'{cobject_function_identifier} \\1 \\2', txt)
txt = re.sub(f'{cobject_function_identifier}\\((.*),(.*)\\)', f'{cobject_function_identifier} \\1\\2', txt)
# handle property members
txt = re.sub(f'{cobject_property_identifier}\\((.*),(.*),(.*)\\)', f'{cobject_property_identifier} \\1\\2\\3', txt)
# strip macros
txt = re.sub(r'[^a-zA-Z0-9_][A-Z0-9_]+\(.*\)', '', txt)

View file

@ -1207,6 +1207,10 @@
--- @field public isStream boolean
--- @field public baseVolume number
--- @field public loaded boolean
--- @field public position number
--- @field public looping boolean
--- @field public frequency number
--- @field public volume number
--- @class ModFs
--- @field public mod Mod

View file

@ -1763,6 +1763,10 @@
| isStream | `boolean` | read-only |
| baseVolume | `number` | |
| loaded | `boolean` | read-only |
| position | `number` | |
| looping | `boolean` | |
| frequency | `number` | |
| volume | `number` | |
[:arrow_up_small:](#)

View file

@ -21,6 +21,12 @@
// Optional parameters must be contiguous until the last parameter (a mandatory parameter following an optional parameter is not allowed)
#define OPTIONAL
/* A macro to tell autogen the field `name` is a property member of the struct that calls `get` or `set` accessors
- get: fun(self) -> value
- set: fun(self, value)
*/
#define PROPERTY(name, get, set)
// A macro to tell autogen the field `name` is a function member of the struct that calls `c_function`
#define FUNCTION(name, c_function)

View file

@ -101,6 +101,7 @@ static const char *sLuaLvtNames[] = {
[LVT_LUATABLE] = "LuaTable",
[LVT_POINTER] = "pointer",
[LVT_FUNCTION] = "function",
[LVT_PROPERTY] = "property",
[LVT_MAX] = "unknown",
};
@ -553,8 +554,16 @@ static int smlua__get_field(lua_State* L) {
// CObject function members
if (data->valueType == LVT_FUNCTION) {
const char *function = (const char *) data->valueOffset;
lua_getglobal(L, function);
lua_getglobal(L, data->function);
LUA_STACK_CHECK_END(L);
return 1;
}
// CObject property
if (data->valueType == LVT_PROPERTY) {;
lua_getglobal(L, data->get);
lua_pushvalue(L, 1);
smlua_pcall(L, 1, 1, 0);
LUA_STACK_CHECK_END(L);
return 1;
}
@ -634,7 +643,17 @@ static int smlua__set_field(lua_State* L) {
return 0;
}
if (data->immutable) {
// CObject property
if (data->valueType == LVT_PROPERTY) {
lua_getglobal(L, data->set);
lua_pushvalue(L, 1);
lua_pushvalue(L, 3);
smlua_pcall(L, 2, 1, 0);
LUA_STACK_CHECK_END(L);
return 1;
}
if (data->immutable || data->valueType == LVT_FUNCTION) {
LOG_LUA_LINE("_set_field on immutable key '%s'", key);
return 0;
}

View file

@ -36,17 +36,27 @@ enum LuaValueType {
LVT_LUATABLE,
LVT_POINTER,
LVT_FUNCTION,
LVT_PROPERTY,
LVT_MAX,
};
struct LuaObjectField {
const char* key;
enum LuaValueType valueType;
size_t valueOffset;
bool immutable;
u16 lot;
u16 count;
u32 size;
union {
struct {
size_t valueOffset;
bool immutable;
u16 lot;
u16 count;
u32 size;
};
const char* function;
struct {
const char* get;
const char* set;
};
};
};
struct LuaObjectTable {

View file

@ -1492,60 +1492,64 @@ static struct LuaObjectField sModFields[LUA_MOD_FIELD_COUNT] = {
{ "size", LVT_U64, offsetof(struct Mod, size), true, LOT_NONE, 1, sizeof(size_t) },
};
#define LUA_MOD_AUDIO_FIELD_COUNT 4
#define LUA_MOD_AUDIO_FIELD_COUNT 8
static struct LuaObjectField sModAudioFields[LUA_MOD_AUDIO_FIELD_COUNT] = {
{ "baseVolume", LVT_F32, offsetof(struct ModAudio, baseVolume), false, LOT_NONE, 1, sizeof(f32) },
{ "filepath", LVT_STRING_P, offsetof(struct ModAudio, filepath), true, LOT_NONE, 1, sizeof(const char*) },
{ "frequency", LVT_PROPERTY, .get = "audio_stream_get_frequency", .set = "audio_stream_set_frequency" },
{ "isStream", LVT_BOOL, offsetof(struct ModAudio, isStream), true, LOT_NONE, 1, sizeof(bool) },
{ "loaded", LVT_BOOL, offsetof(struct ModAudio, loaded), true, LOT_NONE, 1, sizeof(bool) },
{ "looping", LVT_PROPERTY, .get = "audio_stream_get_looping", .set = "audio_stream_set_looping" },
{ "position", LVT_PROPERTY, .get = "audio_stream_get_position", .set = "audio_stream_set_position" },
{ "volume", LVT_PROPERTY, .get = "audio_stream_get_volume", .set = "audio_stream_set_volume" },
};
#define LUA_MOD_FS_FIELD_COUNT 15
static struct LuaObjectField sModFsFields[LUA_MOD_FS_FIELD_COUNT] = {
{ "clear", LVT_FUNCTION, (size_t) "mod_fs_clear", true, LOT_NONE, 1, sizeof(const char *) },
{ "copy_file", LVT_FUNCTION, (size_t) "mod_fs_copy_file", true, LOT_NONE, 1, sizeof(const char *) },
{ "create_file", LVT_FUNCTION, (size_t) "mod_fs_create_file", true, LOT_NONE, 1, sizeof(const char *) },
{ "delete", LVT_FUNCTION, (size_t) "mod_fs_delete", true, LOT_NONE, 1, sizeof(const char *) },
{ "delete_file", LVT_FUNCTION, (size_t) "mod_fs_delete_file", true, LOT_NONE, 1, sizeof(const char *) },
{ "get_file", LVT_FUNCTION, (size_t) "mod_fs_get_file", true, LOT_NONE, 1, sizeof(const char *) },
{ "get_filename", LVT_FUNCTION, (size_t) "mod_fs_get_filename", true, LOT_NONE, 1, sizeof(const char *) },
{ "isPublic", LVT_BOOL, offsetof(struct ModFs, isPublic), true, LOT_NONE, 1, sizeof(bool) },
{ "mod", LVT_COBJECT_P, offsetof(struct ModFs, mod), true, LOT_MOD, 1, sizeof(struct Mod*) },
{ "modPath", LVT_STRING, offsetof(struct ModFs, modPath), true, LOT_NONE, 1, sizeof(char) },
{ "move_file", LVT_FUNCTION, (size_t) "mod_fs_move_file", true, LOT_NONE, 1, sizeof(const char *) },
{ "numFiles", LVT_U16, offsetof(struct ModFs, numFiles), true, LOT_NONE, 1, sizeof(u16) },
{ "save", LVT_FUNCTION, (size_t) "mod_fs_save", true, LOT_NONE, 1, sizeof(const char *) },
{ "set_public", LVT_FUNCTION, (size_t) "mod_fs_set_public", true, LOT_NONE, 1, sizeof(const char *) },
{ "totalSize", LVT_U32, offsetof(struct ModFs, totalSize), true, LOT_NONE, 1, sizeof(u32) },
{ "clear", LVT_FUNCTION, .function = "mod_fs_clear" },
{ "copy_file", LVT_FUNCTION, .function = "mod_fs_copy_file" },
{ "create_file", LVT_FUNCTION, .function = "mod_fs_create_file" },
{ "delete", LVT_FUNCTION, .function = "mod_fs_delete" },
{ "delete_file", LVT_FUNCTION, .function = "mod_fs_delete_file" },
{ "get_file", LVT_FUNCTION, .function = "mod_fs_get_file" },
{ "get_filename", LVT_FUNCTION, .function = "mod_fs_get_filename" },
{ "isPublic", LVT_BOOL, offsetof(struct ModFs, isPublic), true, LOT_NONE, 1, sizeof(bool) },
{ "mod", LVT_COBJECT_P, offsetof(struct ModFs, mod), true, LOT_MOD, 1, sizeof(struct Mod*) },
{ "modPath", LVT_STRING, offsetof(struct ModFs, modPath), true, LOT_NONE, 1, sizeof(char) },
{ "move_file", LVT_FUNCTION, .function = "mod_fs_move_file" },
{ "numFiles", LVT_U16, offsetof(struct ModFs, numFiles), true, LOT_NONE, 1, sizeof(u16) },
{ "save", LVT_FUNCTION, .function = "mod_fs_save" },
{ "set_public", LVT_FUNCTION, .function = "mod_fs_set_public" },
{ "totalSize", LVT_U32, offsetof(struct ModFs, totalSize), true, LOT_NONE, 1, sizeof(u32) },
};
#define LUA_MOD_FS_FILE_FIELD_COUNT 25
static struct LuaObjectField sModFsFileFields[LUA_MOD_FS_FILE_FIELD_COUNT] = {
{ "erase", LVT_FUNCTION, (size_t) "mod_fs_file_erase", true, LOT_NONE, 1, sizeof(const char *) },
{ "erase", LVT_FUNCTION, .function = "mod_fs_file_erase" },
{ "filepath", LVT_STRING, offsetof(struct ModFsFile, filepath), true, LOT_NONE, 1, sizeof(char) },
{ "fill", LVT_FUNCTION, (size_t) "mod_fs_file_fill", true, LOT_NONE, 1, sizeof(const char *) },
{ "fill", LVT_FUNCTION, .function = "mod_fs_file_fill" },
{ "isPublic", LVT_BOOL, offsetof(struct ModFsFile, isPublic), true, LOT_NONE, 1, sizeof(bool) },
{ "isText", LVT_BOOL, offsetof(struct ModFsFile, isText), true, LOT_NONE, 1, sizeof(bool) },
{ "is_eof", LVT_FUNCTION, (size_t) "mod_fs_file_is_eof", true, LOT_NONE, 1, sizeof(const char *) },
{ "is_eof", LVT_FUNCTION, .function = "mod_fs_file_is_eof" },
{ "modFs", LVT_COBJECT_P, offsetof(struct ModFsFile, modFs), true, LOT_MODFS, 1, sizeof(struct ModFs*) },
{ "offset", LVT_U32, offsetof(struct ModFsFile, offset), true, LOT_NONE, 1, sizeof(u32) },
{ "read_bool", LVT_FUNCTION, (size_t) "mod_fs_file_read_bool", true, LOT_NONE, 1, sizeof(const char *) },
{ "read_bytes", LVT_FUNCTION, (size_t) "mod_fs_file_read_bytes", true, LOT_NONE, 1, sizeof(const char *) },
{ "read_integer", LVT_FUNCTION, (size_t) "mod_fs_file_read_integer", true, LOT_NONE, 1, sizeof(const char *) },
{ "read_line", LVT_FUNCTION, (size_t) "mod_fs_file_read_line", true, LOT_NONE, 1, sizeof(const char *) },
{ "read_number", LVT_FUNCTION, (size_t) "mod_fs_file_read_number", true, LOT_NONE, 1, sizeof(const char *) },
{ "read_string", LVT_FUNCTION, (size_t) "mod_fs_file_read_string", true, LOT_NONE, 1, sizeof(const char *) },
{ "rewind", LVT_FUNCTION, (size_t) "mod_fs_file_rewind", true, LOT_NONE, 1, sizeof(const char *) },
{ "seek", LVT_FUNCTION, (size_t) "mod_fs_file_seek", true, LOT_NONE, 1, sizeof(const char *) },
{ "set_public", LVT_FUNCTION, (size_t) "mod_fs_file_set_public", true, LOT_NONE, 1, sizeof(const char *) },
{ "set_text_mode", LVT_FUNCTION, (size_t) "mod_fs_file_set_text_mode", true, LOT_NONE, 1, sizeof(const char *) },
{ "read_bool", LVT_FUNCTION, .function = "mod_fs_file_read_bool" },
{ "read_bytes", LVT_FUNCTION, .function = "mod_fs_file_read_bytes" },
{ "read_integer", LVT_FUNCTION, .function = "mod_fs_file_read_integer" },
{ "read_line", LVT_FUNCTION, .function = "mod_fs_file_read_line" },
{ "read_number", LVT_FUNCTION, .function = "mod_fs_file_read_number" },
{ "read_string", LVT_FUNCTION, .function = "mod_fs_file_read_string" },
{ "rewind", LVT_FUNCTION, .function = "mod_fs_file_rewind" },
{ "seek", LVT_FUNCTION, .function = "mod_fs_file_seek" },
{ "set_public", LVT_FUNCTION, .function = "mod_fs_file_set_public" },
{ "set_text_mode", LVT_FUNCTION, .function = "mod_fs_file_set_text_mode" },
{ "size", LVT_U32, offsetof(struct ModFsFile, size), true, LOT_NONE, 1, sizeof(u32) },
{ "write_bool", LVT_FUNCTION, (size_t) "mod_fs_file_write_bool", true, LOT_NONE, 1, sizeof(const char *) },
{ "write_bytes", LVT_FUNCTION, (size_t) "mod_fs_file_write_bytes", true, LOT_NONE, 1, sizeof(const char *) },
{ "write_integer", LVT_FUNCTION, (size_t) "mod_fs_file_write_integer", true, LOT_NONE, 1, sizeof(const char *) },
{ "write_line", LVT_FUNCTION, (size_t) "mod_fs_file_write_line", true, LOT_NONE, 1, sizeof(const char *) },
{ "write_number", LVT_FUNCTION, (size_t) "mod_fs_file_write_number", true, LOT_NONE, 1, sizeof(const char *) },
{ "write_string", LVT_FUNCTION, (size_t) "mod_fs_file_write_string", true, LOT_NONE, 1, sizeof(const char *) },
{ "write_bool", LVT_FUNCTION, .function = "mod_fs_file_write_bool" },
{ "write_bytes", LVT_FUNCTION, .function = "mod_fs_file_write_bytes" },
{ "write_integer", LVT_FUNCTION, .function = "mod_fs_file_write_integer" },
{ "write_line", LVT_FUNCTION, .function = "mod_fs_file_write_line" },
{ "write_number", LVT_FUNCTION, .function = "mod_fs_file_write_number" },
{ "write_string", LVT_FUNCTION, .function = "mod_fs_file_write_string" },
};
#define LUA_NAMETAGS_SETTINGS_FIELD_COUNT 2

View file

@ -31,6 +31,11 @@ struct ModAudio {
bool isStream;
f32 baseVolume;
bool loaded;
PROPERTY(position, audio_stream_get_position, audio_stream_set_position);
PROPERTY(looping, audio_stream_get_looping, audio_stream_set_looping);
PROPERTY(frequency, audio_stream_get_frequency, audio_stream_set_frequency);
PROPERTY(volume, audio_stream_get_volume, audio_stream_set_volume);
};
/* |description|Loads an `audio` stream by `filename` (with extension)|descriptionEnd| */