Mod file system (#850)
Some checks are pending
Build coop / build-linux (push) Waiting to run
Build coop / build-steamos (push) Waiting to run
Build coop / build-windows-opengl (push) Waiting to run
Build coop / build-windows-directx (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run

* modfs; optional function parameters in autogen

* errors and stuff

* script to turn a directory into a modfs file and vice versa

* bug fixes

* read: raise error on eof

* properly check eof on read_string

* fill; reload; check pointer validity; skip private files when loading non-active modfs

* added bytestrings

* move ByteString to smlua_utils.h
This commit is contained in:
PeachyPeach 2025-07-01 01:53:47 +02:00 committed by GitHub
parent cf43b5d465
commit 4c3ee14f55
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 4554 additions and 730 deletions

View file

@ -148,6 +148,9 @@ def translate_type_to_lot(ptype, allowArrays=True):
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)):
return 'LOT_NONE'
@ -215,6 +218,9 @@ def translate_type_to_lua(ptype):
if ptype == 'const char*':
return '`string`', None
if ptype == 'ByteString':
return '`string`', None
if 'unsigned' not in ptype and (ptype == 'char*' or ('char' in ptype and '[' in ptype)):
return '`string`', None
@ -253,9 +259,15 @@ def translate_type_to_lua(ptype):
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':
return '`number`', None

View file

@ -46,6 +46,7 @@ in_files = [
"src/audio/external.h",
"src/game/envfx_snow.h",
"src/pc/mods/mod_storage.h",
"src/pc/mods/mod_fs.h",
"src/game/first_person_cam.h",
"src/pc/djui/djui_console.h",
"src/game/player_palette.h",
@ -65,7 +66,8 @@ exclude_constants = {
"src/game/obj_behaviors.c": [ "^o$" ],
"src/pc/djui/djui_console.h": [ "CONSOLE_MAX_TMP_BUFFER" ],
"src/pc/lua/smlua_hooks.h": [ "MAX_HOOKED_MOD_MENU_ELEMENTS", "^HOOK_RETURN_.*", "^ACTION_HOOK_.*", "^MOD_MENU_ELEMENT_.*" ],
"src/pc/djui/djui_panel_menu.h": [ "RAINBOW_TEXT_LEN" ]
"src/pc/djui/djui_panel_menu.h": [ "RAINBOW_TEXT_LEN" ],
"src/pc/mods/mod_fs.h": [ "MOD_FS_DIRECTORY", "MOD_FS_EXTENSION", "MOD_FS_VERSION", "INT_TYPE_MAX", "FLOAT_TYPE_MAX", "FILE_SEEK_MAX" ]
}
include_constants = {

View file

@ -7,8 +7,8 @@ from vec_types import *
verbose = len(sys.argv) > 1 and (sys.argv[1] == "-v" or sys.argv[1] == "--verbose")
rejects = ""
integer_types = ["u8", "u16", "u32", "u64", "s8", "s16", "s32", "s64", "int"]
number_types = ["f32", "float", "f64", "double"]
integer_types = ["u8", "u16", "u32", "u64", "s8", "s16", "s32", "s64", "int", "lua_Integer"]
number_types = ["f32", "float", "f64", "double", "lua_Number"]
out_filename = 'src/pc/lua/smlua_functions_autogen.c'
out_filename_docs = 'docs/lua/functions%s.md'
out_filename_defs = 'autogen/lua_definitions/functions.lua'
@ -69,6 +69,7 @@ in_files = [
"src/game/behavior_actions.h",
"src/game/mario_misc.h",
"src/pc/mods/mod_storage.h",
"src/pc/mods/mod_fs.h",
"src/pc/utils/misc.h",
"src/game/level_update.h",
"src/game/area.h",
@ -156,6 +157,11 @@ lua_function_params = {
"src/pc/lua/utils/smlua_obj_utils.h::spawn_object_sync::objSetupFunction": [ "struct Object*" ]
}
parameter_keywords = [
"OUT",
"OPTIONAL"
]
###########################################################
template = """/* THIS FILE IS AUTOGENERATED */
@ -803,6 +809,8 @@ def build_param(fid, param, i):
return ' %s %s = smlua_to_number(L, %d);\n' % (ptype, pid, i)
elif ptype == 'const char*':
return ' %s %s = smlua_to_string(L, %d);\n' % (ptype, pid, i)
elif ptype == 'ByteString':
return ' %s %s = smlua_to_bytestring(L, %d);\n' % (ptype, pid, i)
elif ptype == 'LuaFunction':
return ' %s %s = smlua_to_lua_function(L, %d);\n' % (ptype, pid, i)
elif translate_type_to_lot(ptype) == 'LOT_POINTER':
@ -822,7 +830,7 @@ def build_param(fid, param, i):
def build_param_after(param, i):
ptype = param['type']
pid = param['identifier']
is_output = param.get('out', False)
is_output = 'OUT' in param
if ptype in VEC_TYPES and is_output:
return (vec_type_after % (ptype.lower())).replace('$[IDENTIFIER]', str(pid)).replace('$[INDEX]', str(i))
@ -858,6 +866,8 @@ def build_call(function):
lfunc = 'lua_pushstring'
elif ftype == 'const char*':
lfunc = 'lua_pushstring'
elif ftype == 'ByteString':
lfunc = 'smlua_push_bytestring'
elif translate_type_to_lot(ftype) == 'LOT_POINTER':
lvt = translate_type_to_lvt(ftype)
return ' smlua_push_pointer(L, %s, (void*)%s, NULL);\n' % (lvt, ccall)
@ -884,19 +894,39 @@ def build_function(function, do_extern):
if 'bhv_' in fid:
s += ' if (!gCurrentObject) { return 0; }\n'
s += """ if (L == NULL) { return 0; }\n
params_max = len(function['params'])
params_min = len([param for param in function['params'] if 'OPTIONAL' not in param])
if params_min == params_max:
s += """ if (L == NULL) { return 0; }\n
int top = lua_gettop(L);
if (top != %d) {
LOG_LUA_LINE("Improper param count for '%%s': Expected %%u, Received %%u", "%s", %d, top);
return 0;
}\n\n""" % (len(function['params']), function['identifier'], len(function['params']))
}\n\n""" % (params_max, function['identifier'], params_max)
else:
s += """ if (L == NULL) { return 0; }\n
int top = lua_gettop(L);
if (top < %d || top > %d) {
LOG_LUA_LINE("Improper param count for '%%s': Expected between %%u and %%u, Received %%u", "%s", %d, %d, top);
return 0;
}\n\n""" % (params_min, params_max, function['identifier'], params_min, params_max)
is_interact_func = fid.startswith('interact_') and fname == 'interaction.h'
i = 1
for param in function['params']:
if is_interact_func and param['identifier'] == 'interactType':
pid = param['identifier']
if is_interact_func and pid == 'interactType':
s += " // interactType skipped so mods can't lie about what interaction it is\n"
elif 'OPTIONAL' in param:
sparam = build_param(fid, param, i)
param_var, param_value = sparam.split('=')
param_type = param_var.replace(pid, '').strip()
s += ' %s = (%s) NULL;\n' % (param_var.strip(), param_type)
s += ' if (top >= %d) {\n' % (i)
s += ' %s = %s\n' % (pid, param_value.strip())
s += ' if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %%u for function \'%%s\'", %d, "%s"); return 0; }\n' % (i, fid)
s += ' }\n'
else:
s += build_param(fid, param, i)
s += ' if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %%u for function \'%%s\'", %d, "%s"); return 0; }\n' % (i, fid)
@ -921,7 +951,7 @@ def build_function(function, do_extern):
# To allow chaining vector functions calls, return the table corresponding to the `OUT` parameter
if function['type'] in VECP_TYPES:
for i, param in enumerate(function['params']):
if param.get('out', False):
if 'OUT' in param:
s += ' lua_settop(L, %d);\n' % (i + 1)
break
@ -1020,13 +1050,16 @@ def process_function(fname, line, description):
pass
else:
param_index = 0
last_param_optional = None
for param_str in params_str.split(','):
param = {}
param_str = param_str.strip()
if param_str.startswith('OUT '):
param['out'] = True
param_str = param_str[len('OUT'):].strip()
for param_keyword in parameter_keywords:
keyword_index = param_str.find(param_keyword + ' ')
if keyword_index != -1:
param[param_keyword] = True
param_str = (param_str[:keyword_index] + param_str[keyword_index+len(param_keyword)+1:]).strip()
if param_str.endswith('*') or ' ' not in param_str:
param['type'] = normalize_type(param_str)
@ -1038,6 +1071,12 @@ def process_function(fname, line, description):
param['type'] = normalize_type(param_str[0:match.span()[0]])
param['identifier'] = match.group()
if 'OPTIONAL' in param:
last_param_optional = param['identifier']
elif last_param_optional is not None:
print(f"REJECTED: {function['identifier']} -> mandatory parameter `{param['identifier']}` is following optional parameter `{last_param_optional}`")
return None
# override Vec3s/f
if param['identifier'] == 'pos':
if param['type'].replace(' ', '') == 'f32*':
@ -1354,7 +1393,7 @@ def def_function(fname, function):
if ptype.startswith('Pointer_') and ptype not in def_pointers:
def_pointers.append(ptype)
s += '--- @param %s %s\n' % (pid, ptype)
s += '--- @param %s%s %s\n' % (pid, ('?' if 'OPTIONAL' in param else ''), ptype)
rtype = translate_to_def(rtype)
if rtype.startswith('Pointer_') and rtype not in def_pointers:

View file

@ -27,6 +27,7 @@ in_files = [
"src/pc/network/network.h",
"src/game/hardcoded.h",
"src/pc/mods/mod.h",
"src/pc/mods/mod_fs.h",
"src/pc/lua/utils/smlua_audio_utils.h",
"src/game/paintings.h",
"src/pc/djui/djui_types.h",
@ -97,7 +98,9 @@ override_field_invisible = {
"FnGraphNode": [ "luaTokenIndex" ],
"Object": [ "firstSurface" ],
"ModAudio": [ "sound", "decoder", "buffer", "bufferSize", "sampleCopiesTail" ],
"DialogEntry": [ "str" ]
"DialogEntry": [ "str" ],
"ModFsFile": [ "data", "capacity" ],
"ModFs": [ "files" ],
}
override_field_deprecated = {
@ -137,7 +140,9 @@ override_field_immutable = {
"FirstPersonCamera": [ "enabled" ],
"ModAudio": [ "isStream", "loaded" ],
"Gfx": [ "w0", "w1" ], # to protect from invalid type conversions
"DialogEntry": [ "unused", "linesPerBox", "leftOffset", "width", "str", "text"]
"DialogEntry": [ "unused", "linesPerBox", "leftOffset", "width", "str", "text"],
"ModFsFile": [ "*" ],
"ModFs": [ "*" ],
}
override_field_version_excludes = {

View file

@ -4533,6 +4533,50 @@ GRAB_POS_BOWSER = 3 --- @type MarioGrabPosGSCId
--- | `GRAB_POS_HEAVY_OBJ`
--- | `GRAB_POS_BOWSER`
--- @type integer
MOD_FS_MAX_SIZE = 0x1000000
--- @type integer
MOD_FS_MAX_FILES = 0x100
--- @type integer
MOD_FS_MAX_PATH = 0x100
INT_TYPE_U8 = 0 --- @type ModFsFileIntType
INT_TYPE_U16 = 1 --- @type ModFsFileIntType
INT_TYPE_U32 = 2 --- @type ModFsFileIntType
INT_TYPE_U64 = 3 --- @type ModFsFileIntType
INT_TYPE_S8 = 4 --- @type ModFsFileIntType
INT_TYPE_S16 = 5 --- @type ModFsFileIntType
INT_TYPE_S32 = 6 --- @type ModFsFileIntType
INT_TYPE_S64 = 7 --- @type ModFsFileIntType
--- @alias ModFsFileIntType
--- | `INT_TYPE_U8`
--- | `INT_TYPE_U16`
--- | `INT_TYPE_U32`
--- | `INT_TYPE_U64`
--- | `INT_TYPE_S8`
--- | `INT_TYPE_S16`
--- | `INT_TYPE_S32`
--- | `INT_TYPE_S64`
FLOAT_TYPE_F32 = 0 --- @type ModFsFileFloatType
FLOAT_TYPE_F64 = 1 --- @type ModFsFileFloatType
--- @alias ModFsFileFloatType
--- | `FLOAT_TYPE_F32`
--- | `FLOAT_TYPE_F64`
FILE_SEEK_SET = 0 --- @type ModFsFileSeek
FILE_SEEK_CUR = 1 --- @type ModFsFileSeek
FILE_SEEK_END = 2 --- @type ModFsFileSeek
--- @alias ModFsFileSeek
--- | `FILE_SEEK_SET`
--- | `FILE_SEEK_CUR`
--- | `FILE_SEEK_END`
--- @type integer
MAX_KEYS = 4096

View file

@ -7340,6 +7340,260 @@ function delta_interpolate_vec3s(res, a, b, delta)
-- ...
end
--- @param modPath? string
--- @return boolean
--- Checks the existence of a modfs at path `modPath` or for the active mod if not provided. Checking for the existence of a private modfs will return false, even if it exists
function mod_fs_exists(modPath)
-- ...
end
--- @param modPath? string
--- @return ModFs
--- Gets the modfs object at path `modPath` or the active mod one if not provided. This function will return nil for a private modfs, even if it exists
function mod_fs_get(modPath)
-- ...
end
--- @param modPath? string
--- @return ModFs
--- Reloads the modfs object at path `modPath`. This function will return nil for a private modfs, even if it exists
function mod_fs_reload(modPath)
-- ...
end
--- @return ModFs
--- Creates a modfs object for the active mod if it doesn't exist. Returns the modfs object on success
function mod_fs_create()
-- ...
end
--- @return boolean
--- Deletes the modfs object of the active mod if it exists. Returns true on success
function mod_fs_delete()
-- ...
end
--- @return boolean
--- Saves the modfs object of the active mod if it exists. Returns true on success
function mod_fs_save()
-- ...
end
--- @param pub boolean
--- @return boolean
--- Marks the modfs object of the active mod as public (i.e. readable by other mods) if it exists. Returns true on success
function mod_fs_set_public(pub)
-- ...
end
--- @param modFs ModFs
--- @param index integer
--- @return string
--- Gets the filename at position `index` of the provided `modFs`
function mod_fs_get_filename(modFs, index)
-- ...
end
--- @param modFs ModFs
--- @param filepath string
--- @return ModFsFile
--- Gets the file object at path `filepath` of the provided `modFs`. This function will return nil for a private modfs file, even if it exists
function mod_fs_get_file(modFs, filepath)
-- ...
end
--- @param modFs ModFs
--- @param filepath string
--- @param text boolean
--- @return ModFsFile
--- Creates a new file at path `filepath` for the provided `modFs`. Set `text` to true to treat the file as a pure text file, not a binary file. Returns the created file on success
function mod_fs_create_file(modFs, filepath, text)
-- ...
end
--- @param modFs ModFs
--- @param oldpath string
--- @param newpath string
--- @param overwriteExisting boolean
--- @return boolean
--- Moves the file at path `oldpath` to `newpath` of the provided `modFs`. Set `overwriteExisting` to true to overwrite the file at path `newpath` if it exists. Returns true on success
function mod_fs_move_file(modFs, oldpath, newpath, overwriteExisting)
-- ...
end
--- @param modFs ModFs
--- @param srcpath string
--- @param dstpath string
--- @param overwriteExisting boolean
--- @return boolean
--- Copies the file at path `srcpath` to `dstpath` of the provided `modFs`. Set `overwriteExisting` to true to overwrite the file at path `dstpath` if it exists. Returns true on success
function mod_fs_copy_file(modFs, srcpath, dstpath, overwriteExisting)
-- ...
end
--- @param modFs ModFs
--- @param filepath string
--- @return boolean
--- Deletes the file at path `filepath` of the provided `modFs`. Returns true on success
function mod_fs_delete_file(modFs, filepath)
-- ...
end
--- @param modFs ModFs
--- @return boolean
--- Deletes all files of the provided `modFs`. Returns true on success
function mod_fs_clear(modFs)
-- ...
end
--- @param file ModFsFile
--- @return boolean
--- Reads a boolean from a binary modfs `file`
function mod_fs_file_read_bool(file)
-- ...
end
--- @param file ModFsFile
--- @param intType ModFsFileIntType
--- @return integer
--- Reads an integer from a binary modfs `file`. `intType` must be one of the `INT_TYPE_*` constants
function mod_fs_file_read_integer(file, intType)
-- ...
end
--- @param file ModFsFile
--- @param floatType ModFsFileFloatType
--- @return number
--- Reads an floating-point number from a binary modfs `file`. `floatType` must be one of the `FLOAT_TYPE_*` constants
function mod_fs_file_read_number(file, floatType)
-- ...
end
--- @param file ModFsFile
--- @param length integer
--- @return string
--- Reads a bytestring of `length` bytes from a binary modfs `file`
function mod_fs_file_read_bytes(file, length)
-- ...
end
--- @param file ModFsFile
--- @return string
--- Reads a string from a binary modfs `file`, or read the whole content of a text modfs `file`
function mod_fs_file_read_string(file)
-- ...
end
--- @param file ModFsFile
--- @return string
--- Reads a line from a text modfs `file`
function mod_fs_file_read_line(file)
-- ...
end
--- @param file ModFsFile
--- @param value boolean
--- @return boolean
--- Writes a boolean to a binary modfs `file`. Returns true on success
function mod_fs_file_write_bool(file, value)
-- ...
end
--- @param file ModFsFile
--- @param value integer
--- @param intType ModFsFileIntType
--- @return boolean
--- Writes an integer to a binary modfs `file`. `intType` must be one of the `INT_TYPE_*` constants. Returns true on success
function mod_fs_file_write_integer(file, value, intType)
-- ...
end
--- @param file ModFsFile
--- @param value number
--- @param floatType ModFsFileFloatType
--- @return boolean
--- Writes an floating-point number to a binary modfs `file`. `floatType` must be one of the `FLOAT_TYPE_*` constants. Returns true on success
function mod_fs_file_write_number(file, value, floatType)
-- ...
end
--- @param file ModFsFile
--- @param bytestring string
--- @return boolean
--- Writes a bytestring to a modfs `file`. Returns true on success
function mod_fs_file_write_bytes(file, bytestring)
-- ...
end
--- @param file ModFsFile
--- @param str string
--- @return boolean
--- Writes a string to a modfs `file`. Returns true on success
function mod_fs_file_write_string(file, str)
-- ...
end
--- @param file ModFsFile
--- @param str string
--- @return boolean
--- Writes a line to a text modfs `file`. Returns true on success
function mod_fs_file_write_line(file, str)
-- ...
end
--- @param file ModFsFile
--- @param offset integer
--- @param origin ModFsFileSeek
--- @return boolean
--- Sets the current position of a modfs `file`. If `origin` is `FILE_SEEK_SET`, file position is set to `offset`. If `origin` is `FILE_SEEK_CUR`, `offset` is added to file current position. If `origin` is `FILE_SEEK_END`, file position is set to `end of file + offset`. Returns true on success
function mod_fs_file_seek(file, offset, origin)
-- ...
end
--- @param file ModFsFile
--- @return boolean
--- Returns true if the provided modfs `file` has reached its end of file
function mod_fs_file_is_eof(file)
-- ...
end
--- @param file ModFsFile
--- @param byte integer
--- @param length integer
--- @return boolean
--- Fills a modfs `file` with `byte` repeated `length` times. Returns true on success
function mod_fs_file_fill(file, byte, length)
-- ...
end
--- @param file ModFsFile
--- @param length integer
--- @return boolean
--- Erases `length` bytes or characters from a modfs `file`. Returns true on success
function mod_fs_file_erase(file, length)
-- ...
end
--- @param file ModFsFile
--- @param pub boolean
--- @return boolean
--- Marks the provided modfs `file` as public (i.e. readable by other mods). Returns true on success
function mod_fs_file_set_public(file, pub)
-- ...
end
--- @param hide boolean
--- Hides script errors raised by `mod_fs` functions. Errors messages are still generated and can be retrieved with `mod_fs_get_last_error()`
function mod_fs_hide_errors(hide)
-- ...
end
--- @return string
--- Returns the last error message generated by `mod_fs` functions or nil if no error occurred
function mod_fs_get_last_error()
-- ...
end
--- @param key string
--- @param value string
--- @return boolean

View file

@ -1289,6 +1289,21 @@
--- @field public relativePath string
--- @field public wroteBytes integer
--- @class ModFs
--- @field public isPublic boolean
--- @field public mod Mod
--- @field public modPath string
--- @field public numFiles integer
--- @field public totalSize integer
--- @class ModFsFile
--- @field public filepath string
--- @field public isPublic boolean
--- @field public isText boolean
--- @field public modFs ModFs
--- @field public offset integer
--- @field public size integer
--- @class ModeTransitionInfo
--- @field public frame integer
--- @field public lastMode integer

190
developer/dir2modfs.py Normal file
View file

@ -0,0 +1,190 @@
import os, sys, re
MOD_FS_MAGIC = "MODFSSM64COOPDX"
MOD_FS_HEADER_SIZE = 32
MOD_FS_EXTENSION = ".modfs"
MOD_FS_VERSION = 1
MOD_FS_MAX_SIZE = 0x1000000
MOD_FS_MAX_FILES = 0x100
MOD_FS_MAX_PATH = 0x100
def usage():
print("""
Directory to modfs:
python dir2modfs.py <dirpath> [--set-public] [--set-file-public <files>...]
Parameters:
dirpath Path to directory to turn into a .modfs file
Options:
--set-public Set modfs file as public (readable by other mods)
--set-file-public <files> Set the provided files as public (readable by other mods)
modfs to directory:
python dir2modfs.py <filepath> --extract
Parameters:
filepath Path to modfs file to extract files from
""")
exit(0)
def is_binary_file(bytes: bytes):
textchars = bytearray({0x07, 0x08, 0x09, 0x0A, 0x0C, 0x0D, 0x1B} | set(range(0x20, 0x100)) - {0x7F})
return bool(bytes.translate(None, textchars))
def get_files(dirpath: str, public_files: list):
files = []
for root, _, filenames in os.walk(dirpath):
for filename in filenames:
relpath = os.path.join(root, filename)
filepath = relpath.removeprefix(dirpath).strip("/\\").replace('\\', '/')
is_public = False
for public_file in public_files:
if re.match(public_file, relpath) or re.match(public_file, filepath):
is_public = True
break
files.append({
"relpath": relpath,
"filepath": filepath,
"is_public": is_public,
"is_text": False,
"data": None
})
return files
def convert(dirpath: str, set_public: bool, public_files: list):
dirpath = dirpath.rstrip("/\\")
files = sorted(get_files(dirpath, public_files), key=lambda file: file["filepath"])
if len(files) > MOD_FS_MAX_FILES:
raise Exception(f"Max number of files exceeded: {len(files)} (max is: {MOD_FS_MAX_FILES})")
total_size = 0
for file in files:
filepath = file["filepath"]
if len(filepath) >= MOD_FS_MAX_PATH:
raise Exception(f"{filepath} - Exceeded filepath length: {len(filepath)} (max is: {MOD_FS_MAX_PATH-1})")
with open(file["relpath"], "rb") as f:
data = f.read()
total_size += len(data)
if total_size > MOD_FS_MAX_SIZE:
raise Exception(f"{filepath} - Total size exceeded: {total_size} (max is: {MOD_FS_MAX_SIZE})")
file["data"] = data
file["is_text"] = not is_binary_file(data)
# write file
destpath = dirpath + MOD_FS_EXTENSION
with open(destpath, "wb") as f:
# magic + version
f.write(MOD_FS_MAGIC.encode())
f.write(MOD_FS_VERSION.to_bytes(1, byteorder="little", signed=False))
# header
f.write(len(files).to_bytes(2, byteorder="little", signed=False))
f.write(set_public.to_bytes(1, byteorder="little", signed=False))
# padding (empty space for future versions)
padding = MOD_FS_HEADER_SIZE - f.tell()
f.write(b'\0' * padding)
# files
for file in files:
# filepath
f.write(len(file["filepath"]).to_bytes(2, byteorder="little", signed=False))
f.write(file["filepath"].encode())
# data
f.write(len(file["data"]).to_bytes(4, byteorder="little", signed=False))
f.write(file["is_public"].to_bytes(1, byteorder="little", signed=False))
f.write(file["is_text"].to_bytes(1, byteorder="little", signed=False))
f.write(file["data"])
# summary
print("")
print(f"Directory: {dirpath}")
print(f"Num files: {len(files)}")
print(f"Total size: {total_size}")
print(f"Is public: {set_public}")
filepaths_max = max(8, len(max([file["filepath"] for file in files], key=len)))
sizes_max = max(4, len(max([str(len(file["data"])) for file in files], key=len)))
print("")
print(f"{'FILEPATH'.ljust(filepaths_max)} {'SIZE'.rjust(sizes_max)} {'TEXT'.rjust(5)} {'PUBLIC'.rjust(6)}")
print(f"{'--------'.ljust(filepaths_max)} {'----'.rjust(sizes_max)} {'----'.rjust(5)} {'------'.rjust(6)}")
for file in files:
filepath = file["filepath"]
size = str(len(file["data"]))
is_text = str(file["is_text"])
is_public = str(file["is_public"])
print(f"{filepath.ljust(filepaths_max)} {size.rjust(sizes_max)} {is_text.rjust(5)} {is_public.rjust(6)}")
def extract(filepath: str):
if not filepath.endswith(MOD_FS_EXTENSION):
raise Exception("Not a modfs file")
with open(filepath, "rb") as f:
# magic + version
magic = f.read(len(MOD_FS_MAGIC)).decode()
if magic != MOD_FS_MAGIC:
raise Exception("Not a modfs file")
version = int.from_bytes(f.read(1), byteorder="little", signed=False)
if version != MOD_FS_VERSION:
raise Exception("Version mismatch")
# header
num_files = int.from_bytes(f.read(2), byteorder="little", signed=False)
is_public = bool.from_bytes(f.read(1), byteorder="little", signed=False)
# padding (empty space for future versions)
f.seek(MOD_FS_HEADER_SIZE, 0)
# create directory
dirpath = filepath.removesuffix(MOD_FS_EXTENSION)
os.makedirs(dirpath, exist_ok=True)
# files
for _ in range(num_files):
# filepath
filepath_len = int.from_bytes(f.read(2), byteorder="little", signed=False)
filepath = os.path.join(dirpath, f.read(filepath_len).decode())
# data
file_size = int.from_bytes(f.read(4), byteorder="little", signed=False)
file_is_public = bool.from_bytes(f.read(1), byteorder="little", signed=False)
file_is_text = bool.from_bytes(f.read(1), byteorder="little", signed=False)
file_data = f.read(file_size)
# write file
os.makedirs(os.path.dirname(filepath), exist_ok=True)
with open(filepath, "wb") as g:
g.write(file_data)
print(f"Extracted file of size {file_size} to: {filepath}")
def main(argc: int, argv: list):
if argc < 2:
usage()
if "--extract" in argv:
extract(argv[1])
else:
set_public = "--set-public" in argv
set_file_public_index = argv.index("--set-file-public") if "--set-file-public" in argv else argc
convert(argv[1], set_public, argv[set_file_public_index+1:])
if __name__ == "__main__":
main(len(sys.argv), sys.argv)

View file

@ -52,6 +52,10 @@
- [enum MarioHandGSCId](#enum-MarioHandGSCId)
- [enum MarioCapGSCId](#enum-MarioCapGSCId)
- [enum MarioGrabPosGSCId](#enum-MarioGrabPosGSCId)
- [mod_fs.h](#mod_fsh)
- [enum ModFsFileIntType](#enum-ModFsFileIntType)
- [enum ModFsFileFloatType](#enum-ModFsFileFloatType)
- [enum ModFsFileSeek](#enum-ModFsFileSeek)
- [mod_storage.h](#mod_storageh)
- [network.h](#networkh)
- [enum NetworkSystemType](#enum-NetworkSystemType)
@ -2129,6 +2133,40 @@
<br />
## [mod_fs.h](#mod_fs.h)
- MOD_FS_MAX_SIZE
- MOD_FS_MAX_FILES
- MOD_FS_MAX_PATH
### [enum ModFsFileIntType](#ModFsFileIntType)
| Identifier | Value |
| :--------- | :---- |
| INT_TYPE_U8 | 0 |
| INT_TYPE_U16 | 1 |
| INT_TYPE_U32 | 2 |
| INT_TYPE_U64 | 3 |
| INT_TYPE_S8 | 4 |
| INT_TYPE_S16 | 5 |
| INT_TYPE_S32 | 6 |
| INT_TYPE_S64 | 7 |
### [enum ModFsFileFloatType](#ModFsFileFloatType)
| Identifier | Value |
| :--------- | :---- |
| FLOAT_TYPE_F32 | 0 |
| FLOAT_TYPE_F64 | 1 |
### [enum ModFsFileSeek](#ModFsFileSeek)
| Identifier | Value |
| :--------- | :---- |
| FILE_SEEK_SET | 0 |
| FILE_SEEK_CUR | 1 |
| FILE_SEEK_END | 2 |
[:arrow_up_small:](#)
<br />
## [mod_storage.h](#mod_storage.h)
- MAX_KEYS
- MAX_KEY_VALUE_LENGTH

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,690 @@
[< prev](functions-5.md) | [1](functions.md) | [2](functions-2.md) | [3](functions-3.md) | [4](functions-4.md) | [5](functions-5.md) | 6]
---
# functions from object_list_processor.h
<br />
## [set_object_respawn_info_bits](#set_object_respawn_info_bits)
### Description
Runs an OR operator on the `obj`'s respawn info with `bits` << 8. If `bits` is 0xFF, this prevents the object from respawning after leaving and re-entering the area
### Lua Example
`set_object_respawn_info_bits(obj, bits)`
### Parameters
| Field | Type |
| ----- | ---- |
| obj | [Object](structs.md#Object) |
| bits | `integer` |
### Returns
- None
### C Prototype
`void set_object_respawn_info_bits(struct Object *obj, u8 bits);`
[:arrow_up_small:](#)
<br />
---
# functions from platform_displacement.h
<br />
## [apply_platform_displacement](#apply_platform_displacement)
### Description
Apply one frame of platform rotation to the object using the given platform
### Lua Example
`apply_platform_displacement(o, platform)`
### Parameters
| Field | Type |
| ----- | ---- |
| o | [Object](structs.md#Object) |
| platform | [Object](structs.md#Object) |
### Returns
- None
### C Prototype
`void apply_platform_displacement(struct Object *o, struct Object *platform);`
[:arrow_up_small:](#)
<br />
---
# functions from rumble_init.h
<br />
## [queue_rumble_data](#queue_rumble_data)
### Description
Queues rumble data
### Lua Example
`queue_rumble_data(a0, a1)`
### Parameters
| Field | Type |
| ----- | ---- |
| a0 | `integer` |
| a1 | `integer` |
### Returns
- None
### C Prototype
`void queue_rumble_data(s16 a0, s16 a1);`
[:arrow_up_small:](#)
<br />
## [queue_rumble_data_object](#queue_rumble_data_object)
### Description
Queues rumble data for object, factoring in its distance from Mario
### Lua Example
`queue_rumble_data_object(object, a0, a1)`
### Parameters
| Field | Type |
| ----- | ---- |
| object | [Object](structs.md#Object) |
| a0 | `integer` |
| a1 | `integer` |
### Returns
- None
### C Prototype
`void queue_rumble_data_object(struct Object* object, s16 a0, s16 a1);`
[:arrow_up_small:](#)
<br />
## [queue_rumble_data_mario](#queue_rumble_data_mario)
### Description
Queues rumble data for Mario
### Lua Example
`queue_rumble_data_mario(m, a0, a1)`
### Parameters
| Field | Type |
| ----- | ---- |
| m | [MarioState](structs.md#MarioState) |
| a0 | `integer` |
| a1 | `integer` |
### Returns
- None
### C Prototype
`void queue_rumble_data_mario(struct MarioState* m, s16 a0, s16 a1);`
[:arrow_up_small:](#)
<br />
## [reset_rumble_timers](#reset_rumble_timers)
### Description
Resets rumble timers
### Lua Example
`reset_rumble_timers(m)`
### Parameters
| Field | Type |
| ----- | ---- |
| m | [MarioState](structs.md#MarioState) |
### Returns
- None
### C Prototype
`void reset_rumble_timers(struct MarioState* m);`
[:arrow_up_small:](#)
<br />
## [reset_rumble_timers_2](#reset_rumble_timers_2)
### Description
Resets rumble timers and sets a field based on `a0`
### Lua Example
`reset_rumble_timers_2(m, a0)`
### Parameters
| Field | Type |
| ----- | ---- |
| m | [MarioState](structs.md#MarioState) |
| a0 | `integer` |
### Returns
- None
### C Prototype
`void reset_rumble_timers_2(struct MarioState* m, s32 a0);`
[:arrow_up_small:](#)
<br />
---
# functions from save_file.h
<br />
## [get_level_num_from_course_num](#get_level_num_from_course_num)
### Description
Gets the course number's corresponding level number
### Lua Example
`local integerValue = get_level_num_from_course_num(courseNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseNum | `integer` |
### Returns
- `integer`
### C Prototype
`s8 get_level_num_from_course_num(s16 courseNum);`
[:arrow_up_small:](#)
<br />
## [get_level_course_num](#get_level_course_num)
### Description
Gets the level number's corresponding course number
### Lua Example
`local integerValue = get_level_course_num(levelNum)`
### Parameters
| Field | Type |
| ----- | ---- |
| levelNum | `integer` |
### Returns
- `integer`
### C Prototype
`s8 get_level_course_num(s16 levelNum);`
[:arrow_up_small:](#)
<br />
## [touch_coin_score_age](#touch_coin_score_age)
### Description
Marks the coin score for a specific course as the newest among all save files. Adjusts the age of other scores to reflect the update. Useful for leaderboard tracking or displaying recent progress
### Lua Example
`touch_coin_score_age(fileIndex, courseIndex)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
| courseIndex | `integer` |
### Returns
- None
### C Prototype
`void touch_coin_score_age(s32 fileIndex, s32 courseIndex);`
[:arrow_up_small:](#)
<br />
## [save_file_do_save](#save_file_do_save)
### Description
Saves the current state of the game into a specified save file. Includes data verification and backup management. Useful for maintaining game progress during play or when saving manually
### Lua Example
`save_file_do_save(fileIndex, forceSave)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
| forceSave | `integer` |
### Returns
- None
### C Prototype
`void save_file_do_save(s32 fileIndex, s8 forceSave);`
[:arrow_up_small:](#)
<br />
## [save_file_erase](#save_file_erase)
### Description
Erases all data in a specified save file, including backup slots. Marks the save file as modified and performs a save to apply the changes. Useful for resetting a save file to its default state
### Lua Example
`save_file_erase(fileIndex)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
### Returns
- None
### C Prototype
`void save_file_erase(s32 fileIndex);`
[:arrow_up_small:](#)
<br />
## [save_file_erase_current_backup_save](#save_file_erase_current_backup_save)
### Description
Erases the backup data for the current save file without affecting the primary save data. Reloads the save file afterward
### Lua Example
`save_file_erase_current_backup_save()`
### Parameters
- None
### Returns
- None
### C Prototype
`void save_file_erase_current_backup_save(void);`
[:arrow_up_small:](#)
<br />
## [save_file_reload](#save_file_reload)
### Description
Reloads the save file data into memory, optionally resetting all save files. Marks the save file as modified. Useful for reloading state after data corruption or during development debugging
### Lua Example
`save_file_reload(load_all)`
### Parameters
| Field | Type |
| ----- | ---- |
| load_all | `integer` |
### Returns
- None
### C Prototype
`void save_file_reload(u8 load_all);`
[:arrow_up_small:](#)
<br />
## [save_file_get_max_coin_score](#save_file_get_max_coin_score)
### Description
Determines the maximum coin score for a course across all save files. Returns the score along with the file index of the save containing it. Useful for leaderboard-style comparisons and overall progress tracking
### Lua Example
`local integerValue = save_file_get_max_coin_score(courseIndex)`
### Parameters
| Field | Type |
| ----- | ---- |
| courseIndex | `integer` |
### Returns
- `integer`
### C Prototype
`u32 save_file_get_max_coin_score(s32 courseIndex);`
[:arrow_up_small:](#)
<br />
## [save_file_get_course_star_count](#save_file_get_course_star_count)
### Description
Calculates the total number of stars collected in a specific course for a given save file. Useful for determining completion status of individual levels
### Lua Example
`local integerValue = save_file_get_course_star_count(fileIndex, courseIndex)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
| courseIndex | `integer` |
### Returns
- `integer`
### C Prototype
`s32 save_file_get_course_star_count(s32 fileIndex, s32 courseIndex);`
[:arrow_up_small:](#)
<br />
## [save_file_get_total_star_count](#save_file_get_total_star_count)
### Description
Calculates the total number of stars collected across multiple courses within a specified range. Useful for determining the overall progress toward game completion
### Lua Example
`local integerValue = save_file_get_total_star_count(fileIndex, minCourse, maxCourse)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
| minCourse | `integer` |
| maxCourse | `integer` |
### Returns
- `integer`
### C Prototype
`s32 save_file_get_total_star_count(s32 fileIndex, s32 minCourse, s32 maxCourse);`
[:arrow_up_small:](#)
<br />
## [save_file_set_flags](#save_file_set_flags)
### Description
Adds new flags to the save file's flag bitmask. Useful for updating progress or triggering new gameplay features
### Lua Example
`save_file_set_flags(flags)`
### Parameters
| Field | Type |
| ----- | ---- |
| flags | `integer` |
### Returns
- None
### C Prototype
`void save_file_set_flags(u32 flags);`
[:arrow_up_small:](#)
<br />
## [save_file_clear_flags](#save_file_clear_flags)
### Description
Clears specific flags in the current save file. The flags are specified as a bitmask in the `flags` parameter. Ensures that the save file remains valid after clearing. Useful for removing specific game states, such as collected items or completed objectives, without resetting the entire save
### Lua Example
`save_file_clear_flags(flags)`
### Parameters
| Field | Type |
| ----- | ---- |
| flags | `integer` |
### Returns
- None
### C Prototype
`void save_file_clear_flags(u32 flags);`
[:arrow_up_small:](#)
<br />
## [save_file_get_flags](#save_file_get_flags)
### Description
Retrieves the bitmask of flags representing the current state of the save file. Flags indicate collected items, completed objectives, and other game states. Useful for checking specific game progress details
### Lua Example
`local integerValue = save_file_get_flags()`
### Parameters
- None
### Returns
- `integer`
### C Prototype
`u32 save_file_get_flags(void);`
[:arrow_up_small:](#)
<br />
## [save_file_get_star_flags](#save_file_get_star_flags)
### Description
Retrieves the bitmask of stars collected in a specific course or castle secret stars (-1). Useful for evaluating level progress and completion
### Lua Example
`local integerValue = save_file_get_star_flags(fileIndex, courseIndex)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
| courseIndex | `integer` |
### Returns
- `integer`
### C Prototype
`u32 save_file_get_star_flags(s32 fileIndex, s32 courseIndex);`
[:arrow_up_small:](#)
<br />
## [save_file_set_star_flags](#save_file_set_star_flags)
### Description
Adds specific star flags to the save file, indicating collected stars for a course or castle secret stars. Updates the save file flags as necessary. Useful for recording progress after star collection
### Lua Example
`save_file_set_star_flags(fileIndex, courseIndex, starFlags)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
| courseIndex | `integer` |
| starFlags | `integer` |
### Returns
- None
### C Prototype
`void save_file_set_star_flags(s32 fileIndex, s32 courseIndex, u32 starFlags);`
[:arrow_up_small:](#)
<br />
## [save_file_remove_star_flags](#save_file_remove_star_flags)
### Description
Removes specific star flags from the save file. This modifies the bitmask representing collected stars for a course or castle secret stars. Useful for undoing progress or debugging collected stars
### Lua Example
`save_file_remove_star_flags(fileIndex, courseIndex, starFlagsToRemove)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
| courseIndex | `integer` |
| starFlagsToRemove | `integer` |
### Returns
- None
### C Prototype
`void save_file_remove_star_flags(s32 fileIndex, s32 courseIndex, u32 starFlagsToRemove);`
[:arrow_up_small:](#)
<br />
## [save_file_get_course_coin_score](#save_file_get_course_coin_score)
### Description
Returns the highest coin score for a specified course in the save file. Performs checks to ensure the coin score is valid. Useful for tracking player achievements and high scores
### Lua Example
`local integerValue = save_file_get_course_coin_score(fileIndex, courseIndex)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
| courseIndex | `integer` |
### Returns
- `integer`
### C Prototype
`s32 save_file_get_course_coin_score(s32 fileIndex, s32 courseIndex);`
[:arrow_up_small:](#)
<br />
## [save_file_set_course_coin_score](#save_file_set_course_coin_score)
### Description
Updates the coin score for a specific course in the save file. The new score is provided in the `coinScore` parameter. Useful for manually setting achievements such as high coin counts in individual levels
### Lua Example
`save_file_set_course_coin_score(fileIndex, courseIndex, coinScore)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
| courseIndex | `integer` |
| coinScore | `integer` |
### Returns
- None
### C Prototype
`void save_file_set_course_coin_score(s32 fileIndex, s32 courseIndex, u8 coinScore);`
[:arrow_up_small:](#)
<br />
## [save_file_is_cannon_unlocked](#save_file_is_cannon_unlocked)
### Description
Checks whether the cannon in the specified course is unlocked. Returns true if the cannon is unlocked, otherwise false. Useful for tracking course-specific progress and enabling shortcuts
### Lua Example
`local integerValue = save_file_is_cannon_unlocked(fileIndex, courseIndex)`
### Parameters
| Field | Type |
| ----- | ---- |
| fileIndex | `integer` |
| courseIndex | `integer` |
### Returns
- `integer`
### C Prototype
`s32 save_file_is_cannon_unlocked(s32 fileIndex, s32 courseIndex);`
[:arrow_up_small:](#)
<br />
## [save_file_get_cap_pos](#save_file_get_cap_pos)
### Description
Retrieves the current position of Mario's cap, if it is on the ground in the current level and area. The position is stored in the provided `capPos` parameter. Useful for tracking the cap's location after it has been dropped or lost
### Lua Example
`local integerValue = save_file_get_cap_pos(capPos)`
### Parameters
| Field | Type |
| ----- | ---- |
| capPos | [Vec3s](structs.md#Vec3s) |
### Returns
- `integer`
### C Prototype
`s32 save_file_get_cap_pos(OUT Vec3s capPos);`
[:arrow_up_small:](#)
<br />
## [save_file_get_sound_mode](#save_file_get_sound_mode)
### Description
Returns the current sound mode (e.g., stereo, mono) stored in the save file. Useful for checking the audio output preferences when loading a save
### Lua Example
`local integerValue = save_file_get_sound_mode()`
### Parameters
- None
### Returns
- `integer`
### C Prototype
`u16 save_file_get_sound_mode(void);`
[:arrow_up_small:](#)
<br />
---
# functions from seqplayer.h

View file

@ -1338,6 +1338,43 @@
<br />
- mod_fs.h
- [mod_fs_exists](functions-5.md#mod_fs_exists)
- [mod_fs_get](functions-5.md#mod_fs_get)
- [mod_fs_reload](functions-5.md#mod_fs_reload)
- [mod_fs_create](functions-5.md#mod_fs_create)
- [mod_fs_delete](functions-5.md#mod_fs_delete)
- [mod_fs_save](functions-5.md#mod_fs_save)
- [mod_fs_set_public](functions-5.md#mod_fs_set_public)
- [mod_fs_get_filename](functions-5.md#mod_fs_get_filename)
- [mod_fs_get_file](functions-5.md#mod_fs_get_file)
- [mod_fs_create_file](functions-5.md#mod_fs_create_file)
- [mod_fs_move_file](functions-5.md#mod_fs_move_file)
- [mod_fs_copy_file](functions-5.md#mod_fs_copy_file)
- [mod_fs_delete_file](functions-5.md#mod_fs_delete_file)
- [mod_fs_clear](functions-5.md#mod_fs_clear)
- [mod_fs_file_read_bool](functions-5.md#mod_fs_file_read_bool)
- [mod_fs_file_read_integer](functions-5.md#mod_fs_file_read_integer)
- [mod_fs_file_read_number](functions-5.md#mod_fs_file_read_number)
- [mod_fs_file_read_bytes](functions-5.md#mod_fs_file_read_bytes)
- [mod_fs_file_read_string](functions-5.md#mod_fs_file_read_string)
- [mod_fs_file_read_line](functions-5.md#mod_fs_file_read_line)
- [mod_fs_file_write_bool](functions-5.md#mod_fs_file_write_bool)
- [mod_fs_file_write_integer](functions-5.md#mod_fs_file_write_integer)
- [mod_fs_file_write_number](functions-5.md#mod_fs_file_write_number)
- [mod_fs_file_write_bytes](functions-5.md#mod_fs_file_write_bytes)
- [mod_fs_file_write_string](functions-5.md#mod_fs_file_write_string)
- [mod_fs_file_write_line](functions-5.md#mod_fs_file_write_line)
- [mod_fs_file_seek](functions-5.md#mod_fs_file_seek)
- [mod_fs_file_is_eof](functions-5.md#mod_fs_file_is_eof)
- [mod_fs_file_fill](functions-5.md#mod_fs_file_fill)
- [mod_fs_file_erase](functions-5.md#mod_fs_file_erase)
- [mod_fs_file_set_public](functions-5.md#mod_fs_file_set_public)
- [mod_fs_hide_errors](functions-5.md#mod_fs_hide_errors)
- [mod_fs_get_last_error](functions-5.md#mod_fs_get_last_error)
<br />
- mod_storage.h
- [mod_storage_save](functions-5.md#mod_storage_save)
- [mod_storage_save_number](functions-5.md#mod_storage_save_number)
@ -1698,46 +1735,46 @@
<br />
- object_list_processor.h
- [set_object_respawn_info_bits](functions-5.md#set_object_respawn_info_bits)
- [set_object_respawn_info_bits](functions-6.md#set_object_respawn_info_bits)
<br />
- platform_displacement.h
- [apply_platform_displacement](functions-5.md#apply_platform_displacement)
- [apply_platform_displacement](functions-6.md#apply_platform_displacement)
<br />
- rumble_init.h
- [queue_rumble_data](functions-5.md#queue_rumble_data)
- [queue_rumble_data_object](functions-5.md#queue_rumble_data_object)
- [queue_rumble_data_mario](functions-5.md#queue_rumble_data_mario)
- [reset_rumble_timers](functions-5.md#reset_rumble_timers)
- [reset_rumble_timers_2](functions-5.md#reset_rumble_timers_2)
- [queue_rumble_data](functions-6.md#queue_rumble_data)
- [queue_rumble_data_object](functions-6.md#queue_rumble_data_object)
- [queue_rumble_data_mario](functions-6.md#queue_rumble_data_mario)
- [reset_rumble_timers](functions-6.md#reset_rumble_timers)
- [reset_rumble_timers_2](functions-6.md#reset_rumble_timers_2)
<br />
- save_file.h
- [get_level_num_from_course_num](functions-5.md#get_level_num_from_course_num)
- [get_level_course_num](functions-5.md#get_level_course_num)
- [touch_coin_score_age](functions-5.md#touch_coin_score_age)
- [save_file_do_save](functions-5.md#save_file_do_save)
- [save_file_erase](functions-5.md#save_file_erase)
- [save_file_erase_current_backup_save](functions-5.md#save_file_erase_current_backup_save)
- [save_file_reload](functions-5.md#save_file_reload)
- [save_file_get_max_coin_score](functions-5.md#save_file_get_max_coin_score)
- [save_file_get_course_star_count](functions-5.md#save_file_get_course_star_count)
- [save_file_get_total_star_count](functions-5.md#save_file_get_total_star_count)
- [save_file_set_flags](functions-5.md#save_file_set_flags)
- [save_file_clear_flags](functions-5.md#save_file_clear_flags)
- [save_file_get_flags](functions-5.md#save_file_get_flags)
- [save_file_get_star_flags](functions-5.md#save_file_get_star_flags)
- [save_file_set_star_flags](functions-5.md#save_file_set_star_flags)
- [save_file_remove_star_flags](functions-5.md#save_file_remove_star_flags)
- [save_file_get_course_coin_score](functions-5.md#save_file_get_course_coin_score)
- [save_file_set_course_coin_score](functions-5.md#save_file_set_course_coin_score)
- [save_file_is_cannon_unlocked](functions-5.md#save_file_is_cannon_unlocked)
- [save_file_get_cap_pos](functions-5.md#save_file_get_cap_pos)
- [save_file_get_sound_mode](functions-5.md#save_file_get_sound_mode)
- [get_level_num_from_course_num](functions-6.md#get_level_num_from_course_num)
- [get_level_course_num](functions-6.md#get_level_course_num)
- [touch_coin_score_age](functions-6.md#touch_coin_score_age)
- [save_file_do_save](functions-6.md#save_file_do_save)
- [save_file_erase](functions-6.md#save_file_erase)
- [save_file_erase_current_backup_save](functions-6.md#save_file_erase_current_backup_save)
- [save_file_reload](functions-6.md#save_file_reload)
- [save_file_get_max_coin_score](functions-6.md#save_file_get_max_coin_score)
- [save_file_get_course_star_count](functions-6.md#save_file_get_course_star_count)
- [save_file_get_total_star_count](functions-6.md#save_file_get_total_star_count)
- [save_file_set_flags](functions-6.md#save_file_set_flags)
- [save_file_clear_flags](functions-6.md#save_file_clear_flags)
- [save_file_get_flags](functions-6.md#save_file_get_flags)
- [save_file_get_star_flags](functions-6.md#save_file_get_star_flags)
- [save_file_set_star_flags](functions-6.md#save_file_set_star_flags)
- [save_file_remove_star_flags](functions-6.md#save_file_remove_star_flags)
- [save_file_get_course_coin_score](functions-6.md#save_file_get_course_coin_score)
- [save_file_set_course_coin_score](functions-6.md#save_file_set_course_coin_score)
- [save_file_is_cannon_unlocked](functions-6.md#save_file_is_cannon_unlocked)
- [save_file_get_cap_pos](functions-6.md#save_file_get_cap_pos)
- [save_file_get_sound_mode](functions-6.md#save_file_get_sound_mode)
<br />

View file

@ -77,6 +77,8 @@
- [ModAudio](#ModAudio)
- [ModAudioSampleCopies](#ModAudioSampleCopies)
- [ModFile](#ModFile)
- [ModFs](#ModFs)
- [ModFsFile](#ModFsFile)
- [ModeTransitionInfo](#ModeTransitionInfo)
- [NametagsSettings](#NametagsSettings)
- [NetworkPlayer](#NetworkPlayer)
@ -1964,6 +1966,35 @@
<br />
## [ModFs](#ModFs)
| Field | Type | Access |
| ----- | ---- | ------ |
| isPublic | `boolean` | read-only |
| mod | [Mod](structs.md#Mod) | read-only |
| modPath | `string` | read-only |
| numFiles | `integer` | read-only |
| totalSize | `integer` | read-only |
[:arrow_up_small:](#)
<br />
## [ModFsFile](#ModFsFile)
| Field | Type | Access |
| ----- | ---- | ------ |
| filepath | `string` | read-only |
| isPublic | `boolean` | read-only |
| isText | `boolean` | read-only |
| modFs | [ModFs](structs.md#ModFs) | read-only |
| offset | `integer` | read-only |
| size | `integer` | read-only |
[:arrow_up_small:](#)
<br />
## [ModeTransitionInfo](#ModeTransitionInfo)
| Field | Type | Access |

View file

@ -40,10 +40,6 @@ struct Controller
OSContPad *controllerData;
};
// A macro to tell autogen which function parameters are modified during the function call and should be pushed again
// Only works with Vec3, Mat4 and Color types
#define OUT
typedef f32 Vec2f[2]; // X, Y
typedef s16 Vec2s[2];
typedef s32 Vec2i[2];
@ -602,5 +598,6 @@ struct TextureInfo
#include "game/characters.h"
#include "data/dynos.c.h"
#include "src/pc/lua/smlua_autogen.h"
#endif // _SM64_TYPES_H_

View file

@ -0,0 +1,16 @@
#ifndef SMLUA_AUTOGEN_H
#define SMLUA_AUTOGEN_H
//
// Autogen macros
//
// A macro to tell autogen which function parameters are modified during the function call and should be pushed again
// Only works with Vec3, Mat4 and Color types
#define OUT
// A macro to tell autogen this parameter can be omitted and replaced by 'nil' during a function call
// Optional parameters must be contiguous until the last parameter (a mandatory parameter following an optional parameter is not allowed)
#define OPTIONAL
#endif // SMLUA_AUTOGEN_H

View file

@ -21,6 +21,7 @@
#include "src/pc/network/network.h"
#include "src/game/hardcoded.h"
#include "src/pc/mods/mod.h"
#include "src/pc/mods/mod_fs.h"
#include "src/pc/lua/utils/smlua_audio_utils.h"
#include "src/game/paintings.h"
#include "src/pc/djui/djui_types.h"
@ -1620,6 +1621,25 @@ static struct LuaObjectField sModFileFields[LUA_MOD_FILE_FIELD_COUNT] = {
{ "wroteBytes", LVT_U64, offsetof(struct ModFile, wroteBytes), true, LOT_NONE, 1, sizeof(u64) },
};
#define LUA_MOD_FS_FIELD_COUNT 5
static struct LuaObjectField sModFsFields[LUA_MOD_FS_FIELD_COUNT] = {
{ "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) },
{ "numFiles", LVT_U16, offsetof(struct ModFs, numFiles), true, LOT_NONE, 1, sizeof(u16) },
{ "totalSize", LVT_U32, offsetof(struct ModFs, totalSize), true, LOT_NONE, 1, sizeof(u32) },
};
#define LUA_MOD_FS_FILE_FIELD_COUNT 6
static struct LuaObjectField sModFsFileFields[LUA_MOD_FS_FILE_FIELD_COUNT] = {
{ "filepath", LVT_STRING, offsetof(struct ModFsFile, filepath), true, LOT_NONE, 1, sizeof(char) },
{ "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) },
{ "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) },
{ "size", LVT_U32, offsetof(struct ModFsFile, size), true, LOT_NONE, 1, sizeof(u32) },
};
#define LUA_MODE_TRANSITION_INFO_FIELD_COUNT 6
static struct LuaObjectField sModeTransitionInfoFields[LUA_MODE_TRANSITION_INFO_FIELD_COUNT] = {
{ "frame", LVT_S16, offsetof(struct ModeTransitionInfo, frame), false, LOT_NONE, 1, sizeof(s16) },
@ -2925,6 +2945,8 @@ struct LuaObjectTable sLuaObjectAutogenTable[LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN]
{ LOT_MODAUDIO, sModAudioFields, LUA_MOD_AUDIO_FIELD_COUNT },
{ LOT_MODAUDIOSAMPLECOPIES, sModAudioSampleCopiesFields, LUA_MOD_AUDIO_SAMPLE_COPIES_FIELD_COUNT },
{ LOT_MODFILE, sModFileFields, LUA_MOD_FILE_FIELD_COUNT },
{ LOT_MODFS, sModFsFields, LUA_MOD_FS_FIELD_COUNT },
{ LOT_MODFSFILE, sModFsFileFields, LUA_MOD_FS_FILE_FIELD_COUNT },
{ LOT_MODETRANSITIONINFO, sModeTransitionInfoFields, LUA_MODE_TRANSITION_INFO_FIELD_COUNT },
{ LOT_NAMETAGSSETTINGS, sNametagsSettingsFields, LUA_NAMETAGS_SETTINGS_FIELD_COUNT },
{ LOT_NETWORKPLAYER, sNetworkPlayerFields, LUA_NETWORK_PLAYER_FIELD_COUNT },
@ -3051,6 +3073,8 @@ const char *sLuaLotNames[] = {
[LOT_MODAUDIO] = "ModAudio",
[LOT_MODAUDIOSAMPLECOPIES] = "ModAudioSampleCopies",
[LOT_MODFILE] = "ModFile",
[LOT_MODFS] = "ModFs",
[LOT_MODFSFILE] = "ModFsFile",
[LOT_MODETRANSITIONINFO] = "ModeTransitionInfo",
[LOT_NAMETAGSSETTINGS] = "NametagsSettings",
[LOT_NETWORKPLAYER] = "NetworkPlayer",

View file

@ -96,6 +96,8 @@ enum LuaObjectAutogenType {
LOT_MODAUDIO,
LOT_MODAUDIOSAMPLECOPIES,
LOT_MODFILE,
LOT_MODFS,
LOT_MODFSFILE,
LOT_MODETRANSITIONINFO,
LOT_NAMETAGSSETTINGS,
LOT_NETWORKPLAYER,

View file

@ -2227,6 +2227,22 @@ char gSmluaConstants[] = ""
"GRAB_POS_LIGHT_OBJ=1\n"
"GRAB_POS_HEAVY_OBJ=2\n"
"GRAB_POS_BOWSER=3\n"
"MOD_FS_MAX_SIZE=0x1000000\n"
"MOD_FS_MAX_FILES=0x100\n"
"MOD_FS_MAX_PATH=0x100\n"
"INT_TYPE_U8=0\n"
"INT_TYPE_U16=1\n"
"INT_TYPE_U32=2\n"
"INT_TYPE_U64=3\n"
"INT_TYPE_S8=4\n"
"INT_TYPE_S16=5\n"
"INT_TYPE_S32=6\n"
"INT_TYPE_S64=7\n"
"FLOAT_TYPE_F32=0\n"
"FLOAT_TYPE_F64=1\n"
"FILE_SEEK_SET=0\n"
"FILE_SEEK_CUR=1\n"
"FILE_SEEK_END=2\n"
"MAX_KEYS=4096\n"
"MAX_KEY_VALUE_LENGTH=1024\n"
"SYNC_DISTANCE_ONLY_DEATH=-1\n"

View file

@ -43,6 +43,7 @@
#include "src/game/behavior_actions.h"
#include "src/game/mario_misc.h"
#include "src/pc/mods/mod_storage.h"
#include "src/pc/mods/mod_fs.h"
#include "src/pc/utils/misc.h"
#include "src/game/level_update.h"
#include "src/game/area.h"
@ -22201,6 +22202,628 @@ int smlua_func_delta_interpolate_vec3s(lua_State* L) {
return 1;
}
//////////////
// mod_fs.h //
//////////////
int smlua_func_mod_fs_exists(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top < 0 || top > 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected between %u and %u, Received %u", "mod_fs_exists", 0, 1, top);
return 0;
}
const char* modPath = (const char*) NULL;
if (top >= 1) {
modPath = smlua_to_string(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_exists"); return 0; }
}
lua_pushboolean(L, mod_fs_exists(modPath));
return 1;
}
int smlua_func_mod_fs_get(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top < 0 || top > 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected between %u and %u, Received %u", "mod_fs_get", 0, 1, top);
return 0;
}
const char* modPath = (const char*) NULL;
if (top >= 1) {
modPath = smlua_to_string(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_get"); return 0; }
}
smlua_push_object(L, LOT_MODFS, mod_fs_get(modPath), NULL);
return 1;
}
int smlua_func_mod_fs_reload(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top < 0 || top > 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected between %u and %u, Received %u", "mod_fs_reload", 0, 1, top);
return 0;
}
const char* modPath = (const char*) NULL;
if (top >= 1) {
modPath = smlua_to_string(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_reload"); return 0; }
}
smlua_push_object(L, LOT_MODFS, mod_fs_reload(modPath), NULL);
return 1;
}
int smlua_func_mod_fs_create(UNUSED lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 0) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_create", 0, top);
return 0;
}
smlua_push_object(L, LOT_MODFS, mod_fs_create(), NULL);
return 1;
}
int smlua_func_mod_fs_delete(UNUSED lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 0) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_delete", 0, top);
return 0;
}
lua_pushboolean(L, mod_fs_delete());
return 1;
}
int smlua_func_mod_fs_save(UNUSED lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 0) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_save", 0, top);
return 0;
}
lua_pushboolean(L, mod_fs_save());
return 1;
}
int smlua_func_mod_fs_set_public(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_set_public", 1, top);
return 0;
}
bool pub = smlua_to_boolean(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_set_public"); return 0; }
lua_pushboolean(L, mod_fs_set_public(pub));
return 1;
}
int smlua_func_mod_fs_get_filename(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_get_filename", 2, top);
return 0;
}
struct ModFs* modFs = (struct ModFs*)smlua_to_cobject(L, 1, LOT_MODFS);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_get_filename"); return 0; }
u16 index = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_get_filename"); return 0; }
lua_pushstring(L, mod_fs_get_filename(modFs, index));
return 1;
}
int smlua_func_mod_fs_get_file(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_get_file", 2, top);
return 0;
}
struct ModFs* modFs = (struct ModFs*)smlua_to_cobject(L, 1, LOT_MODFS);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_get_file"); return 0; }
const char* filepath = smlua_to_string(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_get_file"); return 0; }
smlua_push_object(L, LOT_MODFSFILE, mod_fs_get_file(modFs, filepath), NULL);
return 1;
}
int smlua_func_mod_fs_create_file(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 3) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_create_file", 3, top);
return 0;
}
struct ModFs* modFs = (struct ModFs*)smlua_to_cobject(L, 1, LOT_MODFS);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_create_file"); return 0; }
const char* filepath = smlua_to_string(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_create_file"); return 0; }
bool text = smlua_to_boolean(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "mod_fs_create_file"); return 0; }
smlua_push_object(L, LOT_MODFSFILE, mod_fs_create_file(modFs, filepath, text), NULL);
return 1;
}
int smlua_func_mod_fs_move_file(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 4) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_move_file", 4, top);
return 0;
}
struct ModFs* modFs = (struct ModFs*)smlua_to_cobject(L, 1, LOT_MODFS);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_move_file"); return 0; }
const char* oldpath = smlua_to_string(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_move_file"); return 0; }
const char* newpath = smlua_to_string(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "mod_fs_move_file"); return 0; }
bool overwriteExisting = smlua_to_boolean(L, 4);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "mod_fs_move_file"); return 0; }
lua_pushboolean(L, mod_fs_move_file(modFs, oldpath, newpath, overwriteExisting));
return 1;
}
int smlua_func_mod_fs_copy_file(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 4) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_copy_file", 4, top);
return 0;
}
struct ModFs* modFs = (struct ModFs*)smlua_to_cobject(L, 1, LOT_MODFS);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_copy_file"); return 0; }
const char* srcpath = smlua_to_string(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_copy_file"); return 0; }
const char* dstpath = smlua_to_string(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "mod_fs_copy_file"); return 0; }
bool overwriteExisting = smlua_to_boolean(L, 4);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "mod_fs_copy_file"); return 0; }
lua_pushboolean(L, mod_fs_copy_file(modFs, srcpath, dstpath, overwriteExisting));
return 1;
}
int smlua_func_mod_fs_delete_file(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_delete_file", 2, top);
return 0;
}
struct ModFs* modFs = (struct ModFs*)smlua_to_cobject(L, 1, LOT_MODFS);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_delete_file"); return 0; }
const char* filepath = smlua_to_string(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_delete_file"); return 0; }
lua_pushboolean(L, mod_fs_delete_file(modFs, filepath));
return 1;
}
int smlua_func_mod_fs_clear(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_clear", 1, top);
return 0;
}
struct ModFs* modFs = (struct ModFs*)smlua_to_cobject(L, 1, LOT_MODFS);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_clear"); return 0; }
lua_pushboolean(L, mod_fs_clear(modFs));
return 1;
}
int smlua_func_mod_fs_file_read_bool(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_read_bool", 1, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_read_bool"); return 0; }
lua_pushboolean(L, mod_fs_file_read_bool(file));
return 1;
}
int smlua_func_mod_fs_file_read_integer(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_read_integer", 2, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_read_integer"); return 0; }
int intType = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_read_integer"); return 0; }
lua_pushinteger(L, mod_fs_file_read_integer(file, intType));
return 1;
}
int smlua_func_mod_fs_file_read_number(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_read_number", 2, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_read_number"); return 0; }
int floatType = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_read_number"); return 0; }
lua_pushnumber(L, mod_fs_file_read_number(file, floatType));
return 1;
}
int smlua_func_mod_fs_file_read_bytes(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_read_bytes", 2, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_read_bytes"); return 0; }
u32 length = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_read_bytes"); return 0; }
smlua_push_bytestring(L, mod_fs_file_read_bytes(file, length));
return 1;
}
int smlua_func_mod_fs_file_read_string(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_read_string", 1, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_read_string"); return 0; }
lua_pushstring(L, mod_fs_file_read_string(file));
return 1;
}
int smlua_func_mod_fs_file_read_line(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_read_line", 1, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_read_line"); return 0; }
lua_pushstring(L, mod_fs_file_read_line(file));
return 1;
}
int smlua_func_mod_fs_file_write_bool(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_write_bool", 2, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_write_bool"); return 0; }
bool value = smlua_to_boolean(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_write_bool"); return 0; }
lua_pushboolean(L, mod_fs_file_write_bool(file, value));
return 1;
}
int smlua_func_mod_fs_file_write_integer(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 3) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_write_integer", 3, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_write_integer"); return 0; }
lua_Integer value = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_write_integer"); return 0; }
int intType = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "mod_fs_file_write_integer"); return 0; }
lua_pushboolean(L, mod_fs_file_write_integer(file, value, intType));
return 1;
}
int smlua_func_mod_fs_file_write_number(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 3) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_write_number", 3, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_write_number"); return 0; }
lua_Number value = smlua_to_number(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_write_number"); return 0; }
int floatType = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "mod_fs_file_write_number"); return 0; }
lua_pushboolean(L, mod_fs_file_write_number(file, value, floatType));
return 1;
}
int smlua_func_mod_fs_file_write_bytes(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_write_bytes", 2, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_write_bytes"); return 0; }
ByteString bytestring = smlua_to_bytestring(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_write_bytes"); return 0; }
lua_pushboolean(L, mod_fs_file_write_bytes(file, bytestring));
return 1;
}
int smlua_func_mod_fs_file_write_string(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_write_string", 2, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_write_string"); return 0; }
const char* str = smlua_to_string(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_write_string"); return 0; }
lua_pushboolean(L, mod_fs_file_write_string(file, str));
return 1;
}
int smlua_func_mod_fs_file_write_line(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_write_line", 2, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_write_line"); return 0; }
const char* str = smlua_to_string(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_write_line"); return 0; }
lua_pushboolean(L, mod_fs_file_write_line(file, str));
return 1;
}
int smlua_func_mod_fs_file_seek(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 3) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_seek", 3, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_seek"); return 0; }
s32 offset = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_seek"); return 0; }
int origin = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "mod_fs_file_seek"); return 0; }
lua_pushboolean(L, mod_fs_file_seek(file, offset, origin));
return 1;
}
int smlua_func_mod_fs_file_is_eof(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_is_eof", 1, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_is_eof"); return 0; }
lua_pushboolean(L, mod_fs_file_is_eof(file));
return 1;
}
int smlua_func_mod_fs_file_fill(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 3) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_fill", 3, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_fill"); return 0; }
u8 byte = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_fill"); return 0; }
u32 length = smlua_to_integer(L, 3);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "mod_fs_file_fill"); return 0; }
lua_pushboolean(L, mod_fs_file_fill(file, byte, length));
return 1;
}
int smlua_func_mod_fs_file_erase(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_erase", 2, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_erase"); return 0; }
u32 length = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_erase"); return 0; }
lua_pushboolean(L, mod_fs_file_erase(file, length));
return 1;
}
int smlua_func_mod_fs_file_set_public(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_file_set_public", 2, top);
return 0;
}
struct ModFsFile* file = (struct ModFsFile*)smlua_to_cobject(L, 1, LOT_MODFSFILE);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_file_set_public"); return 0; }
bool pub = smlua_to_boolean(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mod_fs_file_set_public"); return 0; }
lua_pushboolean(L, mod_fs_file_set_public(file, pub));
return 1;
}
int smlua_func_mod_fs_hide_errors(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_hide_errors", 1, top);
return 0;
}
bool hide = smlua_to_boolean(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mod_fs_hide_errors"); return 0; }
mod_fs_hide_errors(hide);
return 1;
}
int smlua_func_mod_fs_get_last_error(UNUSED lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 0) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mod_fs_get_last_error", 0, top);
return 0;
}
lua_pushstring(L, mod_fs_get_last_error());
return 1;
}
///////////////////
// mod_storage.h //
///////////////////
@ -36863,6 +37486,41 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "delta_interpolate_vec3f", smlua_func_delta_interpolate_vec3f);
smlua_bind_function(L, "delta_interpolate_vec3s", smlua_func_delta_interpolate_vec3s);
// mod_fs.h
smlua_bind_function(L, "mod_fs_exists", smlua_func_mod_fs_exists);
smlua_bind_function(L, "mod_fs_get", smlua_func_mod_fs_get);
smlua_bind_function(L, "mod_fs_reload", smlua_func_mod_fs_reload);
smlua_bind_function(L, "mod_fs_create", smlua_func_mod_fs_create);
smlua_bind_function(L, "mod_fs_delete", smlua_func_mod_fs_delete);
smlua_bind_function(L, "mod_fs_save", smlua_func_mod_fs_save);
smlua_bind_function(L, "mod_fs_set_public", smlua_func_mod_fs_set_public);
smlua_bind_function(L, "mod_fs_get_filename", smlua_func_mod_fs_get_filename);
smlua_bind_function(L, "mod_fs_get_file", smlua_func_mod_fs_get_file);
smlua_bind_function(L, "mod_fs_create_file", smlua_func_mod_fs_create_file);
smlua_bind_function(L, "mod_fs_move_file", smlua_func_mod_fs_move_file);
smlua_bind_function(L, "mod_fs_copy_file", smlua_func_mod_fs_copy_file);
smlua_bind_function(L, "mod_fs_delete_file", smlua_func_mod_fs_delete_file);
smlua_bind_function(L, "mod_fs_clear", smlua_func_mod_fs_clear);
smlua_bind_function(L, "mod_fs_file_read_bool", smlua_func_mod_fs_file_read_bool);
smlua_bind_function(L, "mod_fs_file_read_integer", smlua_func_mod_fs_file_read_integer);
smlua_bind_function(L, "mod_fs_file_read_number", smlua_func_mod_fs_file_read_number);
smlua_bind_function(L, "mod_fs_file_read_bytes", smlua_func_mod_fs_file_read_bytes);
smlua_bind_function(L, "mod_fs_file_read_string", smlua_func_mod_fs_file_read_string);
smlua_bind_function(L, "mod_fs_file_read_line", smlua_func_mod_fs_file_read_line);
smlua_bind_function(L, "mod_fs_file_write_bool", smlua_func_mod_fs_file_write_bool);
smlua_bind_function(L, "mod_fs_file_write_integer", smlua_func_mod_fs_file_write_integer);
smlua_bind_function(L, "mod_fs_file_write_number", smlua_func_mod_fs_file_write_number);
smlua_bind_function(L, "mod_fs_file_write_bytes", smlua_func_mod_fs_file_write_bytes);
smlua_bind_function(L, "mod_fs_file_write_string", smlua_func_mod_fs_file_write_string);
smlua_bind_function(L, "mod_fs_file_write_line", smlua_func_mod_fs_file_write_line);
smlua_bind_function(L, "mod_fs_file_seek", smlua_func_mod_fs_file_seek);
smlua_bind_function(L, "mod_fs_file_is_eof", smlua_func_mod_fs_file_is_eof);
smlua_bind_function(L, "mod_fs_file_fill", smlua_func_mod_fs_file_fill);
smlua_bind_function(L, "mod_fs_file_erase", smlua_func_mod_fs_file_erase);
smlua_bind_function(L, "mod_fs_file_set_public", smlua_func_mod_fs_file_set_public);
smlua_bind_function(L, "mod_fs_hide_errors", smlua_func_mod_fs_hide_errors);
smlua_bind_function(L, "mod_fs_get_last_error", smlua_func_mod_fs_get_last_error);
// mod_storage.h
smlua_bind_function(L, "mod_storage_save", smlua_func_mod_storage_save);
smlua_bind_function(L, "mod_storage_save_number", smlua_func_mod_storage_save_number);

View file

@ -128,6 +128,18 @@ const char* smlua_to_string(lua_State* L, int index) {
return lua_tostring(L, index);
}
ByteString smlua_to_bytestring(lua_State* L, int index) {
ByteString bytestring = { NULL, 0 };
if (lua_type(L, index) != LUA_TSTRING) {
LOG_LUA_LINE("smlua_to_string received improper type '%s'", luaL_typename(L, index));
gSmLuaConvertSuccess = false;
return bytestring;
}
gSmLuaConvertSuccess = true;
bytestring.bytes = lua_tolstring(L, index, &bytestring.length);
return bytestring;
}
LuaFunction smlua_to_lua_function(lua_State* L, int index) {
if (lua_type(L, index) == LUA_TNIL) {
return 0;
@ -475,6 +487,14 @@ void smlua_push_table_field(int index, const char* name) {
///////////////////////////////////////////////////////////////////////////////////////////
void smlua_push_bytestring(lua_State* L, ByteString bytestring) {
if (bytestring.bytes) {
lua_pushlstring(L, bytestring.bytes, bytestring.length);
} else {
lua_pushnil(L);
}
}
void smlua_push_lnt(struct LSTNetworkType* lnt) {
lua_State* L = gLuaState;
switch (lnt->type) {

View file

@ -6,6 +6,11 @@ typedef int LuaFunction;
struct Packet;
struct LSTNetworkType;
typedef struct ByteString {
const char *bytes;
size_t length;
} ByteString;
f32* smlua_get_vec3f_from_buffer(void);
s16* smlua_get_vec3s_from_buffer(void);
f32* smlua_get_vec4f_from_buffer(void);
@ -19,6 +24,7 @@ bool smlua_to_boolean(lua_State* L, int index);
lua_Integer smlua_to_integer(lua_State* L, int index);
lua_Number smlua_to_number(lua_State* L, int index);
const char* smlua_to_string(lua_State* L, int index);
ByteString smlua_to_bytestring(lua_State* L, int index);
LuaFunction smlua_to_lua_function(lua_State* L, int index);
bool smlua_is_cobject(lua_State* L, int index, u16 lot);
void* smlua_to_cobject(lua_State* L, int index, u16 lot);
@ -37,6 +43,7 @@ void smlua_push_string_field(int index, const char* name, const char* val);
void smlua_push_nil_field(int index, const char* name);
void smlua_push_table_field(int index, const char* name);
void smlua_push_bytestring(lua_State* L, ByteString bytestring);
void smlua_push_lnt(struct LSTNetworkType* lnt);
lua_Integer smlua_get_integer_field(int index, const char* name);

1396
src/pc/mods/mod_fs.cpp Normal file

File diff suppressed because it is too large Load diff

236
src/pc/mods/mod_fs.h Normal file
View file

@ -0,0 +1,236 @@
#ifndef MOD_FS_H
#define MOD_FS_H
#include "types.h"
#include "src/pc/lua/smlua.h"
#define MOD_FS_MAX_SIZE 0x1000000 // 16 MB
#define MOD_FS_MAX_FILES 0x100
#define MOD_FS_MAX_PATH 0x100
#define MOD_FS_DIRECTORY "sav"
#define MOD_FS_EXTENSION ".modfs"
#define MOD_FS_VERSION 1
enum ModFsFileIntType {
INT_TYPE_U8,
INT_TYPE_U16,
INT_TYPE_U32,
INT_TYPE_U64,
INT_TYPE_S8,
INT_TYPE_S16,
INT_TYPE_S32,
INT_TYPE_S64,
INT_TYPE_MAX
};
enum ModFsFileFloatType {
FLOAT_TYPE_F32,
FLOAT_TYPE_F64,
FLOAT_TYPE_MAX
};
enum ModFsFileSeek {
FILE_SEEK_SET,
FILE_SEEK_CUR,
FILE_SEEK_END,
FILE_SEEK_MAX
};
struct Mod;
struct ModFsFile {
struct ModFs *modFs;
char filepath[MOD_FS_MAX_PATH];
union {
u8 *bin;
char *text;
} data;
u32 size;
u32 capacity;
u32 offset;
bool isText;
bool isPublic;
};
struct ModFs {
struct Mod *mod;
char modPath[SYS_MAX_PATH];
struct ModFsFile **files;
u16 numFiles;
u32 totalSize;
bool isPublic;
};
/* |description|
Checks the existence of a modfs at path `modPath` or for the active mod if not provided. Checking for the existence of a private modfs will return false, even if it exists
|descriptionEnd| */
bool mod_fs_exists(OPTIONAL const char *modPath);
/* |description|
Gets the modfs object at path `modPath` or the active mod one if not provided. This function will return nil for a private modfs, even if it exists
|descriptionEnd| */
struct ModFs *mod_fs_get(OPTIONAL const char *modPath);
/* |description|
Reloads the modfs object at path `modPath`. This function will return nil for a private modfs, even if it exists
|descriptionEnd| */
struct ModFs *mod_fs_reload(OPTIONAL const char *modPath);
/* |description|
Creates a modfs object for the active mod if it doesn't exist. Returns the modfs object on success
|descriptionEnd| */
struct ModFs *mod_fs_create();
/* |description|
Deletes the modfs object of the active mod if it exists. Returns true on success
|descriptionEnd| */
bool mod_fs_delete();
/* |description|
Saves the modfs object of the active mod if it exists. Returns true on success
|descriptionEnd| */
bool mod_fs_save();
/* |description|
Marks the modfs object of the active mod as public (i.e. readable by other mods) if it exists. Returns true on success
|descriptionEnd| */
bool mod_fs_set_public(bool pub);
/* |description|
Gets the filename at position `index` of the provided `modFs`
|descriptionEnd| */
const char *mod_fs_get_filename(struct ModFs *modFs, u16 index);
/* |description|
Gets the file object at path `filepath` of the provided `modFs`. This function will return nil for a private modfs file, even if it exists
|descriptionEnd| */
struct ModFsFile *mod_fs_get_file(struct ModFs *modFs, const char *filepath);
/* |description|
Creates a new file at path `filepath` for the provided `modFs`. Set `text` to true to treat the file as a pure text file, not a binary file. Returns the created file on success
|descriptionEnd| */
struct ModFsFile *mod_fs_create_file(struct ModFs *modFs, const char *filepath, bool text);
/* |description|
Moves the file at path `oldpath` to `newpath` of the provided `modFs`. Set `overwriteExisting` to true to overwrite the file at path `newpath` if it exists. Returns true on success
|descriptionEnd| */
bool mod_fs_move_file(struct ModFs *modFs, const char *oldpath, const char *newpath, bool overwriteExisting);
/* |description|
Copies the file at path `srcpath` to `dstpath` of the provided `modFs`. Set `overwriteExisting` to true to overwrite the file at path `dstpath` if it exists. Returns true on success
|descriptionEnd| */
bool mod_fs_copy_file(struct ModFs *modFs, const char *srcpath, const char *dstpath, bool overwriteExisting);
/* |description|
Deletes the file at path `filepath` of the provided `modFs`. Returns true on success
|descriptionEnd| */
bool mod_fs_delete_file(struct ModFs *modFs, const char *filepath);
/* |description|
Deletes all files of the provided `modFs`. Returns true on success
|descriptionEnd| */
bool mod_fs_clear(struct ModFs *modFs);
/* |description|
Reads a boolean from a binary modfs `file`
|descriptionEnd| */
bool mod_fs_file_read_bool(struct ModFsFile *file);
/* |description|
Reads an integer from a binary modfs `file`. `intType` must be one of the `INT_TYPE_*` constants
|descriptionEnd| */
lua_Integer mod_fs_file_read_integer(struct ModFsFile *file, enum ModFsFileIntType intType);
/* |description|
Reads an floating-point number from a binary modfs `file`. `floatType` must be one of the `FLOAT_TYPE_*` constants
|descriptionEnd| */
lua_Number mod_fs_file_read_number(struct ModFsFile *file, enum ModFsFileFloatType floatType);
/* |description|
Reads a bytestring of `length` bytes from a binary modfs `file`
|descriptionEnd| */
ByteString mod_fs_file_read_bytes(struct ModFsFile *file, u32 length);
/* |description|
Reads a string from a binary modfs `file`, or read the whole content of a text modfs `file`
|descriptionEnd| */
const char *mod_fs_file_read_string(struct ModFsFile *file);
/* |description|
Reads a line from a text modfs `file`
|descriptionEnd| */
const char *mod_fs_file_read_line(struct ModFsFile *file);
/* |description|
Writes a boolean to a binary modfs `file`. Returns true on success
|descriptionEnd| */
bool mod_fs_file_write_bool(struct ModFsFile *file, bool value);
/* |description|
Writes an integer to a binary modfs `file`. `intType` must be one of the `INT_TYPE_*` constants. Returns true on success
|descriptionEnd| */
bool mod_fs_file_write_integer(struct ModFsFile *file, lua_Integer value, enum ModFsFileIntType intType);
/* |description|
Writes an floating-point number to a binary modfs `file`. `floatType` must be one of the `FLOAT_TYPE_*` constants. Returns true on success
|descriptionEnd| */
bool mod_fs_file_write_number(struct ModFsFile *file, lua_Number value, enum ModFsFileFloatType floatType);
/* |description|
Writes a bytestring to a modfs `file`. Returns true on success
|descriptionEnd| */
bool mod_fs_file_write_bytes(struct ModFsFile *file, ByteString bytestring);
/* |description|
Writes a string to a modfs `file`. Returns true on success
|descriptionEnd| */
bool mod_fs_file_write_string(struct ModFsFile *file, const char *str);
/* |description|
Writes a line to a text modfs `file`. Returns true on success
|descriptionEnd| */
bool mod_fs_file_write_line(struct ModFsFile *file, const char *str);
/* |description|
Sets the current position of a modfs `file`.
If `origin` is `FILE_SEEK_SET`, file position is set to `offset`.
If `origin` is `FILE_SEEK_CUR`, `offset` is added to file current position.
If `origin` is `FILE_SEEK_END`, file position is set to `end of file + offset`.
Returns true on success
|descriptionEnd| */
bool mod_fs_file_seek(struct ModFsFile *file, s32 offset, enum ModFsFileSeek origin);
/* |description|
Returns true if the provided modfs `file` has reached its end of file
|descriptionEnd| */
bool mod_fs_file_is_eof(struct ModFsFile *file);
/* |description|
Fills a modfs `file` with `byte` repeated `length` times. Returns true on success
|descriptionEnd| */
bool mod_fs_file_fill(struct ModFsFile *file, u8 byte, u32 length);
/* |description|
Erases `length` bytes or characters from a modfs `file`. Returns true on success
|descriptionEnd| */
bool mod_fs_file_erase(struct ModFsFile *file, u32 length);
/* |description|
Marks the provided modfs `file` as public (i.e. readable by other mods). Returns true on success
|descriptionEnd| */
bool mod_fs_file_set_public(struct ModFsFile *file, bool pub);
/* |description|
Hides script errors raised by `mod_fs` functions. Errors messages are still generated and can be retrieved with `mod_fs_get_last_error()`
|descriptionEnd| */
void mod_fs_hide_errors(bool hide);
/* |description|
Returns the last error message generated by `mod_fs` functions or nil if no error occurred
|descriptionEnd| */
const char *mod_fs_get_last_error();
#endif // MOD_FS_H