From dedf75e87a3ef5aaf8a602e579a046ff51fb8c6c Mon Sep 17 00:00:00 2001 From: Isaac0-dev <62234577+Isaac0-dev@users.noreply.github.com> Date: Tue, 2 May 2023 12:49:42 +1000 Subject: [PATCH 1/3] port crash handler to Linux (#363) --- Makefile | 4 + src/pc/crash_handler.c | 276 ++++++++++++++++++++++++++++++++--------- 2 files changed, 219 insertions(+), 61 deletions(-) diff --git a/Makefile b/Makefile index f305cc04c..ba7dcaa42 100644 --- a/Makefile +++ b/Makefile @@ -914,6 +914,10 @@ else LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -no-pie -lpthread endif +ifeq ($(WINDOWS_BUILD),0) + LDFLAGS += -rdynamic +endif + # icon ifeq ($(WINDOWS_BUILD),1) ifeq ($(ICON),1) diff --git a/src/pc/crash_handler.c b/src/pc/crash_handler.c index 5d307f7f6..757b92707 100644 --- a/src/pc/crash_handler.c +++ b/src/pc/crash_handler.c @@ -1,18 +1,14 @@ -// Adapted from PeachyPeach's sm64pc-omm +// Adapted from PeachyPeach's sm64pc-omm (now sm64ex-omm) #include "crash_handler.h" -#if defined(_WIN32) && !defined(WAPI_DUMMY) +#if (defined(_WIN32) || defined(__linux__)) && !defined(WAPI_DUMMY) #ifdef HAVE_SDL2 #include #endif -#include -#include -#include #include #include -#include #include "config.h" #include "pc/gfx/gfx_window_manager_api.h" #include "pc/gfx/gfx_dxgi.h" @@ -28,7 +24,23 @@ #include "pc/network/network.h" #include "pc/gfx/gfx_rendering_api.h" #include "pc/mods/mods.h" -#include "dbghelp.h" + +typedef struct { + s32 x, y; + u8 r, g, b; + char s[128]; +} CrashHandlerText; +static CrashHandlerText sCrashHandlerText[128 + 256]; + +#define PTR long long unsigned int)(uintptr_t + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +#define MEMNEW(typ, cnt) calloc(sizeof(typ), cnt) +#define STRING(str, size, fmt, ...) char str[size]; snprintf(str, size, fmt, __VA_ARGS__); + +#ifdef _WIN32 + +#define OS_NAME "Windows" #if IS_64_BIT #define CRASH_HANDLER_TYPE LONG @@ -44,15 +56,11 @@ #define ARCHITECTURE_STR "32-bit" #endif -#define PTR long long unsigned int)(uintptr_t - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) -#define MEMNEW(typ, cnt) calloc(sizeof(typ), cnt) -#define STRING(str, size, fmt, ...) char str[size]; snprintf(str, size, fmt, __VA_ARGS__); - -#define DEF(smex, smms, r96a, xalo, sm74, smsr) smex -#define load_gfx_memory_pool() DEF(config_gfx_pool(), config_gfx_pool(), config_gfx_pool(), select_gfx_pool(), select_gfx_pool(), select_gfx_pool()) -#define init_scene_rendering() DEF(init_render_image(), init_render_image(), init_render_image(), init_rcp(), init_rcp(), init_rcp()) +#include +#include +#include +#include +#include "dbghelp.h" static struct { u32 code; @@ -79,12 +87,79 @@ static struct { { 0, "Unknown Exception", "An unknown exception occurred." }, }; -typedef struct { - s32 x, y; - u8 r, g, b; - char s[128]; -} CrashHandlerText; -static CrashHandlerText sCrashHandlerText[128 + 256]; + +#if !IS_64_BIT +static ULONG CaptureStackWalkBackTrace(CONTEXT* ctx, DWORD FramesToSkip, DWORD FramesToCapture, void* BackTrace[]) { + + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + + STACKFRAME64 stack; + memset(&stack, 0, sizeof(STACKFRAME64)); +#if IS_64_BIT + stack.AddrPC.Offset = (*ctx).Rip; + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrStack.Offset = (*ctx).Rsp; + stack.AddrStack.Mode = AddrModeFlat; + stack.AddrFrame.Offset = (*ctx).Rbp; + stack.AddrFrame.Mode = AddrModeFlat; +#else + stack.AddrPC.Offset = (*ctx).Eip; + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrStack.Offset = (*ctx).Esp; + stack.AddrStack.Mode = AddrModeFlat; + stack.AddrFrame.Offset = (*ctx).Ebp; + stack.AddrFrame.Mode = AddrModeFlat; +#endif + + ULONG frame = 0; + for (frame = 0; ; frame++) + { + if (!StackWalk64(MACHINE_TYPE, process, thread, &stack, ctx, NULL, NULL, NULL, NULL)) { break; } + if (frame < FramesToSkip || frame >= FramesToCapture) { continue; } + BackTrace[frame+1] = (void*)(intptr_t)stack.AddrPC.Offset; + } + return frame; +} +#endif + +#elif __linux__ + +#define OS_NAME "Linux" + +#if IS_64_BIT + #define CRASH_HANDLER_TYPE LONG + #define SYMBOL_INCREMENT 16 + #define SYMBOL_SCAN_FORMAT "%ld" + #define MACHINE_TYPE IMAGE_FILE_MACHINE_AMD64 + #define ARCHITECTURE_STR "64-bit" +#else + #define CRASH_HANDLER_TYPE LONG WINAPI + #define SYMBOL_INCREMENT 9 + #define SYMBOL_SCAN_FORMAT "%ld" + #define MACHINE_TYPE IMAGE_FILE_MACHINE_I386 + #define ARCHITECTURE_STR "32-bit" +#endif + +#define __USE_GNU + +#include +#include +#include +#include + +static struct { + u32 code; + const char *error; + const char *message; +} sCrashHandlerErrors[] = { + { SIGBUS, "Bad Memory Access", "The game tried to access memory out of bounds." }, + { SIGFPE, "Floating Point Exception", "The game tried to perform illegal arithmetic on a floating point." }, + { SIGILL, "Illegal Instruction", "The game tried to execute an invalid instruction." }, + { SIGSEGV, "Segmentation Fault", "The game tried to %s at address 0x%016llX." }, +}; + +#endif #define crash_handler_set_text(_x_, _y_, _r_, _g_, _b_, _fmt_, ...) \ { \ @@ -126,8 +201,8 @@ static void crash_handler_produce_one_frame() { // Start frame gfx_start_frame(); - load_gfx_memory_pool(); - init_scene_rendering(); + config_gfx_pool(); + init_render_image(); float minAspectRatio = 1.743468f; float aspectScale = 1.0f; @@ -202,41 +277,6 @@ static void crash_handler_produce_one_frame() { gfx_end_frame(); } -#if !IS_64_BIT -static ULONG CaptureStackWalkBackTrace(CONTEXT* ctx, DWORD FramesToSkip, DWORD FramesToCapture, void* BackTrace[]) { - - HANDLE process = GetCurrentProcess(); - HANDLE thread = GetCurrentThread(); - - STACKFRAME64 stack; - memset(&stack, 0, sizeof(STACKFRAME64)); -#if IS_64_BIT - stack.AddrPC.Offset = (*ctx).Rip; - stack.AddrPC.Mode = AddrModeFlat; - stack.AddrStack.Offset = (*ctx).Rsp; - stack.AddrStack.Mode = AddrModeFlat; - stack.AddrFrame.Offset = (*ctx).Rbp; - stack.AddrFrame.Mode = AddrModeFlat; -#else - stack.AddrPC.Offset = (*ctx).Eip; - stack.AddrPC.Mode = AddrModeFlat; - stack.AddrStack.Offset = (*ctx).Esp; - stack.AddrStack.Mode = AddrModeFlat; - stack.AddrFrame.Offset = (*ctx).Ebp; - stack.AddrFrame.Mode = AddrModeFlat; -#endif - - ULONG frame = 0; - for (frame = 0; ; frame++) - { - if (!StackWalk64(MACHINE_TYPE, process, thread, &stack, ctx, NULL, NULL, NULL, NULL)) { break; } - if (frame < FramesToSkip || frame >= FramesToCapture) { continue; } - BackTrace[frame+1] = (void*)(intptr_t)stack.AddrPC.Offset; - } - return frame; -} -#endif - static void crash_handler_add_info_str(CrashHandlerText** pTextP, f32 x, f32 y, char* title, char* value) { CrashHandlerText* pText = *pTextP; crash_handler_set_text(x, y, 0xFF, 0xFF, 0x00, "%s", title); @@ -253,7 +293,11 @@ static void crash_handler_add_info_int(CrashHandlerText** pTextP, f32 x, f32 y, *pTextP = pText; } +#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) { +#endif memset(sCrashHandlerText, 0, sizeof(sCrashHandlerText)); CrashHandlerText *pText = &sCrashHandlerText[0]; gDjuiDisabled = true; @@ -262,6 +306,7 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) { crash_handler_set_text(8, -4, 0xFF, 0x80, 0x00, "%s", "Please report this crash with a consistent way to reproduce it."); // Exception address, code, type and info +#ifdef _WIN32 if (ExceptionInfo && ExceptionInfo->ExceptionRecord) { PEXCEPTION_RECORD er = ExceptionInfo->ExceptionRecord; crash_handler_set_text( 8, 4, 0xFF, 0x00, 0x00, "%s", "Exception occurred at address "); @@ -281,15 +326,45 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) { break; } } +#elif __linux__ + if (signalNum != 0 && info != NULL) { + crash_handler_set_text( 8, 4, 0xFF, 0x00, 0x00, "%s", "Exception occurred at address "); + crash_handler_set_text(-1, 4, 0xFF, 0xFF, 0x00, "0x%016llX", (u64) info->si_addr); + crash_handler_set_text(-1, 4, 0xFF, 0x00, 0x00, "%s", " with error code "); + crash_handler_set_text(-1, 4, 0xFF, 0x00, 0xFF, "0x%08X", (u32) signalNum); + crash_handler_set_text(-1, 4, 0xFF, 0x00, 0x00, "%s", ":"); + for (s32 i = 0; i != ARRAY_SIZE(sCrashHandlerErrors); ++i) { + if (sCrashHandlerErrors[i].code == (u32) signalNum || sCrashHandlerErrors[i].code == 0) { + crash_handler_set_text( 8, 12, 0xFF, 0x00, 0x00, "%s", sCrashHandlerErrors[i].error); + crash_handler_set_text(-1, 12, 0xFF, 0xFF, 0xFF, "%s", " - "); + if (signalNum == SIGSEGV) { + 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); + } 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); + } else { + snprintf(segFaultStr, 255, "Unknown segmentation fault at address %p", info->si_addr); + } + + crash_handler_set_text(-1, 12, 0xFF, 0xFF, 0xFF, "%s", segFaultStr); + } else { + crash_handler_set_text(-1, 12, 0xFF, 0xFF, 0xFF, "%s", sCrashHandlerErrors[i].message); + } + break; + } + } +#endif } else { crash_handler_set_text(8, 4, 0xFF, 0x00, 0x00, "%s", "An unknown exception occurred somewhere in the game's code."); crash_handler_set_text(8, 12, 0x80, 0x80, 0x80, "%s", "Unable to retrieve the exception info."); } // Registers + crash_handler_set_text(8, 22, 0xFF, 0xFF, 0xFF, "%s", "Registers:"); +#ifdef _WIN32 if (ExceptionInfo && ExceptionInfo->ContextRecord) { PCONTEXT cr = ExceptionInfo->ContextRecord; - crash_handler_set_text( 8, 22, 0xFF, 0xFF, 0xFF, "%s", "Registers:"); #if IS_64_BIT crash_handler_set_text( 8, 30, 0xFF, 0xFF, 0xFF, "RSP: 0x%016llX", (PTR)cr->Rsp); crash_handler_set_text(-1, 30, 0xFF, 0xFF, 0xFF, " RBP: 0x%016llX", (PTR)cr->Rbp); @@ -326,14 +401,54 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) { crash_handler_set_text(-1, 54, 0xFF, 0xFF, 0xFF, " SS: 0x%016llX", (PTR)cr->SegSs); crash_handler_set_text( 8, 62, 0xFF, 0xFF, 0xFF, "DR0: 0x%016llX", (PTR)cr->Dr0); crash_handler_set_text(-1, 62, 0xFF, 0xFF, 0xFF, " DR1: 0x%016llX", (PTR)cr->Dr1); +#endif +#elif __linux__ + if (context->uc_mcontext.gregs[REG_RSP] != 0) { +#if IS_64_BIT + crash_handler_set_text( 8, 30, 0xFF, 0xFF, 0xFF, "RSP: 0x%016llX", context->uc_mcontext.gregs[REG_RSP]); + crash_handler_set_text(-1, 30, 0xFF, 0xFF, 0xFF, " RBP: 0x%016llX", context->uc_mcontext.gregs[REG_RBP]); + crash_handler_set_text(-1, 30, 0xFF, 0xFF, 0xFF, " RIP: 0x%016llX", context->uc_mcontext.gregs[REG_RIP]); + crash_handler_set_text( 8, 38, 0xFF, 0xFF, 0xFF, "RAX: 0x%016llX", context->uc_mcontext.gregs[REG_RAX]); + crash_handler_set_text(-1, 38, 0xFF, 0xFF, 0xFF, " RBX: 0x%016llX", context->uc_mcontext.gregs[REG_RBX]); + crash_handler_set_text(-1, 38, 0xFF, 0xFF, 0xFF, " RCX: 0x%016llX", context->uc_mcontext.gregs[REG_RCX]); + crash_handler_set_text(-1, 38, 0xFF, 0xFF, 0xFF, " RDX: 0x%016llX", context->uc_mcontext.gregs[REG_RDX]); + crash_handler_set_text( 8, 46, 0xFF, 0xFF, 0xFF, "R08: 0x%016llX", context->uc_mcontext.gregs[REG_R8]); + crash_handler_set_text(-1, 46, 0xFF, 0xFF, 0xFF, " R09: 0x%016llX", context->uc_mcontext.gregs[REG_R9]); + crash_handler_set_text(-1, 46, 0xFF, 0xFF, 0xFF, " R10: 0x%016llX", context->uc_mcontext.gregs[REG_R10]); + crash_handler_set_text(-1, 46, 0xFF, 0xFF, 0xFF, " R11: 0x%016llX", context->uc_mcontext.gregs[REG_R11]); + crash_handler_set_text( 8, 54, 0xFF, 0xFF, 0xFF, "R12: 0x%016llX", context->uc_mcontext.gregs[REG_R12]); + crash_handler_set_text(-1, 54, 0xFF, 0xFF, 0xFF, " R13: 0x%016llX", context->uc_mcontext.gregs[REG_R13]); + crash_handler_set_text(-1, 54, 0xFF, 0xFF, 0xFF, " R14: 0x%016llX", context->uc_mcontext.gregs[REG_R14]); + crash_handler_set_text(-1, 54, 0xFF, 0xFF, 0xFF, " R15: 0x%016llX", context->uc_mcontext.gregs[REG_R15]); + crash_handler_set_text( 8, 62, 0xFF, 0xFF, 0xFF, "RSI: 0x%016llX", context->uc_mcontext.gregs[REG_RSI]); + crash_handler_set_text(-1, 62, 0xFF, 0xFF, 0xFF, " RDI: 0x%016llX", context->uc_mcontext.gregs[REG_RDI]); +#else + crash_handler_set_text( 8, 30, 0xFF, 0xFF, 0xFF, "EAX: 0x%016llX", context->uc_mcontext.gregs[REG_EAX]); + crash_handler_set_text(-1, 30, 0xFF, 0xFF, 0xFF, " EBX: 0x%016llX", context->uc_mcontext.gregs[REG_EBX]); + crash_handler_set_text(-1, 30, 0xFF, 0xFF, 0xFF, " ECX: 0x%016llX", context->uc_mcontext.gregs[REG_ECX]); + crash_handler_set_text( 8, 38, 0xFF, 0xFF, 0xFF, "EDX: 0x%016llX", context->uc_mcontext.gregs[REG_EDX]); + crash_handler_set_text(-1, 38, 0xFF, 0xFF, 0xFF, " ESI: 0x%016llX", context->uc_mcontext.gregs[REG_ESI]); + crash_handler_set_text(-1, 38, 0xFF, 0xFF, 0xFF, " EDI: 0x%016llX", context->uc_mcontext.gregs[REG_EDI]); + crash_handler_set_text(-1, 38, 0xFF, 0xFF, 0xFF, " EBP: 0x%016llX", context->uc_mcontext.gregs[REG_EBP]); + crash_handler_set_text( 8, 46, 0xFF, 0xFF, 0xFF, "EIP: 0x%016llX", context->uc_mcontext.gregs[REG_EIP]); + crash_handler_set_text(-1, 46, 0xFF, 0xFF, 0xFF, " ESP: 0x%016llX", context->uc_mcontext.gregs[REG_ESP]); + crash_handler_set_text(-1, 46, 0xFF, 0xFF, 0xFF, " CS: 0x%016llX", context->uc_mcontext.gregs[REG_CS]); + crash_handler_set_text(-1, 46, 0xFF, 0xFF, 0xFF, " DS: 0x%016llX", context->uc_mcontext.gregs[REG_DS]); + crash_handler_set_text( 8, 54, 0xFF, 0xFF, 0xFF, " ES: 0x%016llX", context->uc_mcontext.gregs[REG_ES]); + crash_handler_set_text(-1, 54, 0xFF, 0xFF, 0xFF, " FS: 0x%016llX", context->uc_mcontext.gregs[REG_FS]); + crash_handler_set_text(-1, 54, 0xFF, 0xFF, 0xFF, " GS: 0x%016llX", context->uc_mcontext.gregs[REG_GS]); + crash_handler_set_text(-1, 54, 0xFF, 0xFF, 0xFF, " SS: 0x%016llX", context->uc_mcontext.gregs[REG_SS]); + crash_handler_set_text( 8, 62, 0xFF, 0xFF, 0xFF, "DR0: 0x%016llX", context->uc_mcontext.gregs[REG_RDI]); + crash_handler_set_text(-1, 62, 0xFF, 0xFF, 0xFF, " DR1: 0x%016llX", context->uc_mcontext.gregs[REG_RDX]); +#endif #endif } else { - crash_handler_set_text(8, 22, 0xFF, 0xFF, 0xFF, "%s", "Registers:"); crash_handler_set_text(8, 30, 0x80, 0x80, 0x80, "%s", "Unable to access the registers."); } // Stack trace crash_handler_set_text(8, 72, 0xFF, 0xFF, 0xFF, "%s", "Stack trace:"); +#ifdef _WIN32 if (ExceptionInfo && ExceptionInfo->ContextRecord) { static const char sGlobalFunctionIdentifier[] = "(sec1)(fl0x00)(ty20)(scl2)(nx0)0x"; static const char sStaticFunctionIdentifier[] = "(sec1)(fl0x00)(ty20)(scl3)(nx0)0x"; @@ -436,6 +551,28 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) { } } } +#elif __linux__ + void *trace[15]; + int traceSize = backtrace(trace, 15); + + 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) { + 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", ": "); + + // dladdr gives us function names if -rdynamic/-export-dynamic is set in compiler flags + Dl_info info; + if (dladdr(trace[i], &info) && info.dli_sname) { + crash_handler_set_text(-1, y, 0x00, 0xFF, 0xFF, "%s", info.dli_sname); + crash_handler_set_text(-1, y, 0xFF, 0xFF, 0xFF, " + 0x%lX", trace[i] - info.dli_saddr); + } else { + crash_handler_set_text(-1, y, 0x00, 0xFF, 0xFF, "%s", "????"); + } + } +#endif } else { crash_handler_set_text(8, 116, 0x80, 0x80, 0x80, "%s", "Unable to unwind the call stack."); } @@ -459,6 +596,8 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) { crash_handler_add_info_int(&pText, 380, -4 + (8 * 2), "Mods", gActiveMods.entryCount); + crash_handler_add_info_str(&pText, 380, -4 + (8 * 3), "OS", OS_NAME); + // Mods crash_handler_set_text(245, 64, 0xFF, 0xFF, 0xFF, "%s", "Mods:"); { @@ -525,7 +664,22 @@ static CRASH_HANDLER_TYPE crash_handler(EXCEPTION_POINTERS *ExceptionInfo) { } __attribute__((constructor)) static void init_crash_handler() { +#ifdef _WIN32 + // Windows SetUnhandledExceptionFilter(crash_handler); +#elif __linux__ + // Linux + struct sigaction linux_crash_handler; + + linux_crash_handler.sa_handler = (void *)crash_handler; + sigemptyset(&linux_crash_handler.sa_mask); + linux_crash_handler.sa_flags = SA_SIGINFO; // Get extra info about the crash + + sigaction(SIGBUS, &linux_crash_handler, NULL); + sigaction(SIGFPE, &linux_crash_handler, NULL); + sigaction(SIGILL, &linux_crash_handler, NULL); + sigaction(SIGSEGV, &linux_crash_handler, NULL); +#endif } #endif From 52d70e33a56be857be271b87d6c992501d5dc760 Mon Sep 17 00:00:00 2001 From: Agent X <44549182+Agent-11@users.noreply.github.com> Date: Wed, 3 May 2023 03:54:57 -0400 Subject: [PATCH 2/3] Expose some painting functions to Lua (#357) * Expose some painting functions to Lua get_painting_warp_node initiate_painting_warp * Change initiate_painting_warp u8 to s16 In initiate_painting_warp, pass in -1 to not override the painting index. * Add sanity checks to get_painting_warp_node * Add requested changes --- autogen/convert_functions.py | 2 +- autogen/lua_definitions/functions.lua | 11 ++++++++ docs/lua/functions-3.md | 38 +++++++++++++++++++++++++++ docs/lua/functions.md | 2 ++ src/engine/level_script.c | 4 +-- src/engine/level_script.h | 2 ++ src/game/level_update.c | 12 ++++++--- src/game/level_update.h | 2 ++ src/pc/lua/smlua_functions_autogen.c | 34 ++++++++++++++++++++++++ 9 files changed, 100 insertions(+), 7 deletions(-) diff --git a/autogen/convert_functions.py b/autogen/convert_functions.py index 8f90c70b6..fccc41a89 100644 --- a/autogen/convert_functions.py +++ b/autogen/convert_functions.py @@ -72,7 +72,7 @@ override_allowed_functions = { "src/game/object_list_processor.h": [ "set_object_respawn_info_bits" ], "src/game/mario_misc.h": [ "bhv_toad.*", "bhv_unlock_door.*" ], "src/pc/utils/misc.h": [ "update_all_mario_stars" ], - "src/game/level_update.h": [ "level_trigger_warp" ], + "src/game/level_update.h": [ "level_trigger_warp", "get_painting_warp_node", "initiate_painting_warp" ], "src/game/area.h": [ "area_get_warp_node" ], "src/engine/level_script.h": [ "area_create_warp_node" ] } diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index beb583298..3c0fb7c28 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -4101,6 +4101,17 @@ function area_create_warp_node(id, destLevel, destArea, destNode, checkpoint, o) -- ... end +--- @return WarpNode +function get_painting_warp_node() + -- ... +end + +--- @param paintingIndex integer +--- @return nil +function initiate_painting_warp(paintingIndex) + -- ... +end + --- @param m MarioState --- @param warpOp integer --- @return integer diff --git a/docs/lua/functions-3.md b/docs/lua/functions-3.md index 0055638cd..d0c228c58 100644 --- a/docs/lua/functions-3.md +++ b/docs/lua/functions-3.md @@ -3567,6 +3567,44 @@
+## [get_painting_warp_node](#get_painting_warp_node) + +### Lua Example +`local WarpNodeValue = get_painting_warp_node()` + +### Parameters +- None + +### Returns +[WarpNode](structs.md#WarpNode) + +### C Prototype +`struct WarpNode *get_painting_warp_node(void);` + +[:arrow_up_small:](#) + +
+ +## [initiate_painting_warp](#initiate_painting_warp) + +### Lua Example +`initiate_painting_warp(paintingIndex)` + +### Parameters +| Field | Type | +| ----- | ---- | +| paintingIndex | `integer` | + +### Returns +- None + +### C Prototype +`void initiate_painting_warp(s16 paintingIndex);` + +[:arrow_up_small:](#) + +
+ ## [level_trigger_warp](#level_trigger_warp) ### Lua Example diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 2c79d0ca2..5262ae275 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -816,6 +816,8 @@
- level_update.h + - [get_painting_warp_node](functions-3.md#get_painting_warp_node) + - [initiate_painting_warp](functions-3.md#initiate_painting_warp) - [level_trigger_warp](functions-3.md#level_trigger_warp)
diff --git a/src/engine/level_script.c b/src/engine/level_script.c index b410dac07..2cace6b5e 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -626,9 +626,9 @@ static void level_cmd_create_painting_warp_node(void) { if (sCurrAreaIndex != -1) { if (gAreas[sCurrAreaIndex].paintingWarpNodes == NULL) { gAreas[sCurrAreaIndex].paintingWarpNodes = - alloc_only_pool_alloc(sLevelPool, 45 * sizeof(struct WarpNode)); + alloc_only_pool_alloc(sLevelPool, MAX_PAINTING_WARP_NODES * sizeof(struct WarpNode)); - for (i = 0; i < 45; i++) { + for (i = 0; i < MAX_PAINTING_WARP_NODES; i++) { gAreas[sCurrAreaIndex].paintingWarpNodes[i].id = 0; } } diff --git a/src/engine/level_script.h b/src/engine/level_script.h index ba4557da2..f62c4cebc 100644 --- a/src/engine/level_script.h +++ b/src/engine/level_script.h @@ -3,6 +3,8 @@ #include +#define MAX_PAINTING_WARP_NODES 45 + struct LevelCommand; extern s32 gLevelScriptModIndex; diff --git a/src/game/level_update.c b/src/game/level_update.c index b11c26929..f8b0f4472 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -45,6 +45,8 @@ #include "game/screen_transition.h" +#include "engine/level_script.h" + #define WARP_NODE_F0 0xF0 #define WARP_NODE_DEATH 0xF1 #define WARP_NODE_F2 0xF2 @@ -748,6 +750,8 @@ void initiate_warp(s16 destLevel, s16 destArea, s16 destWarpNode, s32 arg3) { * corresponding warp node. */ struct WarpNode *get_painting_warp_node(void) { + if (!gMarioState || !gMarioState->floor || !gCurrentArea || !gCurrentArea->paintingWarpNodes) { return NULL; } + struct WarpNode *warpNode = NULL; s32 paintingIndex = gMarioState->floor->type - SURFACE_PAINTING_WARP_D3; @@ -783,9 +787,9 @@ static void initiate_painting_warp_node(struct WarpNode *pWarpNode) { /** * Check is Mario has entered a painting, and if so, initiate a warp. */ -void initiate_painting_warp(void) { - if (gCurrentArea != NULL && gCurrentArea->paintingWarpNodes != NULL && gMarioState->floor != NULL) { - struct WarpNode *pWarpNode = get_painting_warp_node(); +void initiate_painting_warp(s16 paintingIndex) { + if (gCurrentArea && gCurrentArea->paintingWarpNodes && gMarioState && gMarioState->floor && paintingIndex >= 0 && paintingIndex < MAX_PAINTING_WARP_NODES) { + struct WarpNode *pWarpNode = paintingIndex == -1 ? get_painting_warp_node() : &gCurrentArea->paintingWarpNodes[paintingIndex]; if (pWarpNode != NULL) { if (gMarioState->action & ACT_FLAG_INTANGIBLE) { @@ -1229,7 +1233,7 @@ s32 play_mode_normal(void) { update_camera(gCurrentArea->camera); } - initiate_painting_warp(); + initiate_painting_warp(-1); initiate_delayed_warp(); // If either initiate_painting_warp or initiate_delayed_warp initiated a diff --git a/src/game/level_update.h b/src/game/level_update.h index 904d7de4b..dbc729579 100644 --- a/src/game/level_update.h +++ b/src/game/level_update.h @@ -151,6 +151,8 @@ u8 level_control_timer_running(void); u16 level_control_timer(s32 timerOp); void fade_into_special_warp(u32 arg, u32 color); void load_level_init_text(u32 arg); +struct WarpNode *get_painting_warp_node(void); +void initiate_painting_warp(s16 paintingIndex); s16 level_trigger_warp(struct MarioState *m, s32 warpOp); void level_set_transition(s16 length, void (*updateFunction)(s16 *)); diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 1b014336b..4f3874841 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -12899,6 +12899,38 @@ int smlua_func_area_create_warp_node(lua_State* L) { // level_update.h // //////////////////// +int smlua_func_get_painting_warp_node(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", "get_painting_warp_node", 0, top); + return 0; + } + + + smlua_push_object(L, LOT_WARPNODE, get_painting_warp_node()); + + return 1; +} + +int smlua_func_initiate_painting_warp(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", "initiate_painting_warp", 1, top); + return 0; + } + + s16 paintingIndex = smlua_to_integer(L, 1); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "initiate_painting_warp"); return 0; } + + initiate_painting_warp(paintingIndex); + + return 1; +} + int smlua_func_level_trigger_warp(lua_State* L) { if (L == NULL) { return 0; } @@ -30135,6 +30167,8 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "area_create_warp_node", smlua_func_area_create_warp_node); // level_update.h + smlua_bind_function(L, "get_painting_warp_node", smlua_func_get_painting_warp_node); + smlua_bind_function(L, "initiate_painting_warp", smlua_func_initiate_painting_warp); smlua_bind_function(L, "level_trigger_warp", smlua_func_level_trigger_warp); // mario.h From 2bd2089ed3d3e0f7cc50db11fb0912a711657548 Mon Sep 17 00:00:00 2001 From: Skeltan <110261917+Skeltan@users.noreply.github.com> Date: Wed, 3 May 2023 09:58:19 +0200 Subject: [PATCH 3/3] Added Toad default palette + other palette tweaks (#370) --- lang/English.ini | 1 + lang/French.ini | 1 + lang/German.ini | 1 + lang/Italian.ini | 1 + lang/Portuguese.ini | 1 + lang/Russian.ini | 1 + lang/Spanish.ini | 1 + src/game/characters.c | 5 +++-- src/game/characters.h | 2 +- src/pc/djui/djui_panel_player.c | 1 + 10 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lang/English.ini b/lang/English.ini index c28677799..27efbd09a 100644 --- a/lang/English.ini +++ b/lang/English.ini @@ -323,6 +323,7 @@ RASPBERRY = "Raspberry" BUBBLEGUM = "Bubblegum" ICE_MARIO = "Ice Mario" ICE_LUIGI = "Ice Luigi" +TOAD = "Toad" CUSTOM = "Custom" [PLAYER_LIST] diff --git a/lang/French.ini b/lang/French.ini index 23d819f97..22b7ef90b 100644 --- a/lang/French.ini +++ b/lang/French.ini @@ -323,6 +323,7 @@ RASPBERRY = "Framboise" BUBBLEGUM = "Bubblegum" ICE_MARIO = "Mario de glace" ICE_LUIGI = "Luigi de glace" +TOAD = "Toad" CUSTOM = "Personnalisée" [PLAYER_LIST] diff --git a/lang/German.ini b/lang/German.ini index 8b238c1cd..f3c0efe61 100644 --- a/lang/German.ini +++ b/lang/German.ini @@ -323,6 +323,7 @@ RASPBERRY = "Himbeere" BUBBLEGUM = "Kaugummi" ICE_MARIO = "Eis Mario" ICE_LUIGI = "Eis Luigi" +TOAD = "Toad" CUSTOM = "Selbstgemacht" [PLAYER_LIST] diff --git a/lang/Italian.ini b/lang/Italian.ini index 002624cc9..e5443135c 100644 --- a/lang/Italian.ini +++ b/lang/Italian.ini @@ -320,6 +320,7 @@ RASPBERRY = "Mora" BUBBLEGUM = "Gomma da Masticare" ICE_MARIO = "Mario Ghiaccio" ICE_LUIGI = "Luigi Ghiaccio" +TOAD = "Toad" CUSTOM = "Personalizzato" [PLAYER_LIST] diff --git a/lang/Portuguese.ini b/lang/Portuguese.ini index 29564b637..09d12f520 100644 --- a/lang/Portuguese.ini +++ b/lang/Portuguese.ini @@ -323,6 +323,7 @@ RASPBERRY = "Framboesa" BUBBLEGUM = "Chiclete" ICE_MARIO = "Mario de Gelo" ICE_LUIGI = "Luigi de Gelo" +TOAD = "Toad" CUSTOM = "Customizado" [PLAYER_LIST] diff --git a/lang/Russian.ini b/lang/Russian.ini index f1db254b0..9c784775e 100644 --- a/lang/Russian.ini +++ b/lang/Russian.ini @@ -322,6 +322,7 @@ RASPBERRY = "Малина" BUBBLEGUM = "Жвачка" ICE_MARIO = "Ледяной Марио" ICE_LUIGI = "Ледяной Луиджи" +TOAD = "Тоад"s CUSTOM = "Свой" [PLAYER_LIST] diff --git a/lang/Spanish.ini b/lang/Spanish.ini index ca49c9735..1b92e4494 100644 --- a/lang/Spanish.ini +++ b/lang/Spanish.ini @@ -323,6 +323,7 @@ RASPBERRY = "Frambuesa" BUBBLEGUM = "Chicle" ICE_MARIO = "Mario de Hielo" ICE_LUIGI = "Luigi de Hielo" +TOAD = "Toad" CUSTOM = "Personalizada" [PLAYER_LIST] diff --git a/src/game/characters.c b/src/game/characters.c index b6a53cace..684375a1d 100644 --- a/src/game/characters.c +++ b/src/game/characters.c @@ -363,8 +363,8 @@ const struct PlayerPalette gPalettePresets[PALETTE_PRESET_MAX] = { /* ---- PANTS ----- ---- SHIRT ----- ---- GLOVES ---- ---- SHOES ----- ----- HAIR ----- ----- SKIN ----- ----- CAP ------ */ {{{ 0x00, 0x00, 0xff }, { 0xff, 0x00, 0x00 }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0xff, 0x00, 0x00 }}}, // Mario {{{ 0x00, 0x00, 0xfe }, { 0x00, 0x98, 0x00 }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0x00, 0x98, 0x00 }}}, // Luigi -{{{ 0x2c, 0x26, 0x3f }, { 0x6d, 0x3c, 0x9a }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0x6d, 0x3c, 0x9a }}}, // Waluigi -{{{ 0x7f, 0x20, 0x7a }, { 0xf9, 0xeb, 0x30 }, { 0xff, 0xff, 0xff }, { 0x0e, 0x72, 0x1c }, { 0x73, 0x53, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0xf9, 0xeb, 0x30 }}}, // Wario +{{{ 0x2c, 0x26, 0x3f }, { 0x61, 0x26, 0xb0 }, { 0xff, 0xff, 0xff }, { 0xfe, 0x76, 0x00 }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0x61, 0x26, 0xb0 }}}, // Waluigi +{{{ 0x7f, 0x20, 0x7a }, { 0xe3, 0xa9, 0x01 }, { 0xff, 0xff, 0xff }, { 0x0e, 0x72, 0x1c }, { 0x73, 0x53, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0xe3, 0xa9, 0x01 }}}, // Wario {{{ 0xff, 0x00, 0x00 }, { 0x7b, 0x00, 0xde }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0x7b, 0x00, 0xde }}}, // Chuckya {{{ 0xc6, 0xb1, 0x32 }, { 0x95, 0x43, 0x01 }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0x95, 0x43, 0x01 }}}, // Goomba {{{ 0x07, 0x09, 0x07 }, { 0x4c, 0x5f, 0x20 }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0x4c, 0x5f, 0x20 }}}, // Clover @@ -393,6 +393,7 @@ const struct PlayerPalette gPalettePresets[PALETTE_PRESET_MAX] = { {{{ 0xd6, 0x35, 0x4d }, { 0xff, 0x8e, 0xb2 }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0xff, 0x8e, 0xb2 }}}, // Bubblegum {{{ 0xb2, 0x28, 0x18 }, { 0x47, 0xc5, 0xff }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0x47, 0xc5, 0xff }}}, // Ice Mario {{{ 0x00, 0x98, 0x00 }, { 0x47, 0xc5, 0xff }, { 0xff, 0xff, 0xff }, { 0x72, 0x1c, 0x0e }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xc1, 0x79 }, { 0x47, 0xc5, 0xff }}}, // Ice Luigi +{{{ 0x4c, 0x2c, 0xd3 }, { 0xff, 0xff, 0xff }, { 0xff, 0xff, 0xff }, { 0x68, 0x40, 0x1b }, { 0x73, 0x06, 0x00 }, { 0xfe, 0xd5, 0xa1 }, { 0xff, 0x00, 0x00 }}}, // Toad }; enum AnimType { diff --git a/src/game/characters.h b/src/game/characters.h index 8606ebe72..726fca4b3 100644 --- a/src/game/characters.h +++ b/src/game/characters.h @@ -5,7 +5,7 @@ #include "pc/configfile.h" // NOTE: do not include any additional headers -#define PALETTE_PRESET_MAX 32 +#define PALETTE_PRESET_MAX 33 enum PlayerParts { PANTS, SHIRT, GLOVES, SHOES, HAIR, SKIN, CAP, PLAYER_PART_MAX, METAL = CAP diff --git a/src/pc/djui/djui_panel_player.c b/src/pc/djui/djui_panel_player.c index a05d87b06..22e0e2d54 100644 --- a/src/pc/djui/djui_panel_player.c +++ b/src/pc/djui/djui_panel_player.c @@ -298,6 +298,7 @@ void djui_panel_player_create(struct DjuiBase* caller) { DLANG(PALETTE, BUBBLEGUM), DLANG(PALETTE, ICE_MARIO), DLANG(PALETTE, ICE_LUIGI), + DLANG(PALETTE, TOAD), DLANG(PALETTE, CUSTOM), };