diff --git a/Makefile b/Makefile index 64581eaac..d24772611 100644 --- a/Makefile +++ b/Makefile @@ -66,8 +66,6 @@ ifeq ($(shell arch),arm64) else MIN_MACOS_VERSION ?= 10.15 endif -# Homebrew Prefix -BREW_PREFIX ?= $(shell brew --prefix) # Make some small adjustments for handheld devices HANDHELD ?= 0 @@ -122,6 +120,10 @@ endif ifeq ($(HOST_OS),Darwin) OSX_BUILD := 1 + + ifndef BREW_PREFIX + BREW_PREFIX := $(shell brew --prefix) + endif endif # MXE overrides diff --git a/autogen/convert_functions.py b/autogen/convert_functions.py index cc77a0e1d..2279cccee 100644 --- a/autogen/convert_functions.py +++ b/autogen/convert_functions.py @@ -114,7 +114,7 @@ override_disallowed_functions = { "src/pc/lua/utils/smlua_obj_utils.h": [ "spawn_object_remember_field" ], "src/game/camera.h": [ "update_camera", "init_camera", "stub_camera", "^reset_camera", "move_point_along_spline" ], "src/game/behavior_actions.h": [ "bhv_dust_smoke_loop", "bhv_init_room" ], - "src/pc/lua/utils/smlua_audio_utils.h": [ "smlua_audio_utils_override", "audio_custom_shutdown", "smlua_audio_custom_init", "smlua_audio_custom_deinit", "audio_sample_destroy_pending_copies", "audio_custom_update_volume" ], + "src/pc/lua/utils/smlua_audio_utils.h": [ "smlua_audio_utils_override", "audio_custom_shutdown", "smlua_audio_custom_deinit", "audio_sample_destroy_pending_copies", "audio_custom_update_volume" ], "src/pc/djui/djui_hud_utils.h": [ "djui_hud_render_texture", "djui_hud_render_texture_raw", "djui_hud_render_texture_tile", "djui_hud_render_texture_tile_raw" ], "src/pc/lua/utils/smlua_level_utils.h": [ "smlua_level_util_reset" ], "src/pc/lua/utils/smlua_text_utils.h": [ "smlua_text_utils_init", "smlua_text_utils_shutdown", "smlua_text_utils_reset_all" ], diff --git a/autogen/lua_constants/built-in.lua b/autogen/lua_constants/built-in.lua index 8cb619784..29266a674 100644 --- a/autogen/lua_constants/built-in.lua +++ b/autogen/lua_constants/built-in.lua @@ -1,77 +1,5 @@ math.randomseed(get_time()) - --------------- --- CObjects -- --------------- - -_CObjectPool = {} - -_CObject = { - __index = function (t,k) - return _get_field(t['_lot'], t['_pointer'], k, t) - end, - __newindex = function (t,k,v) - _set_field(t['_lot'], t['_pointer'], k, v, t) - end, - __tostring = function(t) - return 'CObject: ' .. t['_lot'] .. ', [' .. string.format('0x%08X', t['_pointer']) .. ']' - end, - __eq = function (a, b) - return a['_pointer'] == b['_pointer'] and a['_lot'] == b['_lot'] and a['_pointer'] ~= nil and a['_lot'] ~= nil - end -} - -function _NewCObject(lot, pointer) - if _CObjectPool[lot] == nil then - _CObjectPool[lot] = {} - end - - if _CObjectPool[lot][pointer] == nil then - local obj = {} - rawset(obj, '_pointer', pointer) - rawset(obj, '_lot', lot) - setmetatable(obj, _CObject) - _CObjectPool[lot][pointer] = obj - return obj - end - - return _CObjectPool[lot][pointer] -end - -local _CPointerPool = {} - -_CPointer = { - __index = function (t,k) - return nil - end, - __newindex = function (t,k,v) - end, - __tostring = function(t) - return 'CPointer: ' .. t['_lvt'] .. ', [' .. string.format('0x%08X', t['_pointer']) .. ']' - end, - __eq = function (a, b) - return a['_pointer'] == b['_pointer'] and a['_pointer'] ~= nil and a['_lvt'] ~= nil - end -} - -function _NewCPointer(lvt, pointer) - if _CPointerPool[lvt] == nil then - _CPointerPool[lvt] = {} - end - - if _CPointerPool[lvt][pointer] == nil then - local obj = {} - rawset(obj, '_pointer', pointer) - rawset(obj, '_lvt', lvt) - setmetatable(obj, _CPointer) - _CPointerPool[lvt][pointer] = obj - return obj - end - - return _CPointerPool[lvt][pointer] -end - _SyncTable = { __index = function (t,k) local _table = rawget(t, '_table') diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index 68e4cfb93..94b734983 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -2,78 +2,6 @@ math.randomseed(get_time()) - --------------- --- CObjects -- --------------- - -_CObjectPool = {} - -_CObject = { - __index = function (t,k) - return _get_field(t['_lot'], t['_pointer'], k, t) - end, - __newindex = function (t,k,v) - _set_field(t['_lot'], t['_pointer'], k, v, t) - end, - __tostring = function(t) - return 'CObject: ' .. t['_lot'] .. ', [' .. string.format('0x%08X', t['_pointer']) .. ']' - end, - __eq = function (a, b) - return a['_pointer'] == b['_pointer'] and a['_lot'] == b['_lot'] and a['_pointer'] ~= nil and a['_lot'] ~= nil - end -} - -function _NewCObject(lot, pointer) - if _CObjectPool[lot] == nil then - _CObjectPool[lot] = {} - end - - if _CObjectPool[lot][pointer] == nil then - local obj = {} - rawset(obj, '_pointer', pointer) - rawset(obj, '_lot', lot) - setmetatable(obj, _CObject) - _CObjectPool[lot][pointer] = obj - return obj - end - - return _CObjectPool[lot][pointer] -end - -local _CPointerPool = {} - -_CPointer = { - __index = function (t,k) - return nil - end, - __newindex = function (t,k,v) - end, - __tostring = function(t) - return 'CPointer: ' .. t['_lvt'] .. ', [' .. string.format('0x%08X', t['_pointer']) .. ']' - end, - __eq = function (a, b) - return a['_pointer'] == b['_pointer'] and a['_pointer'] ~= nil and a['_lvt'] ~= nil - end -} - -function _NewCPointer(lvt, pointer) - if _CPointerPool[lvt] == nil then - _CPointerPool[lvt] = {} - end - - if _CPointerPool[lvt][pointer] == nil then - local obj = {} - rawset(obj, '_pointer', pointer) - rawset(obj, '_lvt', lvt) - setmetatable(obj, _CPointer) - _CPointerPool[lvt][pointer] = obj - return obj - end - - return _CPointerPool[lvt][pointer] -end - _SyncTable = { __index = function (t,k) local _table = rawget(t, '_table') diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index ccd0bd685..31c147565 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -7807,6 +7807,11 @@ function camera_freeze() -- ... end +--- @return boolean +function camera_get_checking_surfaces() + -- ... +end + --- @return boolean function camera_is_frozen() -- ... @@ -7826,6 +7831,11 @@ function camera_romhack_allow_dpad_usage(allow) -- ... end +--- @param value boolean +function camera_set_checking_surfaces(value) + -- ... +end + --- @param rco RomhackCameraOverride function camera_set_romhack_override(rco) -- ... diff --git a/data/dynos_bin_actor.cpp b/data/dynos_bin_actor.cpp index aa49a2fa1..60d62bcf1 100644 --- a/data/dynos_bin_actor.cpp +++ b/data/dynos_bin_actor.cpp @@ -149,12 +149,12 @@ static void DynOS_Actor_Generate(const SysPath &aPackFolder, Arrayd_name) == ".") continue; if (SysPath(_PackEnt->d_name) == "..") continue; -#ifdef DEVELOPMENT // Compress .bin files to gain some space - SysPath _Filename = fstring("%s/%s", aPackFolder.c_str(), _PackEnt->d_name); - if (SysPath(_PackEnt->d_name).find(".bin") != SysPath::npos && !DynOS_Bin_IsCompressed(_Filename)) { - DynOS_Bin_Compress(_Filename); - continue; + if (configCompressOnStartup) { + SysPath _Filename = fstring("%s/%s", aPackFolder.c_str(), _PackEnt->d_name); + if (SysPath(_PackEnt->d_name).find(".bin") != SysPath::npos && !DynOS_Bin_IsCompressed(_Filename)) { + DynOS_Bin_Compress(_Filename); + continue; + } } -#endif // For each subfolder, read tokens from model.inc.c and geo.inc.c SysPath _Folder = fstring("%s/%s", aPackFolder.c_str(), _PackEnt->d_name); diff --git a/data/dynos_bin_col.cpp b/data/dynos_bin_col.cpp index d17c47c37..cebc98cae 100644 --- a/data/dynos_bin_col.cpp +++ b/data/dynos_bin_col.cpp @@ -691,13 +691,13 @@ void DynOS_Col_Generate(const SysPath &aPackFolder, Array> _Ac // If there is an existing binary file for this collision, skip and go to the next actor SysPath _ColFilename = fstring("%s/%s.col", aPackFolder.c_str(), _ColRootName.begin()); if (fs_sys_file_exists(_ColFilename.c_str())) { -#ifdef DEVELOPMENT + // Compress file to gain some space - if (!DynOS_Bin_IsCompressed(_ColFilename)) { + if (configCompressOnStartup && !DynOS_Bin_IsCompressed(_ColFilename)) { DynOS_Bin_Compress(_ColFilename); } + continue; -#endif } // Init diff --git a/data/dynos_bin_lvl.cpp b/data/dynos_bin_lvl.cpp index d8f0dc9c1..c991c8d63 100644 --- a/data/dynos_bin_lvl.cpp +++ b/data/dynos_bin_lvl.cpp @@ -1119,12 +1119,12 @@ static bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Arrayd_name) == ".") continue; if (SysPath(_PackEnt->d_name) == "..") continue; -#ifdef DEVELOPMENT // Compress .lvl files to gain some space - // TODO: is this required anymore? - /*SysPath _Filename = fstring("%s/%s", aPackFolder.c_str(), _PackEnt->d_name); - if (SysPath(_PackEnt->d_name).find(".lvl") != SysPath::npos && !DynOS_Bin_IsCompressed(_Filename)) { - DynOS_Bin_Compress(_Filename); - continue; - }*/ -#endif + if (configCompressOnStartup) { + SysPath _Filename = fstring("%s/%s", aPackFolder.c_str(), _PackEnt->d_name); + if (SysPath(_PackEnt->d_name).find(".lvl") != SysPath::npos && !DynOS_Bin_IsCompressed(_Filename)) { + DynOS_Bin_Compress(_Filename); + continue; + } + } // For each subfolder, read tokens from script.c SysPath _Folder = fstring("%s/%s", aPackFolder.c_str(), _PackEnt->d_name); diff --git a/data/dynos_gfx_init.cpp b/data/dynos_gfx_init.cpp index c1f3b10b2..3fbae797c 100644 --- a/data/dynos_gfx_init.cpp +++ b/data/dynos_gfx_init.cpp @@ -1,8 +1,13 @@ #include "dynos.cpp.h" +extern "C" { #include "pc/loading.h" +} void DynOS_Gfx_GeneratePacks(const char* directory) { - LOADING_SCREEN_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Generating DynOS Packs In Path:\n\\#808080\\%s", directory)); + LOADING_SCREEN_MUTEX( + loading_screen_reset_progress_bar(); + snprintf(gCurrLoadingSegment.str, 256, "Generating DynOS Packs In Path:\n\\#808080\\%s", directory); + ); DIR *modsDir = opendir(directory); if (!modsDir) { return; } diff --git a/docs/lua/functions-5.md b/docs/lua/functions-5.md index 207fccb76..95f66b394 100644 --- a/docs/lua/functions-5.md +++ b/docs/lua/functions-5.md @@ -824,6 +824,24 @@
+## [camera_get_checking_surfaces](#camera_get_checking_surfaces) + +### Lua Example +`local booleanValue = camera_get_checking_surfaces()` + +### Parameters +- None + +### Returns +- `boolean` + +### C Prototype +`bool camera_get_checking_surfaces(void);` + +[:arrow_up_small:](#) + +
+ ## [camera_is_frozen](#camera_is_frozen) ### Lua Example @@ -900,6 +918,26 @@
+## [camera_set_checking_surfaces](#camera_set_checking_surfaces) + +### Lua Example +`camera_set_checking_surfaces(value)` + +### Parameters +| Field | Type | +| ----- | ---- | +| value | `boolean` | + +### Returns +- None + +### C Prototype +`void camera_set_checking_surfaces(bool value);` + +[:arrow_up_small:](#) + +
+ ## [camera_set_romhack_override](#camera_set_romhack_override) ### Lua Example diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 5cba926d8..c1245be90 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -1641,10 +1641,12 @@ - [camera_config_set_x_sensitivity](functions-5.md#camera_config_set_x_sensitivity) - [camera_config_set_y_sensitivity](functions-5.md#camera_config_set_y_sensitivity) - [camera_freeze](functions-5.md#camera_freeze) + - [camera_get_checking_surfaces](functions-5.md#camera_get_checking_surfaces) - [camera_is_frozen](functions-5.md#camera_is_frozen) - [camera_reset_overrides](functions-5.md#camera_reset_overrides) - [camera_romhack_allow_centering](functions-5.md#camera_romhack_allow_centering) - [camera_romhack_allow_dpad_usage](functions-5.md#camera_romhack_allow_dpad_usage) + - [camera_set_checking_surfaces](functions-5.md#camera_set_checking_surfaces) - [camera_set_romhack_override](functions-5.md#camera_set_romhack_override) - [camera_unfreeze](functions-5.md#camera_unfreeze) diff --git a/src/game/camera.c b/src/game/camera.c index 07c2ff451..e03d5d4c5 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -3085,7 +3085,7 @@ void update_lakitu(struct Camera *c) { distToFloor = find_floor(gLakituState.pos[0], gLakituState.pos[1] + 20.0f, gLakituState.pos[2], &floor); - gCheckingSurfaceCollisionsForCamera = false; + gCheckingSurfaceCollisionsForCamera = FALSE; if (distToFloor != gLevelValues.floorLowerLimit) { if (gLakituState.pos[1] < (distToFloor += 100.0f)) { gLakituState.pos[1] = distToFloor; diff --git a/src/game/level_update.c b/src/game/level_update.c index 14f5a948b..34e275981 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -251,7 +251,7 @@ u16 level_control_timer(s32 timerOp) { u32 pressed_pause(void) { if (gServerSettings.pauseAnywhere) { - if (get_dialog_id() < 0 && !gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE) { + if (get_dialog_id() < 0) { return gPlayer1Controller->buttonPressed & START_BUTTON; } } else { diff --git a/src/game/memory.c b/src/game/memory.c index a4da7b705..5a58b85e3 100644 --- a/src/game/memory.c +++ b/src/game/memory.c @@ -4,6 +4,7 @@ #include "memory.h" #include "print.h" #include "pc/debuglog.h" +#include "pc/lua/smlua.h" #define ALIGN16(val) (((val) + 0xF) & ~0xF) @@ -222,7 +223,7 @@ void growing_array_free(struct GrowingArray **array) { if (*array) { for (u32 i = 0; i != (*array)->capacity; ++i) { if ((*array)->buffer[i]) { - free((*array)->buffer[i]); + smlua_free((*array)->buffer[i]); } } free((*array)->buffer); diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index d581145d1..9f7adeacc 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -616,7 +616,7 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation Mat4 mtxf; Vec3f translation; - // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\. + // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB. if ((gMatStackIndex + 1) >= MATRIX_STACK_SIZE) { LOG_ERROR("Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i.", MATRIX_STACK_SIZE - 1, gMatStackIndex); return; } vec3s_to_vec3f(translation, node->translation); diff --git a/src/pc/configfile.c b/src/pc/configfile.c index 845c723d7..1cd646471 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -186,6 +186,10 @@ unsigned int configDjuiThemeFont = FONT_NORMAL; unsigned int configDjuiScale = 0; // other unsigned int configRulesVersion = 0; +bool configCompressOnStartup = false; + +// secrets +bool configExCoopTheme = false; static const struct ConfigOption options[] = { // window settings @@ -311,7 +315,27 @@ static const struct ConfigOption options[] = { {.name = "djui_theme_font", .type = CONFIG_TYPE_UINT, .uintValue = &configDjuiThemeFont}, {.name = "djui_scale", .type = CONFIG_TYPE_UINT, .uintValue = &configDjuiScale}, // other - {.name = "rules_version", .type = CONFIG_TYPE_UINT, .uintValue = &configRulesVersion} + {.name = "rules_version", .type = CONFIG_TYPE_UINT, .uintValue = &configRulesVersion}, + {.name = "compress_on_startup", .type = CONFIG_TYPE_BOOL, .boolValue = &configCompressOnStartup}, +}; + +struct SecretConfigOption { + const char *name; + enum ConfigOptionType type; + union { + bool *boolValue; + unsigned int *uintValue; + float* floatValue; + char* stringValue; + u64* u64Value; + u8 (*colorValue)[3]; + }; + int maxStringLength; + bool inConfig; +}; + +static struct SecretConfigOption secret_options[] = { + {.name = "ex_coop_theme", .type = CONFIG_TYPE_BOOL, .boolValue = &configExCoopTheme}, }; // FunctionConfigOption functions @@ -619,6 +643,15 @@ static void configfile_load_internal(const char *filename, bool* error) { } } + // secret options + for (unsigned int i = 0; i < ARRAY_LEN(secret_options); i++) { + if (strcmp(tokens[0], secret_options[i].name) == 0) { + secret_options[i].inConfig = true; + option = (const struct ConfigOption *) &secret_options[i]; + break; + } + } + if (option == NULL) { #ifdef DEVELOPMENT printf("unknown option '%s'\n", tokens[0]); @@ -708,6 +741,42 @@ void configfile_load(void) { #endif } +static void configfile_save_option(FILE *file, const struct ConfigOption *option, bool isSecret) { + if (isSecret) { + const struct SecretConfigOption *secret_option = (const struct SecretConfigOption *) option; + if (!secret_option->inConfig) { return; } + } + switch (option->type) { + case CONFIG_TYPE_BOOL: + fprintf(file, "%s %s\n", option->name, *option->boolValue ? "true" : "false"); + break; + case CONFIG_TYPE_UINT: + fprintf(file, "%s %u\n", option->name, *option->uintValue); + break; + case CONFIG_TYPE_FLOAT: + fprintf(file, "%s %f\n", option->name, *option->floatValue); + break; + case CONFIG_TYPE_BIND: + fprintf(file, "%s ", option->name); + for (int i = 0; i < MAX_BINDS; ++i) + fprintf(file, "%04x ", option->uintValue[i]); + fprintf(file, "\n"); + break; + case CONFIG_TYPE_STRING: + fprintf(file, "%s %s\n", option->name, option->stringValue); + break; + case CONFIG_TYPE_U64: + fprintf(file, "%s %llu\n", option->name, *option->u64Value); + break; + case CONFIG_TYPE_COLOR: + fprintf(file, "%s %02x %02x %02x\n", option->name, (*option->colorValue)[0], (*option->colorValue)[1], (*option->colorValue)[2]); + break; + default: + LOG_ERROR("Configfile wrote bad type '%d': %s", (int)option->type, option->name); + break; + } +} + // Writes the config file to 'filename' void configfile_save(const char *filename) { FILE *file; @@ -722,36 +791,12 @@ void configfile_save(const char *filename) { for (unsigned int i = 0; i < ARRAY_LEN(options); i++) { const struct ConfigOption *option = &options[i]; + configfile_save_option(file, option, false); + } - switch (option->type) { - case CONFIG_TYPE_BOOL: - fprintf(file, "%s %s\n", option->name, *option->boolValue ? "true" : "false"); - break; - case CONFIG_TYPE_UINT: - fprintf(file, "%s %u\n", option->name, *option->uintValue); - break; - case CONFIG_TYPE_FLOAT: - fprintf(file, "%s %f\n", option->name, *option->floatValue); - break; - case CONFIG_TYPE_BIND: - fprintf(file, "%s ", option->name); - for (int i = 0; i < MAX_BINDS; ++i) - fprintf(file, "%04x ", option->uintValue[i]); - fprintf(file, "\n"); - break; - case CONFIG_TYPE_STRING: - fprintf(file, "%s %s\n", option->name, option->stringValue); - break; - case CONFIG_TYPE_U64: - fprintf(file, "%s %llu\n", option->name, *option->u64Value); - break; - case CONFIG_TYPE_COLOR: - fprintf(file, "%s %02x %02x %02x\n", option->name, (*option->colorValue)[0], (*option->colorValue)[1], (*option->colorValue)[2]); - break; - default: - LOG_ERROR("Configfile wrote bad type '%d': %s", (int)option->type, option->name); - break; - } + for (unsigned int i = 0; i < ARRAY_LEN(secret_options); i++) { + const struct ConfigOption *option = (const struct ConfigOption *) &secret_options[i]; + configfile_save_option(file, option, true); } // save function options diff --git a/src/pc/configfile.h b/src/pc/configfile.h index 642f47e58..aa080e1e7 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -135,6 +135,10 @@ extern unsigned int configDjuiThemeFont; extern unsigned int configDjuiScale; // other extern unsigned int configRulesVersion; +extern bool configCompressOnStartup; + +// secrets +extern bool configExCoopTheme; void enable_queued_mods(void); void enable_queued_dynos_packs(void); diff --git a/src/pc/djui/djui_font.c b/src/pc/djui/djui_font.c index ea495dd71..39457f704 100644 --- a/src/pc/djui/djui_font.c +++ b/src/pc/djui/djui_font.c @@ -20,7 +20,7 @@ static void djui_font_normal_render_char(char* c) { } static f32 djui_font_normal_char_width(char* c) { - if (*c == ' ') { return 0.30f; } + if (*c == ' ') { return configExCoopTheme ? 6 / 32.0f : 0.30f; } extern const f32 font_normal_widths[]; return djui_unicode_get_sprite_width(c, font_normal_widths, 32.0f); } @@ -62,7 +62,7 @@ static f32 djui_font_title_char_width(char* text) { if (c == ' ') { return 0.30f; } c = djui_unicode_get_base_char(text); extern const f32 font_title_widths[]; - return font_title_widths[(u8)c - '!'] * 1.1f; + return font_title_widths[(u8)c - '!'] * (configExCoopTheme ? 1.0f : 1.1f); } static const struct DjuiFont sDjuiFontTitle = { diff --git a/src/pc/djui/djui_interactable.c b/src/pc/djui/djui_interactable.c index 767e5870b..1a9e0e310 100644 --- a/src/pc/djui/djui_interactable.c +++ b/src/pc/djui/djui_interactable.c @@ -409,17 +409,15 @@ void djui_interactable_update(void) { if (gInteractableFocus) { u16 mainButtons = PAD_BUTTON_A | PAD_BUTTON_B; if ((mouseButtons & MOUSE_BUTTON_1) && !(sLastMouseButtons && MOUSE_BUTTON_1) && !djui_cursor_inside_base(gInteractableFocus)) { - // clicked outside of focused - // if (!gDjuiChatBoxFocus && gDjuiChatBox != NULL && gInteractableFocus != &gDjuiChatBox->chatInput->base) { - // djui_interactable_set_input_focus(NULL); - // } - djui_interactable_set_input_focus(NULL); + // clicked outside of focus + if (!gDjuiChatBoxFocus) { + djui_interactable_set_input_focus(NULL); + } } else if ((padButtons & mainButtons) && !(sLastInteractablePad.button & mainButtons)) { // pressed main face button - // if (!gDjuiChatBoxFocus && gDjuiChatBox != NULL && gInteractableFocus != &gDjuiChatBox->chatInput->base) { - // djui_interactable_set_input_focus(NULL); - // } - djui_interactable_set_input_focus(NULL); + if (!gDjuiChatBoxFocus) { + djui_interactable_set_input_focus(NULL); + } } else { djui_interactable_on_focus(gInteractableFocus); } diff --git a/src/pc/djui/djui_panel.c b/src/pc/djui/djui_panel.c index 95f31d053..e0253303e 100644 --- a/src/pc/djui/djui_panel.c +++ b/src/pc/djui/djui_panel.c @@ -58,6 +58,7 @@ struct DjuiPanel* djui_panel_add(struct DjuiBase* caller, struct DjuiThreePanel* panel->defaultElementBase = defaultElementBase; panel->on_back = threePanel->on_back; panel->on_panel_destroy = NULL; + panel->temporary = threePanel->temporary; sPanelList = panel; // find better defaultElementBase @@ -118,6 +119,7 @@ void djui_panel_back(void) { // set the previous active sPanelList = sPanelList->parent; + if (sPanelList->temporary) { sPanelList = sPanelList->parent; } // reset move amount sMoveAmount = 0; diff --git a/src/pc/djui/djui_panel_main.c b/src/pc/djui/djui_panel_main.c index 4b4b889e7..a32f3d415 100644 --- a/src/pc/djui/djui_panel_main.c +++ b/src/pc/djui/djui_panel_main.c @@ -25,30 +25,32 @@ static void djui_panel_main_quit(struct DjuiBase* caller) { } void djui_panel_main_create(struct DjuiBase* caller) { - struct DjuiThreePanel* panel = djui_panel_menu_create("", false); + struct DjuiThreePanel* panel = djui_panel_menu_create(configExCoopTheme ? "\\#ff0800\\SM\\#1be700\\64\\#00b3ff\\EX\n\\#ffef00\\COOP" : "", false); { struct DjuiBase* body = djui_three_panel_get_body(panel); { - struct DjuiImage* logo = djui_image_create(body, texture_coopdx_logo, 2048, 1024, 32); - if (configDjuiThemeCenter) { - djui_base_set_size(&logo->base, 550, 275); - } else { - djui_base_set_size(&logo->base, 480, 240); + if (!configExCoopTheme) { + struct DjuiImage* logo = djui_image_create(body, texture_coopdx_logo, 2048, 1024, 32); + if (configDjuiThemeCenter) { + djui_base_set_size(&logo->base, 550, 275); + } else { + djui_base_set_size(&logo->base, 480, 240); + } + djui_base_set_alignment(&logo->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP); + djui_base_set_location_type(&logo->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_location(&logo->base, 0, -30); } - djui_base_set_alignment(&logo->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP); - djui_base_set_location_type(&logo->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); - djui_base_set_location(&logo->base, 0, -30); struct DjuiButton* button1 = djui_button_create(body, DLANG(MAIN, HOST), DJUI_BUTTON_STYLE_NORMAL, djui_panel_host_create); - djui_base_set_location(&button1->base, 0, -30); + if (!configExCoopTheme) { djui_base_set_location(&button1->base, 0, -30); } djui_cursor_input_controlled_center(&button1->base); struct DjuiButton* button2 = djui_button_create(body, DLANG(MAIN, JOIN), DJUI_BUTTON_STYLE_NORMAL, djui_panel_join_create); - djui_base_set_location(&button2->base, 0, -30); + if (!configExCoopTheme) { djui_base_set_location(&button2->base, 0, -30); } struct DjuiButton* button3 = djui_button_create(body, DLANG(MAIN, OPTIONS), DJUI_BUTTON_STYLE_NORMAL, djui_panel_options_create); - djui_base_set_location(&button3->base, 0, -30); + if (!configExCoopTheme) { djui_base_set_location(&button3->base, 0, -30); } struct DjuiButton* button4 = djui_button_create(body, DLANG(MAIN, QUIT), DJUI_BUTTON_STYLE_BACK, djui_panel_main_quit); - djui_base_set_location(&button4->base, 0, -30); + if (!configExCoopTheme) { djui_base_set_location(&button4->base, 0, -30); } } // these two cannot co-exist for some reason diff --git a/src/pc/djui/djui_panel_menu.c b/src/pc/djui/djui_panel_menu.c index 7a6e3dd33..552cba5b3 100644 --- a/src/pc/djui/djui_panel_menu.c +++ b/src/pc/djui/djui_panel_menu.c @@ -13,6 +13,13 @@ char* sRainbowColors[] = { "\\#ffef40\\", }; +char* sExCoopRainbowColors[] = { + "\\#ff0800\\", + "\\#1be700\\", + "\\#00b3ff\\", + "\\#ffef00\\", +}; + char sRainbowText[RAINBOW_TEXT_LEN + 1] = { 0 }; static void generate_rainbow_text(char* text) { @@ -28,7 +35,7 @@ static void generate_rainbow_text(char* text) { } s32 restrictSize = RAINBOW_TEXT_LEN - (s32)(dst - sRainbowText); if (restrictSize <= 0) { break; } - snprintf(dst, restrictSize, "%s", sRainbowColors[i++ % 4]); + snprintf(dst, restrictSize, "%s", configExCoopTheme ? sExCoopRainbowColors[i++ % 4] : sRainbowColors[i++ % 4]); dst = &sRainbowText[strlen(sRainbowText)]; restrictSize = RAINBOW_TEXT_LEN - (s32)(dst - sRainbowText); @@ -75,7 +82,11 @@ struct DjuiThreePanel* djui_panel_menu_create(char* headerText, bool forcedLeftS djui_base_set_location(&header->base, 0, DJUI_PANEL_HEADER_OFFSET); djui_text_set_alignment(header, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM); djui_text_set_font(header, hudFontHeader ? gDjuiFonts[2] : gDjuiFonts[1]); - djui_text_set_font_scale(header, gDjuiFonts[1]->defaultFontScale * (hudFontHeader ? 0.7f : 1.0f) * (strlen(headerText) > 15 ? 0.9f : 1.0f)); + if (configExCoopTheme) { + djui_text_set_font_scale(header, gDjuiFonts[1]->defaultFontScale); + } else { + djui_text_set_font_scale(header, gDjuiFonts[1]->defaultFontScale * (hudFontHeader ? 0.7f : 1.0f) * (strlen(headerText) > 15 ? 0.9f : 1.0f)); + } struct DjuiFlowLayout* body = djui_flow_layout_create(&panel->base); djui_base_set_alignment(&body->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); diff --git a/src/pc/djui/djui_panel_rules.c b/src/pc/djui/djui_panel_rules.c index 17e6e569e..e2e8d0ba7 100644 --- a/src/pc/djui/djui_panel_rules.c +++ b/src/pc/djui/djui_panel_rules.c @@ -21,16 +21,7 @@ void djui_panel_rules_create(struct DjuiBase* caller) { struct DjuiThreePanel* panel = djui_panel_menu_create(DLANG(RULES, RULES_TITLE), false); struct DjuiBase* body = djui_three_panel_get_body(panel); { - snprintf(sRules, 512, "%s\n\ -%s\n\ -%s\n\ -%s\n\ -%s", -DLANG(RULES, RULE_1), -DLANG(RULES, RULE_2), -DLANG(RULES, RULE_3), -DLANG(RULES, RULE_4), -DLANG(RULES, RULE_5)); + snprintf(sRules, 512, "%s\n%s\n%s\n%s\n%s", DLANG(RULES, RULE_1), DLANG(RULES, RULE_2), DLANG(RULES, RULE_3), DLANG(RULES, RULE_4), DLANG(RULES, RULE_5)); struct DjuiText* text1 = djui_text_create(body, sRules); djui_base_set_location(&text1->base, 0, 0); @@ -65,6 +56,7 @@ DLANG(RULES, RULE_5)); } + panel->temporary = true; djui_panel_add(caller, panel, NULL); } #endif diff --git a/src/pc/djui/djui_progress_bar.c b/src/pc/djui/djui_progress_bar.c index 08a4b08a0..64cc86ad7 100644 --- a/src/pc/djui/djui_progress_bar.c +++ b/src/pc/djui/djui_progress_bar.c @@ -2,7 +2,7 @@ void djui_progress_bar_render_pre(struct DjuiBase* base, UNUSED bool* unused) { struct DjuiProgressBar* progress = (struct DjuiProgressBar*)base; - progress->smoothValue = progress->smoothValue * 0.95f + *progress->value * 0.05f; + progress->smoothValue = progress->smoothValue * progress->smoothenHigh + *progress->value * progress->smoothenLow; float min = progress->min; float max = progress->max; djui_base_set_size(&progress->rectValue->base, ((f32)progress->smoothValue - min) / ((f32)max - min), 1.0f); @@ -13,7 +13,7 @@ void djui_progress_bar_render_pre_infinite(struct DjuiBase* base, UNUSED bool* u float min = progress->min; float max = progress->max; - progress->smoothValue = progress->smoothValue * 0.95f + *progress->value * 0.05f; + progress->smoothValue = progress->smoothValue * progress->smoothenHigh + *progress->value * progress->smoothenLow; float modValue = progress->smoothValue - ((int)progress->smoothValue); float x = (modValue - min - 0.25f) / (max - min - 0.25f); float w = 0.25f; @@ -43,6 +43,8 @@ struct DjuiProgressBar* djui_progress_bar_create(struct DjuiBase* parent, float* progress->smoothValue = *value; progress->min = min; progress->max = max; + progress->smoothenHigh = 0.95f; + progress->smoothenLow = 0.05f; djui_base_init(parent, base, NULL, djui_progress_bar_destroy); djui_base_set_size_type(base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); diff --git a/src/pc/djui/djui_progress_bar.h b/src/pc/djui/djui_progress_bar.h index 08494301b..bc6bc2cec 100644 --- a/src/pc/djui/djui_progress_bar.h +++ b/src/pc/djui/djui_progress_bar.h @@ -9,6 +9,8 @@ struct DjuiProgressBar { float smoothValue; float min; float max; + float smoothenHigh; + float smoothenLow; }; struct DjuiProgressBar* djui_progress_bar_create(struct DjuiBase* parent, float* value, float min, float max, bool infinite); diff --git a/src/pc/djui/djui_three_panel.h b/src/pc/djui/djui_three_panel.h index c00515d55..1cd96fd2c 100644 --- a/src/pc/djui/djui_three_panel.h +++ b/src/pc/djui/djui_three_panel.h @@ -6,6 +6,7 @@ struct DjuiThreePanel { struct DjuiScreenValue minHeaderSize; struct DjuiScreenValue bodySize; struct DjuiScreenValue minFooterSize; + bool temporary; bool (*on_back)(struct DjuiBase*); }; diff --git a/src/pc/loading.c b/src/pc/loading.c index 1683ddcbf..82b518ce6 100644 --- a/src/pc/loading.c +++ b/src/pc/loading.c @@ -17,6 +17,7 @@ struct LoadingSegment gCurrLoadingSegment = { "", 0 }; struct LoadingScreen { struct DjuiBase base; struct DjuiImage* splashImage; + struct DjuiText* splashText; struct DjuiText* loadingDesc; struct DjuiProgressBar *loadingBar; }; @@ -32,6 +33,10 @@ void loading_screen_set_segment_text(const char* text) { snprintf(gCurrLoadingSegment.str, 256, text); } +void loading_screen_reset_progress_bar(void) { + sLoading->loadingBar->smoothValue = 0; +} + static void loading_screen_produce_frame_callback(void) { if (sLoading) { djui_base_render(&sLoading->base); } } @@ -49,12 +54,19 @@ static bool loading_screen_on_render(struct DjuiBase* base) { windowWidth /= scale; windowHeight /= scale; - f32 loadingDescY1 = windowHeight * 0.5f + sLoading->splashImage->base.height.value * 0.25f; - f32 loadingDescY2 = windowHeight * 0.5f + sLoading->splashImage->base.height.value * 0.55f; + f32 loadingDescY1 = windowHeight * 0.5f - sLoading->loadingDesc->base.height.value * 0.5f; + f32 loadingDescY2 = windowHeight * 0.5f + sLoading->loadingDesc->base.height.value * 0.5f; // fill the screen djui_base_set_size(base, windowWidth, windowHeight); + // splash logo + if (configExCoopTheme) { + djui_base_set_location(&sLoading->splashText->base, 0, loadingDescY1 - sLoading->splashText->base.height.value); + } else { + djui_base_set_location(&sLoading->splashImage->base, 0, loadingDescY1 - sLoading->splashImage->base.height.value); + } + { // loading text description char buffer[256] = ""; @@ -73,7 +85,7 @@ static bool loading_screen_on_render(struct DjuiBase* base) { } // loading bar - djui_base_set_location(&sLoading->loadingBar->base, windowWidth / 4, loadingDescY2); + djui_base_set_location(&sLoading->loadingBar->base, windowWidth / 4, loadingDescY2 + 64); djui_base_set_visible(&sLoading->loadingBar->base, gCurrLoadingSegment.percentage > 0 && strlen(gCurrLoadingSegment.str) > 0); djui_base_compute(base); @@ -95,12 +107,26 @@ static void init_loading_screen(void) { djui_base_init(NULL, base, loading_screen_on_render, loading_screen_destroy); - { - // splash image + // splash text (easter egg) + if (configExCoopTheme) { + struct DjuiText* splashDjuiText = djui_text_create(base, "\\#ff0800\\SM\\#1be700\\64\\#00b3ff\\EX\n\\#ffef00\\COOP"); + djui_base_set_location_type(&splashDjuiText->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_location(&splashDjuiText->base, 0, 0); + djui_text_set_font(splashDjuiText, gDjuiFonts[1]); + djui_text_set_font_scale(splashDjuiText, gDjuiFonts[1]->defaultFontScale); + djui_text_set_alignment(splashDjuiText, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + djui_base_set_size_type(&splashDjuiText->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&splashDjuiText->base, 1.0f, gDjuiFonts[1]->defaultFontScale * 3.0f); + + load->splashText = splashDjuiText; + + // splash image + } else { struct DjuiImage* splashImage = djui_image_create(base, texture_coopdx_logo, 2048, 1024, 32); + djui_base_set_location_type(&splashImage->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_alignment(&splashImage->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP); djui_base_set_location(&splashImage->base, 0, -100); - djui_base_set_alignment(&splashImage->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); - djui_base_set_size(&splashImage->base, 1024, 512); + djui_base_set_size(&splashImage->base, 512, 256); load->splashImage = splashImage; } @@ -112,11 +138,11 @@ static void init_loading_screen(void) { djui_base_set_location(&text->base, 0, 0); djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); - djui_base_set_size(&text->base, 1.0f, gDjuiFonts[0]->defaultFontScale * 4.5f); // 3 lines + djui_base_set_size(&text->base, 1.0f, gDjuiFonts[0]->defaultFontScale * 3.0f); djui_base_set_color(&text->base, 220, 220, 220, 255); djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP); djui_text_set_font(text, gDjuiFonts[0]); - djui_text_set_font_scale(text, gDjuiFonts[0]->defaultFontScale * 1.5f); + djui_text_set_font_scale(text, gDjuiFonts[0]->defaultFontScale); load->loadingDesc = text; } @@ -127,7 +153,9 @@ static void init_loading_screen(void) { djui_base_set_location_type(&progressBar->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); djui_base_set_location(&progressBar->base, 0, 0); djui_base_set_visible(&progressBar->base, false); - djui_base_set_size(&progressBar->base, 0.5f, 32); + progressBar->base.width.value = 0.5; + progressBar->smoothenHigh = 0.75f; + progressBar->smoothenLow = 0.25f; load->loadingBar = progressBar; } diff --git a/src/pc/loading.h b/src/pc/loading.h index 4f12040a0..11fdb0b5a 100644 --- a/src/pc/loading.h +++ b/src/pc/loading.h @@ -32,6 +32,7 @@ extern pthread_mutex_t gLoadingThreadMutex; extern bool gIsThreaded; void loading_screen_set_segment_text(const char* text); +void loading_screen_reset_progress_bar(void); void render_loading_screen(void); void loading_screen_reset(void); void render_rom_setup_screen(void); diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index 4d9de298a..75432f9cc 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -1,4 +1,5 @@ #include "smlua.h" +#include "smlua_cobject_map.h" #include "game/hardcoded.h" #include "pc/mods/mods.h" #include "pc/mods/mods_utils.h" @@ -281,8 +282,7 @@ static void smlua_load_script(struct Mod* mod, struct ModFile* file, u16 remoteI void smlua_init(void) { smlua_shutdown(); - smlua_cobject_allowlist_init(); - smlua_cpointer_allowlist_init(); + smlua_pointer_user_data_init(); gLuaState = luaL_newstate(); lua_State* L = gLuaState; @@ -364,8 +364,7 @@ void smlua_shutdown(void) { smlua_text_utils_reset_all(); smlua_audio_utils_reset_all(); audio_custom_shutdown(); - smlua_cobject_allowlist_shutdown(); - smlua_cpointer_allowlist_shutdown(); + smlua_pointer_user_data_shutdown(); smlua_clear_hooks(); smlua_model_util_clear(); smlua_level_util_reset(); diff --git a/src/pc/lua/smlua.h b/src/pc/lua/smlua.h index 937612008..3ed42aab5 100644 --- a/src/pc/lua/smlua.h +++ b/src/pc/lua/smlua.h @@ -9,7 +9,6 @@ #include "types.h" #include "smlua_cobject.h" -#include "smlua_cobject_allowlist.h" #include "smlua_cobject_autogen.h" #include "smlua_utils.h" #include "smlua_functions.h" diff --git a/src/pc/lua/smlua_cobject.c b/src/pc/lua/smlua_cobject.c index e0b64f52e..32bbaedfb 100644 --- a/src/pc/lua/smlua_cobject.c +++ b/src/pc/lua/smlua_cobject.c @@ -10,6 +10,7 @@ #include "object_fields.h" #include "pc/djui/djui_hud_utils.h" #include "pc/lua/smlua.h" +#include "pc/lua/smlua_cobject_map.h" #include "pc/lua/utils/smlua_anim_utils.h" #include "pc/lua/utils/smlua_collision_utils.h" #include "pc/lua/utils/smlua_obj_utils.h" @@ -381,38 +382,30 @@ struct LuaObjectField* smlua_get_custom_field(lua_State* L, u32 lot, int keyInde static int smlua__get_field(lua_State* L) { LUA_STACK_CHECK_BEGIN(); - if (!smlua_functions_valid_param_count(L, 4)) { return 0; } - enum LuaObjectType lot = smlua_to_integer(L, 1); - if (!gSmLuaConvertSuccess) { return 0; } + CObject *cobj = lua_touserdata(L, 1); + enum LuaObjectType lot = cobj->lot; + u64 pointer = (u64)(intptr_t) cobj->pointer; + const char *key = smlua_to_string(L, 2); - u64 pointer = smlua_to_integer(L, 2); - if (!gSmLuaConvertSuccess) { return 0; } - - const char* key = smlua_to_string(L, 3); - if (!gSmLuaConvertSuccess) { - LOG_LUA_LINE("Tried to get a non-string field of cobject"); - return 0; + // Legacy support + if (strcmp(key, "_pointer") == 0) { + lua_pushinteger(L, (u64)(intptr_t) cobj->pointer); + return 1; + } + if (strcmp(key, "_lot") == 0) { + lua_pushinteger(L, cobj->lot); + return 1; } - if (pointer == 0) { - LOG_LUA_LINE("_get_field on null pointer"); - return 0; - } - - if (!smlua_valid_lot(lot)) { - LOG_LUA_LINE("_get_field on invalid LOT '%u'", lot); - return 0; - } - - if (!smlua_cobject_allowlist_contains(lot, pointer)) { - LOG_LUA_LINE("_get_field received a pointer not in allow list. '%u', '%llu", lot, (u64)pointer); + if (cobj->freed) { + LOG_LUA_LINE("_get_field on freed object"); return 0; } struct LuaObjectField* data = smlua_get_object_field(lot, key); if (data == NULL) { - data = smlua_get_custom_field(L, lot, 3); + data = smlua_get_custom_field(L, lot, 2); } if (data == NULL) { LOG_LUA_LINE("_get_field on invalid key '%s', lot '%d'", key, lot); @@ -470,38 +463,20 @@ static int smlua__get_field(lua_State* L) { static int smlua__set_field(lua_State* L) { LUA_STACK_CHECK_BEGIN(); - if (!smlua_functions_valid_param_count(L, 5)) { return 0; } - enum LuaObjectType lot = smlua_to_integer(L, 1); - if (!gSmLuaConvertSuccess) { return 0; } + CObject *cobj = lua_touserdata(L, 1); + enum LuaObjectType lot = cobj->lot; + u64 pointer = (u64)(intptr_t) cobj->pointer; + const char *key = smlua_to_string(L, 2); - u64 pointer = smlua_to_integer(L, 2); - if (!gSmLuaConvertSuccess) { return 0; } - - const char* key = smlua_to_string(L, 3); - if (!gSmLuaConvertSuccess) { - LOG_LUA_LINE("Tried to set a non-string field of cobject"); - return 0; - } - - if (pointer == 0) { - LOG_LUA_LINE("_set_field on null pointer"); - return 0; - } - - if (!smlua_valid_lot(lot)) { - LOG_LUA_LINE("_set_field on invalid LOT '%u'", lot); - return 0; - } - - if (!smlua_cobject_allowlist_contains(lot, pointer)) { - LOG_LUA_LINE("_set_field received a pointer not in allow list. '%u', '%llu", lot, (u64)pointer); + if (cobj->freed) { + LOG_LUA_LINE("_set_field on freed object"); return 0; } struct LuaObjectField* data = smlua_get_object_field(lot, key); if (data == NULL) { - data = smlua_get_custom_field(L, lot, 3); + data = smlua_get_custom_field(L, lot, 2); } if (data == NULL) { @@ -517,18 +492,18 @@ static int smlua__set_field(lua_State* L) { void* valuePointer = NULL; u8* p = ((u8*)(intptr_t)pointer) + data->valueOffset; switch (data->valueType) { - case LVT_BOOL:*(u8*) p = smlua_to_boolean(L, 4); break; - case LVT_U8: *(u8*) p = smlua_to_integer(L, 4); break; - case LVT_U16: *(u16*)p = smlua_to_integer(L, 4); break; - case LVT_U32: *(u32*)p = smlua_to_integer(L, 4); break; - case LVT_S8: *(s8*) p = smlua_to_integer(L, 4); break; - case LVT_S16: *(s16*)p = smlua_to_integer(L, 4); break; - case LVT_S32: *(s32*)p = smlua_to_integer(L, 4); break; - case LVT_F32: *(f32*)p = smlua_to_number(L, 4); break; - case LVT_U64: *(s64*)p = smlua_to_integer(L, 4); break; + case LVT_BOOL:*(u8*) p = smlua_to_boolean(L, 3); break; + case LVT_U8: *(u8*) p = smlua_to_integer(L, 3); break; + case LVT_U16: *(u16*)p = smlua_to_integer(L, 3); break; + case LVT_U32: *(u32*)p = smlua_to_integer(L, 3); break; + case LVT_S8: *(s8*) p = smlua_to_integer(L, 3); break; + case LVT_S16: *(s16*)p = smlua_to_integer(L, 3); break; + case LVT_S32: *(s32*)p = smlua_to_integer(L, 3); break; + case LVT_F32: *(f32*)p = smlua_to_number(L, 3); break; + case LVT_U64: *(s64*)p = smlua_to_integer(L, 3); break; case LVT_COBJECT_P: - valuePointer = smlua_to_cobject(L, 4, data->lot); + valuePointer = smlua_to_cobject(L, 3, data->lot); if (gSmLuaConvertSuccess) { *(u8**)p = valuePointer; } @@ -548,7 +523,7 @@ static int smlua__set_field(lua_State* L) { case LVT_OBJECTANIMPOINTER_P: case LVT_COLLISION_P: case LVT_TRAJECTORY_P: - valuePointer = smlua_to_cpointer(L, 4, data->valueType); + valuePointer = smlua_to_cpointer(L, 3, data->valueType); if (gSmLuaConvertSuccess) { *(u8**)p = valuePointer; } @@ -567,6 +542,43 @@ static int smlua__set_field(lua_State* L) { return 1; } +int smlua__eq(lua_State *L) { + CObject *a = lua_touserdata(L, 1); + CObject *b = lua_touserdata(L, 2); + lua_pushboolean(L, a->lot == b->lot && a->pointer == b->pointer); + return 1; +} + +int smlua__gc(lua_State *L) { + CObject *cobj = lua_touserdata(L, 1); + if (!cobj->freed) { + switch (cobj->lot) { + case LOT_SURFACE: { + smlua_pointer_user_data_delete((u64)(intptr_t) cobj->pointer); + } + } + } + return 0; +} + +static int smlua_cpointer_get(lua_State* L) { + CPointer *cptr = lua_touserdata(L, 1); + const char *key = smlua_to_string(L, 2); + + // Legacy support + if (strcmp(key, "_pointer") == 0) { + lua_pushinteger(L, (u64)(intptr_t) cptr->pointer); + return 1; + } + if (strcmp(key, "_lot") == 0) { + lua_pushinteger(L, cptr->lvt); + return 1; + } + + return 0; +} +static int smlua_cpointer_set(UNUSED lua_State* L) { return 0; } + ////////// // bind // ////////// @@ -574,6 +586,27 @@ static int smlua__set_field(lua_State* L) { void smlua_cobject_init_globals(void) { lua_State* L = gLuaState; + // Create metatables + luaL_newmetatable(L, "CObject"); + luaL_Reg cObjectMethods[] = { + { "__index", smlua__get_field }, + { "__newindex", smlua__set_field }, + { "__eq", smlua__eq }, + { "__gc", smlua__gc }, + { NULL, NULL } + }; + luaL_setfuncs(L, cObjectMethods, 0); + lua_pop(L, 1); + luaL_newmetatable(L, "CPointer"); + luaL_Reg cPointerMethods[] = { + { "__index", smlua_cpointer_get }, + { "__newindex", smlua_cpointer_set }, + { "__eq", smlua__eq }, + { NULL, NULL } + }; + luaL_setfuncs(L, cPointerMethods, 0); + lua_pop(L, 1); + #define EXPOSE_GLOBAL_ARRAY(lot, ptr, iterator) \ { \ lua_newtable(L); \ @@ -662,8 +695,4 @@ void smlua_bind_cobject(void) { lua_State* L = gLuaState; smlua_bind_function(L, "define_custom_obj_fields", smlua_func_define_custom_obj_fields); - - smlua_bind_function(L, "_get_field", smlua__get_field); - smlua_bind_function(L, "_set_field", smlua__set_field); - } diff --git a/src/pc/lua/smlua_cobject.h b/src/pc/lua/smlua_cobject.h index f0a3381c5..8f1c8cdf0 100644 --- a/src/pc/lua/smlua_cobject.h +++ b/src/pc/lua/smlua_cobject.h @@ -65,6 +65,18 @@ struct LuaObjectTable { u16 fieldCount; }; +typedef struct { + void *pointer; + u16 lot; + bool freed; +} CObject; + +typedef struct { + void *pointer; + u16 lvt; + bool freed; +} CPointer; + bool smlua_valid_lot(u16 lot); bool smlua_valid_lvt(u16 lvt); struct LuaObjectField* smlua_get_object_field_from_ot(struct LuaObjectTable* ot, const char* key); diff --git a/src/pc/lua/smlua_cobject_allowlist.c b/src/pc/lua/smlua_cobject_allowlist.c deleted file mode 100644 index 1d712fed3..000000000 --- a/src/pc/lua/smlua_cobject_allowlist.c +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include "smlua.h" -#include "data/dynos_cmap.cpp.h" - -#define LOT_COUNT (LOT_MAX + (LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN)) -static void* sObjectAllowList[LOT_COUNT] = { NULL }; -static u64 sCachedObjectAllowed[LOT_COUNT] = { 0 }; - -static u16 smlua_lot_mapping(u16 lot) { - if (lot >= LOT_MAX) { - return LOT_MAX + (lot - LOT_AUTOGEN_MIN); - } else { - return lot; - } -} - -void smlua_cobject_allowlist_init(void) { - smlua_cobject_allowlist_shutdown(); -} - -void smlua_cobject_allowlist_shutdown(void) { - for (s32 i = 0; i < LOT_COUNT; i++) { - sCachedObjectAllowed[i] = 0; - - if (sObjectAllowList[i]) { - hmap_clear(sObjectAllowList[i]); - } - } -} - -void smlua_cobject_allowlist_add(u16 lot, u64 pointer) { - if (pointer == 0) { return; } - if (!smlua_valid_lot(lot)) { return; } - - u16 m = smlua_lot_mapping(lot); - if (sCachedObjectAllowed[m] == pointer) { return; } - sCachedObjectAllowed[m] = pointer; - - if (!sObjectAllowList[m]) { - sObjectAllowList[m] = hmap_create(); - } - - if (!hmap_get(sObjectAllowList[m], pointer)) { - hmap_put(sObjectAllowList[m], pointer, (void*)1); - } -} - -bool smlua_cobject_allowlist_contains(u16 lot, u64 pointer) { - if (pointer == 0) { return false; } - if (!smlua_valid_lot(lot)) { return false; } - - u16 m = smlua_lot_mapping(lot); - if (sCachedObjectAllowed[m] == pointer) { return true; } - - if (!sObjectAllowList[m]) { return false; } - return hmap_get(sObjectAllowList[m], pointer) != 0; -} - -///////////////////////////// - -static void* sPointerAllowList[LVT_MAX] = { 0 }; -static u64 sCachedPointerAllowed[LVT_MAX] = { 0 }; - -void smlua_cpointer_allowlist_init(void) { - smlua_cpointer_allowlist_shutdown(); -} - -void smlua_cpointer_allowlist_shutdown(void) { - for (s32 i = 0; i < LVT_MAX; i++) { - sCachedPointerAllowed[i] = 0; - - if (sPointerAllowList[i]) { - hmap_clear(sPointerAllowList[i]); - } - } -} - -void smlua_cpointer_allowlist_add(u16 lvt, u64 pointer) { - if (pointer == 0) { return; } - if (!smlua_valid_lvt(lvt)) { return; } - - if (sCachedPointerAllowed[lvt] == pointer) { return; } - sCachedPointerAllowed[lvt] = pointer; - - if (!sPointerAllowList[lvt]) { - sPointerAllowList[lvt] = hmap_create(); - } - - if (!hmap_get(sPointerAllowList[lvt], pointer)) { - hmap_put(sPointerAllowList[lvt], pointer, (void*)1); - } -} - -bool smlua_cpointer_allowlist_contains(u16 lvt, u64 pointer) { - if (pointer == 0) { return false; } - if (!smlua_valid_lvt(lvt)) { return false; } - - if (sCachedPointerAllowed[lvt] == pointer) { return true; } - - if (!sPointerAllowList[lvt]) { return false; } - return hmap_get(sPointerAllowList[lvt], pointer) != 0; -} \ No newline at end of file diff --git a/src/pc/lua/smlua_cobject_allowlist.h b/src/pc/lua/smlua_cobject_allowlist.h deleted file mode 100644 index 33b24a485..000000000 --- a/src/pc/lua/smlua_cobject_allowlist.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef SMLUA_COBJECT_ALLOWLIST_H -#define SMLUA_COBJECT_ALLOWLIST_H - -void smlua_cobject_allowlist_init(void); -void smlua_cobject_allowlist_shutdown(void); -void smlua_cobject_allowlist_add(u16 lot, u64 pointer); -bool smlua_cobject_allowlist_contains(u16 lot, u64 pointer); - -void smlua_cpointer_allowlist_init(void); -void smlua_cpointer_allowlist_shutdown(void); -void smlua_cpointer_allowlist_add(u16 lvt, u64 pointer); -bool smlua_cpointer_allowlist_contains(u16 lvt, u64 pointer); - -#endif \ No newline at end of file diff --git a/src/pc/lua/smlua_cobject_map.c b/src/pc/lua/smlua_cobject_map.c new file mode 100644 index 000000000..5a6f607c8 --- /dev/null +++ b/src/pc/lua/smlua_cobject_map.c @@ -0,0 +1,35 @@ +#include +#include "smlua.h" +#include "data/dynos_cmap.cpp.h" + +static void* sPointers = NULL; + +void smlua_pointer_user_data_init(void) { + smlua_pointer_user_data_shutdown(); +} + +void smlua_pointer_user_data_shutdown(void) { + hmap_clear(sPointers); +} + +void smlua_pointer_user_data_add(u64 pointer, CObject *obj) { + if (pointer == 0) { return; } + + if (!sPointers) { + sPointers = hmap_create(); + } + + if (!hmap_get(sPointers, pointer)) { + hmap_put(sPointers, pointer, obj); + } +} + +void smlua_pointer_user_data_delete(u64 pointer) { + if (pointer == 0) { return; } + hmap_del(sPointers, pointer); +} + +CObject *smlua_pointer_user_data_get(u64 pointer) { + if (pointer == 0) { return NULL; } + return hmap_get(sPointers, pointer); +} diff --git a/src/pc/lua/smlua_cobject_map.h b/src/pc/lua/smlua_cobject_map.h new file mode 100644 index 000000000..1bbf9c962 --- /dev/null +++ b/src/pc/lua/smlua_cobject_map.h @@ -0,0 +1,10 @@ +#ifndef SMLUA_COBJECT_MAP_H +#define SMLUA_COBJECT_MAP_H + +void smlua_pointer_user_data_init(void); +void smlua_pointer_user_data_shutdown(void); +void smlua_pointer_user_data_add(u64 pointer, CObject *obj); +void smlua_pointer_user_data_delete(u64 pointer); +CObject *smlua_pointer_user_data_get(u64 pointer); + +#endif diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index ee603a17e..e52b244d2 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -1,65 +1,5 @@ char gSmluaConstants[] = "" "math.randomseed(get_time())\n" -"--------------\n" -"-- CObjects --\n" -"--------------\n" -"_CObjectPool = {}\n" -"_CObject = {\n" -" __index = function (t,k)\n" -" return _get_field(t['_lot'], t['_pointer'], k, t)\n" -" end,\n" -" __newindex = function (t,k,v)\n" -" _set_field(t['_lot'], t['_pointer'], k, v, t)\n" -" end,\n" -" __tostring = function(t)\n" -" return 'CObject: ' .. t['_lot'] .. ', [' .. string.format('0x%08X', t['_pointer']) .. ']'\n" -" end,\n" -" __eq = function (a, b)\n" -" return a['_pointer'] == b['_pointer'] and a['_lot'] == b['_lot'] and a['_pointer'] ~= nil and a['_lot'] ~= nil\n" -" end\n" -"}\n" -"function _NewCObject(lot, pointer)\n" -" if _CObjectPool[lot] == nil then\n" -" _CObjectPool[lot] = {}\n" -" end\n" -" if _CObjectPool[lot][pointer] == nil then\n" -" local obj = {}\n" -" rawset(obj, '_pointer', pointer)\n" -" rawset(obj, '_lot', lot)\n" -" setmetatable(obj, _CObject)\n" -" _CObjectPool[lot][pointer] = obj\n" -" return obj\n" -" end\n" -" return _CObjectPool[lot][pointer]\n" -"end\n" -"local _CPointerPool = {}\n" -"_CPointer = {\n" -" __index = function (t,k)\n" -" return nil\n" -" end,\n" -" __newindex = function (t,k,v)\n" -" end,\n" -" __tostring = function(t)\n" -" return 'CPointer: ' .. t['_lvt'] .. ', [' .. string.format('0x%08X', t['_pointer']) .. ']'\n" -" end,\n" -" __eq = function (a, b)\n" -" return a['_pointer'] == b['_pointer'] and a['_pointer'] ~= nil and a['_lvt'] ~= nil\n" -" end\n" -"}\n" -"function _NewCPointer(lvt, pointer)\n" -" if _CPointerPool[lvt] == nil then\n" -" _CPointerPool[lvt] = {}\n" -" end\n" -" if _CPointerPool[lvt][pointer] == nil then\n" -" local obj = {}\n" -" rawset(obj, '_pointer', pointer)\n" -" rawset(obj, '_lvt', lvt)\n" -" setmetatable(obj, _CPointer)\n" -" _CPointerPool[lvt][pointer] = obj\n" -" return obj\n" -" end\n" -" return _CPointerPool[lvt][pointer]\n" -"end\n" "_SyncTable = {\n" " __index = function (t,k)\n" " local _table = rawget(t, '_table')\n" diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index de3e254ac..b19fdae38 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -29015,6 +29015,21 @@ int smlua_func_camera_freeze(UNUSED lua_State* L) { return 1; } +int smlua_func_camera_get_checking_surfaces(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", "camera_get_checking_surfaces", 0, top); + return 0; + } + + + lua_pushboolean(L, camera_get_checking_surfaces()); + + return 1; +} + int smlua_func_camera_is_frozen(UNUSED lua_State* L) { if (L == NULL) { return 0; } @@ -29079,6 +29094,23 @@ int smlua_func_camera_romhack_allow_dpad_usage(lua_State* L) { return 1; } +int smlua_func_camera_set_checking_surfaces(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", "camera_set_checking_surfaces", 1, top); + return 0; + } + + bool value = smlua_to_boolean(L, 1); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "camera_set_checking_surfaces"); return 0; } + + camera_set_checking_surfaces(value); + + return 1; +} + int smlua_func_camera_set_romhack_override(lua_State* L) { if (L == NULL) { return 0; } @@ -34610,10 +34642,12 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "camera_config_set_x_sensitivity", smlua_func_camera_config_set_x_sensitivity); smlua_bind_function(L, "camera_config_set_y_sensitivity", smlua_func_camera_config_set_y_sensitivity); smlua_bind_function(L, "camera_freeze", smlua_func_camera_freeze); + smlua_bind_function(L, "camera_get_checking_surfaces", smlua_func_camera_get_checking_surfaces); smlua_bind_function(L, "camera_is_frozen", smlua_func_camera_is_frozen); smlua_bind_function(L, "camera_reset_overrides", smlua_func_camera_reset_overrides); smlua_bind_function(L, "camera_romhack_allow_centering", smlua_func_camera_romhack_allow_centering); smlua_bind_function(L, "camera_romhack_allow_dpad_usage", smlua_func_camera_romhack_allow_dpad_usage); + smlua_bind_function(L, "camera_set_checking_surfaces", smlua_func_camera_set_checking_surfaces); smlua_bind_function(L, "camera_set_romhack_override", smlua_func_camera_set_romhack_override); smlua_bind_function(L, "camera_unfreeze", smlua_func_camera_unfreeze); diff --git a/src/pc/lua/smlua_utils.c b/src/pc/lua/smlua_utils.c index da91fd4b0..499d8926f 100644 --- a/src/pc/lua/smlua_utils.c +++ b/src/pc/lua/smlua_utils.c @@ -1,4 +1,5 @@ #include "smlua.h" +#include "smlua_cobject_map.h" #include "pc/mods/mods.h" #include "audio/external.h" @@ -144,126 +145,62 @@ LuaFunction smlua_to_lua_function(lua_State* L, int index) { return luaL_ref(L, LUA_REGISTRYINDEX); } -bool smlua_is_cobject(lua_State* L, int index, u16 lot) { - int top = lua_gettop(L); - bool ret = true; - - s32 indexType = lua_type(L, index); - if (indexType != LUA_TTABLE) { - ret = false; - goto result; - } - - lua_getfield(L, index, "_lot"); - if (lua_type(L, -1) != LUA_TNUMBER) { - ret = false; - goto result; - } - - enum LuaObjectType objLot = smlua_to_integer(L, -1); - if (!gSmLuaConvertSuccess) { - gSmLuaConvertSuccess = true; - ret = false; - goto result; - } - - if (lot != objLot) { - ret = false; - goto result; - } - -result: - lua_settop(L, top); - return ret; +bool smlua_is_cobject(lua_State* L, int index, UNUSED u16 lot) { + return lua_isuserdata(L, index); } void* smlua_to_cobject(lua_State* L, int index, u16 lot) { s32 indexType = lua_type(L, index); if (indexType == LUA_TNIL) { return NULL; } - if (indexType != LUA_TTABLE) { - LOG_LUA_LINE("smlua_to_cobject received improper type '%d'", lua_type(L, index)); + if (indexType != LUA_TUSERDATA) { + LOG_LUA_LINE("smlua_to_cobject received improper type '%d'", indexType); gSmLuaConvertSuccess = false; return 0; } - // get LOT - lua_getfield(L, index, "_lot"); - enum LuaObjectType objLot = smlua_to_integer(L, -1); - lua_pop(L, 1); - if (!gSmLuaConvertSuccess) { return NULL; } + CObject *cobject = luaL_checkudata(L, index, "CObject"); - if (lot != objLot) { - LOG_LUA_LINE("smlua_to_cobject received improper LOT. Expected '%d', received '%d'", lot, objLot); + if (lot != cobject->lot) { + LOG_LUA_LINE("smlua_to_cobject received improper LOT. Expected '%d', received '%d'", lot, cobject->lot); gSmLuaConvertSuccess = false; return NULL; } - // get pointer - lua_getfield(L, index, "_pointer"); - void* pointer = (void*)(intptr_t)smlua_to_integer(L, -1); - lua_pop(L, 1); - if (!gSmLuaConvertSuccess) { return NULL; } - - // check allowlist - if (!smlua_cobject_allowlist_contains(lot, (u64)(intptr_t)pointer)) { - LOG_LUA_LINE("smlua_to_cobject received a pointer not in allow list. '%u', '%llu", lot, (u64)(intptr_t)pointer); - gSmLuaConvertSuccess = false; - return NULL; - } - - if (pointer == NULL) { + if (cobject->pointer == NULL) { LOG_LUA_LINE("smlua_to_cobject received null pointer."); gSmLuaConvertSuccess = false; return NULL; } gSmLuaConvertSuccess = true; - return pointer; + return cobject->pointer; } void* smlua_to_cpointer(lua_State* L, int index, u16 lvt) { - if (lua_type(L, index) == LUA_TNIL) { - return NULL; - } - - if (lua_type(L, index) != LUA_TTABLE) { - LOG_LUA_LINE("smlua_to_cpointer received improper type '%d'", lua_type(L, index)); + s32 indexType = lua_type(L, index); + if (indexType == LUA_TNIL) { return NULL; } + if (indexType != LUA_TUSERDATA) { + LOG_LUA_LINE("smlua_to_cpointer received improper type '%d'", indexType); gSmLuaConvertSuccess = false; return 0; } - // get LVT - lua_getfield(L, index, "_lvt"); - enum LuaObjectType objLvt = smlua_to_integer(L, -1); - lua_pop(L, 1); - if (!gSmLuaConvertSuccess) { return NULL; } + CPointer *cpointer = luaL_checkudata(L, index, "CPointer"); - if (lvt != objLvt) { - LOG_LUA_LINE("smlua_to_cpointer received improper LVT. Expected '%d', received '%d'", lvt, objLvt); + if (lvt != cpointer->lvt) { + LOG_LUA_LINE("smlua_to_cpointer received improper LOT. Expected '%d', received '%d'", lvt, cpointer->lvt); gSmLuaConvertSuccess = false; return NULL; } - // get pointer - lua_getfield(L, index, "_pointer"); - void* pointer = (void*)(intptr_t)smlua_to_integer(L, -1); - lua_pop(L, 1); - if (!gSmLuaConvertSuccess) { return NULL; } - - if (!smlua_cpointer_allowlist_contains(lvt, (u64)(intptr_t)pointer)) { - LOG_LUA_LINE("smlua_to_cpointer received a pointer not in allow list. '%u', '%llu", lvt, (u64)(intptr_t)pointer); - gSmLuaConvertSuccess = false; - return NULL; - } - - if (pointer == NULL) { + if (cpointer->pointer == NULL) { LOG_LUA_LINE("smlua_to_cpointer received null pointer."); gSmLuaConvertSuccess = false; return NULL; } gSmLuaConvertSuccess = true; - return pointer; + return cpointer->pointer; } struct LSTNetworkType smlua_to_lnt(lua_State* L, int index) { @@ -418,16 +355,17 @@ void smlua_push_object(lua_State* L, u16 lot, void* p) { return; } - // add to allowlist - smlua_cobject_allowlist_add(lot, (u64)(intptr_t) p); + CObject *cobject = lua_newuserdata(L, sizeof(CObject)); + cobject->pointer = p; + cobject->lot = lot; + cobject->freed = false; + luaL_getmetatable(L, "CObject"); + lua_setmetatable(L, -2); - // get a cobject from a function - lua_getglobal(L, "_NewCObject"); // Get the function by its global name - lua_pushinteger(L, lot); - lua_pushinteger(L, (u64)(intptr_t) p); - - if (lua_pcall(L, 2, 1, 0) != LUA_OK) { - LOG_ERROR("Error calling Lua function: %s\n", lua_tostring(L, -1)); + switch (lot) { + case LOT_SURFACE: { + smlua_pointer_user_data_add((u64)(intptr_t) p, cobject); + } } } @@ -437,15 +375,12 @@ void smlua_push_pointer(lua_State* L, u16 lvt, void* p) { return; } - smlua_cpointer_allowlist_add(lvt, (u64)(intptr_t) p); - - // get a cpointer from a function - lua_getglobal(L, "_NewCPointer"); // Get the function by its global name - lua_pushinteger(L, lvt); - lua_pushinteger(L, (u64)(intptr_t) p); - if (lua_pcall(L, 2, 1, 0) != LUA_OK) { - LOG_ERROR("Error calling Lua function: %s\n", lua_tostring(L, -1)); - } + CPointer *cpointer = lua_newuserdata(L, sizeof(CPointer)); + cpointer->pointer = p; + cpointer->lvt = lvt; + cpointer->freed = false; + luaL_getmetatable(L, "CPointer"); + lua_setmetatable(L, -2); } void smlua_push_integer_field(int index, const char* name, lua_Integer val) { @@ -500,7 +435,7 @@ void smlua_push_lnt(struct LSTNetworkType* lnt) { /////////////////////////////////////////////////////////////////////////////////////////// lua_Integer smlua_get_integer_field(int index, const char* name) { - if (lua_type(gLuaState, index) != LUA_TTABLE) { + if (lua_type(gLuaState, index) != LUA_TTABLE && lua_type(gLuaState, index) != LUA_TUSERDATA) { LOG_LUA_LINE("smlua_get_integer_field received improper type '%d'", lua_type(gLuaState, index)); gSmLuaConvertSuccess = false; return 0; @@ -512,7 +447,7 @@ lua_Integer smlua_get_integer_field(int index, const char* name) { } lua_Number smlua_get_number_field(int index, const char* name) { - if (lua_type(gLuaState, index) != LUA_TTABLE) { + if (lua_type(gLuaState, index) != LUA_TTABLE && lua_type(gLuaState, index) != LUA_TUSERDATA) { LOG_LUA_LINE("smlua_get_number_field received improper type '%d'", lua_type(gLuaState, index)); gSmLuaConvertSuccess = false; return 0; @@ -524,7 +459,7 @@ lua_Number smlua_get_number_field(int index, const char* name) { } const char* smlua_get_string_field(int index, const char* name) { - if (lua_type(gLuaState, index) != LUA_TTABLE) { + if (lua_type(gLuaState, index) != LUA_TTABLE && lua_type(gLuaState, index) != LUA_TUSERDATA) { LOG_LUA_LINE("smlua_get_string_field received improper type '%d'", lua_type(gLuaState, index)); gSmLuaConvertSuccess = false; return 0; @@ -536,7 +471,7 @@ const char* smlua_get_string_field(int index, const char* name) { } LuaFunction smlua_get_function_field(int index, const char *name) { - if (lua_type(gLuaState, index) != LUA_TTABLE) { + if (lua_type(gLuaState, index) != LUA_TTABLE && lua_type(gLuaState, index) != LUA_TUSERDATA) { LOG_LUA_LINE("smlua_get_function_field received improper type '%d'", lua_type(gLuaState, index)); gSmLuaConvertSuccess = false; return 0; @@ -774,9 +709,37 @@ void smlua_logline(void) { int level = 0; while (lua_getstack(L, level, &info)) { lua_getinfo(L, "nSl", &info); - LOG_LUA(" [%d] %s:%d -- %s [%s]", - level, info.short_src, info.currentline, + + // Get the folder and file of the crash + // in the format: "folder/file.lua" + const char* src = info.source; + int slashCount = 0; + const char* folderStart = NULL; + for (const char* p = src + strlen(src); p > src; --p) { + if (*p == '/') { + if (++slashCount == 2) { + folderStart = p + 1; + break; + } + } + } + + LOG_LUA(" [%d] '%s':%d -- %s [%s]", + level, (folderStart ? folderStart : info.short_src), info.currentline, (info.name ? info.name : ""), info.what); ++level; } } + +// If an object is freed that Lua has a CObject to, +// Lua is able to use-after-free that pointer +void smlua_free(void *ptr) { + if (ptr && gLuaState) { + CObject *obj = smlua_pointer_user_data_get((u64)(intptr_t) ptr); + if (obj) { + obj->freed = true; + smlua_pointer_user_data_delete((u64)(intptr_t) ptr); + } + } + free(ptr); +} diff --git a/src/pc/lua/smlua_utils.h b/src/pc/lua/smlua_utils.h index b92468552..7cb55ccf5 100644 --- a/src/pc/lua/smlua_utils.h +++ b/src/pc/lua/smlua_utils.h @@ -54,5 +54,6 @@ void smlua_logline(void); void smlua_dump_stack(void); void smlua_dump_globals(void); void smlua_dump_table(int index); +void smlua_free(void *ptr); #endif \ No newline at end of file diff --git a/src/pc/lua/utils/smlua_audio_utils.c b/src/pc/lua/utils/smlua_audio_utils.c index acabf05c3..2c9770531 100644 --- a/src/pc/lua/utils/smlua_audio_utils.c +++ b/src/pc/lua/utils/smlua_audio_utils.c @@ -166,6 +166,15 @@ void smlua_audio_utils_replace_sequence(u8 sequenceId, u8 bankId, u8 defaultVolu static ma_engine sModAudioEngine; static struct DynamicPool *sModAudioPool; +static void smlua_audio_custom_init(void) { + sModAudioPool = dynamic_pool_init(); + + ma_result result = ma_engine_init(NULL, &sModAudioEngine); + if (result != MA_SUCCESS) { + LOG_ERROR("failed to init Miniaudio: %d", result); + } +} + static struct ModAudio* find_mod_audio(struct ModFile* file) { struct DynamicPoolNode* node = sModAudioPool->tail; while (node) { @@ -178,8 +187,8 @@ static struct ModAudio* find_mod_audio(struct ModFile* file) { } static bool audio_sanity_check(struct ModAudio* audio, bool isStream, const char* action) { - if (audio == NULL || !audio->loaded) { - LOG_LUA_LINE("Tried to %s unloaded audio %s", action, audio->isStream ? "stream" : "sample"); + if (!audio || !audio->loaded) { + LOG_LUA_LINE("Tried to %s unloaded audio %s", action, audio ? (audio->isStream ? "stream" : "sample") : "(NULL)"); return false; } if (isStream && !audio->isStream) { @@ -194,6 +203,8 @@ static bool audio_sanity_check(struct ModAudio* audio, bool isStream, const char } struct ModAudio* audio_load_internal(const char* filename, bool isStream) { + if (!sModAudioPool) { smlua_audio_custom_init(); } + // check file type bool validFileType = false; const char* fileTypes[] = { ".mp3", ".aiff", ".ogg", NULL }; @@ -587,32 +598,18 @@ void audio_custom_shutdown(void) { while (node) { struct DynamicPoolNode* prev = node->prev; struct ModAudio* audio = node->ptr; - if (audio->isStream) { - if (audio->loaded) { ma_sound_uninit(&audio->sound); } - dynamic_pool_free(sModAudioPool, audio); - } else { - if (audio->loaded) { - if (audio->sampleCopiesTail) { - audio_sample_destroy_copies(audio); - } - ma_sound_uninit(&audio->sound); + if (audio->loaded) { + if (!audio->isStream && audio->sampleCopiesTail) { + audio_sample_destroy_copies(audio); } - dynamic_pool_free(sModAudioPool, audio); + ma_sound_uninit(&audio->sound); } + dynamic_pool_free(sModAudioPool, audio); node = prev; } dynamic_pool_free_pool(sModAudioPool); } -void smlua_audio_custom_init(void) { - sModAudioPool = dynamic_pool_init(); - - ma_result result = ma_engine_init(NULL, &sModAudioEngine); - if (result != MA_SUCCESS) { - LOG_ERROR("failed to init Miniaudio: %d", result); - } -} - void smlua_audio_custom_deinit(void) { if (sModAudioPool) { audio_custom_shutdown(); diff --git a/src/pc/lua/utils/smlua_audio_utils.h b/src/pc/lua/utils/smlua_audio_utils.h index b540a35f0..048a699f7 100644 --- a/src/pc/lua/utils/smlua_audio_utils.h +++ b/src/pc/lua/utils/smlua_audio_utils.h @@ -55,7 +55,6 @@ void audio_custom_update_volume(void); void audio_custom_shutdown(void); -void smlua_audio_custom_init(void); void smlua_audio_custom_deinit(void); #endif diff --git a/src/pc/lua/utils/smlua_camera_utils.c b/src/pc/lua/utils/smlua_camera_utils.c index e20ae995e..68e715861 100644 --- a/src/pc/lua/utils/smlua_camera_utils.c +++ b/src/pc/lua/utils/smlua_camera_utils.c @@ -1,5 +1,6 @@ #include "smlua_camera_utils.h" #include "game/bettercamera.h" +#include "game/object_list_processor.h" static struct CameraOverride sOverrideCameraXSens = { 0 }; static struct CameraOverride sOverrideCameraYSens = { 0 }; @@ -152,3 +153,11 @@ void camera_config_set_deceleration(u32 value) { sOverrideCameraDegrade.override = true; newcam_init_settings(); } + +bool camera_get_checking_surfaces(void) { + return gCheckingSurfaceCollisionsForCamera; +} + +void camera_set_checking_surfaces(bool value) { + gCheckingSurfaceCollisionsForCamera = value; +} diff --git a/src/pc/lua/utils/smlua_camera_utils.h b/src/pc/lua/utils/smlua_camera_utils.h index 57ac352bb..982769a19 100644 --- a/src/pc/lua/utils/smlua_camera_utils.h +++ b/src/pc/lua/utils/smlua_camera_utils.h @@ -40,4 +40,7 @@ void camera_config_set_aggression(u32 value); void camera_config_set_pan_level(u32 value); void camera_config_set_deceleration(u32 value); +bool camera_get_checking_surfaces(void); +void camera_set_checking_surfaces(bool value); + #endif diff --git a/src/pc/mods/mod_cache.c b/src/pc/mods/mod_cache.c index 163a86ae0..6f2c066e2 100644 --- a/src/pc/mods/mod_cache.c +++ b/src/pc/mods/mod_cache.c @@ -9,6 +9,7 @@ #include "mods_utils.h" #include "pc/utils/md5.h" #include "pc/lua/smlua_hooks.h" +#include "pc/loading.h" #define MOD_CACHE_FILENAME "mod.cache" #define MOD_CACHE_VERSION 7 @@ -32,7 +33,7 @@ void mod_cache_shutdown(void) { LOG_INFO("Shutting down mod cache."); while (sModCacheHead) { mod_cache_remove_node(sModCacheHead, NULL); - } + } } void mod_cache_md5(const char* inPath, u8* outDataPath) { @@ -255,6 +256,8 @@ void mod_cache_update(struct Mod* mod, struct ModFile* file) { } void mod_cache_load(void) { + LOADING_SCREEN_MUTEX(loading_screen_set_segment_text("Loading Mod Cache")); + mod_cache_shutdown(); LOG_INFO("Loading mod cache"); diff --git a/src/pc/mods/mods.c b/src/pc/mods/mods.c index be37b7785..2485661c0 100644 --- a/src/pc/mods/mods.c +++ b/src/pc/mods/mods.c @@ -252,7 +252,10 @@ static void mods_load(struct Mods* mods, char* modsBasePath, UNUSED bool isUserM } UNUSED f32 count = (f32) mods_count_directory(modsBasePath); - LOADING_SCREEN_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading Mods In %s Mod Path:\n\\#808080\\%s", isUserModPath ? "User" : "Local", modsBasePath)); + LOADING_SCREEN_MUTEX( + loading_screen_reset_progress_bar(); + snprintf(gCurrLoadingSegment.str, 256, "Loading Mods In %s Mod Path:\n\\#808080\\%s", isUserModPath ? "User" : "Local", modsBasePath); + ); // iterate char path[SYS_MAX_PATH] = { 0 }; @@ -276,6 +279,7 @@ static void mods_load(struct Mods* mods, char* modsBasePath, UNUSED bool isUserM } void mods_refresh_local(void) { + LOADING_SCREEN_MUTEX(loading_screen_set_segment_text("Refreshing Mod Cache")); mods_local_store_enabled(); // figure out user path @@ -324,7 +328,6 @@ void mods_enable(char* relativePath) { } void mods_init(void) { - LOADING_SCREEN_MUTEX(loading_screen_set_segment_text("Caching Mods")); // load mod cache mod_cache_load(); diff --git a/src/pc/network/network_utils.c b/src/pc/network/network_utils.c index 5ff1102b2..aff07b6aa 100644 --- a/src/pc/network/network_utils.c +++ b/src/pc/network/network_utils.c @@ -54,7 +54,7 @@ const char* network_get_player_text_color_string(u8 localIndex) { extern s16 gMenuMode; bool network_check_singleplayer_pause(void) { - return gMenuMode != -1 && network_player_connected_count() == 1 && mods_get_all_pausable() && !gDjuiInPlayerMenu; + return gMenuMode != -1 && !gServerSettings.pauseAnywhere && network_player_connected_count() == 1 && mods_get_all_pausable() && !gDjuiInPlayerMenu; } const char* network_discord_id_from_local_index(u8 localIndex) { diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 8aaaf3bf9..0df94fa9e 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -345,7 +345,6 @@ void* main_game_init(UNUSED void* dummy) { audio_init(); sound_init(); - smlua_audio_custom_init(); network_player_init(); gGameInited = true;