This commit is contained in:
TakaRikka
2026-08-07 03:49:10 -07:00
70 changed files with 574 additions and 208 deletions
+19 -8
View File
@@ -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.
+1 -1
+2 -2
View File
@@ -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*);
+2 -2
View File
@@ -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 = {
+2 -2
View File
@@ -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,
+3 -3
View File
@@ -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();
+2 -2
View File
@@ -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,
+3 -3
View File
@@ -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
+2 -2
View File
@@ -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,
};
@@ -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,
@@ -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;
@@ -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;
+2 -2
View File
@@ -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*);
+1 -1
View File
@@ -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;
+3 -3
View File
@@ -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;
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -3,7 +3,7 @@
#include <dolphin/demo.h>
#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);
+1 -1
View File
@@ -1,7 +1,7 @@
#include <dolphin/dolphin.h>
#include <dolphin/demo.h>
u32 DEMOFontBitmap[768] ATTRIBUTE_ALIGN(32) = {
ATTRIBUTE_ALIGN(32) u32 DEMOFontBitmap[768] = {
0x00000000,
0x00000000,
0x00000000,
+1 -1
View File
@@ -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,
};
+5 -5
View File
@@ -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;
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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,
+5 -5
View File
@@ -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;
+1 -1
View File
@@ -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;
+7 -7
View File
@@ -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;
+2 -2
View File
@@ -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) {
+8 -8
View File
@@ -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);
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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,
};
@@ -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;
};
@@ -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<LoadCommand, offsetof(LoadCommand, mLinkNode)> LoadCommandList;
+2 -2
View File
@@ -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;
+4 -4
View File
@@ -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);
}
+3 -3
View File
@@ -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) {
+1 -1
View File
@@ -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) {
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -2,7 +2,7 @@
#include <revolution/nand.h>
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;
+6 -6
View File
@@ -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);
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -2,7 +2,7 @@
#include <revolution/nand.h>
#include <cstring>
static OSStateFlags StateFlags ATTRIBUTE_ALIGN(32);
ATTRIBUTE_ALIGN(32) static OSStateFlags StateFlags;
static u32 CheckSum(OSStateFlags* flags) {
u32* ptr, i, sum;
+6 -6
View File
@@ -5,14 +5,14 @@
#include <revolution/private/iosrestypes.h>
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;
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -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)));
+1 -1
View File
@@ -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;
+10
View File
@@ -53,4 +53,14 @@ ModResult hook_replace(HookReplaceFn callback, const HookOptions* options = null
return hook::replace<Entry>(callback, options);
}
template <class Entry>
ModResult hook_uninstall(const HookService* hooks) {
return hook::uninstall<Entry>(hooks);
}
template <class Entry>
ModResult hook_uninstall() {
return hook::uninstall<Entry>();
}
} // namespace mods
+43 -1
View File
@@ -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(
+33 -14
View File
@@ -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);
+22
View File
@@ -238,5 +238,27 @@ ModResult replace(HookReplaceFn callback, const HookOptions* options = nullptr)
return replace<Entry>(svc_hook, callback, options);
}
template <class Entry>
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<void**>(&Entry::g_orig));
if (result == MOD_OK) {
Entry::hooks = nullptr;
Entry::g_orig = nullptr;
}
return result;
}
template <class Entry>
ModResult uninstall() {
return uninstall<Entry>(svc_hook);
}
} // namespace hook
} // namespace mods
+12 -3
View File
@@ -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);
+2 -1
View File
@@ -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"
+13 -13
View File
@@ -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) {
+1 -1
View File
@@ -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,
+2 -1
View File
@@ -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;
+2 -2
View File
@@ -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];
+13 -13
View File
@@ -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,
+1 -1
View File
@@ -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) {
+2 -2
View File
@@ -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,
+9
View File
@@ -0,0 +1,9 @@
#pragma once
class dCamera_c;
namespace dusk::mods {
bool camera_run_operators(dCamera_c* camera);
} // namespace dusk::mods
+2
View File
@@ -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.
+132
View File
@@ -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 <algorithm>
#include <aurora/gfx.hpp>
#include <cstring>
#include <exception>
#include <fmt/format.h>
#include <string>
#include <vector>
namespace dusk::mods::svc {
namespace {
@@ -117,9 +128,125 @@ ModResult camera_get_camera_from_view(
return snapshot_view(static_cast<const view_class*>(gameView), outInfo);
}
struct CameraOperator {
std::string debugName;
int32_t priority = 0;
uint64_t sequence = 0;
CameraOperateFn operate = nullptr;
void* userData = nullptr;
};
SlotMap<CameraOperator> 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<PendingOperator> 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);
}
+110 -42
View File
@@ -86,6 +86,7 @@ struct InstalledHook {
InstalledBackend backend{};
void* original = nullptr;
ModContext* active = nullptr;
void** activeStore = nullptr;
std::vector<HookCandidate> candidates;
};
@@ -143,6 +144,15 @@ void sort_hooks(std::vector<T>& 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<uintptr_t>(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<void*>(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
+41 -1
View File
@@ -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 <algorithm>
#include <vector>
#include <borealis/io.hpp>
#include <borealis/version.h>
#include <filesystem>
#include <vector>
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
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
+3 -3
View File
@@ -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,
+1 -1
View File
@@ -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();