diff --git a/docs/modding.md b/docs/modding.md index c05e736d8b..ab100b5add 100644 --- a/docs/modding.md +++ b/docs/modding.md @@ -209,8 +209,8 @@ if (svc_resource->load(mod_ctx, "config.txt", &buf) == MOD_OK) { } ``` -Missing files return `MOD_UNAVAILABLE`. Always `free` what you `load`. Note that the bundle is read-only; for writable -storage, use the directory from `svc_host->mod_dir(mod_ctx)`. +Missing files return `MOD_UNAVAILABLE`. Always `free` what you `load`. The bundle is read-only; use +`HostService::data_dir` for persistent storage. ### HostService (`mods/svc/host.h`) @@ -219,9 +219,17 @@ Mod metadata and runtime interaction with the loader: ```cpp IMPORT_SERVICE(HostService, svc_host); -const char* id = svc_host->mod_id(mod_ctx); -const char* dir = svc_host->mod_dir(mod_ctx); // writable per-mod directory -svc_host->fail(mod_ctx, MOD_ERROR, "something unrecoverable happened"); // disables the mod +// Temporary mod data directory, wiped on startup +const char* cacheDir = svc_host->mod_dir(mod_ctx); + +// Persistent mod data directory +const char* dataDir = nullptr; +if (svc_host->data_dir(mod_ctx, &dataDir) == MOD_OK) { + // ... +} + +// Report an error and disable the mod +svc_host->fail(mod_ctx, MOD_ERROR, "something unrecoverable happened"); ``` `get_service`/`publish_service` provide dynamic service lookup; see [Exporting Services](#exporting-services). @@ -625,6 +633,9 @@ if (svc_camera->get_camera(mod_ctx, game_view, &camera) == MOD_OK) { first in-game frame. Projection matrices match the renderer's WebGPU clip convention and renderer depth convention (reversed-Z by default). +Camera operators allow overriding the main camera. When an operator callback returns true, its values replace the camera +state for the current frame. Register and unregister using `register_camera_operator` / `unregister_camera_operator`. + --- ## Hooking Game Functions @@ -927,6 +938,6 @@ const char* nativeDir = svc_host->native_dir(mod_ctx); // read-only ``` Libraries loaded explicitly by the mod remain its responsibility: stop their threads and unload them during -`mod_shutdown`. Do not write into `native_dir`; use `mod_dir` for writable state. Native library namespaces are -process-wide on some platforms, so two mods cannot safely assume that incompatible libraries with the same filename -will remain isolated. +`mod_shutdown`. Do not write into `native_dir`; use `data_dir` for persistent storage or `mod_dir` for temporary +(session) storage. Native library namespaces are process-wide on some platforms, so two mods cannot safely assume that +incompatible libraries with the same filename will remain isolated. diff --git a/extern/aurora b/extern/aurora index 5027ed63a7..8005d336ab 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 5027ed63a73dfba28de9eceed00481fb09a19c35 +Subproject commit 8005d336ab02f0c617fc27fabbea4af42ab04caa diff --git a/extern/borealis b/extern/borealis index eec74b6dec..6fd955e7e6 160000 --- a/extern/borealis +++ b/extern/borealis @@ -1 +1 @@ -Subproject commit eec74b6decf364354d0a94ad308ea6d0186585a2 +Subproject commit 6fd955e7e6a2d2d47c5a4eaf363fb49847e490ba diff --git a/include/m_Do/m_Do_dvd_thread.h b/include/m_Do/m_Do_dvd_thread.h index 83dd4dec1e..dcb3f2fc65 100644 --- a/include/m_Do/m_Do_dvd_thread.h +++ b/include/m_Do/m_Do_dvd_thread.h @@ -130,8 +130,8 @@ private: }; // Size = 0x28 struct mDoDvdThdStack { - u8 stack[4096]; -} ATTRIBUTE_ALIGN(16); + ATTRIBUTE_ALIGN(16) u8 stack[4096]; +}; struct mDoDvdThd { static s32 main(void*); diff --git a/libs/JSystem/src/J3DGraphBase/J3DSys.cpp b/libs/JSystem/src/J3DGraphBase/J3DSys.cpp index d37b4608bf..bdacff4276 100644 --- a/libs/JSystem/src/J3DGraphBase/J3DSys.cpp +++ b/libs/JSystem/src/J3DGraphBase/J3DSys.cpp @@ -23,9 +23,9 @@ DUSK_GAME_DATA Vec J3DSys::mParentS; DUSK_GAME_DATA J3DTexCoordScaleInfo J3DSys::sTexCoordScaleTable[8]; #if TARGET_PC // Original game bug, array is too small. -static u8 NullTexData[0x20] ATTRIBUTE_ALIGN(32) = {0}; +ATTRIBUTE_ALIGN(32) static u8 NullTexData[0x20] = {0}; #else -static u8 NullTexData[0x10] ATTRIBUTE_ALIGN(32) = {0}; +ATTRIBUTE_ALIGN(32) static u8 NullTexData[0x10] = {0}; #endif static Mtx j3dIdentityMtx = { diff --git a/libs/JSystem/src/JAudio2/JASDSPInterface.cpp b/libs/JSystem/src/JAudio2/JASDSPInterface.cpp index 554660f6dc..7a9b5cda3e 100644 --- a/libs/JSystem/src/JAudio2/JASDSPInterface.cpp +++ b/libs/JSystem/src/JAudio2/JASDSPInterface.cpp @@ -99,14 +99,14 @@ void JASDsp::invalChannelAll() { DCInvalidateRange(CH_BUF, sizeof(TChannel) * DSP_CHANNELS); } -DUSK_GAME_DATA u8 const ATTRIBUTE_ALIGN(32) JASDsp::DSPADPCM_FILTER[64] = { +ATTRIBUTE_ALIGN(32) DUSK_GAME_DATA u8 const JASDsp::DSPADPCM_FILTER[64] = { 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x04, 0x00, 0x10, 0x00, 0xF8, 0x00, 0x0E, 0x00, 0xFA, 0x00, 0x0C, 0x00, 0xFC, 0x00, 0x12, 0x00, 0xF6, 0x00, 0x10, 0x68, 0xF7, 0x38, 0x12, 0xC0, 0xF7, 0x04, 0x14, 0x00, 0xF4, 0x00, 0x08, 0x00, 0xF8, 0x00, 0x04, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x04, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, }; -DUSK_GAME_DATA u32 const ATTRIBUTE_ALIGN(32) JASDsp::DSPRES_FILTER[320] = { +ATTRIBUTE_ALIGN(32) DUSK_GAME_DATA u32 const JASDsp::DSPRES_FILTER[320] = { 0x0C3966AD, 0x0D46FFDF, 0x0B396696, diff --git a/libs/JSystem/src/JAudio2/dsptask.cpp b/libs/JSystem/src/JAudio2/dsptask.cpp index 7d2e8dd2ad..ce91ae2e78 100644 --- a/libs/JSystem/src/JAudio2/dsptask.cpp +++ b/libs/JSystem/src/JAudio2/dsptask.cpp @@ -25,7 +25,7 @@ void DspHandShake(void*) { Dsp_Running_Start(); } -static u8 jdsp[7936] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 jdsp[7936] = { 0x02, 0x9F, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02, 0x9F, 0x06, 0xA5, 0x02, 0x9F, 0x00, 0x4E, 0x12, 0x05, 0x02, 0xBF, 0x00, 0x57, 0x81, 0x00, 0x00, 0x9F, 0x10, 0x00, @@ -524,9 +524,9 @@ static u8 jdsp[7936] ATTRIBUTE_ALIGN(32) = { 0x80, 0x01, 0x02, 0xBF, 0x00, 0xF4, 0x02, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static DSPTaskInfo audio_task ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static DSPTaskInfo audio_task; -static u8 AUDIO_YIELD_BUFFER[8192] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u8 AUDIO_YIELD_BUFFER[8192]; void DspBoot(void (*requestCallback)(void*)) { DspInitWork(); diff --git a/libs/JSystem/src/JFramework/JFWDisplay.cpp b/libs/JSystem/src/JFramework/JFWDisplay.cpp index 99b1e63364..0c26e77a53 100644 --- a/libs/JSystem/src/JFramework/JFWDisplay.cpp +++ b/libs/JSystem/src/JFramework/JFWDisplay.cpp @@ -452,13 +452,13 @@ static void dummy() { JUTXfb::getManager()->setDisplayingXfbIndex(0); } -static Mtx e_mtx ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static Mtx e_mtx = { {1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, }; -static u8 clear_z_TX[64] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 clear_z_TX[64] = { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, diff --git a/libs/JSystem/src/JMath/JMATrigonometric.cpp b/libs/JSystem/src/JMath/JMATrigonometric.cpp index 8ebdb57ebc..cc8ce129e6 100644 --- a/libs/JSystem/src/JMath/JMATrigonometric.cpp +++ b/libs/JSystem/src/JMath/JMATrigonometric.cpp @@ -16,10 +16,10 @@ inline f64 getConst2() { return 9.765625E-4; } -DUSK_GAME_DATA TSinCosTable<13, f32> sincosTable_ ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) DUSK_GAME_DATA TSinCosTable<13, f32> sincosTable_; -DUSK_GAME_DATA TAtanTable<1024, f32> atanTable_ ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) DUSK_GAME_DATA TAtanTable<1024, f32> atanTable_; -DUSK_GAME_DATA TAsinAcosTable<1024, f32> asinAcosTable_ ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) DUSK_GAME_DATA TAsinAcosTable<1024, f32> asinAcosTable_; } // namespace JMath diff --git a/libs/JSystem/src/JParticle/JPAResource.cpp b/libs/JSystem/src/JParticle/JPAResource.cpp index 9385b258e7..b67ac47489 100644 --- a/libs/JSystem/src/JParticle/JPAResource.cpp +++ b/libs/JSystem/src/JParticle/JPAResource.cpp @@ -46,7 +46,7 @@ JPAResource::JPAResource() { mUsrIdx = fldNum = keyNum = texNum = mpCalcEmitterFuncListNum = mpDrawEmitterFuncListNum = mpDrawEmitterChildFuncListNum = mpCalcParticleFuncListNum = mpDrawParticleFuncListNum = mpCalcParticleChildFuncListNum = mpDrawParticleChildFuncListNum = 0; } -static u8 jpa_pos[324] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 jpa_pos[324] = { 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x32, 0xCE, 0x00, 0x00, 0xCE, 0x00, 0xE7, 0x00, 0x00, 0x19, 0x00, 0x00, 0x19, 0xCE, 0x00, 0xE7, 0xCE, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0xCE, 0xCE, 0x00, 0x00, 0x19, 0x00, 0x32, 0x19, 0x00, 0x32, 0xE7, 0x00, 0x00, 0xE7, 0x00, @@ -70,7 +70,7 @@ static u8 jpa_pos[324] ATTRIBUTE_ALIGN(32) = { 0x00, 0x00, 0x00, 0xCE, }; -static u8 jpa_crd[32] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 jpa_crd[32] = { 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x02, }; diff --git a/libs/JSystem/src/JUtility/JUTFontData_Ascfont_fix12.cpp b/libs/JSystem/src/JUtility/JUTFontData_Ascfont_fix12.cpp index 64ee2c61d8..0e500e377c 100644 --- a/libs/JSystem/src/JUtility/JUTFontData_Ascfont_fix12.cpp +++ b/libs/JSystem/src/JUtility/JUTFontData_Ascfont_fix12.cpp @@ -8,7 +8,7 @@ #endif #include "global.h" -DUSK_GAME_DATA u8 const JUTResFONT_Ascfont_fix12[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) DUSK_GAME_DATA u8 const JUTResFONT_Ascfont_fix12[] = { 0x46, 0x4F, 0x4E, 0x54, 0x62, 0x66, 0x6E, 0x31, 0x00, 0x00, 0x41, 0x60, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x46, 0x31, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, diff --git a/libs/TRK_MINNOW_DOLPHIN/debugger/embedded/MetroTRK/Os/dolphin/dolphin_trk.c b/libs/TRK_MINNOW_DOLPHIN/debugger/embedded/MetroTRK/Os/dolphin/dolphin_trk.c index 13a30383ba..2564e1298c 100644 --- a/libs/TRK_MINNOW_DOLPHIN/debugger/embedded/MetroTRK/Os/dolphin/dolphin_trk.c +++ b/libs/TRK_MINNOW_DOLPHIN/debugger/embedded/MetroTRK/Os/dolphin/dolphin_trk.c @@ -136,7 +136,7 @@ void TRK__read_aram(__REGISTER int c, __REGISTER u32 p2, void* p3) { } void TRK__write_aram(__REGISTER int c, __REGISTER u32 p2, void* p3) { - u8 buff[32] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 buff[32]; u32 err; __REGISTER int count = c; __REGISTER u32 bf; diff --git a/libs/TRK_MINNOW_DOLPHIN/debugger/embedded/MetroTRK/Portable/msghndlr.c b/libs/TRK_MINNOW_DOLPHIN/debugger/embedded/MetroTRK/Portable/msghndlr.c index 36a33d75fa..f3b5901d5b 100644 --- a/libs/TRK_MINNOW_DOLPHIN/debugger/embedded/MetroTRK/Portable/msghndlr.c +++ b/libs/TRK_MINNOW_DOLPHIN/debugger/embedded/MetroTRK/Portable/msghndlr.c @@ -85,7 +85,7 @@ DSError TRKDoSupportMask(TRKBuffer*) { } DSError TRKDoReadMemory(TRKBuffer* buffer) { - u8 buf[0x820] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 buf[0x820]; size_t tempLength; int result; int replyErr; @@ -158,7 +158,7 @@ DSError TRKDoReadMemory(TRKBuffer* buffer) { } DSError TRKDoWriteMemory(TRKBuffer* b) { - u8 buf[0x820] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 buf[0x820]; size_t tempLength; int options; int result; diff --git a/libs/dolphin/src/ax/AXAux.c b/libs/dolphin/src/ax/AXAux.c index 7d392d8f1c..cf469197ee 100644 --- a/libs/dolphin/src/ax/AXAux.c +++ b/libs/dolphin/src/ax/AXAux.c @@ -3,8 +3,8 @@ #include "__ax.h" -static s32 __AXBufferAuxA[3][480] ATTRIBUTE_ALIGN(32); -static s32 __AXBufferAuxB[3][480] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static s32 __AXBufferAuxA[3][480]; +ATTRIBUTE_ALIGN(32) static s32 __AXBufferAuxB[3][480]; static void (* __AXCallbackAuxA)(void*, void*); static void (* __AXCallbackAuxB)(void*, void*); diff --git a/libs/dolphin/src/ax/AXSPB.c b/libs/dolphin/src/ax/AXSPB.c index 3729589b62..6fad9bae4b 100644 --- a/libs/dolphin/src/ax/AXSPB.c +++ b/libs/dolphin/src/ax/AXSPB.c @@ -3,7 +3,7 @@ #include "__ax.h" -static AXSPB __AXStudio ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static AXSPB __AXStudio; static s32 __AXSpbAL; static s32 __AXSpbAR; diff --git a/libs/dolphin/src/ax/AXVPB.c b/libs/dolphin/src/ax/AXVPB.c index e8cf663470..02b9db2c63 100644 --- a/libs/dolphin/src/ax/AXVPB.c +++ b/libs/dolphin/src/ax/AXVPB.c @@ -35,9 +35,9 @@ static u32 __AXAuxMixCycles[32] = { 0x000009E2, 0x00000E97 }; -static AXPB __AXPB[AX_MAX_VOICES] ATTRIBUTE_ALIGN(32); -static AXPBITDBUFFER __AXITD[AX_MAX_VOICES] ATTRIBUTE_ALIGN(32); -static AXPBU __AXUpdates[AX_MAX_VOICES] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static AXPB __AXPB[AX_MAX_VOICES]; +ATTRIBUTE_ALIGN(32) static AXPBITDBUFFER __AXITD[AX_MAX_VOICES]; +ATTRIBUTE_ALIGN(32) static AXPBU __AXUpdates[AX_MAX_VOICES]; static AXVPB __AXVPB[AX_MAX_VOICES]; static u32 __AXMaxDspCycles; diff --git a/libs/dolphin/src/ax/DSPCode.c b/libs/dolphin/src/ax/DSPCode.c index 7ca0d067ba..a2f77e2805 100644 --- a/libs/dolphin/src/ax/DSPCode.c +++ b/libs/dolphin/src/ax/DSPCode.c @@ -3,7 +3,7 @@ u16 axDspSlaveLength = (AX_DSP_SLAVE_LENGTH * 2); -u16 axDspSlave[AX_DSP_SLAVE_LENGTH] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) u16 axDspSlave[AX_DSP_SLAVE_LENGTH] = { 0x0000, 0x0000, 0x029F, 0x0E88, 0x029F, 0x0E97, 0x029F, 0x0EB3, 0x029F, 0x0ED3, 0x029F, 0x0ED9, 0x029F, 0x0F0B, 0x029F, 0x0F11, 0x1302, 0x1303, diff --git a/libs/dolphin/src/card/CARDUnlock.c b/libs/dolphin/src/card/CARDUnlock.c index 48f64e500a..31138c2995 100644 --- a/libs/dolphin/src/card/CARDUnlock.c +++ b/libs/dolphin/src/card/CARDUnlock.c @@ -4,7 +4,7 @@ #include "__card.h" -static u8 CardData[352] ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT) = { +ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT) static u8 CardData[352] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x02, 0xFF, 0x00, 0x21, 0x13, 0x06, 0x12, 0x03, 0x12, 0x04, 0x13, 0x05, 0x00, 0x92, 0x00, 0xFF, 0x00, 0x88, 0xFF, 0xFF, 0x00, 0x89, 0xFF, 0xFF, 0x00, 0x8A, 0xFF, 0xFF, 0x00, diff --git a/libs/dolphin/src/demo/DEMOAVX.c b/libs/dolphin/src/demo/DEMOAVX.c index 39f5d8f554..6de1cfd01d 100644 --- a/libs/dolphin/src/demo/DEMOAVX.c +++ b/libs/dolphin/src/demo/DEMOAVX.c @@ -3,7 +3,7 @@ #include #include "sdk_math.h" -static s16 __AVX_internal_buffer[3200] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static s16 __AVX_internal_buffer[3200]; static void (*__AVX_save_isr)(void); diff --git a/libs/dolphin/src/demo/DEMOFont.c b/libs/dolphin/src/demo/DEMOFont.c index 48299131d9..3ea63d291e 100644 --- a/libs/dolphin/src/demo/DEMOFont.c +++ b/libs/dolphin/src/demo/DEMOFont.c @@ -1,7 +1,7 @@ #include #include -u32 DEMOFontBitmap[768] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) u32 DEMOFontBitmap[768] = { 0x00000000, 0x00000000, 0x00000000, diff --git a/libs/dolphin/src/gx/GXInit.c b/libs/dolphin/src/gx/GXInit.c index c22f5acbd8..639c990d72 100644 --- a/libs/dolphin/src/gx/GXInit.c +++ b/libs/dolphin/src/gx/GXInit.c @@ -43,7 +43,7 @@ void* __piReg; GXBool __GXinBegin; #endif -static u16 DefaultTexData[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u16 DefaultTexData[] = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, }; diff --git a/libs/dolphin/src/mcc/mcc.c b/libs/dolphin/src/mcc/mcc.c index fa75efe415..1d05d947a6 100644 --- a/libs/dolphin/src/mcc/mcc.c +++ b/libs/dolphin/src/mcc/mcc.c @@ -7,11 +7,11 @@ const char* __MCCVersion = "<< Dolphin SDK - MCC\tdebug build: Apr 5 2004 03:57 const char* __MCCVersion = "<< Dolphin SDK - MCC\trelease build: Apr 5 2004 04:15:49 (0x2301) >>"; #endif -static MCC_ChannelInfo gChannelInfo[16] ATTRIBUTE_ALIGN(32); -static char gStreamWork[32] ATTRIBUTE_ALIGN(32); -static char m_szAdapterMode[32] ATTRIBUTE_ALIGN(32); -static char m_szInitCode[32] ATTRIBUTE_ALIGN(32); -static MCC_Info channelInfo[16] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static MCC_ChannelInfo gChannelInfo[16]; +ATTRIBUTE_ALIGN(32) static char gStreamWork[32]; +ATTRIBUTE_ALIGN(32) static char m_szAdapterMode[32]; +ATTRIBUTE_ALIGN(32) static char m_szInitCode[32]; +ATTRIBUTE_ALIGN(32) static MCC_Info channelInfo[16]; volatile static BOOL gIsChannelinfoDirty = TRUE; diff --git a/libs/dolphin/src/os/OSRtc.c b/libs/dolphin/src/os/OSRtc.c index ee55fcc0e4..c4f9cb7233 100644 --- a/libs/dolphin/src/os/OSRtc.c +++ b/libs/dolphin/src/os/OSRtc.c @@ -3,7 +3,7 @@ #include "__os.h" -static SramControl Scb ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT); +ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT) static SramControl Scb; // prototypes static int GetRTC(u32* rtc); diff --git a/libs/revolution/src/card/CARDUnlock.c b/libs/revolution/src/card/CARDUnlock.c index 93298297c8..1fad65efe4 100644 --- a/libs/revolution/src/card/CARDUnlock.c +++ b/libs/revolution/src/card/CARDUnlock.c @@ -3,7 +3,7 @@ #include "__card.h" -static u8 CardData[352] ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT) = { +ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT) static u8 CardData[352] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x02, 0xFF, 0x00, 0x21, 0x13, 0x06, 0x12, 0x03, 0x12, 0x04, 0x13, 0x05, 0x00, 0x92, 0x00, 0xFF, 0x00, 0x88, 0xFF, 0xFF, 0x00, 0x89, 0xFF, 0xFF, 0x00, 0x8A, 0xFF, 0xFF, 0x00, diff --git a/libs/revolution/src/dvd/dvd.c b/libs/revolution/src/dvd/dvd.c index 0e5dbd0945..9e91f6e3f3 100644 --- a/libs/revolution/src/dvd/dvd.c +++ b/libs/revolution/src/dvd/dvd.c @@ -44,7 +44,7 @@ static u32 LastError; static BOOL ResetRequired; static u32 MotorState; static volatile OSTime LastResetEnd; -static u32 __DVDNumTmdBytes ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u32 __DVDNumTmdBytes; static DVDGameTOC* GameToc; static DVDPartitionInfo* PartInfo; static DVDPartitionInfo* BootGameInfo; @@ -80,10 +80,10 @@ static DVDCommandBlock DummyCommandBlock; static OSAlarm ResetAlarm; static OSAlarm CoverAlarm; -static u8 __DVDGameTocBuffer[OSRoundUp32B(sizeof(DVDGameTOC) * 4)] ATTRIBUTE_ALIGN(32); -static u8 __DVDPartInfoBuffer[OSRoundUp32B(sizeof(DVDPartitionInfo) * 4)] ATTRIBUTE_ALIGN(32); -static u8 __DVDTmdBuffer[OSRoundUp32B(sizeof(ESTitleMeta))] ATTRIBUTE_ALIGN(32); -static u8 __DVDTicketViewBuffer[OSRoundUp32B(sizeof(ESTicketView))] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u8 __DVDGameTocBuffer[OSRoundUp32B(sizeof(DVDGameTOC) * 4)]; +ATTRIBUTE_ALIGN(32) static u8 __DVDPartInfoBuffer[OSRoundUp32B(sizeof(DVDPartitionInfo) * 4)]; +ATTRIBUTE_ALIGN(32) static u8 __DVDTmdBuffer[OSRoundUp32B(sizeof(ESTitleMeta))]; +ATTRIBUTE_ALIGN(32) static u8 __DVDTicketViewBuffer[OSRoundUp32B(sizeof(ESTicketView))]; static OSAlarm FatalAlarm; DVDCommandBlock __DVDStopMotorCommandBlock; diff --git a/libs/revolution/src/dvd/dvdDeviceError.c b/libs/revolution/src/dvd/dvdDeviceError.c index 316346461f..6fa74234ee 100644 --- a/libs/revolution/src/dvd/dvdDeviceError.c +++ b/libs/revolution/src/dvd/dvdDeviceError.c @@ -5,7 +5,7 @@ #include "__os.h" #include "__dvd.h" -static u8 CheckBuffer[32] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u8 CheckBuffer[32]; static volatile BOOL lowDone = TRUE; static volatile u32 lowIntType = 0; diff --git a/libs/revolution/src/dvd/dvd_broadway.c b/libs/revolution/src/dvd/dvd_broadway.c index ab4840791f..c2e8aef89d 100644 --- a/libs/revolution/src/dvd/dvd_broadway.c +++ b/libs/revolution/src/dvd/dvd_broadway.c @@ -8,15 +8,15 @@ static volatile u8 requestInProgress = FALSE; static u8 breakRequested; static u8 callbackInProgress; -static u32 registerBuf[8] ATTRIBUTE_ALIGN(32); -static u32 statusRegister[8] ATTRIBUTE_ALIGN(32); -static u32 controlRegister[8] ATTRIBUTE_ALIGN(32); -static s32 lastTicketError[8] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u32 registerBuf[8]; +ATTRIBUTE_ALIGN(32) static u32 statusRegister[8]; +ATTRIBUTE_ALIGN(32) static u32 controlRegister[8]; +ATTRIBUTE_ALIGN(32) static s32 lastTicketError[8]; static u32 readLength; static u32 spinUpValue; -static diRegVals_t diRegValCache ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static diRegVals_t diRegValCache; static u8 DVDLowInitCalled = FALSE; @@ -42,8 +42,8 @@ typedef struct dvdContext { static int freeDvdContext = 0; static u8 dvdContextsInited = FALSE; -static dvdContext_t dvdContexts[4] ATTRIBUTE_ALIGN(32); -static IOSIoVector ioVec[10] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static dvdContext_t dvdContexts[4]; +ATTRIBUTE_ALIGN(32) static IOSIoVector ioVec[10]; static void* ddrAllocAligned32(const int size) { void* low, *high; diff --git a/libs/revolution/src/dvd/dvderror.c b/libs/revolution/src/dvd/dvderror.c index 7f1e8e52ad..8b12465825 100644 --- a/libs/revolution/src/dvd/dvderror.c +++ b/libs/revolution/src/dvd/dvderror.c @@ -11,8 +11,8 @@ static NANDCommandBlock NandCb; static NANDFileInfo NandInfo; static DVDCBCallback Callback; static u32 NextOffset; -DVDErrorInfo __ErrorInfo ATTRIBUTE_ALIGN(32); -DVDErrorInfo __FirstErrorInfo ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) DVDErrorInfo __ErrorInfo; +ATTRIBUTE_ALIGN(32) DVDErrorInfo __FirstErrorInfo; void cbForNandClose(s32 result, NANDCommandBlock* block) { if (Callback) { diff --git a/libs/revolution/src/esp/esp.c b/libs/revolution/src/esp/esp.c index 68899e2598..aec3e862b1 100644 --- a/libs/revolution/src/esp/esp.c +++ b/libs/revolution/src/esp/esp.c @@ -33,7 +33,7 @@ s32 ESP_CloseLib(void) { s32 ESP_LaunchTitle(u64 titleID, ESTicketView* pTicketView) { s32 ret = 0; - u8 buf[256] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 buf[256]; IOSIoVector* vec = (IOSIoVector*)(buf + 208); u64* id = (u64*)buf; @@ -63,7 +63,7 @@ out: s32 ESP_GetTicketViews(ESTitleId titleId, ESTicketView* ticketViewList, u32* ticketViewCnt) { s32 rv = 0; - u8 __esBuf[256] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 __esBuf[256]; IOSIoVector* v = (IOSIoVector*)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); ESTitleId* p1 = (ESTitleId*)__esBuf; u32* p2 = (u32*)(__esBuf + 32); @@ -111,7 +111,7 @@ out: s32 ESP_DiGetTicketView(const void* ticket, ESTicketView* ticketView) { s32 rv = 0; - u8 __esBuf[256] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 __esBuf[256]; IOSIoVector* v = (IOSIoVector*)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); if (__esFd < 0 || ticketView == NULL) { @@ -142,7 +142,7 @@ out: s32 ESP_DiGetTmd(ESTitleMeta* tmd, u32* tmdSize) { s32 rv = 0; - u8 __esBuf[256] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 __esBuf[256]; IOSIoVector* v = (IOSIoVector*)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); u32* p1 = (u32*)__esBuf; @@ -184,7 +184,7 @@ out: s32 ESP_GetTmdView(ESTitleId titleId, ESTmdView* tmdView, u32* size) { s32 rv = 0; - u8 __esBuf[256] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 __esBuf[256]; IOSIoVector* v = (IOSIoVector*)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); ESTitleId* p1 = (ESTitleId*)__esBuf; u32* p2 = (u32*)(__esBuf + 32); @@ -233,7 +233,7 @@ out: s32 ESP_GetDataDir(ESTitleId titleId, char* dataDir) { s32 rv = 0; - u8 __esBuf[256] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 __esBuf[256]; IOSIoVector* v = (IOSIoVector*)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); ESTitleId* p1 = (ESTitleId*)__esBuf; @@ -260,7 +260,7 @@ out: s32 ESP_GetTitleId(ESTitleId* titleId) { s32 rv = 0; - u8 __esBuf[256] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 __esBuf[256]; IOSIoVector* v = (IOSIoVector*)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); if (__esFd < 0 || titleId == NULL) { @@ -283,7 +283,7 @@ out: s32 ESP_GetConsumption(ESTicketId ticketId, ESLpEntry* entries, u32* nEntries) { s32 rv = 0; - u8 __esBuf[256] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 __esBuf[256]; IOSIoVector* v = (IOSIoVector*)(__esBuf + 256 - 6 * sizeof(IOSIoVector)); ESTicketId* p1 = (ESTicketId*)__esBuf; u32* p2 = (u32*)(__esBuf + 32); diff --git a/libs/revolution/src/fs/fs.c b/libs/revolution/src/fs/fs.c index 1e5f601198..34397254c1 100644 --- a/libs/revolution/src/fs/fs.c +++ b/libs/revolution/src/fs/fs.c @@ -25,7 +25,7 @@ typedef struct isfs_GetUsage { } isfs_GetUsage; typedef struct __isfsCtxt { - u8 ioBuf[ROUNDUP(256)] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 ioBuf[ROUNDUP(256)]; ISFSCallback cb; void* ctxt; u32 func; diff --git a/libs/revolution/src/gx/GXInit.c b/libs/revolution/src/gx/GXInit.c index 0504827170..0ae463d84d 100644 --- a/libs/revolution/src/gx/GXInit.c +++ b/libs/revolution/src/gx/GXInit.c @@ -49,7 +49,7 @@ volatile void* __piReg; GXBool __GXinBegin; #endif -static u16 DefaultTexData[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u16 DefaultTexData[] = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, }; diff --git a/libs/revolution/src/homebuttonLib/nw4hbm/lyt/picture.h b/libs/revolution/src/homebuttonLib/nw4hbm/lyt/picture.h index 4a77129ea7..c34a092a61 100644 --- a/libs/revolution/src/homebuttonLib/nw4hbm/lyt/picture.h +++ b/libs/revolution/src/homebuttonLib/nw4hbm/lyt/picture.h @@ -34,7 +34,7 @@ namespace nw4hbm { private: /* 0x00 (base) */ - /* 0xD4 */ ut::Color mVtxColors[VERTEXCOLOR_MAX] ATTRIBUTE_ALIGN(4); + /* 0xD4 */ ATTRIBUTE_ALIGN(4) ut::Color mVtxColors[VERTEXCOLOR_MAX]; /* 0xE4 */ detail::TexCoordAry mTexCoordAry; }; diff --git a/libs/revolution/src/homebuttonLib/nw4hbm/snd/StrmPlayer.h b/libs/revolution/src/homebuttonLib/nw4hbm/snd/StrmPlayer.h index eae08ba82d..45f682b4b9 100644 --- a/libs/revolution/src/homebuttonLib/nw4hbm/snd/StrmPlayer.h +++ b/libs/revolution/src/homebuttonLib/nw4hbm/snd/StrmPlayer.h @@ -58,7 +58,7 @@ namespace nw4hbm { public: /* 0x14 */ ut::LinkListNode mLinkNode; - static u8 mMramBuf[LOAD_BUFFER_SIZE] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) static u8 mMramBuf[LOAD_BUFFER_SIZE]; }; typedef ut::LinkList LoadCommandList; diff --git a/libs/revolution/src/ipc/ipcclt.c b/libs/revolution/src/ipc/ipcclt.c index 6976775218..449e94ecd0 100644 --- a/libs/revolution/src/ipc/ipcclt.c +++ b/libs/revolution/src/ipc/ipcclt.c @@ -24,7 +24,7 @@ static u32 __relnchFl = 0; typedef struct IOSRpcRequest { IOSResourceRequest request; - IOSIpcCb cb ATTRIBUTE_ALIGN(32); // I am assuming this is aligned due to where cbArg is stored, and I see nothing between cb and callback_arg? + ATTRIBUTE_ALIGN(32) IOSIpcCb cb; // I am assuming this is aligned due to where cbArg is stored, and I see nothing between cb and callback_arg? void* callback_arg; u32 relaunch_flag; OSThreadQueue thread_queue; @@ -37,7 +37,7 @@ static IOSRpcRequest* __relnchRpcSave = 0; #define ROUNDUP(sz) (((u32)(sz) + (IPC_BUF_CNT / 2 - 1)) & ~(u32)(IPC_BUF_CNT / 2 - 1)) -static u8 __rpcBuf[ROUNDUP(sizeof(IOSRpcRequest))] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u8 __rpcBuf[ROUNDUP(sizeof(IOSRpcRequest))]; static struct { u32 rcount; diff --git a/libs/revolution/src/nand/NANDCore.c b/libs/revolution/src/nand/NANDCore.c index c93ec26c9c..8a9818197f 100644 --- a/libs/revolution/src/nand/NANDCore.c +++ b/libs/revolution/src/nand/NANDCore.c @@ -33,8 +33,8 @@ enum LibState { }; static enum LibState s_libState = STATE_NOT_INITIALIZED; -static char s_currentDir[64] ATTRIBUTE_ALIGN(32) = "/"; -static char s_homeDir[64] ATTRIBUTE_ALIGN(32) = ""; +ATTRIBUTE_ALIGN(32) static char s_currentDir[64] = "/"; +ATTRIBUTE_ALIGN(32) static char s_homeDir[64] = ""; static BOOL nandOnShutdown(BOOL final, u32 event); void nandConvertPath(char* abspath, const char* wd, const char* relpath); @@ -262,7 +262,7 @@ s32 nandConvertErrorCode(const ISFSError err) { for (; i < sizeof(ERRMAP) / 4; i = i + 2) { if (ERRMAP[i] == err) { if (err == ISFS_ERROR_ECC_CRIT || err == ISFS_ERROR_HMAC || err == ISFS_ERROR_UNKNOWN || err == IOS_ERROR_UNKNOWN || err == IOS_ERROR_ECC_CRIT) { - char buf[128] ATTRIBUTE_ALIGN(64); + ATTRIBUTE_ALIGN(64) char buf[128]; sprintf(buf, "ISFS error code: %d", err); NANDLoggingAddMessageAsync(nandLoggingCallback, err, buf); } @@ -279,7 +279,7 @@ s32 nandConvertErrorCode(const ISFSError err) { OSReport("CAUTION! Unexpected error code [%d] was found.\n", err); { - char buf[128] ATTRIBUTE_ALIGN(64); + ATTRIBUTE_ALIGN(64) char buf[128]; sprintf(buf, "ISFS unexpected error code: %d", err); NANDLoggingAddMessageAsync(nandLoggingCallback, err, buf); } diff --git a/libs/revolution/src/nand/NANDLogging.c b/libs/revolution/src/nand/NANDLogging.c index 8e620895d5..409fbad527 100644 --- a/libs/revolution/src/nand/NANDLogging.c +++ b/libs/revolution/src/nand/NANDLogging.c @@ -7,7 +7,7 @@ static IOSFd s_fd = -255; static IOSError s_err = ISFS_ERROR_UNKNOWN; static int s_stage; -static char s_message[256] ATTRIBUTE_ALIGN(64); +ATTRIBUTE_ALIGN(64) static char s_message[256]; static NANDLoggingCallback s_callback = 0; static void asyncRoutine(ISFSError, void*); @@ -70,8 +70,8 @@ static void callbackRoutine(BOOL result) { static void asyncRoutine(ISFSError result, void *ctxt) { ISFSError ret = ISFS_ERROR_UNKNOWN; - static char s_rBuf[256] ATTRIBUTE_ALIGN(64); - static char s_wBuf[256] ATTRIBUTE_ALIGN(64); + ATTRIBUTE_ALIGN(64) static char s_rBuf[256]; + ATTRIBUTE_ALIGN(64) static char s_wBuf[256]; ++s_stage; if (s_stage == 2) { diff --git a/libs/revolution/src/nand/nand.c b/libs/revolution/src/nand/nand.c index 6155789690..1fd2640660 100644 --- a/libs/revolution/src/nand/nand.c +++ b/libs/revolution/src/nand/nand.c @@ -293,7 +293,7 @@ s32 NANDMove(const char* path, const char* destDir) { } static ISFSError nandGetFileStatus(IOSFd fd, u32* length, u32* pos) { - ISFSFileStats fstat ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) ISFSFileStats fstat; ISFSError result = ISFS_GetFileStats(fd, &fstat); if (result == ISFS_ERROR_OK) { if (length) { diff --git a/libs/revolution/src/os/OSLaunch.c b/libs/revolution/src/os/OSLaunch.c index 2c57906e95..f82f2ef19f 100644 --- a/libs/revolution/src/os/OSLaunch.c +++ b/libs/revolution/src/os/OSLaunch.c @@ -8,7 +8,7 @@ void __OSRelaunchTitle(u32 resetCode) { s32 rc = 0; u32 ticketCnt = 1; ESTicketView* tik = NULL; - ESTitleId titleId ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) ESTitleId titleId; __OSPlayTimeType type = OSPLAYTIME_PERMANENT; u32 remain = 0; u8* bi2 = NULL; diff --git a/libs/revolution/src/os/OSNet.c b/libs/revolution/src/os/OSNet.c index e68c789734..b749532494 100644 --- a/libs/revolution/src/os/OSNet.c +++ b/libs/revolution/src/os/OSNet.c @@ -85,7 +85,7 @@ NWC24Err NWC24iSynchronizeRtcCounter(BOOL param_0) { } NWC24Err NWC24SuspendScheduler(void) { - static u8 susResult[0x20] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) static u8 susResult[0x20]; NWC24Err rt = NWC24_OK; NWC24Err closeRt = NWC24_OK; IOSFd fd; diff --git a/libs/revolution/src/os/OSPlayRecord.c b/libs/revolution/src/os/OSPlayRecord.c index a1499e71b7..b9743d9946 100644 --- a/libs/revolution/src/os/OSPlayRecord.c +++ b/libs/revolution/src/os/OSPlayRecord.c @@ -2,7 +2,7 @@ #include static BOOL PlayRecordGet = FALSE; -static OSPlayRecord PlayRecord ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static OSPlayRecord PlayRecord; static NANDFileInfo FileInfo; static NANDCommandBlock Block; static s32 PlayRecordState = 9; diff --git a/libs/revolution/src/os/OSPlayTime.c b/libs/revolution/src/os/OSPlayTime.c index 653afad7db..675d88d020 100644 --- a/libs/revolution/src/os/OSPlayTime.c +++ b/libs/revolution/src/os/OSPlayTime.c @@ -7,7 +7,7 @@ #include "__os.h" -OSAlarm __OSExpireAlarm ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) OSAlarm __OSExpireAlarm; OSTime __OSExpireTime; OSPlayTimeCallbackFunc __OSExpireCallback; BOOL __OSExpireSetExpiredFlag; @@ -103,7 +103,7 @@ BOOL __OSWriteExpiredFlag(void) { s32 rv = 0; NANDFileInfo nInfo; BOOL openNInfo = FALSE; - u8 titleId[32] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 titleId[32]; rv = NANDPrivateCreate("/shared2/expired", 63, 0); @@ -162,7 +162,7 @@ BOOL __OSWriteExpiredFlagIfSet(void) { void* __OSPlayTimeRebootThread(void* args) { BOOL enabled; u32 frames, fadeShift = 1; - __OSExpireAIFadeStruct aiFade ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) __OSExpireAIFadeStruct aiFade; __OSExpireAIFade = &aiFade; memset(__OSExpireAIFade, 0, sizeof(__OSExpireAIFadeStruct)); @@ -227,9 +227,9 @@ out: s32 __OSGetPlayTime(ESTicketView* ticket, __OSPlayTimeType* type, u32* playTime) { s32 rv; u32 i; - ESLpEntry lpEntry[8] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) ESLpEntry lpEntry[8]; u32 numCc = 0, seenOther = 0; - ESTicketView ticketAligned ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) ESTicketView ticketAligned; ASSERTLINE(601, ticket && type && playTime); @@ -288,7 +288,7 @@ out: s32 __OSGetPlayTimeCurrent(__OSPlayTimeType* type, u32* playTime) { s32 rv; - ESTicketView ticket ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) ESTicketView ticket; ASSERTLINE(676, type && playTime); diff --git a/libs/revolution/src/os/OSRtc.c b/libs/revolution/src/os/OSRtc.c index 11fa04e05d..d5fa89ee54 100644 --- a/libs/revolution/src/os/OSRtc.c +++ b/libs/revolution/src/os/OSRtc.c @@ -3,7 +3,7 @@ #include "__os.h" -static SramControl Scb ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT); +ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT) static SramControl Scb; // prototypes static int GetRTC(u32* rtc); diff --git a/libs/revolution/src/os/OSStateFlags.c b/libs/revolution/src/os/OSStateFlags.c index 723069d5a6..9283c57499 100644 --- a/libs/revolution/src/os/OSStateFlags.c +++ b/libs/revolution/src/os/OSStateFlags.c @@ -2,7 +2,7 @@ #include #include -static OSStateFlags StateFlags ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static OSStateFlags StateFlags; static u32 CheckSum(OSStateFlags* flags) { u32* ptr, i, sum; diff --git a/libs/revolution/src/os/OSStateTM.c b/libs/revolution/src/os/OSStateTM.c index a81de612cf..d08bf5e6f6 100644 --- a/libs/revolution/src/os/OSStateTM.c +++ b/libs/revolution/src/os/OSStateTM.c @@ -5,14 +5,14 @@ #include -static u32 StmImInBuf[8] ATTRIBUTE_ALIGN(32); -static u32 StmImOutBuf[8] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u32 StmImInBuf[8]; +ATTRIBUTE_ALIGN(32) static u32 StmImOutBuf[8]; -static u32 StmVdInBuf[8] ATTRIBUTE_ALIGN(32); -static u32 StmVdOutBuf[8] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u32 StmVdInBuf[8]; +ATTRIBUTE_ALIGN(32) static u32 StmVdOutBuf[8]; -static u32 StmEhInBuf[8] ATTRIBUTE_ALIGN(32); -static u32 StmEhOutBuf[8] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u32 StmEhInBuf[8]; +ATTRIBUTE_ALIGN(32) static u32 StmEhOutBuf[8]; static OSResetCallback ResetCallback; static OSPowerCallback PowerCallback; diff --git a/libs/revolution/src/os/OSThread.c b/libs/revolution/src/os/OSThread.c index dbe745d17a..447709a17d 100644 --- a/libs/revolution/src/os/OSThread.c +++ b/libs/revolution/src/os/OSThread.c @@ -873,4 +873,4 @@ void* OSGetThreadSpecific(s32 index) { #include "global.h" extern u8 Debug_BBA_804516D0; -u8 Debug_BBA_804516D0 ATTRIBUTE_ALIGN(8); +ATTRIBUTE_ALIGN(8) u8 Debug_BBA_804516D0; diff --git a/libs/revolution/src/sc/scsystem.c b/libs/revolution/src/sc/scsystem.c index 74d78e6bfc..a03fe7b3b7 100644 --- a/libs/revolution/src/sc/scsystem.c +++ b/libs/revolution/src/sc/scsystem.c @@ -75,8 +75,8 @@ static const char ConfDirName[] = "/shared2/sys"; static const char ConfFileName[] = "/shared2/sys/SYSCONF"; static const char ProductInfoFileName[] = "/title/00000001/00000002/data/setting.txt"; -static u8 ConfBuf[0x4000] ATTRIBUTE_ALIGN(32); -static u8 ConfBufForFlush[0x4000] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u8 ConfBuf[0x4000]; +ATTRIBUTE_ALIGN(32) static u8 ConfBufForFlush[0x4000]; static u8 Initialized; static u8 DirtyFlag; diff --git a/libs/revolution/src/wpad/WPAD.c b/libs/revolution/src/wpad/WPAD.c index 20e7509da3..3a0591f396 100644 --- a/libs/revolution/src/wpad/WPAD.c +++ b/libs/revolution/src/wpad/WPAD.c @@ -262,7 +262,7 @@ void WPADiManageHandler(OSAlarm*, OSContext*) { BTA_HhGetAclQueueInfo(); } -u8 __WPADiManageHandlerStack[4096] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) u8 __WPADiManageHandlerStack[4096]; void WPADiManageHandler0(OSAlarm* alarm, OSContext* context) { OSSwitchFiberEx((u32)alarm, (u32)context, 0, 0, (u32)WPADiManageHandler, (u32)(__WPADiManageHandlerStack + sizeof(__WPADiManageHandlerStack))); diff --git a/libs/revolution/src/wud/WUD.c b/libs/revolution/src/wud/WUD.c index 72a2c9b60b..deef3b2624 100644 --- a/libs/revolution/src/wud/WUD.c +++ b/libs/revolution/src/wud/WUD.c @@ -41,7 +41,7 @@ WUDControlBlock _wcb; WUDDevInfo _work; static WUDDiscResp _discResp; SCBtDeviceInfoArray _scArray; -u8 __WUDHandlerStack[0x1000] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) u8 __WUDHandlerStack[0x1000]; extern u8 _scFlush; diff --git a/sdk/include/mods/hook.hpp b/sdk/include/mods/hook.hpp index 6087ff49bb..d0e793204c 100644 --- a/sdk/include/mods/hook.hpp +++ b/sdk/include/mods/hook.hpp @@ -53,4 +53,14 @@ ModResult hook_replace(HookReplaceFn callback, const HookOptions* options = null return hook::replace(callback, options); } +template +ModResult hook_uninstall(const HookService* hooks) { + return hook::uninstall(hooks); +} + +template +ModResult hook_uninstall() { + return hook::uninstall(); +} + } // namespace mods diff --git a/sdk/include/mods/svc/camera.h b/sdk/include/mods/svc/camera.h index 8934340cd6..1dccecfba6 100644 --- a/sdk/include/mods/svc/camera.h +++ b/sdk/include/mods/svc/camera.h @@ -8,7 +8,7 @@ #define CAMERA_SERVICE_ID "dev.twilitrealm.dusklight.camera" #define CAMERA_SERVICE_MAJOR 1u -#define CAMERA_SERVICE_MINOR 0u +#define CAMERA_SERVICE_MINOR 1u /* * Snapshot of a game camera for the frame currently being recorded. @@ -46,6 +46,37 @@ typedef struct CameraInfo { #define CAMERA_INFO_INIT {sizeof(CameraInfo)} +/* 0 is never a valid handle. */ +typedef uint64_t CameraOperatorHandle; + +typedef struct CameraOperatorState { + uint32_t struct_size; + + /* Host inputs. */ + uint64_t frame_counter; + uint64_t ticks; + float aspect; + + /* Initial camera state and callback output. */ + float eye[3]; + float center[3]; + float fovy; + float bank_degrees; +} CameraOperatorState; + +/* Return true to use state for the current frame. Game thread only. */ +typedef bool (*CameraOperateFn)(ModContext* ctx, CameraOperatorState* state, void* user_data); + +typedef struct CameraOperatorDesc { + uint32_t struct_size; + const char* debug_name; + int32_t priority; + CameraOperateFn operate; + void* user_data; +} CameraOperatorDesc; + +#define CAMERA_OPERATOR_DESC_INIT {sizeof(CameraOperatorDesc), NULL, 0, NULL, NULL} + typedef struct CameraService { ServiceHeader header; @@ -55,6 +86,17 @@ typedef struct CameraService { * perspective camera. */ ModResult (*get_camera)(ModContext* ctx, const void* game_view, CameraInfo* out_info); + + /* Minor version 1 */ + + /* + * Register an operator for the main camera. Operators run by descending priority, then + * registration order, until one returns true. debug_name and operate must be set; debug_name + * is copied. out_handle must not be NULL. + */ + ModResult (*register_camera_operator)( + ModContext* ctx, const CameraOperatorDesc* desc, CameraOperatorHandle* out_handle); + ModResult (*unregister_camera_operator)(ModContext* ctx, CameraOperatorHandle handle); } CameraService; MOD_DECLARE_SERVICE( diff --git a/sdk/include/mods/svc/hook.h b/sdk/include/mods/svc/hook.h index e9c64b1ca4..288db3cc14 100644 --- a/sdk/include/mods/svc/hook.h +++ b/sdk/include/mods/svc/hook.h @@ -7,20 +7,22 @@ #endif /* - * Intercept game functions by address. Prefer the typed helpers in mods/svc/hook.hpp - * (mods::hook::add_pre/add_post/replace over a &Class::method): they generate the - * trampoline and hide install/dispatch, which are the low-level primitives those helpers - * build. resolve() maps a symbol name to an address for targets you can't name at compile time - * (file-local statics included). + * Hooks allow intercepting calls to game functions, allowing you to: + * - Modify arguments + * - Perform your own work before (pre), after (post) or instead of (replace) the original call + * - From a pre hook, conditionally skip the original call and return your own value * - * Every call is game-thread-only. Install and removal must run with no hooked function on the - * stack; the loader guarantees this by applying mod lifecycle changes between frames, which is - * why hooking a function that never returns (the outermost loop) makes a mod un-unloadable. + * In most cases, you'll want to instead use the C++ helpers in mods/svc/hook.hpp + * (mods::hook::add_pre/add_post/replace). They generate the trampoline passed to + * install and provide compile-time type checking. + * + * resolve() resolves an address by symbol name for targets you can't name at compile time + * (file-local statics included). */ #define HOOK_SERVICE_ID "dev.twilitrealm.dusklight.hook" #define HOOK_SERVICE_MAJOR 1u -#define HOOK_SERVICE_MINOR 0u +#define HOOK_SERVICE_MINOR 1u /* Symbol flags reported by resolve() */ typedef enum HookSymbolFlags { @@ -72,11 +74,18 @@ typedef struct HookService { ServiceHeader header; /* - * Install a trampoline detour on fn_addr and return the address to call the original through in - * *out_original_fn. The typed helpers generate the trampoline and call this; mods normally - * don't. The first mod to install a given target owns the live detour; later mods register as - * candidates so a hook survives the owner unloading (the detour is handed off and every - * original pointer is rewritten). Idempotent per (mod, out slot). + * Install a hook on fn_addr. + * + * trampoline_fn must point to a function that matches the original function's signature and + * dispatches pre- and post- hooks. This dispatch trampoline is normally generated at compile + * time using C++ template instantiation (see mods/svc/hook.hpp). + * + * The first hook install on a target will implicitly install a detour (patched instructions + * on the target that jump to the dispatch trampoline). When all hooks are uninstalled from a + * target, the detour is completely uninstalled. + * + * The address that the dispatch trampoline should call the original function through is written + * to out_original_fn. */ ModResult (*install)( ModContext* ctx, void* fn_addr, void* trampoline_fn, void** out_original_fn); @@ -116,6 +125,16 @@ typedef struct HookService { */ ModResult (*resolve)( ModContext* ctx, const char* symbol, void** out_addr, HookSymbolFlags* out_flags); + + /* Minor version 1 */ + + /* + * Uninstall the current mod's hook on fn_addr and unregister all callbacks. + * If no other mods have a hook installed on the target, the detour is uninstalled entirely. + * + * original_fn_slot must match the out_original_fn passed to install. + */ + ModResult (*uninstall)(ModContext* ctx, void* fn_addr, void** original_fn_slot); } HookService; MOD_DECLARE_SERVICE(HookService, svc_hook, HOOK_SERVICE_ID, HOOK_SERVICE_MAJOR, HOOK_SERVICE_MINOR); diff --git a/sdk/include/mods/svc/hook.hpp b/sdk/include/mods/svc/hook.hpp index e61562da36..eab3115d01 100644 --- a/sdk/include/mods/svc/hook.hpp +++ b/sdk/include/mods/svc/hook.hpp @@ -238,5 +238,27 @@ ModResult replace(HookReplaceFn callback, const HookOptions* options = nullptr) return replace(svc_hook, callback, options); } +template +ModResult uninstall(const HookService* hooks) { + if (hooks == nullptr || !SERVICE_HAS(hooks, HookService, uninstall) || + hooks->uninstall == nullptr || Entry::target == nullptr) + { + return MOD_UNAVAILABLE; + } + + const ModResult result = + hooks->uninstall(mod_ctx, Entry::target, reinterpret_cast(&Entry::g_orig)); + if (result == MOD_OK) { + Entry::hooks = nullptr; + Entry::g_orig = nullptr; + } + return result; +} + +template +ModResult uninstall() { + return uninstall(svc_hook); +} + } // namespace hook } // namespace mods diff --git a/sdk/include/mods/svc/host.h b/sdk/include/mods/svc/host.h index 24265cab99..45d89eea3e 100644 --- a/sdk/include/mods/svc/host.h +++ b/sdk/include/mods/svc/host.h @@ -13,7 +13,7 @@ #define HOST_SERVICE_ID "dev.twilitrealm.dusklight.host" #define HOST_SERVICE_MAJOR 2u -#define HOST_SERVICE_MINOR 1u +#define HOST_SERVICE_MINOR 2u /* * Ignore unknown values: later service minors may add events. @@ -96,15 +96,24 @@ typedef struct HostService { ModContext* ctx, ModLifecycleFn fn, void* user_data, uint64_t* out_handle); ModResult (*unwatch_mod_lifecycle)(ModContext* ctx, uint64_t handle); + /* Minor version 1 */ + /* * Read-only directory containing this platform's packaged native runtime: the mod module * and any RUNTIME_LIBRARIES. The path is absolute and remains valid until mod_shutdown * returns. Libraries loaded dynamically from here are owned by the mod and must be unloaded * during mod_shutdown. - * - * Added in minor version 1. */ const char* (*native_dir)(ModContext* ctx); + + /* Minor version 2 */ + + /* + * A persistent writable directory reserved for the calling mod, created on first use. + * + * The returned path remains valid until mod_shutdown returns. *out_path is null on failure. + */ + ModResult (*data_dir)(ModContext* ctx, const char** out_path); } HostService; MOD_DECLARE_SERVICE(HostService, svc_host, HOST_SERVICE_ID, HOST_SERVICE_MAJOR, HOST_SERVICE_MINOR); diff --git a/sdk/include/mods/svc/resource.h b/sdk/include/mods/svc/resource.h index 57fddc9778..60b609d2a2 100644 --- a/sdk/include/mods/svc/resource.h +++ b/sdk/include/mods/svc/resource.h @@ -8,7 +8,8 @@ /* * Read-only access to the res/ tree of the calling mod's own bundle. Reload serves the new - * bundle's contents. For writable storage, use HostService::mod_dir. + * bundle's contents. Use HostService::data_dir for persistent storage or HostService::mod_dir + * for temporary storage. */ #define RESOURCE_SERVICE_ID "dev.twilitrealm.dusklight.resource" diff --git a/src/d/actor/d_a_movie_player.cpp b/src/d/actor/d_a_movie_player.cpp index a830f1440f..5f4290611f 100644 --- a/src/d/actor/d_a_movie_player.cpp +++ b/src/d/actor/d_a_movie_player.cpp @@ -218,21 +218,21 @@ static void __THPAudioInitialize(THPAudioDecodeInfo* info, u8* ptr) { } #if !TARGET_PC -static u8 THPStatistics[1120] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u8 THPStatistics[1120]; -static THPHuffmanTab* Ydchuff ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static THPHuffmanTab* Ydchuff; -static THPHuffmanTab* Udchuff ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static THPHuffmanTab* Udchuff; -static THPHuffmanTab* Vdchuff ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static THPHuffmanTab* Vdchuff; -static THPHuffmanTab* Yachuff ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static THPHuffmanTab* Yachuff; -static THPHuffmanTab* Uachuff ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static THPHuffmanTab* Uachuff; -static THPHuffmanTab* Vachuff ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static THPHuffmanTab* Vachuff; -static f32 __THPIDCTWorkspace[64] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static f32 __THPIDCTWorkspace[64]; static u8* __THPHuffmanBits; @@ -240,11 +240,11 @@ static u8* __THPHuffmanSizeTab; static u16* __THPHuffmanCodeTab; -static THPSample* Gbase ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static THPSample* Gbase; -static u32 Gwid ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u32 Gwid; -static f32* Gq ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static f32* Gq; static u8* __THPLCWork512[3]; @@ -3582,7 +3582,7 @@ static void daMP_MixAudio(s16* destination, s16*, u32 sample) { static BOOL daMP_Initialized; -static u32 daMP_WorkBuffer[16] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u32 daMP_WorkBuffer[16]; static OSMessageQueue daMP_PrepareReadyQueue; @@ -3604,7 +3604,7 @@ static void* daMP_CurAudioBuffer; static s32 daMP_AudioSystem; -static u8 daMP_SoundBuffer[2][0x8C0] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u8 daMP_SoundBuffer[2][0x8C0]; static s16* daMP_audioCallbackWithMSound(s32 sample) { if (daMP_ActivePlayer.open == 0 || daMP_ActivePlayer.internalState != 2 || daMP_ActivePlayer.audioExist == 0) { diff --git a/src/d/actor/d_a_obj_flag2.cpp b/src/d/actor/d_a_obj_flag2.cpp index a22e1216d8..20fa2021e9 100644 --- a/src/d/actor/d_a_obj_flag2.cpp +++ b/src/d/actor/d_a_obj_flag2.cpp @@ -101,7 +101,7 @@ static f32 l_texCoord[42] = { 0.8f, 0.9f, 1.0, 0.0, 1.0, 0.2f, 1.0, 0.4f, 1.0, 0.6f, 1.0, 0.8f, 1.0, 1.0, }; -static u8 l_pennant_flagDL[152] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_pennant_flagDL[152] = { 0x98, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x98, 0x00, 0x09, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index 888f9d9ccf..7dc4fd21ce 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -29,6 +29,7 @@ #endif #if TARGET_PC +#include "dusk/camera_operators.hpp" #include "dusk/frame_interpolation.h" #include "dusk/logging.h" #include "dusk/action_bindings.h" @@ -1053,7 +1054,7 @@ void dCamera_c::debugDrawInit() { bool dCamera_c::Run() { #if TARGET_PC ResetView(); - if (executeDebugFlyCam()) { + if (executeDebugFlyCam() || dusk::mods::camera_run_operators(this)) { mFrameCounter++; mTicks++; return true; diff --git a/src/d/d_com_inf_game.cpp b/src/d/d_com_inf_game.cpp index cfadb5aa8a..61aa0dc179 100644 --- a/src/d/d_com_inf_game.cpp +++ b/src/d/d_com_inf_game.cpp @@ -2469,7 +2469,7 @@ struct field_data { }; void dComIfGp_calcNowRegion() { - u8 buffer[0x800] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 buffer[0x800]; dComIfGp_getFieldMapArchive2()->readResource(buffer, 0x800, "dat/field.dat"); u8* entry_num_p = &buffer[((field_data_header*)buffer)->field_0x4]; @@ -2525,7 +2525,7 @@ void dComIfGp_calcNowRegion() { } u8 dComIfG_getNowCalcRegion() { - u8 buffer[0x800] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 buffer[0x800]; dComIfGp_getFieldMapArchive2()->readResource(buffer, 0x800, "dat/field.dat"); u8* entry_num_p = &buffer[((field_data_header*)buffer)->field_0x4]; diff --git a/src/d/d_drawlist.cpp b/src/d/d_drawlist.cpp index 8552ead16e..e8b4464dee 100644 --- a/src/d/d_drawlist.cpp +++ b/src/d/d_drawlist.cpp @@ -529,14 +529,14 @@ void dDlst_2DT2_c::draw() { dComIfGp_getCurrentGrafPort()->setup2D(); } -static u8 l_frontZMat[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_frontZMat[] = { 0x61, 0x40, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x10, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static u8 l_frontNoZSubMat[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_frontNoZSubMat[] = { 0x61, 0x40, 0x00, 0x00, 0x06, 0x61, 0x41, 0x00, 0x09, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -547,14 +547,14 @@ static Vec l_shadowVolPos[] = { {1.0f, -1.0f, 0.0f}, {1.0f, -1.0f, -300.0f}, {1.0f, 1.0f, 0.0f}, {1.0f, 1.0f, -300.0f}, }; -static u8 l_shadowVolDL[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_shadowVolDL[] = { 0x80, 0x00, 0x18, 0x06, 0x02, 0x03, 0x07, 0x00, 0x04, 0x05, 0x01, 0x06, 0x04, 0x00, 0x02, 0x07, 0x05, 0x04, 0x06, 0x03, 0x01, 0x05, 0x07, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static u8 l_shadowProjMat[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_shadowProjMat[] = { 0x61, 0x28, 0x38, 0x03, 0xC0, 0x61, 0xC0, 0x08, 0xFF, 0xFF, 0x61, 0xC1, 0x08, 0xE6, 0x70, 0x61, 0x43, 0x00, 0x00, 0x01, 0x61, 0x40, 0x00, 0x00, 0x07, 0x61, 0x41, 0x00, 0x04, 0xAD, 0x61, 0xF3, 0x64, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x3F, 0x00, 0x00, 0x00, 0x01, 0x10, @@ -563,7 +563,7 @@ static u8 l_shadowProjMat[] ATTRIBUTE_ALIGN(32) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static u8 l_shadowVolMat[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_shadowVolMat[] = { 0x61, 0x28, 0x38, 0x00, 0x00, 0x61, 0xC0, 0x08, 0xFF, 0xFC, 0x61, 0xC1, 0x08, 0xFF, 0x90, 0x61, 0x43, 0x00, 0x00, 0x41, 0x61, 0x40, 0x00, 0x00, 0x0D, 0x61, 0x41, 0x00, 0x01, 0x35, 0x61, 0xF3, 0x7F, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10, @@ -572,7 +572,7 @@ static u8 l_shadowVolMat[] ATTRIBUTE_ALIGN(32) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static u8 l_clearMat[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_clearMat[] = { 0x61, 0x28, 0x38, 0x00, 0x00, 0x61, 0xC0, 0x08, 0xFF, 0xFF, 0x61, 0xC1, 0x08, 0xFF, 0xA0, 0x61, 0x40, 0x00, 0x00, 0x06, 0x61, 0x41, 0x00, 0x00, 0x14, 0x61, 0xF3, 0x7F, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x09, 0x00, @@ -581,7 +581,7 @@ static u8 l_clearMat[] ATTRIBUTE_ALIGN(32) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static u8 l_frontMat[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_frontMat[] = { 0x61, 0x28, 0x38, 0x00, 0x00, 0x61, 0xC0, 0x08, 0xFF, 0xFF, 0x61, 0xC1, 0x08, 0xFF, 0x90, 0x61, 0x43, 0x00, 0x00, 0x41, 0x61, 0x40, 0x00, 0x00, 0x07, 0x61, 0x41, 0x00, 0x01, 0x15, 0x10, 0x00, 0x00, 0x10, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x09, 0x00, @@ -590,7 +590,7 @@ static u8 l_frontMat[] ATTRIBUTE_ALIGN(32) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static u8 l_backSubMat[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_backSubMat[] = { 0x61, 0x41, 0x00, 0x09, 0x35, 0x10, 0x00, 0x00, 0x10, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -604,7 +604,7 @@ static Vec l_simpleShadowPos[] = { {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, }; -static u8 l_shadowVolumeDL[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_shadowVolumeDL[] = { 0x98, 0x00, 0x05, 0x03, 0x09, 0x01, 0x07, 0x05, 0x98, 0x00, 0x05, 0x04, 0x06, 0x00, 0x08, 0x02, 0x98, 0x00, 0x04, 0x04, 0x05, 0x06, 0x07, 0x98, 0x00, 0x04, 0x02, 0x03, 0x04, 0x05, 0x98, 0x00, 0x04, 0x08, 0x09, 0x02, 0x03, 0x98, 0x00, 0x04, 0x06, 0x07, 0x08, 0x09, 0x98, @@ -613,7 +613,7 @@ static u8 l_shadowVolumeDL[] ATTRIBUTE_ALIGN(32) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static u8 l_shadowSealTexDL[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_shadowSealTexDL[] = { 0x61, 0x28, 0x38, 0x03, 0xC0, 0x61, 0x40, 0x00, 0x00, 0x06, 0x61, 0x41, 0x00, 0x06, 0x15, 0x10, 0x00, 0x00, 0x10, 0x3F, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x40, 0x01, 0x80, 0x00, 0x04, 0x0A, 0x00, 0x00, 0x0B, @@ -622,7 +622,7 @@ static u8 l_shadowSealTexDL[] ATTRIBUTE_ALIGN(32) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static u8 l_shadowSealTex2DL[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_shadowSealTex2DL[] = { 0x61, 0x28, 0x38, 0x03, 0xC0, 0x61, 0x40, 0x00, 0x00, 0x06, 0x61, 0x41, 0x00, 0x06, 0x15, 0x10, 0x00, 0x00, 0x10, 0x3F, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x40, 0x01, 0x80, 0x00, 0x04, 0x0A, 0x00, 0x00, 0x0B, @@ -631,7 +631,7 @@ static u8 l_shadowSealTex2DL[] ATTRIBUTE_ALIGN(32) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static u8 l_shadowSealDL[] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_shadowSealDL[] = { 0x10, 0x00, 0x00, 0x10, 0x0E, 0x00, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x05, 0x00, 0x61, 0x28, 0x38, 0x00, 0x00, 0x61, 0xC0, 0x08, 0xFF, 0xFF, 0x61, 0xC1, 0x08, 0xFF, 0xB0, 0x61, 0x40, 0x00, 0x00, 0x06, 0x61, 0x41, 0x00, 0x06, 0xED, 0x10, 0x00, @@ -1534,7 +1534,7 @@ void dDlst_shadowControl_c::reset() { } void dDlst_shadowControl_c::imageDraw(Mtx param_0) { - static u8 l_matDL[] ATTRIBUTE_ALIGN(32) = { + ATTRIBUTE_ALIGN(32) static u8 l_matDL[] = { 0x10, 0x00, 0x00, 0x10, 0x0E, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x04, 0x00, 0x61, 0x28, 0x38, 0x00, 0x00, 0x61, 0xC0, 0x08, 0xFF, 0xF2, 0x61, 0xC1, 0x08, 0xFF, 0x90, 0x61, 0x43, 0x00, 0x00, 0x41, 0x61, 0xF3, 0x7F, 0x00, diff --git a/src/d/d_lib.cpp b/src/d/d_lib.cpp index 91b7726459..d83d4f62c0 100644 --- a/src/d/d_lib.cpp +++ b/src/d/d_lib.cpp @@ -300,7 +300,7 @@ BOOL dLib_checkActorInRectangle(fopAc_ac_c* param_0, fopAc_ac_c* param_1, cXyz c } u32 dLib_getExpandSizeFromAramArchive(JKRAramArchive* i_aramArchive, char const* param_2) { - u8 header[32] ATTRIBUTE_ALIGN(32); + ATTRIBUTE_ALIGN(32) u8 header[32]; JUT_ASSERT(1252, i_aramArchive != NULL); u32 address = i_aramArchive->getAramAddress(param_2); if (address == 0) { diff --git a/src/d/d_menu_dmap_map.cpp b/src/d/d_menu_dmap_map.cpp index 825142bb3a..bc63706617 100644 --- a/src/d/d_menu_dmap_map.cpp +++ b/src/d/d_menu_dmap_map.cpp @@ -172,7 +172,7 @@ int renderingDmap_c::getLineWidth(int param_0) { return var_r31; } -static u32 const l_paletteDmap_m[60] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u32 const l_paletteDmap_m[60] = { 0x00000000, 0x00000000, 0x80008000, @@ -680,7 +680,7 @@ f32 dMenu_DmapMapCtrl_c::getZoomCmPerPixel() { return var_f29; } -static u32 l_data[61] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u32 l_data[61] = { 0x80008000, 0x80008000, 0x00000000, diff --git a/src/dusk/camera_operators.hpp b/src/dusk/camera_operators.hpp new file mode 100644 index 0000000000..c4ba650dfd --- /dev/null +++ b/src/dusk/camera_operators.hpp @@ -0,0 +1,9 @@ +#pragma once + +class dCamera_c; + +namespace dusk::mods { + +bool camera_run_operators(dCamera_c* camera); + +} // namespace dusk::mods diff --git a/src/dusk/mod_loader.hpp b/src/dusk/mod_loader.hpp index fad9ba1501..bf3e93aa53 100644 --- a/src/dusk/mod_loader.hpp +++ b/src/dusk/mod_loader.hpp @@ -166,6 +166,8 @@ struct LoadedMod { std::filesystem::path dir; // Stable UTF-8 storage for HostService::mod_dir. std::string dirUtf8; + // Stable UTF-8 storage for HostService::data_dir. + std::string dataDirUtf8; uint32_t searchDirIndex = 0; // Native lib is dlopen'd in place and stays resident for the session. Reload is unsupported. diff --git a/src/dusk/mods/svc/camera.cpp b/src/dusk/mods/svc/camera.cpp index 37057e2397..60fbf42499 100644 --- a/src/dusk/mods/svc/camera.cpp +++ b/src/dusk/mods/svc/camera.cpp @@ -1,13 +1,24 @@ #include "registry.hpp" +#include "slot_map.hpp" +#include "dusk/camera_operators.hpp" #include "dusk/mods/loader/loader.hpp" #include "mods/svc/camera.h" +#include "SSystem/SComponent/c_angle.h" +#include "d/d_camera.h" +#include "d/d_com_inf_game.h" +#include "f_op/f_op_camera_mng.h" #include "f_op/f_op_view.h" #include "m_Do/m_Do_mtx.h" +#include #include #include +#include +#include +#include +#include namespace dusk::mods::svc { namespace { @@ -117,9 +128,125 @@ ModResult camera_get_camera_from_view( return snapshot_view(static_cast(gameView), outInfo); } +struct CameraOperator { + std::string debugName; + int32_t priority = 0; + uint64_t sequence = 0; + CameraOperateFn operate = nullptr; + void* userData = nullptr; +}; + +SlotMap sOperators; +uint64_t sNextOperatorSequence = 0; + +ModResult camera_register_operator( + ModContext* context, const CameraOperatorDesc* desc, CameraOperatorHandle* outHandle) { + if (outHandle != nullptr) { + *outHandle = 0; + } + + auto* mod = mod_from_context(context); + if (mod == nullptr || desc == nullptr || desc->struct_size < sizeof(CameraOperatorDesc) || + desc->debug_name == nullptr || desc->debug_name[0] == '\0' || desc->operate == nullptr || + outHandle == nullptr) + { + return MOD_INVALID_ARGUMENT; + } + + *outHandle = sOperators.emplace(*mod, CameraOperator{ + .debugName = desc->debug_name, + .priority = desc->priority, + .sequence = sNextOperatorSequence++, + .operate = desc->operate, + .userData = desc->user_data, + }); + return MOD_OK; +} + +ModResult camera_unregister_operator(ModContext* context, CameraOperatorHandle handle) { + auto* mod = mod_from_context(context); + if (mod == nullptr || handle == 0) { + return MOD_INVALID_ARGUMENT; + } + return sOperators.erase_owned(handle, *mod) ? MOD_OK : MOD_INVALID_ARGUMENT; +} + +CameraOperatorState make_operator_state(const dCamera_c& camera) { + return CameraOperatorState{ + .struct_size = sizeof(CameraOperatorState), + .frame_counter = camera.mFrameCounter, + .ticks = camera.mTicks, + .aspect = mDoGph_gInf_c::getAspect(), + .eye = {camera.mEye.x, camera.mEye.y, camera.mEye.z}, + .center = {camera.mCenter.x, camera.mCenter.y, camera.mCenter.z}, + .fovy = camera.mFovy, + .bank_degrees = camera.mBank.Degree(), + }; +} + +bool run_operators(dCamera_c* camera) { + auto* mainCamera = dComIfGp_getCamera(0); + if (camera == nullptr || mainCamera == nullptr || &mainCamera->mCamera != camera) { + return false; + } + + struct PendingOperator { + CameraOperatorHandle handle; + CameraOperator value; + LoadedMod* owner; + }; + std::vector operators; + sOperators.for_each([&](CameraOperatorHandle handle, const auto& entry) { + operators.push_back({.handle = handle, .value = entry.value, .owner = entry.owner}); + }); + std::ranges::sort(operators, [](const PendingOperator& lhs, const PendingOperator& rhs) { + if (lhs.value.priority != rhs.value.priority) { + return lhs.value.priority > rhs.value.priority; + } + return lhs.value.sequence < rhs.value.sequence; + }); + + const auto initialState = make_operator_state(*camera); + for (const auto& entry : operators) { + if (!entry.owner->active || sOperators.find(entry.handle) == nullptr) { + continue; + } + + auto state = initialState; + bool useState = false; + try { + useState = + entry.value.operate(entry.owner->context.get(), &state, entry.value.userData); + } catch (const std::exception& e) { + fail_mod(*entry.owner, MOD_ERROR, + fmt::format( + "exception in camera operator '{}': {}", entry.value.debugName, e.what())); + } catch (...) { + fail_mod(*entry.owner, MOD_ERROR, + fmt::format("unknown exception in camera operator '{}'", entry.value.debugName)); + } + + if (!useState) { + continue; + } + + camera->Reset(cXyz{state.center[0], state.center[1], state.center[2]}, + cXyz{state.eye[0], state.eye[1], state.eye[2]}, state.fovy, + cAngle::Degree_to_SAngle(state.bank_degrees)); + return true; + } + return false; +} + +void camera_mod_detached(LoadedMod& mod) { + sOperators.erase_all(mod); +} + constexpr CameraService s_cameraService{ .header = SERVICE_HEADER(CameraService, CAMERA_SERVICE_MAJOR, CAMERA_SERVICE_MINOR), .get_camera = camera_get_camera_from_view, + .register_camera_operator = camera_register_operator, + .unregister_camera_operator = camera_unregister_operator, }; } // namespace @@ -129,6 +256,11 @@ constinit const ServiceModule g_cameraModule{ .majorVersion = CAMERA_SERVICE_MAJOR, .minorVersion = CAMERA_SERVICE_MINOR, .service = &s_cameraService, + .modDetached = camera_mod_detached, }; } // namespace dusk::mods::svc + +bool dusk::mods::camera_run_operators(dCamera_c* camera) { + return svc::run_operators(camera); +} diff --git a/src/dusk/mods/svc/hook.cpp b/src/dusk/mods/svc/hook.cpp index ec967ae7e6..d8a9005deb 100644 --- a/src/dusk/mods/svc/hook.cpp +++ b/src/dusk/mods/svc/hook.cpp @@ -86,6 +86,7 @@ struct InstalledHook { InstalledBackend backend{}; void* original = nullptr; ModContext* active = nullptr; + void** activeStore = nullptr; std::vector candidates; }; @@ -143,6 +144,15 @@ void sort_hooks(std::vector& hooks) { }); } +bool erase_callbacks(HookSlot& slot, ModContext* context) { + std::erase_if(slot.pre, [&](const PreHookFn& hook) { return hook.context == context; }); + std::erase_if(slot.post, [&](const VoidHookFn& hook) { return hook.context == context; }); + if (slot.replace.context == context) { + slot.replace = {}; + } + return slot.pre.empty() && slot.post.empty() && slot.replace.replaceCallback == nullptr; +} + // Once a hook is installed, funchook has patched the target's entry: its bytes lead to the // detour, not the function, so canonicalization must stop there. [[maybe_unused]] bool installed_target(void* addr) { @@ -336,6 +346,46 @@ bool handoff_backend( #endif } +bool handoff_hook(void* target, InstalledHook& entry) { +#if DUSK_HAS_PREPATCH + const bool prepatched = entry.backend.kind == BackendKind::Prepatch; +#else + constexpr bool prepatched = false; +#endif + if (!prepatched) { + deactivate_backend(target, entry.backend); + } + + entry.active = nullptr; + entry.activeStore = nullptr; + for (auto& candidate : entry.candidates) { + void* original = nullptr; + if (!handoff_backend(target, entry, candidate, &original)) { + continue; + } + entry.original = original; + entry.active = candidate.context; + entry.activeStore = candidate.origStore; + break; + } + + if (entry.active == nullptr) { + DuskLog.warn("HookSystem: no reinstallable trampoline for {:p}; hooks there are " + "disabled until a mod reinstalls one", + target); + for (auto& candidate : entry.candidates) { + *candidate.origStore = target; + } + deactivate_backend(target, entry.backend); + return false; + } + + for (auto& candidate : entry.candidates) { + *candidate.origStore = entry.original; + } + return true; +} + ModResult hook_install(ModContext* context, void* fnAddr, void* trampolineFn, void** outOriginal) { if (fnAddr == nullptr || trampolineFn == nullptr || outOriginal == nullptr) { return MOD_INVALID_ARGUMENT; @@ -390,6 +440,7 @@ ModResult hook_install(ModContext* context, void* fnAddr, void* trampolineFn, vo entry.backend = backend; entry.original = *outOriginal; entry.active = context; + entry.activeStore = outOriginal; entry.candidates.push_back({context, trampolineFn, outOriginal, s_nextOrder++}); return MOD_OK; } @@ -459,6 +510,57 @@ ModResult hook_replace( return MOD_INVALID_ARGUMENT; } +ModResult hook_uninstall(ModContext* context, void* fnAddr, void** originalFnSlot) { + if (context == nullptr || fnAddr == nullptr || originalFnSlot == nullptr) { + return MOD_INVALID_ARGUMENT; + } + + fnAddr = resolve_target(fnAddr); + if (!declared_target(context, fnAddr)) { + return reject_undeclared(context, fnAddr); + } + + const auto key = reinterpret_cast(fnAddr); + const auto installedIt = s_installed.find(key); + if (installedIt == s_installed.end()) { + return MOD_INVALID_ARGUMENT; + } + + auto& entry = installedIt->second; + const auto candidateIt = + std::ranges::find_if(entry.candidates, [&](const HookCandidate& candidate) { + return candidate.context == context && candidate.origStore == originalFnSlot; + }); + if (candidateIt == entry.candidates.end()) { + return MOD_INVALID_ARGUMENT; + } + + if (const auto registryIt = s_registry.find(key); + registryIt != s_registry.end() && erase_callbacks(registryIt->second, context)) + { + s_registry.erase(registryIt); + } + + const bool removedActive = entry.activeStore == originalFnSlot; + entry.candidates.erase(candidateIt); + *originalFnSlot = nullptr; + if (!removedActive) { + return MOD_OK; + } + + auto* target = reinterpret_cast(key); + if (entry.candidates.empty()) { + deactivate_backend(target, entry.backend); + s_installed.erase(installedIt); + return MOD_OK; + } + if (!handoff_hook(target, entry)) { + s_installed.erase(installedIt); + return MOD_ERROR; + } + return MOD_OK; +} + ModResult hook_dispatch_pre( ModContext*, void* fnAddr, void* args, void* retval, int* outSkipOriginal) { if (outSkipOriginal != nullptr) { @@ -775,13 +877,7 @@ void hook_remove_mod(LoadedMod& mod) { s_declaredTargets.erase(context); for (auto it = s_registry.begin(); it != s_registry.end();) { - auto& slot = it->second; - std::erase_if(slot.pre, [&](const PreHookFn& hook) { return hook.context == context; }); - std::erase_if(slot.post, [&](const VoidHookFn& hook) { return hook.context == context; }); - if (slot.replace.context == context) { - slot.replace = {}; - } - if (slot.pre.empty() && slot.post.empty() && slot.replace.replaceCallback == nullptr) { + if (erase_callbacks(it->second, context)) { it = s_registry.erase(it); } else { ++it; @@ -806,44 +902,12 @@ void hook_remove_mod(LoadedMod& mod) { continue; } - // A prepatch may be atomically updated directly. - // Funchook must first restore the original instructions before reinstalling. -#if DUSK_HAS_PREPATCH - const bool prepatched = entry.backend.kind == BackendKind::Prepatch; -#else - constexpr bool prepatched = false; -#endif - if (!prepatched) { - deactivate_backend(target, entry.backend); - } - entry.active = nullptr; - for (auto& cand : entry.candidates) { - void* original = nullptr; - if (!handoff_backend(target, entry, cand, &original)) { - continue; - } - entry.original = original; - entry.active = cand.context; - DuskLog.info("HookSystem: replaced trampoline for {:p}: {} -> {} (tramp={:p})", target, - mod_id_from_context(context), mod_id_from_context(cand.context), cand.trampoline); - break; - } - - if (entry.active == nullptr) { - DuskLog.warn("HookSystem: no reinstallable trampoline for {:p}; hooks there are " - "disabled until a mod reinstalls one", - target); - for (auto& cand : entry.candidates) { - *cand.origStore = target; - } - deactivate_backend(target, entry.backend); + if (!handoff_hook(target, entry)) { it = s_installed.erase(it); continue; } - - for (auto& cand : entry.candidates) { - *cand.origStore = entry.original; - } + DuskLog.info("HookSystem: replaced trampoline for {:p}: {} -> {}", target, + mod_id_from_context(context), mod_id_from_context(entry.active)); ++it; } } @@ -862,6 +926,9 @@ ModResult hook_add_post(ModContext*, void*, HookPostFn, const HookOptions*) { ModResult hook_replace(ModContext*, void*, HookReplaceFn, const HookOptions*) { return MOD_UNSUPPORTED; } +ModResult hook_uninstall(ModContext*, void*, void**) { + return MOD_UNSUPPORTED; +} ModResult hook_dispatch_pre(ModContext*, void*, void*, void*, int* outSkipOriginal) { if (outSkipOriginal != nullptr) { *outSkipOriginal = 0; @@ -902,6 +969,7 @@ constexpr HookService s_hookService{ .dispatch_pre = hook_dispatch_pre, .dispatch_post = hook_dispatch_post, .resolve = hook_resolve, + .uninstall = hook_uninstall, }; } // namespace diff --git a/src/dusk/mods/svc/host.cpp b/src/dusk/mods/svc/host.cpp index 7d6e15b809..a8e975e22f 100644 --- a/src/dusk/mods/svc/host.cpp +++ b/src/dusk/mods/svc/host.cpp @@ -1,13 +1,17 @@ #include "registry.hpp" #include "slot_map.hpp" +#include "dusk/main.h" #include "dusk/mods/loader/loader.hpp" +#include "dusk/mods/log_buffer.hpp" #include "dusk/mods/manifest.hpp" #include "fmt/format.h" #include -#include +#include #include +#include +#include namespace dusk::mods::svc { namespace { @@ -68,6 +72,41 @@ const char* host_native_dir(ModContext* context) { return mod != nullptr ? mod->nativeDirUtf8.c_str() : ""; } +ModResult host_data_dir(ModContext* context, const char** outPath) { + if (outPath == nullptr) { + return MOD_INVALID_ARGUMENT; + } + *outPath = nullptr; + + auto* mod = mod_from_context(context); + if (mod == nullptr) { + return MOD_INVALID_ARGUMENT; + } + + if (mod->dataDirUtf8.empty()) { + namespace fs = std::filesystem; + std::error_code ec; + const fs::path path = fs::absolute(dusk::ConfigPath / "mod_data" / mod->metadata.id, ec); + if (ec) { + log::write(mod->metadata.id, LOG_LEVEL_ERROR, + "failed to resolve persistent mod data directory: {}", ec.message()); + return MOD_ERROR; + } + + fs::create_directories(path, ec); + if (ec) { + log::write(mod->metadata.id, LOG_LEVEL_ERROR, + "failed to create persistent mod data directory {}: {}", + borealis::io::fs_path_to_string(path), ec.message()); + return MOD_ERROR; + } + mod->dataDirUtf8 = borealis::io::fs_path_to_string(path); + } + + *outPath = mod->dataDirUtf8.c_str(); + return MOD_OK; +} + struct LifecycleWatcher { ModLifecycleFn fn = nullptr; void* userData = nullptr; @@ -148,6 +187,7 @@ constinit HostService s_hostService{ .watch_mod_lifecycle = host_watch_mod_lifecycle, .unwatch_mod_lifecycle = host_unwatch_mod_lifecycle, .native_dir = host_native_dir, + .data_dir = host_data_dir, }; } // namespace diff --git a/src/m_Do/m_Do_DVDError.cpp b/src/m_Do/m_Do_DVDError.cpp index 0113ba35ae..a38f2a6f5f 100644 --- a/src/m_Do/m_Do_DVDError.cpp +++ b/src/m_Do/m_Do_DVDError.cpp @@ -22,7 +22,7 @@ static OSThread DvdErr_thread; #pragma push #pragma force_active on -static u8 DvdErr_stack[stack_size] ATTRIBUTE_ALIGN(16); +ATTRIBUTE_ALIGN(16) static u8 DvdErr_stack[stack_size]; #pragma pop static OSAlarm Alarm; diff --git a/src/m_Do/m_Do_MemCard.cpp b/src/m_Do/m_Do_MemCard.cpp index 85b19c10c1..3aafc11d69 100644 --- a/src/m_Do/m_Do_MemCard.cpp +++ b/src/m_Do/m_Do_MemCard.cpp @@ -484,7 +484,7 @@ void mDoMemCd_Ctrl_c::detach() { mCardState = CARD_STATE_NO_CARD_e; } -static u8 MemCardWorkArea0[CARD_WORKAREA_SIZE] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u8 MemCardWorkArea0[CARD_WORKAREA_SIZE]; s32 mDoMemCd_Ctrl_c::mount() { s32 result = CARDMount(mChannel, MemCardWorkArea0, NULL); diff --git a/src/m_Do/m_Do_ext.cpp b/src/m_Do/m_Do_ext.cpp index 740160a2a0..381061e079 100644 --- a/src/m_Do/m_Do_ext.cpp +++ b/src/m_Do/m_Do_ext.cpp @@ -2239,7 +2239,7 @@ void mDoExt_invJntPacket::draw() { } while (shapePkt != NULL); } } else { - static u8 l_invisibleMat[] ATTRIBUTE_ALIGN(32) = { + ATTRIBUTE_ALIGN(32) static u8 l_invisibleMat[] = { 0x10, 0x00, 0x00, 0x10, 0x0E, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x04, 0x00, 0x61, 0x28, 0x38, 0x00, 0x00, 0x61, 0xC0, 0x08, 0xFF, 0xFC, 0x61, 0xC1, 0x08, 0xFF, 0xF0, 0x61, 0xF3, 0x7F, 0x00, 0x00, 0x61, 0x43, 0x00, 0x00, 0x41, 0x61, 0x40, @@ -2357,7 +2357,7 @@ int mDoExt_3DlineMat0_c::init(u16 param_0, u16 param_1, int param_2) { return 1; } -static u8 l_matDL[132] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_matDL[132] = { 0x08, 0x30, 0x3C, 0xF3, 0xCF, 0x00, 0x10, 0x00, 0x00, 0x10, 0x18, 0x3C, 0xF3, 0xCF, 0x00, 0x10, 0x00, 0x00, 0x10, 0x0E, 0x00, 0x00, 0x7F, 0x32, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x10, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x28, 0x38, @@ -2682,7 +2682,7 @@ int mDoExt_3DlineMat1_c::init(u16 param_0, u16 param_1, ResTIMG* param_2, int pa return 1; } -static u8 l_mat1DL[141] ATTRIBUTE_ALIGN(32) = { +ATTRIBUTE_ALIGN(32) static u8 l_mat1DL[141] = { 0x10, 0x00, 0x00, 0x10, 0x40, 0xFF, 0xFF, 0x42, 0x80, 0x08, 0x30, 0x3C, 0xF3, 0xCF, 0x00, 0x10, 0x00, 0x00, 0x10, 0x18, 0x3C, 0xF3, 0xCF, 0x00, 0x10, 0x00, 0x00, 0x10, 0x0E, 0x00, 0x00, 0x7F, 0x32, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x10, 0x0C, 0xFF, diff --git a/src/m_Do/m_Do_printf.cpp b/src/m_Do/m_Do_printf.cpp index 70cde36c32..9e6e719fff 100644 --- a/src/m_Do/m_Do_printf.cpp +++ b/src/m_Do/m_Do_printf.cpp @@ -126,7 +126,7 @@ void OSReportInit() { } } -static u8 mDoPrintf_FiberStack[2048] ATTRIBUTE_ALIGN(32); +ATTRIBUTE_ALIGN(32) static u8 mDoPrintf_FiberStack[2048]; void mDoPrintf_vprintf_Interrupt(char const* fmt, va_list args) { BOOL interruptStatus = OSDisableInterrupts();