diff --git a/mods/Levels/2024_NewSetup/StepsToFollow.txt b/mods/Levels/2024_NewSetup/StepsToFollow.txt new file mode 100644 index 00000000..ea7d4fea --- /dev/null +++ b/mods/Levels/2024_NewSetup/StepsToFollow.txt @@ -0,0 +1,15 @@ +[to-do] generate source code pseudo-auto + +First build with ./build.bat, +this generates .lev file + +Then run textures/start.bat, +this patches .lev and generates .vrm + +Boot retail game in duckstation +Go to Time Trial Crash Cove +Pause +Use "sendToDuck.bat" +Restart Race (from pause) + +[to-do] need to load VRAM file \ No newline at end of file diff --git a/mods/Levels/2024_NewSetup/build.bat b/mods/Levels/2024_NewSetup/build.bat new file mode 100644 index 00000000..34b39533 --- /dev/null +++ b/mods/Levels/2024_NewSetup/build.bat @@ -0,0 +1 @@ +python ../../../../../tools/mod-builder/main.py \ No newline at end of file diff --git a/mods/Levels/2024_NewSetup/buildList.txt b/mods/Levels/2024_NewSetup/buildList.txt new file mode 100644 index 00000000..e8a2d5e4 --- /dev/null +++ b/mods/Levels/2024_NewSetup/buildList.txt @@ -0,0 +1,4 @@ + +// sets lev to bigfile 221 +926, 221, 0x8009f6fc, 0x0, src/Lev221.c +926, 222, 0x8009f6fc, 0x0, src/dataVRAM.bin \ No newline at end of file diff --git a/mods/Levels/2024_NewSetup/sendToDuck.bat b/mods/Levels/2024_NewSetup/sendToDuck.bat new file mode 100644 index 00000000..1e11aabf --- /dev/null +++ b/mods/Levels/2024_NewSetup/sendToDuck.bat @@ -0,0 +1 @@ +..\Automate\LevelUploader\x64\Debug\LevelUploader.exe %cd%\textures\data.lev \ No newline at end of file diff --git a/mods/Levels/2024_NewSetup/src/Lev221.c b/mods/Levels/2024_NewSetup/src/Lev221.c new file mode 100644 index 00000000..cad17bdc --- /dev/null +++ b/mods/Levels/2024_NewSetup/src/Lev221.c @@ -0,0 +1,362 @@ +// Only for generating LEV files +#pragma GCC diagnostic ignored "-Wint-conversion" +#pragma GCC diagnostic ignored "-Woverride-init" +#pragma GCC diagnostic ignored "-Woverflow" + +#include +#include "../../levelBuilder.h" + +#define NUM_BLOCKS 20 + +struct LevelFile +{ + void* ptrMap; + struct Level level; + struct mesh_info mInfo; + struct IconGroup4 test_texture; + struct SpawnType1 spawnType1; + struct CheckpointNode noderespawnsthing[16]; + struct QuadBlock quadBlock[NUM_BLOCKS]; + struct LevVertex levVertex[NUM_BLOCKS*9]; + struct BSP bsp[3]; + struct PVS pvs; + int visBitIndex[4]; + struct VisMem visMem; + + // leave empty + // DstMemcpy must be big for PVS to copy into, + // RenderList must be big enough for 2 pointers to all BSP nodes + int VisMem_bitIndex_DstMemcpyP1[8]; + int VisMem_bspList_RenderListP1[3*2]; + int VisMem_bitIndex_DstMemcpyP2[8]; + int VisMem_bspList_RenderListP2[3*2]; + int VisMem_bitIndex_DstMemcpyP3[8]; + int VisMem_bspList_RenderListP3[3*2]; + int VisMem_bitIndex_DstMemcpyP4[8]; + int VisMem_bspList_RenderListP4[3*2]; + + int map[(3)+1]; +}; + +struct LevelFile file = +{ + .ptrMap = LEV_OFFSETOF(map[0]), + + .level = + { + .ptr_mesh_info = LEV_OFFSETOF(mInfo), + .visMem = LEV_OFFSETOF(visMem), + + // the game will add +0x400 to the yaw of spawn positions automatically + // we should probably look into why this even happens... + .DriverSpawn[0].pos = {0,0,0}, + .DriverSpawn[0].rot = {0,0-0x400,0}, + + .DriverSpawn[1].pos = {0,0,0}, + .DriverSpawn[1].rot = {0,0-0x400,0}, + + .DriverSpawn[2].pos = {0,0,0}, + .DriverSpawn[2].rot = {0,0-0x400,0}, + + .DriverSpawn[3].pos = {0,0,0}, + .DriverSpawn[3].rot = {0,0-0x400,0}, + + .ptrSpawnType1 = LEV_OFFSETOF(spawnType1), + + .configFlags = 1, + + .glowGradient[0] = + { + .pointFrom = -0xF0, + .pointTo = -0x10, + .colorFrom = 0x8000, + .colorTo = 0, + }, + + // amount of respawn points in the track + // and pointer to respawn data itself + .cnt_restart_points = 16, + .ptr_restart_points = LEV_OFFSETOF(noderespawnsthing[0]), + }, + + // pointers and amounts of variables + .mInfo = + { + .numQuadBlock = NUM_BLOCKS, + .numVertex = NUM_BLOCKS*9, // not really used + .unk1 = 0, // idk, fine to leave null + .ptrQuadBlockArray = LEV_OFFSETOF(quadBlock[0]), + .ptrVertexArray = LEV_OFFSETOF(levVertex[0]), + .unk2 = 0, // idk, fine to leave null + .bspRoot = LEV_OFFSETOF(bsp[0]), + .numBspNodes = 3, + }, + + // quadblock texture type + // see IconGroup4 in namespace_Decal.h + .test_texture = + { + .far = ImageName_Blend(512, 0, 32, 128, 32, 32, BPP_4, ADD), // very far + .middle = ImageName_Blend(512, 0, 32, 128, 32, 32, BPP_4, ADD), // far + .near = ImageName_Blend(512, 0, 32, 128, 32, 32, BPP_4, ADD), // close + .mosaic = ImageName_Blend(512, 0, 32, 128, 32, 32, BPP_4, ADD), // close + }, + + // this must exist, or else camera fly-in checks for "count" without nullptr check, and crashes dereferencing nullptr on real PSX + .spawnType1 = + { + .count = 0, + }, + + // automatically-generated quadblock insertions courtesy of pngtotrack.py + NEW_BLOCK(0, test_texture, 0x0000, 0x0000, NULL, 0x1800, (0xFFFFFF)),NEW_BLOCK(1, test_texture, 0x0300, 0x0000, NULL, 0x1800, (0x000000)), + NEW_BLOCK(2, test_texture, -0x300, 0x0300, NULL, 0x1800, RGBtoBGR(0x804000)),NEW_BLOCK(3, test_texture, 0x0000, 0x0300, NULL, 0x1800, (0xFFFFFF)),NEW_BLOCK(4, test_texture, 0x0300, 0x0300, NULL, 0x1800, RGBtoBGR(0x804000)),NEW_BLOCK(5, test_texture, 0x0600, 0x0300, NULL, 0x1800, RGBtoBGR(0x804000)), + NEW_BLOCK(6, test_texture, -0x300, 0x0600, NULL, 0x1800, RGBtoBGR(0x804000)), NEW_BLOCK(7, test_texture, 0x0600, 0x0600, NULL, 0x1800, RGBtoBGR(0x804000)), + NEW_BLOCK(8, test_texture, -0x300, 0x0900, NULL, 0x1800, RGBtoBGR(0x804000)), NEW_BLOCK(9, test_texture, 0x0600, 0x0900, NULL, 0x1800, RGBtoBGR(0x804000)), + NEW_BLOCK(10, test_texture, -0x300, 0x0c00, NULL, 0x1800, RGBtoBGR(0x804000)), NEW_BLOCK(11, test_texture, 0x0600, 0x0c00, NULL, 0x1800, RGBtoBGR(0x804000)), + NEW_BLOCK(12, test_texture, -0x300, 0x0f00, NULL, 0x1800, RGBtoBGR(0x804000)), NEW_BLOCK(13, test_texture, 0x0600, 0x0f00, NULL, 0x1800, RGBtoBGR(0x804000)), + NEW_BLOCK(14, test_texture, -0x300, 0x1200, NULL, 0x1800, RGBtoBGR(0x804000)),NEW_BLOCK(15, test_texture, 0x0000, 0x1200, NULL, 0x1800, RGBtoBGR(0x804000)),NEW_BLOCK(16, test_texture, 0x0300, 0x1200, NULL, 0x1800, RGBtoBGR(0x804000)),NEW_BLOCK(17, test_texture, 0x0600, 0x1200, NULL, 0x1800, RGBtoBGR(0x804000)), + NEW_BLOCK(18, test_texture, 0x0000, 0x1500, NULL, 0x1800, RGBtoBGR(0x804000)),NEW_BLOCK(19, test_texture, 0x0300, 0x1500, NULL, 0x1800, RGBtoBGR(0x804000)), + + /* + + 00 01 + 02 03 04 05 + 06 07 + 08 09 + 10 11 + 12 13 + 14 15 16 17 + 18 19 + + */ + + // checkpoint and respawn indices + // starts at 2 and ends at 3, which are the first and last quadblocks in terms of progression respectively + // 0, 1, 18, and 19 aren't used for progression + .quadBlock[2].checkpointIndex = 0, + .quadBlock[6].checkpointIndex = 1, + .quadBlock[8].checkpointIndex = 2, + .quadBlock[10].checkpointIndex = 3, + .quadBlock[12].checkpointIndex = 4, + .quadBlock[14].checkpointIndex = 5, + .quadBlock[15].checkpointIndex = 6, + .quadBlock[16].checkpointIndex = 7, + .quadBlock[17].checkpointIndex = 8, + .quadBlock[13].checkpointIndex = 9, + .quadBlock[11].checkpointIndex = 10, + .quadBlock[9].checkpointIndex = 11, + .quadBlock[7].checkpointIndex = 12, + .quadBlock[5].checkpointIndex = 13, + .quadBlock[4].checkpointIndex = 14, + .quadBlock[3].checkpointIndex = 15, + + // checkpoint and respawn data, split into 16 nodes + // the positions of each node are the same as certain quadblocks + .noderespawnsthing = + { + [0] = + { + .pos = {-0x300, 0, 0x300}, // same as quadblock 2 + .distToFinish = 0x200*15, + .nextIndex_forward = 1, + .nextIndex_left = -1, + .nextIndex_backward = 15, + .nextIndex_right = -1, + }, + [1] = + { + .pos = {-0x300, 0, 0x600}, // same as quadblock 6 + .distToFinish = 0x200*14, + .nextIndex_forward = 2, + .nextIndex_left = -1, + .nextIndex_backward = 0, + .nextIndex_right = -1, + }, + [2] = + { + .pos = {-0x300, 0, 0x300*3}, // same as quadblock 8 + .distToFinish = 0x200*13, + .nextIndex_forward = 3, + .nextIndex_left = -1, + .nextIndex_backward = 1, + .nextIndex_right = -1, + }, + [3] = + { + .pos = {-0x300, 0, 0x300*4}, // same as quadblock 10 + .distToFinish = 0x200*12, + .nextIndex_forward = 4, + .nextIndex_left = -1, + .nextIndex_backward = 2, + .nextIndex_right = -1, + }, + [4] = + { + .pos = {-0x300, 0, 0x300*5}, // same as quadblock 12 + .distToFinish = 0x200*11, + .nextIndex_forward = 5, + .nextIndex_left = -1, + .nextIndex_backward = 3, + .nextIndex_right = -1, + }, + [5] = + { + .pos = {-0x300, 0, 0x300*6}, // same as quadblock 14 + .distToFinish = 0x200*10, + .nextIndex_forward = 6, + .nextIndex_left = -1, + .nextIndex_backward = 4, + .nextIndex_right = -1, + }, + [6] = + { + .pos = {0, 0, 0x300*6}, // same as quadblock 15 + .distToFinish = 0x200*9, + .nextIndex_forward = 7, + .nextIndex_left = -1, + .nextIndex_backward = 5, + .nextIndex_right = -1, + }, + [7] = + { + .pos = {0x300, 0, 0x300*6}, // same as quadblock 16 + .distToFinish = 0x200*8, + .nextIndex_forward = 8, + .nextIndex_left = -1, + .nextIndex_backward = 6, + .nextIndex_right = -1, + }, + [8] = + { + .pos = {0x600, 0, 0x300*6}, // same as quadblock 17 + .distToFinish = 0x200*7, + .nextIndex_forward = 9, + .nextIndex_left = -1, + .nextIndex_backward = 7, + .nextIndex_right = -1, + }, + [9] = + { + .pos = {0x600, 0, 0x300*5}, // same as quadblock 13 + .distToFinish = 0x200*6, + .nextIndex_forward = 10, + .nextIndex_left = -1, + .nextIndex_backward = 8, + .nextIndex_right = -1, + }, + [10] = + { + .pos = {0x600, 0, 0x300*4}, // same as quadblock 11 + .distToFinish = 0x200*5, + .nextIndex_forward = 11, + .nextIndex_left = -1, + .nextIndex_backward = 9, + .nextIndex_right = -1, + }, + [11] = + { + .pos = {0x600, 0, 0x300*3}, // same as quadblock 9 + .distToFinish = 0x200*4, + .nextIndex_forward = 12, + .nextIndex_left = -1, + .nextIndex_backward = 10, + .nextIndex_right = -1, + }, + [12] = + { + .pos = {0x600, 0, 0x300*2}, // same as quadblock 7 + .distToFinish = 0x200*3, + .nextIndex_forward = 13, + .nextIndex_left = -1, + .nextIndex_backward = 11, + .nextIndex_right = -1, + }, + [13] = + { + .pos = {0x600, 0, 0x300*1}, // same as quadblock 5 + .distToFinish = 0x200*2, + .nextIndex_forward = 14, + .nextIndex_left = -1, + .nextIndex_backward = 12, + .nextIndex_right = -1, + }, + [14] = + { + .pos = {0x300, 0, 0x300*1}, // same as quadblock 4 + .distToFinish = 0x200*1, + .nextIndex_forward = 15, + .nextIndex_left = -1, + .nextIndex_backward = 13, + .nextIndex_right = -1, + }, + [15] = + { + .pos = {0, 0, 0x300*1}, // same as quadblock 3 + .distToFinish = 0x200*0, + .nextIndex_forward = 0, + .nextIndex_left = -1, + .nextIndex_backward = 14, + .nextIndex_right = -1, + }, + }, + + // ========== bsp ====================== + + .bsp = + { + // root node + BSP_BRANCH(0, SPLIT_Z, 0x1, 0x2), + + // bsp[1], start with quadblock[0], 2 quadblocks + BSP_LEAF(1, 0, 2), + + // bsp[2], start with quadblock[2], 18 quadblocks + BSP_LEAF(2, 2, 18), + }, + + .pvs = + { + .visLeafSrc = LEV_OFFSETOF(visBitIndex[0]), + .visFaceSrc = LEV_OFFSETOF(visBitIndex[0]), + .visInstSrc = 0, + .visExtraSrc = 0, + }, + + .visBitIndex = + { + // all 0xFFFFFFFFFFFF + -1, -1, -1, -1 + }, + + .visMem = + { + // P1 + .visLeafList[0] = LEV_OFFSETOF(VisMem_bitIndex_DstMemcpyP1[0]), + .visFaceList[0] = LEV_OFFSETOF(VisMem_bitIndex_DstMemcpyP1[4]), + .bspList[0] = LEV_OFFSETOF(VisMem_bspList_RenderListP1[0]), + + // P2 + .visLeafList[1] = LEV_OFFSETOF(VisMem_bitIndex_DstMemcpyP2[0]), + .visFaceList[1] = LEV_OFFSETOF(VisMem_bitIndex_DstMemcpyP2[4]), + .bspList[1] = LEV_OFFSETOF(VisMem_bspList_RenderListP2[0]), + + // P3 + .visLeafList[2] = LEV_OFFSETOF(VisMem_bitIndex_DstMemcpyP3[0]), + .visFaceList[2] = LEV_OFFSETOF(VisMem_bitIndex_DstMemcpyP3[4]), + .bspList[2] = LEV_OFFSETOF(VisMem_bspList_RenderListP3[0]), + + // P4 + .visLeafList[3] = LEV_OFFSETOF(VisMem_bitIndex_DstMemcpyP4[0]), + .visFaceList[3] = LEV_OFFSETOF(VisMem_bitIndex_DstMemcpyP4[4]), + .bspList[3] = LEV_OFFSETOF(VisMem_bspList_RenderListP4[0]), + }, + + .map = + { + (2)<<2, + + LEV_OFFSETOF(pvs.visLeafSrc), + LEV_OFFSETOF(pvs.visFaceSrc), + }, +}; \ No newline at end of file diff --git a/mods/Levels/2024_NewSetup/textures/.gitignore b/mods/Levels/2024_NewSetup/textures/.gitignore new file mode 100644 index 00000000..05271de5 --- /dev/null +++ b/mods/Levels/2024_NewSetup/textures/.gitignore @@ -0,0 +1,6 @@ +data +data.lev +data.vrm +data.vrm.bkp +debug_vram_first.bmp +debug_vram_latest.bmp \ No newline at end of file diff --git a/mods/Levels/2024_NewSetup/textures/newtex/512_0_32_128_32_32_1.png b/mods/Levels/2024_NewSetup/textures/newtex/512_0_32_128_32_32_1.png new file mode 100644 index 00000000..c485b13c Binary files /dev/null and b/mods/Levels/2024_NewSetup/textures/newtex/512_0_32_128_32_32_1.png differ diff --git a/mods/Levels/2024_NewSetup/textures/start.bat b/mods/Levels/2024_NewSetup/textures/start.bat new file mode 100644 index 00000000..c08773c0 --- /dev/null +++ b/mods/Levels/2024_NewSetup/textures/start.bat @@ -0,0 +1,25 @@ +@echo off +cd %~dp0 + +:: Get Newest Level File +copy ..\output\Lev221c.bin .\data.lev + +:: Get Blank VRAM File +copy ..\..\Automate\blankVRAM_dontErase.vrm .\data.vrm + +:: Patch Level with Automation +..\..\Automate\LevelPatcher\Debug\LevelPatcher.exe %cd%\data.lev + +:: Generate Layout +..\..\Automate\model_reader.exe .\data.lev + +:: Generate VRAM +..\..\Automate\vrmtool.exe .\data.vrm + +:: Submit Level File +copy .\data.lev ..\output\Lev221c.bin + +:: Submit VRAM File +copy .\data.vrm ..\src\dataVRAM.bin + +pause \ No newline at end of file diff --git a/mods/Levels/Automate/LevelUploader/LevelUploader.sln b/mods/Levels/Automate/LevelUploader/LevelUploader.sln new file mode 100644 index 00000000..9370959b --- /dev/null +++ b/mods/Levels/Automate/LevelUploader/LevelUploader.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34714.143 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LevelUploader", "LevelUploader\LevelUploader.vcxproj", "{790AB99C-0121-4286-99FA-1EE5B3611DD1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {790AB99C-0121-4286-99FA-1EE5B3611DD1}.Debug|x64.ActiveCfg = Debug|x64 + {790AB99C-0121-4286-99FA-1EE5B3611DD1}.Debug|x64.Build.0 = Debug|x64 + {790AB99C-0121-4286-99FA-1EE5B3611DD1}.Debug|x86.ActiveCfg = Debug|Win32 + {790AB99C-0121-4286-99FA-1EE5B3611DD1}.Debug|x86.Build.0 = Debug|Win32 + {790AB99C-0121-4286-99FA-1EE5B3611DD1}.Release|x64.ActiveCfg = Release|x64 + {790AB99C-0121-4286-99FA-1EE5B3611DD1}.Release|x64.Build.0 = Release|x64 + {790AB99C-0121-4286-99FA-1EE5B3611DD1}.Release|x86.ActiveCfg = Release|Win32 + {790AB99C-0121-4286-99FA-1EE5B3611DD1}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9205B891-8640-41E3-9614-D14BC9009A39} + EndGlobalSection +EndGlobal diff --git a/mods/Levels/Automate/LevelUploader/LevelUploader/LevelUploader.vcxproj b/mods/Levels/Automate/LevelUploader/LevelUploader/LevelUploader.vcxproj new file mode 100644 index 00000000..53a6382a --- /dev/null +++ b/mods/Levels/Automate/LevelUploader/LevelUploader/LevelUploader.vcxproj @@ -0,0 +1,135 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 17.0 + Win32Proj + {790ab99c-0121-4286-99fa-1ee5b3611dd1} + LevelUploader + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/mods/Levels/Automate/LevelUploader/LevelUploader/LevelUploader.vcxproj.filters b/mods/Levels/Automate/LevelUploader/LevelUploader/LevelUploader.vcxproj.filters new file mode 100644 index 00000000..decff766 --- /dev/null +++ b/mods/Levels/Automate/LevelUploader/LevelUploader/LevelUploader.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/mods/Levels/Automate/LevelUploader/LevelUploader/LevelUploader.vcxproj.user b/mods/Levels/Automate/LevelUploader/LevelUploader/LevelUploader.vcxproj.user new file mode 100644 index 00000000..e59d6e1b --- /dev/null +++ b/mods/Levels/Automate/LevelUploader/LevelUploader/LevelUploader.vcxproj.user @@ -0,0 +1,14 @@ + + + + + + + + WindowsLocalDebugger + + + C:\Users\Niko\Desktop\CTR\psx-modding-toolchain\games\CTR-ModSDK\mods\Levels\2024_NewSetup\textures\data.lev + WindowsLocalDebugger + + \ No newline at end of file diff --git a/mods/Levels/Automate/LevelUploader/LevelUploader/main.c b/mods/Levels/Automate/LevelUploader/LevelUploader/main.c new file mode 100644 index 00000000..7d5228cc --- /dev/null +++ b/mods/Levels/Automate/LevelUploader/LevelUploader/main.c @@ -0,0 +1,158 @@ +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include +#include +#include + +char* pBuf; + +#pragma comment (lib, "Ws2_32.lib") +#pragma comment (lib, "Mswsock.lib") +#pragma comment (lib, "AdvApi32.lib") + +// for EnumProcessModules +#pragma comment(lib, "psapi.lib") + +void DECOMP_LOAD_RunPtrMap(char* origin, int* patchArr, int numPtrs, int dstAddr) +{ + for (int i = 0; i < numPtrs; i++) + { + *(int*)&origin[patchArr[i]] += dstAddr; + } +} + +struct DramPointerMap +{ + int numBytes; + + //int offsets[0]; +}; + +#define DRAM_GETOFFSETS(x) \ + ((char*)x + sizeof(struct DramPointerMap)) + +void UploadToDuck(char** argv) +{ + printf("%s\n", argv[1]); + FILE* f = fopen(argv[1], "rb"); + + fseek(f, 0, SEEK_END); + int size = ftell(f); + rewind(f); + + // read to 2mb on PS1 + fread(&pBuf[0x200000], size, 1, f); + + fclose(f); + + char* fileBuf = &pBuf[0x200000]; + int ptrMapOffset = *(int*)&fileBuf[0]; + char* realFileBuf = &fileBuf[4]; + + struct DramPointerMap* dpm = &realFileBuf[ptrMapOffset]; + DECOMP_LOAD_RunPtrMap( + realFileBuf, + (int*)DRAM_GETOFFSETS(dpm), + dpm->numBytes >> 2, + 0x80200004); + + // set level file pointer + *(int*)&pBuf[(0x80096b20 + 0x160) & 0xffffff] = 0x80200004; + + printf("Here\n"); + system("pause"); + exit(0); +} + +int main(int argc, char** argv) +{ + int numDuckInstances = 0; + char* duckTemplate = "duckstation"; + int duckPID = -1; + + // copy from + // https://learn.microsoft.com/en-us/windows/win32/psapi/enumerating-all-processes + DWORD aProcesses[1024], cbNeeded, cProcesses; + EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded); + cProcesses = cbNeeded / sizeof(DWORD); + + for (int i = 0; i < cProcesses; i++) + { + DWORD processID = aProcesses[i]; + + if (processID != 0) + { + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); + + if (NULL != hProcess) + { + HMODULE hMod; + DWORD cbNeeded; + + if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) + { + TCHAR szProcessName[MAX_PATH]; + GetModuleBaseNameA(hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR)); + + char* procName = (char*)&szProcessName[0]; + + if ( + (*(int*)&procName[0] == *(int*)&duckTemplate[0]) && + (*(int*)&procName[4] == *(int*)&duckTemplate[4]) + ) + { + numDuckInstances++; + duckPID = processID; + } + } + } + } + } + + if (numDuckInstances == 0) + { + printf("Error: DuckStation is not running!\n\n"); + system("pause"); + exit(0); + } + else printf("Client: DuckStation detected\n"); + + char pidStr[16]; + + if (numDuckInstances > 1) + { + printf("Warning: Multiple DuckStations detected\n"); + printf("Please enter the PID manually\n\n"); + + printf("Input.: DuckStation PID: "); + scanf_s("%s", pidStr, (int)sizeof(pidStr)); + } + else + { + sprintf_s(pidStr, 100, "%d", duckPID); + } + + char duckName[100]; + sprintf_s(duckName, 100, "duckstation_%s", pidStr); + + TCHAR duckNameT[100]; + swprintf(duckNameT, 100, L"%hs", duckName); + + // 8 MB RAM + const unsigned int size = 0x800000; + HANDLE hFile = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, duckNameT); + pBuf = (char*)MapViewOfFile(hFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, size); + + if (pBuf == 0) + { + printf("Error: Failed to open DuckStation!\n\n"); + system("pause"); + system("cls"); + main(argc, argv); + } + + UploadToDuck(argv); +} \ No newline at end of file