diff --git a/Makefile b/Makefile index 5e0ab752..ffc0877b 100644 --- a/Makefile +++ b/Makefile @@ -868,8 +868,9 @@ else LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -no-pie -lpthread endif +# used by crash handler and loading screen on linux ifeq ($(WINDOWS_BUILD),0) - LDFLAGS += -rdynamic + LDFLAGS += -rdynamic -ldl -pthread endif # icon diff --git a/data/behavior_table.c b/data/behavior_table.c index f541e419..0ee6cd31 100644 --- a/data/behavior_table.c +++ b/data/behavior_table.c @@ -581,7 +581,7 @@ const BehaviorScript* get_behavior_from_id(enum BehaviorId id) { const char* get_behavior_name_from_id(enum BehaviorId id) { if (id < 0 || id >= id_bhv_max_count) { - return NULL; + return smlua_get_name_from_hooked_behavior_id(id); } return gBehaviorTable[id].name; diff --git a/data/dynos_gfx_init.cpp b/data/dynos_gfx_init.cpp index cf53695f..be429349 100644 --- a/data/dynos_gfx_init.cpp +++ b/data/dynos_gfx_init.cpp @@ -2,7 +2,7 @@ #include "src/pc/loading.h" void DynOS_Gfx_GeneratePacks(const char* directory) { - if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Generating DynOS Packs In Path:\n\\#808080\\%s", directory)); } + snprintf(gCurrLoadingSegment.str, 256, "Generating DynOS Packs In Path:\n\\#808080\\%s", directory); DIR *modsDir = opendir(directory); if (!modsDir) { return; } @@ -40,7 +40,7 @@ void DynOS_Gfx_GeneratePacks(const char* directory) { DynOS_Tex_GeneratePack(_TexturePackFolder, _TexturePackOutputFolder, true); } - if (gIsThreaded) REFRESH_MUTEX(gCurrLoadingSegment.percentage = (f32) i / (f32) pathCount); + REFRESH_MUTEX(gCurrLoadingSegment.percentage = (f32) i / (f32) pathCount); } closedir(modsDir); diff --git a/src/game/game_init.c b/src/game/game_init.c index e6f475af..100d3544 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -588,6 +588,8 @@ void thread5_game_loop(UNUSED void *arg) { play_music(SEQ_PLAYER_SFX, SEQUENCE_ARGS(0, SEQ_SOUND_PLAYER), 0); set_sound_mode(save_file_get_sound_mode()); + thread6_rumble_loop(NULL); + gGlobalTimer++; } diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 44beff50..b37e50aa 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -36,6 +36,8 @@ #include "pc/lua/smlua_hooks.h" #include "game/camera.h" #include "level_info.h" +#include "pc/lua/utils/smlua_text_utils.h" +#include "pc/lua/utils/smlua_math_utils.h" u16 gDialogColorFadeTimer; s8 gLastDialogLineNum; @@ -2513,8 +2515,9 @@ void render_pause_my_score_coins(void) { u8 strCourseNum[4]; u8 courseIndex = gCurrCourseNum - 1; + u8 starIndex = clamp(gDialogCourseActNum, 1, MAX_ACTS); u8 *courseName = (u8*) get_level_name_sm64(gCurrCourseNum, gCurrLevelNum, gCurrAreaIndex, 1); - u8 *actName = (u8*) get_star_name_sm64(gCurrCourseNum, gDialogCourseActNum, 1); + u8 *actName = (u8*) get_star_name_sm64(gCurrCourseNum, starIndex, 1); u8 starFlags; starFlags = save_file_get_star_flags(gCurrSaveFileNum - 1, gCurrCourseNum - 1); @@ -2549,7 +2552,7 @@ void render_pause_my_score_coins(void) { print_generic_string(CRS_NUM_X1, 157, strCourseNum); #endif - if (starFlags & (1 << (gDialogCourseActNum - 1))) { + if (starFlags & (1 << (starIndex - 1))) { print_generic_string(TXT_STAR_X, 140, textStar); } else { print_generic_string(TXT_STAR_X, 140, textUnfilledStar); diff --git a/src/game/interaction.c b/src/game/interaction.c index cf72ed67..7f8af404 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -956,11 +956,8 @@ u32 interact_star_or_key(struct MarioState *m, UNUSED u32 interactType, struct O } } - for (s32 i = 0; i < MAX_PLAYERS; i++) { - struct MarioState* marioState = &gMarioStates[i]; - if (!is_player_active(marioState)) { continue; } - if (marioState->marioObj == NULL) { continue; } - spawn_object(marioState->marioObj, MODEL_NONE, bhvStarKeyCollectionPuffSpawner); + if (m->marioObj != NULL) { + spawn_object(m->marioObj, MODEL_NONE, bhvStarKeyCollectionPuffSpawner); } o->oInteractStatus = INT_STATUS_INTERACTED; @@ -2366,7 +2363,7 @@ void check_death_barrier(struct MarioState *m) { if (!gLevelValues.bubbleOnDeathBarrierInCapStages){ break; } - default: + default: mario_set_bubbled(m); return; } diff --git a/src/game/level_update.c b/src/game/level_update.c index 12757343..85436add 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -60,6 +60,7 @@ s16 gChangeLevel = -1; s16 gChangeLevelTransition = -1; s16 gChangeActNum = -1; +static bool sCancelNextActSelector = true; // Cancel the act selector after the main menu static bool sFirstCastleGroundsMenu = true; bool gIsDemoActive = false; bool gInPlayerMenu = false; @@ -247,7 +248,7 @@ u16 level_control_timer(s32 timerOp) { u32 pressed_pause(void) { u32 dialogActive = get_dialog_id() >= 0; u32 intangible = (gMarioState->action & ACT_FLAG_INTANGIBLE) != 0; - u32 firstPerson = gMarioState->action == ACT_FIRST_PERSON; + u32 firstPerson = gMarioState->action == ACT_FIRST_PERSON; if (!intangible && !dialogActive && !firstPerson && !gWarpTransition.isActive && sDelayedWarpOp == WARP_OP_NONE && (gPlayer1Controller->buttonPressed & START_BUTTON)) { @@ -1637,6 +1638,7 @@ s32 update_level(void) { if (gDjuiInMainMenu) { update_menu_level(); } + sCancelNextActSelector = gDjuiInMainMenu; if (gFanFareDebounce > 0) { gFanFareDebounce--; } @@ -1917,6 +1919,11 @@ s32 lvl_set_current_level(UNUSED s16 arg0, s32 levelNum) { return 0; } + if (sCancelNextActSelector) { + sCancelNextActSelector = false; + return 0; + } + return 1; } diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index f2f65891..011c914a 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -284,13 +284,10 @@ void bhv_mario_update(void) { if ((stateIndex == 0) || (!is_player_active(gMarioState))) { gMarioState->particleFlags = 0; } - + smlua_call_event_hooks_mario_param(HOOK_BEFORE_MARIO_UPDATE, gMarioState); - u32 particleFlags = 0; - s32 i; - - particleFlags = execute_mario_action(gCurrentObject); + u32 particleFlags = execute_mario_action(gCurrentObject); smlua_call_event_hooks_mario_param(HOOK_MARIO_UPDATE, gMarioState); particleFlags |= gMarioState->particleFlags; gCurrentObject->oMarioParticleFlags = particleFlags; @@ -320,14 +317,10 @@ void bhv_mario_update(void) { // to sync it with the Mario object copy_mario_state_to_object(gMarioState); - i = 0; - while (sParticleTypes[i].particleFlag != 0) { + for (s32 i = 0; sParticleTypes[i].particleFlag != 0; i++) { if (particleFlags & sParticleTypes[i].particleFlag) { - spawn_particle(sParticleTypes[i].activeParticleFlag, sParticleTypes[i].model, - sParticleTypes[i].behavior); + spawn_particle(sParticleTypes[i].activeParticleFlag, sParticleTypes[i].model, sParticleTypes[i].behavior); } - - i++; } update_character_anim_offset(gMarioState); diff --git a/src/menu/star_select.c b/src/menu/star_select.c index df43f7bd..810c259a 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -469,6 +469,9 @@ s32 lvl_update_obj_and_load_act_button_actions(UNUSED s32 arg, UNUSED s32 unused sReceivedLoadedActNum = 0; } + // Cancel the act selector while on the main menu + if (gDjuiInMainMenu) { return 1; } + area_update_objects(); sActSelectorMenuTimer++; return sLoadedActNum; diff --git a/src/pc/crash_handler.c b/src/pc/crash_handler.c index ee2cfb92..daef7c93 100644 --- a/src/pc/crash_handler.c +++ b/src/pc/crash_handler.c @@ -42,6 +42,8 @@ static CrashHandlerText sCrashHandlerText[128 + 256 + 4]; #define MEMNEW(typ, cnt) calloc(sizeof(typ), cnt) #define STRING(str, size, fmt, ...) char str[size]; snprintf(str, size, fmt, __VA_ARGS__); +#define BACK_TRACE_SIZE 15 + #ifdef _WIN32 #define OS_NAME "Windows" @@ -207,6 +209,7 @@ static void crash_handler_produce_one_frame(void) { gfx_start_frame(); config_gfx_pool(); init_render_image(); + create_dl_ortho_matrix(); float minAspectRatio = 1.743468f; float aspectScale = 1.0f; @@ -306,7 +309,7 @@ static void crash_handler_add_info_int(CrashHandlerText** pTextP, f32 x, f32 y, #ifdef _WIN32 static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) { #elif __linux__ -static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *context) { +static void crash_handler(const int signalNum, siginfo_t *info, UNUSED ucontext_t *context) { #endif printf("Game crashed! preparing crash screen...\n"); memset(sCrashHandlerText, 0, sizeof(sCrashHandlerText)); @@ -352,8 +355,10 @@ static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *cont char segFaultStr[255] = ""; if (info->si_code == SEGV_MAPERR) { snprintf(segFaultStr, 255, "The game tried to read unmapped memory at address %p", info->si_addr); +#ifdef __x86_64__ } else if (info->si_code == SEGV_ACCERR) { snprintf(segFaultStr, 255, "The game tried to %s at address %016llX", ((context->uc_mcontext.gregs[REG_ERR] & 0x2) != 0 ? "write" : "read"), (u64) info->si_addr); +#endif } else { snprintf(segFaultStr, 255, "Unknown segmentation fault at address %p", info->si_addr); } @@ -373,6 +378,7 @@ static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *cont // Registers crash_handler_set_text(8, 22, 0xFF, 0xFF, 0xFF, "%s", "Registers:"); +#if defined(_WIN32) || (defined(__linux__) && defined(__x86_64__)) #ifdef _WIN32 if (ExceptionInfo && ExceptionInfo->ContextRecord) { PCONTEXT cr = ExceptionInfo->ContextRecord; @@ -456,6 +462,9 @@ static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *cont } else { crash_handler_set_text(8, 30, 0x80, 0x80, 0x80, "%s", "Unable to access the registers."); } +#else + crash_handler_set_text(8, 30, 0x80, 0x80, 0x80, "%s", "Cannot access the registers on this system."); +#endif // Stack trace crash_handler_set_text(8, 72, 0xFF, 0xFF, 0xFF, "%s", "Stack trace:"); @@ -542,7 +551,7 @@ static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *cont #else s32 frames = CaptureStackWalkBackTrace(ExceptionInfo->ContextRecord, 0, 64, stack); #endif - for (s32 i = 1, j = 0; i < frames && j < 15; ++i) { + for (s32 i = 1, j = 0; i < frames && j < BACK_TRACE_SIZE; ++i) { s32 y = 80 + j++ * 8; crash_handler_set_text( 8, y, 0xFF, 0xFF, 0x00, "0x%016llX", (PTR) stack[i]); crash_handler_set_text(-1, y, 0xFF, 0xFF, 0xFF, "%s", ": "); @@ -563,13 +572,12 @@ static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *cont } } #elif __linux__ - void *trace[15]; - int traceSize = backtrace(trace, 15); - + void *trace[BACK_TRACE_SIZE]; + u8 traceSize = backtrace(trace, BACK_TRACE_SIZE); if (traceSize > 0) { // Unwind and print call stack char **messages = backtrace_symbols(trace, traceSize); - for (s32 i = 1, j = 0; i < traceSize && j < 15; ++i) { + for (s32 i = 1, j = 0; i < traceSize && j < BACK_TRACE_SIZE; ++i) { s32 y = 80 + j++ * 8; crash_handler_set_text( 8, y, 0xFF, 0xFF, 0x00, "0x%016llX", (u64) strtoul(strstr(messages[i], "[") + 1, NULL, 16)); crash_handler_set_text(-1, y, 0xFF, 0xFF, 0xFF, "%s", ": "); @@ -595,8 +603,10 @@ static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *cont crash_handler_add_info_int(&pText, 315, -4 + (8 * 3), "Players", network_player_connected_count()); s32 syncObjects = 0; - for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { - if (so->o != NULL) { syncObjects++; } + if (gGameInited) { + for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) { + if (so->o != NULL) { syncObjects++; } + } } crash_handler_add_info_int(&pText, 315, -4 + (8 * 4), "SyncObj", syncObjects); @@ -664,10 +674,9 @@ static void crash_handler(const int signalNum, siginfo_t *info, ucontext_t *cont } #endif - // Incase it crashed before the game window opened + // In case the game crashed before the game window opened if (!gGfxInited) gfx_init(&WAPI, &RAPI, TITLE); - djui_init(); - djui_unicode_init(); + if (!gGameInited) djui_unicode_init(); // Main loop while (true) { diff --git a/src/pc/djui/djui.c b/src/pc/djui/djui.c index 5bcd9608..12ea4b45 100644 --- a/src/pc/djui/djui.c +++ b/src/pc/djui/djui.c @@ -28,19 +28,28 @@ static bool sDjuiInited = false; bool sDjuiRendered60fps = false; -void reset_djui_text(void); - -void reset_djui(void) { +void djui_shutdown(void) { sSavedDisplayListHead = NULL; + if (sDjuiPauseOptions) djui_base_destroy(&sDjuiPauseOptions->base); + if (sDjuiLuaError) djui_base_destroy(&sDjuiLuaError->base); sDjuiPauseOptions = NULL; sDjuiLuaError = NULL; sDjuiLuaErrorTimeout = 0; - if (gDjuiRoot) djui_base_destroy(&gDjuiRoot->base); - if (gDjuiConsole) djui_base_destroy(&gDjuiConsole->base); + if (gDjuiConsole) { + djui_base_destroy(&gDjuiConsole->base); + free(gDjuiConsole); + gDjuiConsole = NULL; + } extern u32 sDjuiConsoleMessages; sDjuiConsoleMessages = 0; + if (gDjuiRoot) { + djui_base_destroy(&gDjuiRoot->base); + } + + djui_fps_display_destroy(); + sDjuiInited = false; } diff --git a/src/pc/djui/djui.h b/src/pc/djui/djui.h index 09f6d9ec..9cc37ba0 100644 --- a/src/pc/djui/djui.h +++ b/src/pc/djui/djui.h @@ -47,4 +47,4 @@ void djui_lua_error(char* text); void djui_render(void); void djui_reset_hud_params(void); -void reset_djui(void); +void djui_shutdown(void); diff --git a/src/pc/djui/djui_console.c b/src/pc/djui/djui_console.c index 8104c2ca..0a45163e 100644 --- a/src/pc/djui/djui_console.c +++ b/src/pc/djui/djui_console.c @@ -161,6 +161,7 @@ void djui_console_message_create(const char* message, enum ConsoleMessageLevel l struct DjuiConsole* djui_console_create(void) { if (gDjuiConsole != NULL) { djui_base_destroy(&gDjuiConsole->base); + free(gDjuiConsole); gDjuiConsole = NULL; } diff --git a/src/pc/djui/djui_cursor.c b/src/pc/djui/djui_cursor.c index 0438de44..d57ffeb0 100644 --- a/src/pc/djui/djui_cursor.c +++ b/src/pc/djui/djui_cursor.c @@ -48,7 +48,7 @@ static void djui_cursor_base_hover_location(struct DjuiBase* base, f32* x, f32* } void djui_cursor_input_controlled_center(struct DjuiBase* base) { - if (!sCursorMouseControlled) { + if (!sCursorMouseControlled && (!base || (base && base->interactable && base->interactable->enabled))) { sInputControlledBase = base; djui_cursor_set_visible(base != NULL); } @@ -65,7 +65,7 @@ static f32 djui_cursor_base_distance(struct DjuiBase* base, f32 xScale, f32 ySca static void djui_cursor_move_check(s8 xDir, s8 yDir, struct DjuiBase** pick, struct DjuiBase* base) { if (!base->visible) { return; } - if (base->interactable != NULL) { + if (base->interactable != NULL && base->interactable->enabled) { f32 x1, y1, x2, y2; x1 = base->elem.x; y1 = base->elem.y; @@ -160,4 +160,4 @@ void djui_cursor_create(void) { sMouseCursor = djui_image_create(NULL, gd_texture_hand_open, 32, 32, 16); djui_base_set_location(&sMouseCursor->base, 0, 0); djui_base_set_size(&sMouseCursor->base, 64, 64); -} \ No newline at end of file +} diff --git a/src/pc/djui/djui_fps_display.c b/src/pc/djui/djui_fps_display.c index 90d067ea..702882cd 100644 --- a/src/pc/djui/djui_fps_display.c +++ b/src/pc/djui/djui_fps_display.c @@ -23,10 +23,14 @@ void djui_fps_display_render(void) { } } +void djui_fps_display_on_destroy(UNUSED struct DjuiBase* base) { + free(sFpsDisplay); +} + void djui_fps_display_create(void) { - struct DjuiFpsDisplay *fpsDisplay = malloc(sizeof(struct DjuiFpsDisplay)); + struct DjuiFpsDisplay *fpsDisplay = calloc(1, sizeof(struct DjuiFpsDisplay)); struct DjuiBase* base = &fpsDisplay->base; - djui_base_init(NULL, base, NULL, NULL); + djui_base_init(NULL, base, NULL, djui_fps_display_on_destroy); djui_base_set_size(base, 150, 50); djui_base_set_color(base, 0, 0, 0, 240); djui_base_set_border_color(base, 0, 0, 0, 200); @@ -46,3 +50,9 @@ void djui_fps_display_create(void) { sFpsDisplay = fpsDisplay; } + +void djui_fps_display_destroy(void) { + if (sFpsDisplay) { + djui_base_destroy(&sFpsDisplay->base); + } +} diff --git a/src/pc/djui/djui_fps_display.h b/src/pc/djui/djui_fps_display.h index a35ea17b..f398fed0 100644 --- a/src/pc/djui/djui_fps_display.h +++ b/src/pc/djui/djui_fps_display.h @@ -4,3 +4,4 @@ void djui_fps_display_update(s16 fps); void djui_fps_display_render(void); void djui_fps_display_create(void); +void djui_fps_display_destroy(void); diff --git a/src/pc/djui/djui_panel.c b/src/pc/djui/djui_panel.c index 9d3ab5ba..bf056a61 100644 --- a/src/pc/djui/djui_panel.c +++ b/src/pc/djui/djui_panel.c @@ -18,7 +18,7 @@ bool djui_panel_is_active(void) { return (sPanelList != NULL); } -struct DjuiBase* djui_panel_find_first_interactable(struct DjuiBaseChild* child) { +static struct DjuiBase* djui_panel_find_first_interactable(struct DjuiBaseChild* child) { while (child) { if (child->base->interactable && child->base->interactable->enabled) { return child->base; diff --git a/src/pc/djui/djui_panel_language.c b/src/pc/djui/djui_panel_language.c index b29240e0..d7d0447b 100644 --- a/src/pc/djui/djui_panel_language.c +++ b/src/pc/djui/djui_panel_language.c @@ -48,23 +48,19 @@ static void djui_panel_language_destroy(UNUSED struct DjuiBase* caller) { snprintf(configLanguage, MAX_CONFIG_STRING, "%s", ""); } + djui_panel_shutdown(); if (gPanelLanguageOnStartup) { - djui_panel_shutdown(); gDjuiInMainMenu = true; djui_panel_main_create(NULL); } else if (gDjuiInMainMenu) { - djui_panel_shutdown(); gDjuiInMainMenu = true; djui_panel_main_create(NULL); djui_panel_options_create(NULL); djui_panel_misc_create(NULL); } else if (gDjuiPanelPauseCreated) { - djui_panel_shutdown(); djui_panel_pause_create(NULL); djui_panel_options_create(NULL); djui_panel_misc_create(NULL); - } else { - djui_panel_shutdown(); } } if (configLanguage[0] == '\0') { diff --git a/src/pc/djui/djui_panel_pause.c b/src/pc/djui/djui_panel_pause.c index b7cb1c5a..4d342a9c 100644 --- a/src/pc/djui/djui_panel_pause.c +++ b/src/pc/djui/djui_panel_pause.c @@ -34,7 +34,7 @@ void djui_panel_pause_disconnect_key_update(int scancode) { } static void djui_panel_pause_quit(struct DjuiBase* caller) { - if (find_object_with_behavior(bhvActSelector) != NULL || gMarioStates[0].action == ACT_PUSHING_DOOR || gMarioStates[0].action == ACT_PULLING_DOOR) { return; } + if (gMarioStates[0].action == ACT_PUSHING_DOOR || gMarioStates[0].action == ACT_PULLING_DOOR) { return; } if (gNetworkType == NT_SERVER) { djui_panel_confirm_create(caller, @@ -56,7 +56,7 @@ void djui_panel_pause_create(struct DjuiBase* caller) { struct DjuiThreePanel* panel = djui_panel_menu_create(DLANG(PAUSE, PAUSE_TITLE)); struct DjuiBase* body = djui_three_panel_get_body(panel); { - + struct DjuiRect* rect1 = djui_rect_container_create(body, 64); { djui_button_left_create(&rect1->base, DLANG(PAUSE, PLAYER), DJUI_BUTTON_STYLE_NORMAL, djui_panel_player_create); @@ -78,7 +78,7 @@ void djui_panel_pause_create(struct DjuiBase* caller) { djui_button_create(body, DLANG(PAUSE, DISCONNECT), DJUI_BUTTON_STYLE_BACK, djui_panel_pause_quit); } } - + djui_panel_add(caller, panel, defaultBase); gInteractableOverridePad = true; gDjuiPanelPauseCreated = true; diff --git a/src/pc/loading.c b/src/pc/loading.c index 065070c8..6851edcd 100644 --- a/src/pc/loading.c +++ b/src/pc/loading.c @@ -20,7 +20,7 @@ struct LoadingScreen { struct DjuiProgressBar *loadingBar; }; -struct LoadingScreen* sLoading = NULL; +static struct LoadingScreen* sLoading = NULL; pthread_t gLoadingThreadId; pthread_mutex_t gLoadingThreadMutex = PTHREAD_MUTEX_INITIALIZER; @@ -77,7 +77,7 @@ static bool loading_screen_on_render(struct DjuiBase* base) { u32 length = strlen(gCurrLoadingSegment.str); if (length > 0) { if (gCurrLoadingSegment.percentage > 0) { - snprintf(buffer, 256, "%s\n\\#c8c8c8\\%d%%", gCurrLoadingSegment.str, (u8)floor(gCurrLoadingSegment.percentage * 100)); + snprintf(buffer, 256, "%s\n\\#dcdcdc\\%d%%", gCurrLoadingSegment.str, (u8)floor(gCurrLoadingSegment.percentage * 100)); } else { snprintf(buffer, 256, "%s...", gCurrLoadingSegment.str); } @@ -106,7 +106,7 @@ static void loading_screen_destroy(struct DjuiBase* base) { } void render_loading_screen(void) { - struct LoadingScreen* load = malloc(sizeof(struct LoadingScreen)); + struct LoadingScreen* load = calloc(1, sizeof(struct LoadingScreen)); struct DjuiBase* base = &load->base; djui_base_init(NULL, base, loading_screen_on_render, loading_screen_destroy); @@ -156,13 +156,13 @@ void render_loading_screen(void) { } pthread_join(gLoadingThreadId, NULL); + gIsThreaded = false; // reset some things after rendering the loading screen - reset_djui(); + djui_base_destroy(base); + djui_shutdown(); alloc_display_list_reset(); gDisplayListHead = NULL; - djui_init(); - djui_unicode_init(); rendering_init(); configWindow.settings_changed = true; } diff --git a/src/pc/loading.h b/src/pc/loading.h index 0e8fad83..e53181a4 100644 --- a/src/pc/loading.h +++ b/src/pc/loading.h @@ -10,16 +10,18 @@ struct LoadingSegment { extern struct LoadingSegment gCurrLoadingSegment; +extern bool gIsThreaded; + #define REFRESH_MUTEX(...) \ +if (gIsThreaded) { \ pthread_mutex_lock(&gLoadingThreadMutex); \ __VA_ARGS__; \ pthread_mutex_unlock(&gLoadingThreadMutex); \ +} \ extern pthread_t gLoadingThreadId; extern pthread_mutex_t gLoadingThreadMutex; -extern bool gIsThreaded; - void render_loading_screen(void); #endif diff --git a/src/pc/lua/smlua_hooks.c b/src/pc/lua/smlua_hooks.c index cba7bc1a..c04e713c 100644 --- a/src/pc/lua/smlua_hooks.c +++ b/src/pc/lua/smlua_hooks.c @@ -1175,6 +1175,7 @@ struct LuaHookedBehavior { u32 originalId; BehaviorScript *behavior; const BehaviorScript* originalBehavior; + const char* bhvName; int initReference; int loopReference; bool replace; @@ -1235,6 +1236,15 @@ bool smlua_is_behavior_hooked(const BehaviorScript *behavior) { return false; } +const char* smlua_get_name_from_hooked_behavior_id(enum BehaviorId id) { + for (int i = 0; i < sHookedBehaviorsCount; i++) { + struct LuaHookedBehavior *hooked = &sHookedBehaviors[i]; + if (hooked->behaviorId != id && hooked->overrideId != id) { continue; } + return hooked->bhvName; + } + return NULL; +} + int smlua_hook_custom_bhv(BehaviorScript *bhvScript, const char *bhvName) { if (sHookedBehaviorsCount >= MAX_HOOKED_BEHAVIORS) { LOG_ERROR("Hooked behaviors exceeded maximum references!"); @@ -1392,6 +1402,7 @@ int smlua_hook_behavior(lua_State* L) { hooked->overrideId = noOverrideId ? customBehaviorId : overrideBehaviorId; hooked->originalId = customBehaviorId; // For LUA behaviors. The only behavior id they have IS their custom one. hooked->originalBehavior = originalBehavior ? originalBehavior : hooked->behavior; + hooked->bhvName = bhvName; hooked->initReference = initReference; hooked->loopReference = loopReference; hooked->replace = replaceBehavior; diff --git a/src/pc/lua/smlua_hooks.h b/src/pc/lua/smlua_hooks.h index 02add472..aa039c92 100644 --- a/src/pc/lua/smlua_hooks.h +++ b/src/pc/lua/smlua_hooks.h @@ -152,6 +152,7 @@ enum BehaviorId smlua_get_original_behavior_id(const BehaviorScript* behavior); const BehaviorScript* smlua_override_behavior(const BehaviorScript* behavior); const BehaviorScript* smlua_get_hooked_behavior_from_id(enum BehaviorId id, bool returnOriginal); bool smlua_is_behavior_hooked(const BehaviorScript *behavior); +const char* smlua_get_name_from_hooked_behavior_id(enum BehaviorId id); bool smlua_call_behavior_hook(const BehaviorScript** behavior, struct Object* object, bool before); int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, struct Mod* activeMod); diff --git a/src/pc/mods/mods.c b/src/pc/mods/mods.c index b1bbd9f8..276147a7 100644 --- a/src/pc/mods/mods.c +++ b/src/pc/mods/mods.c @@ -45,7 +45,7 @@ u16 mods_get_enabled_count(void) { if (!gLocalMods.entries[i]->enabled) { continue; } enabled++; } - + return enabled; } @@ -193,7 +193,7 @@ static u32 mods_count_directory(char* modsBasePath) { } static void mods_load(struct Mods* mods, char* modsBasePath, bool isUserModPath) { - if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Generating DynOS Packs In %s Mod Path:\n\\#808080\\%s", isUserModPath ? "User" : "Local", modsBasePath)); } + REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Generating DynOS Packs In %s Mod Path:\n\\#808080\\%s", isUserModPath ? "User" : "Local", modsBasePath)); // generate bins dynos_generate_packs(modsBasePath); @@ -223,7 +223,7 @@ static void mods_load(struct Mods* mods, char* modsBasePath, bool isUserModPath) } f32 count = (f32) mods_count_directory(modsBasePath); - if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading Mods In %s Mod Path:\n\\#808080\\%s", isUserModPath ? "User" : "Local", modsBasePath)); } + REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading Mods In %s Mod Path:\n\\#808080\\%s", isUserModPath ? "User" : "Local", modsBasePath)); // iterate char path[SYS_MAX_PATH] = { 0 }; @@ -232,18 +232,18 @@ static void mods_load(struct Mods* mods, char* modsBasePath, bool isUserModPath) // sanity check / fill path[] if (!directory_sanity_check(dir, modsBasePath, path)) { continue; } - if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading Mod:\n\\#808080\\%s/%s", modsBasePath, dir->d_name)); } + REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading Mod:\n\\#808080\\%s/%s", modsBasePath, dir->d_name)); // load the mod if (!mod_load(mods, modsBasePath, dir->d_name)) { break; } - if (gIsThreaded) { REFRESH_MUTEX(gCurrLoadingSegment.percentage = (f32) i / count); } + REFRESH_MUTEX(gCurrLoadingSegment.percentage = (f32) i / count); } closedir(d); - if (gIsThreaded) { REFRESH_MUTEX(gCurrLoadingSegment.percentage = 1); } + REFRESH_MUTEX(gCurrLoadingSegment.percentage = 1); } void mods_refresh_local(void) { @@ -297,7 +297,7 @@ void mods_enable(char* relativePath) { } void mods_init(void) { - if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Caching Mods")); } + REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Caching Mods")); // load mod cache mod_cache_load(); diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 979319e8..1d499fdb 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -683,11 +683,6 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup, bool reconnect mods_clear(&gActiveMods); mods_clear(&gRemoteMods); smlua_shutdown(); - extern s16 gChangeLevel; - gChangeLevel = LEVEL_CASTLE_GROUNDS; - if (gSkipInterpolationTitleScreen || find_object_with_behavior(bhvActSelector) != NULL) { - dynos_warp_to_level(LEVEL_CASTLE_GROUNDS, 1, 0); - } network_player_init(); camera_set_use_course_specific_settings(true); free_vtx_scroll_targets(); diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index a9936b28..7150d66d 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -258,6 +258,7 @@ void game_deinit(void) { network_shutdown(true, true, false, false); smlua_shutdown(); mods_shutdown(); + djui_shutdown(); gGameInited = false; } @@ -267,11 +268,13 @@ void game_exit(void) { exit(0); } -void* main_game_init(UNUSED void* arg) { +void* main_game_init(void* isThreaded) { + gIsThreaded = isThreaded != NULL; + const char *userpath = gCLIOpts.savePath[0] ? gCLIOpts.savePath : sys_user_path(); fs_init(sys_ropaths, FS_BASEDIR, userpath); - if (gIsThreaded) { REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading")); } + REFRESH_MUTEX(snprintf(gCurrLoadingSegment.str, 256, "Loading")); dynos_gfx_init(); // load config @@ -288,12 +291,10 @@ void* main_game_init(UNUSED void* arg) { mods_init(); enable_queued_mods(); - if (gIsThreaded) { - REFRESH_MUTEX( - gCurrLoadingSegment.percentage = 0; - snprintf(gCurrLoadingSegment.str, 256, "Starting Game"); - ); - } + REFRESH_MUTEX( + gCurrLoadingSegment.percentage = 0; + snprintf(gCurrLoadingSegment.str, 256, "Starting game"); + ); // If coop_custom_palette_* values are not found in sm64config.txt, the custom palette config will use the default values (Mario's palette) // But if no preset is found, that means the current palette is a custom palette @@ -308,20 +309,11 @@ void* main_game_init(UNUSED void* arg) { if (gCLIOpts.fullscreen == 1) { configWindow.fullscreen = true; } else if (gCLIOpts.fullscreen == 2) { configWindow.fullscreen = false; } - if (gCLIOpts.playerName[0] != '\0') { - snprintf(configPlayerName, MAX_PLAYER_STRING, "%s", gCLIOpts.playerName); - } - if (!gGfxInited) { gfx_init(&WAPI, &RAPI, TITLE); WAPI.set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_text_input); } -#if defined(AAPI_SDL1) || defined(AAPI_SDL2) - if (audio_api == NULL && audio_sdl.init()) { audio_api = &audio_sdl; } -#endif - if (audio_api == NULL) { audio_api = &audio_null; } - audio_init(); sound_init(); bassh_init(); @@ -352,21 +344,29 @@ int main(int argc, char *argv[]) { // Start the thread for setting up the game #ifndef WAPI_DXGI - if (pthread_mutex_init(&gLoadingThreadMutex, NULL) == 0 && pthread_create(&gLoadingThreadId, NULL, main_game_init, (void*) 1) == 0) { - gIsThreaded = true; - render_loading_screen(); // Render the loading screen while the game is setup - gIsThreaded = false; - } else { -#else - { + bool threadSuccess = false; + if (pthread_mutex_init(&gLoadingThreadMutex, NULL) == 0) { + if (pthread_create(&gLoadingThreadId, NULL, main_game_init, (void*) 1) == 0) { + render_loading_screen(); // Render the loading screen while the game is setup + threadSuccess = true; + } + pthread_mutex_destroy(&gLoadingThreadMutex); + } + if (!threadSuccess) #endif + { main_game_init(NULL); // Failsafe incase threading doesn't work } - pthread_mutex_destroy(&gLoadingThreadMutex); // initialize sm64 data and controllers thread5_game_loop(NULL); + // Initialize sound outside threads +#if defined(AAPI_SDL1) || defined(AAPI_SDL2) + if (!audio_api && audio_sdl.init()) { audio_api = &audio_sdl; } +#endif + if (!audio_api) { audio_api = &audio_null; } + // Initialize djui djui_init(); djui_unicode_init();