├── .gitignore ├── GH3+.sln ├── readme.md ├── src ├── core │ ├── GH3Plus.cpp │ ├── GH3Plus.h │ ├── GH3PlusCore.vcxproj │ ├── GH3PlusCore.vcxproj.filters │ ├── PatchManager.cpp │ ├── PatchManager.h │ ├── Patcher.cpp │ ├── Patcher.h │ ├── ScopedUnprotect.cpp │ ├── ScopedUnprotect.h │ ├── core.cpp │ ├── core.h │ └── dllmain.cpp ├── gh3 │ ├── BinaryTree.cpp │ ├── BinaryTree.h │ ├── CAliveRefCounted.h │ ├── CObject.h │ ├── CRefCounted.h │ ├── CScreenElement.h │ ├── CTextElement.h │ ├── CXboxFont.h │ ├── CXboxText.h │ ├── GH3CodeConstants.h │ ├── GH3GlobalAddresses.h │ ├── GH3Keys.h │ ├── GlobalMap.cpp │ ├── GlobalMap.h │ ├── List.h │ ├── QbArray.cpp │ ├── QbArray.h │ ├── QbImage.h │ ├── QbKey.cpp │ ├── QbKey.h │ ├── QbMap.cpp │ ├── QbMap.h │ ├── QbPair.h │ ├── QbScript.cpp │ ├── QbScript.h │ ├── QbStruct.cpp │ ├── QbStruct.h │ ├── QbValueType.h │ ├── QbVector.h │ ├── SDraw2D.h │ ├── SText.h │ ├── TextureMetadata.h │ └── malloc.h └── plugins │ ├── alwaysDoubleNotes │ ├── AlwaysDoubleNotes.vcxproj │ ├── AlwaysDoubleNotes.vcxproj.filters │ ├── dllmain.cpp │ ├── doubleNotes.cpp │ └── doubleNotes.h │ ├── doubleNotesHopo │ ├── DoubleNotesHopo.vcxproj │ └── DoubleNotesHopo.vcxproj.filters │ ├── forceStrumNotes │ ├── ForceStrumNotes.vcxproj │ ├── ForceStrumNotes.vcxproj.filters │ ├── dllmain.cpp │ ├── forceStrumNotes.cpp │ └── forceStrumNotes.h │ ├── forceTapNotes │ ├── ForceTapNotes.vcxproj │ ├── ForceTapNotes.vcxproj.filters │ ├── dllmain.cpp │ ├── forceTapNotes.cpp │ └── forceTapNotes.h │ ├── gemShuffle │ ├── GemShuffle.vcxproj │ ├── dllmain.cpp │ ├── gemShuffle.cpp │ └── gemShuffle.h │ ├── keyHijacker │ ├── KeyHijacker.rc │ ├── KeyHijacker.vcxproj │ ├── dllmain.cpp │ ├── keyHijacker.cpp │ ├── keyHijacker.h │ ├── quack.wav │ └── resource.h │ ├── mirrorMode │ ├── MirrorMode.vcxproj │ ├── dllmain.cpp │ ├── mirrorMode.cpp │ └── mirrorMode.h │ ├── noteLimit │ ├── NoteLimitFix.cpp │ ├── NoteLimitFix.h │ ├── NoteLimitFix.vcxproj │ ├── NoteLimitFix.vcxproj.filters │ └── dllmain.cpp │ ├── songLimit │ ├── SongLimitFix.vcxproj │ ├── dllmain.cpp │ ├── songLimitFix.cpp │ └── songLimitFix.h │ ├── spooky │ ├── Spooky.vcxproj │ ├── dllmain.cpp │ ├── garbagetext.cpp │ ├── garbagetext.h │ ├── garbagetext.txt │ ├── keydebugging.cpp │ ├── keydebugging.h │ ├── spooky.cpp │ ├── spooky.h │ ├── stringscramble.cpp │ ├── stringscramble.h │ ├── weakrand.cpp │ └── weakrand.h │ ├── tapHopoChord │ ├── TapHopoChord.vcxproj │ ├── TapHopoChord.vcxproj.filters │ ├── dllmain.cpp │ ├── gemConstants.cpp │ ├── gemLoading.cpp │ ├── gemMutation.cpp │ ├── globalArrayReplacements.cpp │ ├── noteLoading.cpp │ ├── noteLogic.cpp │ ├── tapHopoChord.cpp │ ├── tapHopoChord.h │ └── textureTakeover.cpp │ ├── textureHelper │ ├── TextureHelper.vcxproj │ ├── dllmain.cpp │ ├── textureHelper.cpp │ └── textureHelper.h │ ├── tiltFix │ ├── TiltFix.vcxproj │ ├── dllmain.cpp │ ├── tiltFix.cpp │ └── tiltFix.h │ └── whammyFix │ ├── WhammyFix.vcxproj │ ├── WhammyFix.vcxproj.filters │ ├── dllmain.cpp │ ├── whammyFix.cpp │ └── whammyFix.h └── templates └── GH3+ Plugin Project.zip /.gitignore: -------------------------------------------------------------------------------- 1 | *.opensdf 2 | *.sdf 3 | *.suo 4 | 5 | *.log 6 | *.tlog 7 | *.lastbuildstate 8 | 9 | *.cache 10 | *.pdb 11 | *.obj 12 | *.aps 13 | 14 | *.vcxproj.user 15 | 16 | /GH3+.VC.db 17 | /.vs 18 | 19 | bin/ 20 | Release/ 21 | Debug/ 22 | /src/plugins/giveMeTimeToHookUpAGodDamnDebugger 23 | /src/plugins/helgaBot 24 | /src/plugins/gemLimit 25 | /src/plugins/GH3+ Plugin Project 26 | 27 | *.opendb -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | GH3+ 2 | ==== 3 | 4 | GH3+ is a work in progress plugin system for Guitar Hero III written in C++. 5 | 6 | Latest release 7 | -------------- 8 | 9 | The most recent release is v0.6. This release contains: 10 | - core 11 | - AlwaysDoubleNotes 12 | - ForceStrumNotes 13 | - ForceTapNotes 14 | - GemShuffle 15 | - Speedhack 16 | - MirrorMode 17 | - NoteLimitFix 18 | - TapHopoChord 19 | - TextureHelper 20 | - TiltFix 21 | - WhammyFix 22 | 23 | Fixes from the latest version include: 24 | - Major updates to the GH3+ API include support for most of GH3's native "Qb" structures/classes. 25 | - Open notes -------------------------------------------------------------------------------- /src/core/GH3Plus.cpp: -------------------------------------------------------------------------------- 1 | #include "ScopedUnprotect.h" 2 | #include 3 | #include "GH3Plus.h" 4 | 5 | namespace GH3P 6 | { 7 | void WriteJmp(LPVOID address, LPVOID target) 8 | { 9 | GH3P::ScopedUnprotect unprotect(address, 12); 10 | 11 | DWORD jmpSize = (DWORD)target - (DWORD)address - 5; 12 | BYTE *arr = static_cast(address); 13 | 14 | arr[0] = 0xE9; 15 | memcpy(&arr[1], &jmpSize, sizeof(jmpSize)); 16 | } 17 | 18 | void WriteJmp(void * address, void * target) 19 | { 20 | } 21 | } -------------------------------------------------------------------------------- /src/core/GH3Plus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef GH3P_EXPORTS 4 | #define GH3P_API __declspec(dllexport) 5 | #else 6 | #define GH3P_API __declspec(dllimport) 7 | #endif -------------------------------------------------------------------------------- /src/core/GH3PlusCore.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {3ECB28CB-CDCA-4193-B4BF-1F7EC67C9E03} 15 | Win32Proj 16 | GH3PlusCore 17 | core 18 | 8.1 19 | 20 | 21 | 22 | DynamicLibrary 23 | true 24 | v140 25 | Unicode 26 | 27 | 28 | DynamicLibrary 29 | false 30 | v140 31 | true 32 | Unicode 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | true 46 | core 47 | $(SolutionDir)bin\$(Configuration)\ 48 | 49 | 50 | false 51 | $(SolutionDir)bin\$(Configuration)\ 52 | core 53 | 54 | 55 | 56 | 57 | 58 | Level3 59 | Disabled 60 | WIN32;_DEBUG;_WINDOWS;_USRDLL;GH3P_EXPORTS;%(PreprocessorDefinitions) 61 | MultiThreadedDebug 62 | ..\;%(AdditionalIncludeDirectories) 63 | AssemblyAndSourceCode 64 | 65 | 66 | Windows 67 | true 68 | 0.5 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | Level3 78 | 79 | 80 | MaxSpeed 81 | true 82 | true 83 | WIN32;NDEBUG;_WINDOWS;_USRDLL;GH3P_EXPORTS;%(PreprocessorDefinitions) 84 | MultiThreaded 85 | ..\;%(AdditionalIncludeDirectories) 86 | AssemblyAndSourceCode 87 | 88 | 89 | Windows 90 | true 91 | true 92 | true 93 | 0.5 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /src/core/GH3PlusCore.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {68f1dbba-d57e-4edb-9759-6d0ffb7f7336} 18 | 19 | 20 | {5985b1a0-e80c-49fc-b255-8331b9029133} 21 | 22 | 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files\GH3 41 | 42 | 43 | Source Files\GH3 44 | 45 | 46 | Source Files\GH3 47 | 48 | 49 | Source Files\GH3 50 | 51 | 52 | Source Files\GH3 53 | 54 | 55 | Source Files\GH3 56 | 57 | 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files\GH3 76 | 77 | 78 | Header Files\GH3 79 | 80 | 81 | Header Files\GH3 82 | 83 | 84 | Header Files\GH3 85 | 86 | 87 | Header Files\GH3 88 | 89 | 90 | Header Files\GH3 91 | 92 | 93 | Header Files\GH3 94 | 95 | 96 | Header Files\GH3 97 | 98 | 99 | Header Files\GH3 100 | 101 | 102 | Header Files\GH3 103 | 104 | 105 | Header Files\GH3 106 | 107 | 108 | Header Files\GH3 109 | 110 | 111 | Header Files\GH3 112 | 113 | 114 | Header Files\GH3 115 | 116 | 117 | Header Files\GH3 118 | 119 | 120 | Header Files\GH3 121 | 122 | 123 | Header Files\GH3 124 | 125 | 126 | Header Files\GH3 127 | 128 | 129 | Header Files\GH3 130 | 131 | 132 | Header Files\GH3 133 | 134 | 135 | Header Files\GH3 136 | 137 | 138 | Header Files\GH3 139 | 140 | 141 | Header Files\GH3 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/core/PatchManager.cpp: -------------------------------------------------------------------------------- 1 | #include "PatchManager.h" 2 | #include "ScopedUnprotect.h" 3 | #include 4 | #include 5 | #include 6 | 7 | namespace GH3P 8 | { 9 | 10 | static std::map< uint8_t *, std::vector > sOriginalCode; 11 | static std::map< uint8_t *, uint32_t > sPatchOwners; 12 | static std::map< uint32_t, std::vector > sOwnerPatches; 13 | 14 | void PatchManager::FindPatch(const uint8_t *start, uint32_t size, uint8_t* &patchStart, uint32_t &patchOwner) 15 | { 16 | const uint8_t *end = start + size; 17 | 18 | for (auto kv : sOriginalCode) 19 | { 20 | uint32_t patchSize = kv.second.size(); 21 | patchStart = kv.first; 22 | const uint8_t *patchEnd = patchStart + patchSize; 23 | patchOwner = sPatchOwners[patchStart]; 24 | 25 | //Does the existing patch start within our patch range? 26 | if (patchStart >= start && patchStart < end) 27 | return; 28 | 29 | //Does the existing patch end within our patch range? 30 | if (patchEnd >= start && patchEnd < end) 31 | return; 32 | 33 | //Does the existing patch completely encapsulate our patch range? 34 | if (patchStart < start && patchEnd >= end) 35 | return; 36 | 37 | } 38 | 39 | patchStart = nullptr; 40 | patchOwner = 0x00000000; 41 | } 42 | 43 | bool PatchManager::ApplyPatch(const uint8_t *src, uint8_t *dest, uint32_t size, uint32_t ownerID) 44 | { 45 | //Assert that the code we want to patch isn't patched already 46 | uint8_t *patchStart; 47 | uint32_t patchOwner; 48 | FindPatch(dest, size, patchStart, patchOwner); 49 | if (patchOwner != 0) 50 | return false; 51 | 52 | //Back up original code and then patch 53 | ScopedUnprotect memUnprotect(dest, size); 54 | std::vector oldCode(size); 55 | memcpy(&(oldCode[0]), dest, size); 56 | memcpy(dest, src, size); 57 | 58 | if (sOwnerPatches.find(ownerID) == sOwnerPatches.end()) 59 | sOwnerPatches[ownerID] = std::vector(); 60 | 61 | sOwnerPatches[ownerID].push_back(dest); 62 | sOriginalCode[dest] = oldCode; 63 | sPatchOwners[dest] = ownerID; 64 | 65 | return true; 66 | } 67 | 68 | bool PatchManager::RemovePatch(uint8_t *dest) 69 | { 70 | if (sOriginalCode.find(dest) == sOriginalCode.end()) 71 | return false; 72 | 73 | //Restore original code 74 | std::vector oldCode = sOriginalCode[dest]; 75 | ScopedUnprotect memUnprotect(dest, oldCode.size()); 76 | memcpy(dest, &(oldCode[0]), oldCode.size()); 77 | 78 | //Remove entries 79 | uint32_t patchOwner = sPatchOwners[dest]; 80 | sOriginalCode.erase(dest); 81 | sPatchOwners.erase(dest); 82 | std::vector &v = sOwnerPatches[patchOwner]; 83 | v.erase(std::remove(v.begin(), v.end(), dest), v.end()); 84 | if (v.empty()) 85 | sOwnerPatches.erase(patchOwner); 86 | 87 | return true; 88 | } 89 | 90 | bool PatchManager::RemovePatches(uint32_t ownerID) 91 | { 92 | std::vector patchesToRemove; 93 | 94 | for (auto kv : sPatchOwners) 95 | { 96 | uint8_t *patchLocation = kv.first; 97 | uint32_t owner = kv.second; 98 | 99 | if (owner != ownerID) 100 | continue; 101 | 102 | patchesToRemove.push_back(patchLocation); 103 | } 104 | 105 | for (uint8_t *patch : patchesToRemove) 106 | { 107 | PatchManager::RemovePatch(patch); 108 | } 109 | 110 | return true; 111 | } 112 | 113 | } -------------------------------------------------------------------------------- /src/core/PatchManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GH3Plus.h" 3 | #include 4 | 5 | namespace GH3P 6 | { 7 | /// A memberless static class for managing the patches of loaded plugins in GH3+. It should be rare to need to access this class directly. 8 | class GH3P_API PatchManager final 9 | { 10 | private: 11 | PatchManager() = delete; 12 | 13 | public: 14 | /// Given a starting address and size in bytes, finds a patch that starts in that area along with the owner of that patch. 15 | static void FindPatch(const uint8_t *start, uint32_t size, uint8_t* &patchStart, uint32_t &patchOwner); 16 | 17 | /// Writes an amount of bytes from source to destination based on the size passed in. The patch will be assigned to the specified owner ID. 18 | static bool ApplyPatch(const uint8_t * src, uint8_t *dest, uint32_t size, uint32_t ownerID); 19 | 20 | /// Removes a patch starting at the specified destination. 21 | static bool RemovePatch(uint8_t *dest); 22 | 23 | /// Removes all patches belonging to a specific owner. 24 | static bool RemovePatches(uint32_t ownerID); 25 | }; 26 | 27 | } -------------------------------------------------------------------------------- /src/core/Patcher.cpp: -------------------------------------------------------------------------------- 1 | #include "Patcher.h" 2 | #include "PatchManager.h" 3 | 4 | #include 5 | 6 | namespace GH3P 7 | { 8 | 9 | //Constructors and destructors 10 | Patcher::Patcher(GH3::QbKey owner) : owner_(owner) {} 11 | 12 | Patcher::~Patcher() 13 | { 14 | RemoveAllChanges(); 15 | } 16 | 17 | bool Patcher::RemoveAllChanges() 18 | { 19 | return PatchManager::RemovePatches(owner_); 20 | } 21 | 22 | //Jumps 23 | bool Patcher::WriteJmp(void *addr, const void *jumpDestination) const 24 | { 25 | return WriteJmpVariant<0xE9>(addr, jumpDestination); //0xE9 is the x86 JMP instruction 26 | } 27 | 28 | bool Patcher::WriteJmpMulti(void * const *addresses, std::size_t addressCount, const void *jumpDestination) const 29 | { 30 | for (std::size_t i = 0; i < addressCount; ++i) 31 | { 32 | if (!WriteJmp(addresses[i], jumpDestination)) 33 | return false; 34 | } 35 | 36 | return true; 37 | } 38 | 39 | //Calls 40 | bool Patcher::WriteCall(void *addr, const void * calleeAddress) const 41 | { 42 | return WriteJmpVariant<0xE8>(addr, calleeAddress); //0xE8 is the x86 CALL instruction 43 | } 44 | 45 | bool Patcher::WriteCallMulti(void * const *addresses, std::size_t addressCount, const void * calleeAddress) const 46 | { 47 | for (std::size_t i = 0; i < addressCount; ++i) 48 | { 49 | if (!WriteCall(addresses[i], calleeAddress)) 50 | return false; 51 | } 52 | 53 | return true; 54 | } 55 | 56 | //Int8 Writes 57 | bool Patcher::WriteInt8(void *addr, uint8_t value) const 58 | { 59 | return Write(addr, value); 60 | } 61 | 62 | bool Patcher::WriteInt8Multi(void * const *addresses, std::size_t addressCount, uint8_t value) const 63 | { 64 | return WriteMulti(addresses, addressCount, value); 65 | } 66 | 67 | //Int16 Writes 68 | bool Patcher::WriteInt16(void *addr, uint16_t value) const 69 | { 70 | return Write(addr, value); 71 | } 72 | 73 | bool Patcher::WriteInt16Multi(void * const *addresses, std::size_t addressCount, uint16_t value) const 74 | { 75 | for (std::size_t i = 0; i < addressCount; ++i) 76 | { 77 | if (!WriteInt16(addresses[i], value)) 78 | return false; 79 | } 80 | 81 | return true; 82 | } 83 | 84 | //Int32 Writes 85 | bool Patcher::WriteInt32(void *addr, uint32_t value) const 86 | { 87 | return Write(addr, value); 88 | } 89 | 90 | bool Patcher::WriteInt32Multi(void * const *addresses, std::size_t addressCount, uint32_t value) const 91 | { 92 | for (std::size_t i = 0; i < addressCount; ++i) 93 | { 94 | if (!WriteInt32(addresses[i], value)) 95 | return false; 96 | } 97 | 98 | return true; 99 | } 100 | 101 | //Int64 Writes 102 | bool Patcher::WriteInt64(void *addr, uint64_t value) const 103 | { 104 | return Write(addr, value); 105 | } 106 | 107 | bool Patcher::WriteInt64Multi(void * const *addresses, std::size_t addressCount, uint64_t value) const 108 | { 109 | for (std::size_t i = 0; i < addressCount; ++i) 110 | { 111 | if (!WriteInt64(addresses[i], value)) 112 | return false; 113 | } 114 | 115 | return true; 116 | } 117 | 118 | //Pointer Writes 119 | bool Patcher::WritePointer(void *addr, void * value) const 120 | { 121 | return WriteInt32(addr, reinterpret_cast(value)); 122 | } 123 | 124 | bool Patcher::WritePointerMulti(void * const *addresses, std::size_t addressCount, const void * value) const 125 | { 126 | return WriteInt32Multi(addresses, addressCount, reinterpret_cast(value)); 127 | } 128 | 129 | //Array Writes 130 | bool Patcher::WriteArray(void *addr, const uint8_t *value, uint32_t length) const 131 | { 132 | if (length == 0) 133 | return true; 134 | 135 | return PatchManager::ApplyPatch(value, reinterpret_cast(addr), length, owner_); 136 | } 137 | 138 | bool Patcher::WriteArrayMulti(void * const *addresses, std::size_t addressCount, const uint8_t *value, uint32_t length) const 139 | { 140 | for (std::size_t i = 0; i < addressCount; ++i) 141 | { 142 | if (!WriteArray(addresses[i], value, length)) 143 | return false; 144 | } 145 | 146 | return true; 147 | } 148 | 149 | //NOP Writes 150 | bool Patcher::WriteNOPs(void *addr, uint32_t length) const 151 | { 152 | if (length == 0) 153 | return true; 154 | 155 | std::vector nopArray(length); 156 | memset(&(nopArray[0]), 0x90, length); 157 | return PatchManager::ApplyPatch(&nopArray[0], reinterpret_cast(addr), nopArray.size(), owner_); 158 | } 159 | 160 | bool Patcher::WriteNOPsMulti(void * const *addresses, std::size_t addressCount, uint32_t length) const 161 | { 162 | for (std::size_t i = 0; i < addressCount; ++i) 163 | { 164 | if (!WriteNOPs(addresses[i], length)) 165 | return false; 166 | } 167 | 168 | return true; 169 | } 170 | } -------------------------------------------------------------------------------- /src/core/ScopedUnprotect.cpp: -------------------------------------------------------------------------------- 1 | #include "ScopedUnprotect.h" 2 | #include 3 | 4 | namespace GH3P 5 | { 6 | static const LPVOID GH3_CODE_START = (LPVOID)0x00401010; 7 | static const SIZE_T GH3_CODE_SIZE = 0x00490000; 8 | 9 | ScopedUnprotect::ScopedUnprotect() : ScopedUnprotect(GH3_CODE_START, GH3_CODE_SIZE) 10 | { 11 | } 12 | 13 | ScopedUnprotect::ScopedUnprotect(LPVOID addr, SIZE_T length) : addr_(addr), length_(length) 14 | { 15 | VirtualProtect(addr_, length_, PAGE_EXECUTE_READWRITE, &oldProtect_); 16 | } 17 | 18 | ScopedUnprotect::~ScopedUnprotect() 19 | { 20 | VirtualProtect(addr_, length_, oldProtect_, &oldProtect_); 21 | } 22 | } -------------------------------------------------------------------------------- /src/core/ScopedUnprotect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GH3Plus.h" 3 | #include 4 | 5 | namespace GH3P 6 | { 7 | /// A class that will make protected memory (such as code segments) writable while it is in scope. 8 | class GH3P_API ScopedUnprotect final 9 | { 10 | private: 11 | DWORD oldProtect_; 12 | LPVOID addr_; 13 | SIZE_T length_; 14 | public: 15 | ScopedUnprotect(); 16 | ScopedUnprotect(LPVOID addr, SIZE_T length); 17 | ~ScopedUnprotect(); 18 | }; 19 | } -------------------------------------------------------------------------------- /src/core/core.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "core.h" 10 | 11 | std::vector g_loadedPlugins; 12 | 13 | /// Load all plugins in the plugins folder. 14 | /// This has the potential to load a malicious binary! Ensure that all binaries in the plugins folder are trusted! 15 | void LoadPlugins() 16 | { 17 | std::wofstream log; 18 | log.open("debug.txt"); 19 | log << L"Loading plugins...\n"; 20 | 21 | HANDLE hFind; 22 | WIN32_FIND_DATA data; 23 | 24 | hFind = FindFirstFile(L"plugins\\*.dll", &data); 25 | 26 | if (hFind != INVALID_HANDLE_VALUE) 27 | { 28 | do 29 | { 30 | HANDLE plugin = LoadPlugin(data.cFileName, log); 31 | 32 | if (plugin != NULL) 33 | { 34 | g_loadedPlugins.push_back(plugin); 35 | } 36 | 37 | } while (FindNextFile(hFind, &data)); 38 | 39 | FindClose(hFind); 40 | } 41 | 42 | log << L"All plugins loaded...\n"; 43 | log.close(); 44 | } 45 | 46 | /// Attempt's to load a DLL in the plugins folder (which is trusted to be a GH3+ plugin) 47 | HANDLE LoadPlugin(LPCWSTR plugin, std::wofstream &log) 48 | { 49 | std::wstring plugin2(plugin); 50 | std::wstring lowerPlugin2(plugin); 51 | std::transform(lowerPlugin2.begin(), lowerPlugin2.end(), lowerPlugin2.begin(), ::towlower); 52 | 53 | if (lstrcmp(lowerPlugin2.c_str(), L"core.dll") == 0 || !lendswith(lowerPlugin2.c_str(), L".dll")) 54 | return NULL; 55 | 56 | std::wstring dir(L"plugins\\"); 57 | dir.append(lowerPlugin2); 58 | 59 | HANDLE pluginHandle = LoadLibraryW(dir.c_str()); 60 | 61 | if (pluginHandle != INVALID_HANDLE_VALUE && pluginHandle != NULL) 62 | { 63 | log << L"Loaded " << dir.c_str() << " at " << pluginHandle << L"\n"; 64 | } 65 | else 66 | { 67 | log << L"Failed to load " << dir.c_str() << L". Error code given: " << GetLastError() << L"\n"; 68 | } 69 | 70 | return pluginHandle; 71 | } 72 | 73 | /// Returns true if the wide string ends with the specified ending 74 | bool lendswith(LPCWSTR str, LPCWSTR ending) 75 | { 76 | int length = lstrlen(str); 77 | int endLength = lstrlen(ending); 78 | 79 | if (endLength > length) 80 | return false; 81 | 82 | LPCWSTR strEnding = str + length - endLength; 83 | 84 | if (lstrcmp(strEnding, ending) == 0) 85 | return true; 86 | 87 | return false; 88 | } -------------------------------------------------------------------------------- /src/core/core.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | bool lendswith(LPCWSTR str, LPCWSTR ending); 7 | HANDLE LoadPlugin(LPCWSTR plugin, std::wofstream &log); 8 | void LoadPlugins(); -------------------------------------------------------------------------------- /src/core/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // Entry point for GH3+ 2 | #include 3 | #include "core.h" 4 | 5 | BOOL APIENTRY DllMain( HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | LoadPlugins(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/gh3/BinaryTree.cpp: -------------------------------------------------------------------------------- 1 | #include "BinaryTree.h" 2 | 3 | 4 | namespace GH3 5 | { 6 | 7 | bool BinaryTree::GetTypedValue(QbKey aKey, QbValueType valueType, void * pValue) 8 | { 9 | uint32_t searchValue; // ebx@2 10 | uint32_t *data; // ebp@2 11 | uint32_t left; // esi@2 12 | uint32_t right; // edi@2 13 | uint32_t middle; // eax@3 14 | uint32_t leftNode; // edx@3 15 | 16 | uint32_t * const iValue = static_cast(pValue); 17 | float * const fValue = static_cast(pValue); 18 | 19 | if (this->root) 20 | { 21 | searchValue = aKey + valueType; 22 | data = &this->data[this->arrayOffset]; 23 | left = 0; 24 | for (right = this->root; ; left = (right + left) >> 1) 25 | { 26 | while (1) 27 | { 28 | middle = (right + left) >> 1; 29 | 30 | leftNode = data[2 * middle]; 31 | if (searchValue >= leftNode) 32 | break; 33 | 34 | if (right == middle) 35 | goto MAYBE_FLOAT; 36 | right = (right + left) >> 1; 37 | } 38 | 39 | if (searchValue <= leftNode) 40 | break; 41 | 42 | if (left == middle) 43 | goto MAYBE_FLOAT; 44 | } 45 | *iValue = data[2 * middle + 1]; 46 | return true; 47 | } 48 | 49 | MAYBE_FLOAT: 50 | uint32_t tmp; 51 | if (valueType == TypeFloat && GetTypedValue(aKey, QbValueType::TypeInt, &tmp)) 52 | { 53 | *fValue = (float)tmp; 54 | return true; 55 | } 56 | 57 | return false; 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /src/gh3/BinaryTree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core\GH3Plus.h" 4 | #include "QbKey.h" 5 | #include "QbValueType.h" 6 | #include 7 | 8 | 9 | namespace GH3 10 | { 11 | /// A class representing some sort of binary tree. Details are scarce as this isn't really used from what I've seen. 12 | struct GH3P_API BinaryTree 13 | { 14 | private: 15 | uint16_t root; 16 | uint8_t arrayOffset; 17 | uint8_t byte3; //probably length? 18 | uint32_t data[1]; 19 | public: 20 | bool GetTypedValue(QbKey aKey, QbValueType valueType, void *pValue); 21 | }; 22 | } -------------------------------------------------------------------------------- /src/gh3/CAliveRefCounted.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "gh3\CRefCounted.h" 4 | #include "gh3\QbKey.h" 5 | 6 | namespace GH3 7 | { 8 | /// Unknown. More specific version of CRefCounted 9 | class GH3P_API CAliveRefCounted : CRefCounted 10 | { 11 | 12 | public: 13 | uint32_t object8; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/gh3/CObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "gh3\CRefCounted.h" 4 | #include "gh3\CAliveRefCounted.h" 5 | #include "gh3\QbKey.h" 6 | #include "gh3\QbStruct.h" 7 | #include "gh3\List.h" 8 | 9 | namespace GH3 10 | { 11 | /// Object. Base class of a large amount of classes in the Neversoft engine. 12 | class GH3P_API CObject : CRefCounted 13 | { 14 | public: 15 | enum CObjectFlags 16 | { 17 | UnkFlag1 = 0x1, 18 | UnkFlag2 = 0x2, 19 | UnkFlag3 = 0x4, 20 | UnkFlag4 = 0x8, 21 | UnkFlag5 = 0x10, 22 | UnkFlag6 = 0x20, 23 | UnkFlag7 = 0x40, 24 | UnkFlag8 = 0x80, 25 | UnkFlag9 = 0x100, 26 | UnkFlag10 = 0x200, 27 | UnkAnimationFlag11 = 0x400, 28 | UnkFlag12 = 0x800, 29 | UnkFlag13 = 0x1000, 30 | OddScaleFlag = 0x2000, 31 | UnkFlag15 = 0x4000, 32 | UnkFlag16 = 0x8000, 33 | UnkFlag17 = 0x10000, 34 | UnkFlag18 = 0x20000, 35 | UnkFlag19 = 0x40000, 36 | Invisible1 = 0x80000, 37 | UnkFlag21 = 0x100000, 38 | UnkFlag22 = 0x200000, 39 | Invisible2 = 0x400000, 40 | UnkFlag24 = 0x800000, 41 | MessesUpAnglesFlag = 0x1000000, 42 | MirrorVertically = 0x2000000, 43 | MirrorHorizontally = 0x4000000, 44 | UnkFlag28 = 0x8000000, 45 | UnkFlag29 = 0x10000000, 46 | Immortal = 0x20000000, 47 | UnkFlag31 = 0x40000000, 48 | UnkFlag32 = 0x80000000, 49 | }; 50 | 51 | struct VFTable 52 | { 53 | CObject *(__thiscall *dtor)(CObject *this_, bool onHeap); 54 | int (__thiscall *method1)(CObject *this_); 55 | int (__thiscall *method2)(CObject *this_, QbStruct *); 56 | int (__thiscall *method3)(CObject *this_); 57 | int (__thiscall *method4)(CObject *this_); 58 | int (__thiscall *method5)(CObject *this_); 59 | int (__thiscall *method6)(CObject *this_); 60 | int (__thiscall *method7)(CObject *this_); 61 | int (__thiscall *method8)(CObject *this_); 62 | }; 63 | 64 | CObjectFlags flags; 65 | uint32_t *unkClass_C; 66 | uint32_t field_10; 67 | uint32_t field_14; 68 | uint32_t field_18; 69 | QbKey elementType; 70 | uint8_t field_20; 71 | uint32_t field_24; 72 | QbStruct *unkStruct; 73 | QbKey name; 74 | uint32_t field_30; 75 | uint32_t field_34; 76 | Lst::Node node; 77 | uint32_t field_4C; 78 | uint32_t field_50; 79 | uint32_t field_54; 80 | CAliveRefCounted crefcounted58; 81 | }; 82 | } -------------------------------------------------------------------------------- /src/gh3/CRefCounted.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "core\GH3Plus.h" 3 | #include 4 | 5 | namespace GH3 6 | { 7 | /// Base class of a large amount of classes in Neversoft's engine. Indicates a class that is supposedly reference counted. 8 | /// The actual methods to CRefCounted haven't been found yet but you probably don't have to worry about them. 9 | class GH3P_API CRefCounted 10 | { 11 | public: 12 | struct VFTable 13 | { 14 | int(__thiscall *dtor)(CRefCounted *this_, bool onHeap); 15 | }; 16 | 17 | void *vftable; 18 | uint32_t dword4; 19 | }; 20 | } -------------------------------------------------------------------------------- /src/gh3/CScreenElement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "gh3\CObject.h" 4 | #include "gh3\QbStruct.h" 5 | 6 | namespace GH3 7 | { 8 | /* List of classes that derive from CScreenElement: 9 | Front::CBaseMenu 10 | Front::CBaseScrollingMenu 11 | Front::CContainerElement 12 | Front::CElement3d 13 | Front::CHMenu 14 | Front::CHScrollingMenu 15 | Front::CMovieElement 16 | Front::CTextBlockElement 17 | Front::CTextElement 18 | Front::CVMenu 19 | Front::CVScrollingMenu 20 | Front::CViewportElement 21 | Front::CWindowElement 22 | */ 23 | 24 | /// Any element that appears on the screen. This should technically live in the "Front" namespace. 25 | class GH3P_API CScreenElement : CObject 26 | { 27 | public: 28 | struct ElementBox 29 | { 30 | CScreenElement *left; 31 | CScreenElement *right; 32 | uint32_t data; 33 | }; 34 | 35 | struct ScrEleStructD4 36 | { 37 | float float0; 38 | uint32_t dword4; 39 | uint32_t dword8; 40 | uint32_t dwordC; 41 | float float10; 42 | float float14; 43 | float float18; 44 | float float1C; 45 | float float20; 46 | uint16_t word24; 47 | uint16_t word26; 48 | float widthScaleMod1; 49 | float heightScaleMod1; 50 | float widthScaleMod2; 51 | float heightScaleMod2; 52 | uint32_t dword38; 53 | uint8_t byte3C; 54 | uint8_t byte3D; 55 | uint8_t byte3E; 56 | uint8_t byte3F; 57 | }; 58 | 59 | 60 | struct ScrEleStruct1C4 61 | { 62 | uint8_t byte0; 63 | uint32_t dword4; 64 | uint32_t dword8; 65 | uint32_t dwordC; 66 | uint32_t dword10; 67 | uint32_t dword14; 68 | ScrEleStruct1C4 *next; 69 | }; 70 | 71 | 72 | struct ScrEleStruct1E4 73 | { 74 | ScrEleStruct1E4 *prev; 75 | ScrEleStruct1E4 *next; 76 | uint32_t data; 77 | }; 78 | 79 | struct __declspec(align(4)) VFTable 80 | { 81 | CScreenElement * (__thiscall *dtor)(CScreenElement *this_, bool onHeap); 82 | int (__thiscall *method1)(CScreenElement *this_); 83 | int (__thiscall *method2)(CScreenElement *this_, GH3::QbStruct *); 84 | int (__thiscall *method3)(CScreenElement *this_); 85 | int (__thiscall *method4)(CScreenElement *this_); 86 | int (__thiscall *method5)(CScreenElement *this_); 87 | int (__thiscall *method6)(CScreenElement *this_); 88 | int (__thiscall *method7)(CScreenElement *this_); 89 | int (__thiscall *method8)(CScreenElement *this_); 90 | int (__thiscall *method9)(CScreenElement *this_); 91 | int (__thiscall *method10)(CScreenElement *this_); 92 | int (__thiscall *method11)(CScreenElement *this_); 93 | int (__thiscall *method12)(CScreenElement *this_); 94 | int (__thiscall *method13)(CScreenElement *this_, void *); 95 | }; 96 | 97 | 98 | ElementBox box64; 99 | ElementBox box70; 100 | ElementBox box7C; 101 | ElementBox box88; 102 | ScrEleStructD4 struct94; 103 | ScrEleStructD4 structD4; 104 | ScrEleStructD4 struct114; 105 | ScrEleStructD4 struct154; 106 | float addedTo1; 107 | float unkFloat_198; 108 | float unkFloat_19C; 109 | float unkFloat_1A0; 110 | float Width; 111 | float Height; 112 | uint8_t byte1AC; 113 | uint8_t byte1AD; 114 | uint8_t byte1AE; 115 | uint8_t byte1AF; 116 | float unk1B0_4_1; 117 | float unk1B4_0_0; 118 | uint32_t field_1B8; 119 | uint32_t field_1BC; 120 | uint32_t field_1C0; 121 | ScrEleStruct1C4 struct1C4; 122 | uint32_t field_1E0; 123 | ScrEleStruct1E4 struct1E4; 124 | }; 125 | } -------------------------------------------------------------------------------- /src/gh3/CTextElement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "gh3\CScreenElement.h" 4 | #include "gh3\CXboxFont.h" 5 | #include "gh3\CXboxText.h" 6 | 7 | namespace GH3 8 | { 9 | /// A UI Text Object. 10 | class GH3P_API CTextElement : CScreenElement 11 | { 12 | public: 13 | QbKey key1F0; 14 | CXboxFont *font; 15 | CXboxText **text; 16 | CXboxText **shadowText; 17 | int32_t textCount; 18 | uint32_t *unkStruct; 19 | bool shadowEnabled; 20 | int32_t shadowXOffset; 21 | int32_t shadowYOffset; 22 | uint32_t dword214; 23 | bool overrideEncodedRgba; 24 | bool storedOverrideRgbaState; 25 | bool overrideEncodedAlpha; 26 | bool flag4; 27 | int32_t fontSpacing; 28 | }; 29 | } -------------------------------------------------------------------------------- /src/gh3/CXboxFont.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gh3\QbKey.h" 3 | #include 4 | 5 | namespace GH3 6 | { 7 | /// A class representing an Xbox 360 font (PC GH3 is a port of GH3 for the Xbox 360) 8 | class GH3P_API CXboxFont 9 | { 10 | public: 11 | struct VFTable 12 | { 13 | CXboxFont *(__thiscall *dtor)(CXboxFont * this_, bool onHeap); 14 | int(__thiscall *vmethod1)(CXboxFont * this_); 15 | int(__thiscall *vmethod2)(CXboxFont * this_); 16 | int(__thiscall *vmethod3)(CXboxFont * this_); 17 | int(__thiscall *vmethod4)(CXboxFont * this_); 18 | int(__thiscall *vmethod5)(CXboxFont * this_); 19 | int(__thiscall *vmethod6)(CXboxFont * this_); 20 | int(__thiscall *vmethod7)(CXboxFont * this_); 21 | int(__thiscall *vmethod8)(CXboxFont * this_); 22 | int(__thiscall *vmethod9)(CXboxFont * this_); 23 | int(__thiscall *vmethod10)(CXboxFont * this_); 24 | }; 25 | 26 | void *vftable; 27 | QbKey name; 28 | uint32_t unknown; 29 | uint32_t *memory; 30 | uint32_t zero1; 31 | uint32_t zero2; 32 | uint32_t zero3; 33 | uint32_t zero4; 34 | uint32_t unk1; 35 | uint32_t unk2; 36 | uint32_t zero5; 37 | uint32_t *ptrToAbove; 38 | }; 39 | } -------------------------------------------------------------------------------- /src/gh3/CXboxText.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "gh3\SText.h" 4 | #include "gh3\CXboxFont.h" 5 | #include "gh3\QbKey.h" 6 | 7 | namespace GH3 8 | { 9 | /// A class representing an Xbox 360 text element (PC GH3 is a port of GH3 for the Xbox 360) 10 | class GH3P_API CXboxText 11 | { 12 | public: 13 | struct __declspec(align(2)) TextTransformation 14 | { 15 | __int16 X; 16 | __int16 Y; 17 | __int16 scaleX; 18 | __int16 scaleY; 19 | __int16 rotation; 20 | }; 21 | struct VFTable 22 | { 23 | CXboxText *(__thiscall CXboxText::*dtor)(CXboxText *this_, bool onHeap); 24 | int(__thiscall *vmethod1)(CXboxText *this_); 25 | int(__thiscall *vmethod2)(CXboxText *this_); 26 | int(__thiscall *CopyAttributesToSText)(CXboxText *this_); 27 | int(__thiscall *vmethod4)(CXboxText *this_); 28 | int(__thiscall *CopyWindowToSText)(CXboxText *this_); 29 | }; 30 | 31 | VFTable *vftable; 32 | CXboxFont *font; 33 | TextTransformation *coordinates; 34 | wchar_t *text; 35 | float float10; 36 | float float14; 37 | float float18; 38 | float float1C; 39 | float float20; 40 | float float24; 41 | uint32_t dword28; 42 | float float2C; 43 | float float30; 44 | float float34; 45 | uint32_t color; 46 | QbKey mode; 47 | uint8_t flag40; 48 | uint8_t flag41; 49 | uint32_t dword44; 50 | uint32_t dword48; 51 | uint32_t dword4C; 52 | uint32_t *cwindow2D; 53 | CXboxText *ctext54; 54 | SText *stext58; 55 | }; 56 | } -------------------------------------------------------------------------------- /src/gh3/GH3CodeConstants.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExileLord/GH3-Plus/309aebb6bc4c3fa82d92617403c17d9585a63f34/src/gh3/GH3CodeConstants.h -------------------------------------------------------------------------------- /src/gh3/GlobalMap.cpp: -------------------------------------------------------------------------------- 1 | #include "GlobalMap.h" 2 | 3 | namespace GH3 4 | { 5 | 6 | bool GlobalMap::GetTypedValue(QbKey key, QbValueType type, void * pValue) 7 | { 8 | HashMapNode *node = GetEntry(key); 9 | uint32_t *pValue2 = reinterpret_cast(pValue); //We don't know what type of data is being stored besides that it's 32 bits but that's all we need. 10 | 11 | while (node != nullptr) 12 | { 13 | if (node->key == key && node->itemType == type) 14 | { 15 | if (pValue2 != nullptr) 16 | *pValue2 = node->value; 17 | return true; 18 | } 19 | node = node->nextItem; 20 | } 21 | 22 | if (pValue2 != nullptr) 23 | *pValue2 = 0; 24 | return false; 25 | } 26 | 27 | //TODO: Update this code to use GetNode 28 | bool GlobalMap::GetValue(QbKey key, void * pValue, QbValueType * pType) 29 | { 30 | HashMapNode *node = GetEntry(key); 31 | uint32_t *pValue2 = reinterpret_cast(pValue); //We don't know what type of data is being stored besides that it's 32 bits but that's all we need. 32 | 33 | while (node != nullptr) 34 | { 35 | if (node->key == key) 36 | { 37 | if (pValue2 != nullptr) 38 | *pValue2 = node->value; 39 | if (pType != nullptr) 40 | *pType = node->itemType; 41 | return true; 42 | } 43 | node = node->nextItem; 44 | } 45 | 46 | if (pValue2 != nullptr) 47 | *pValue2 = 0; 48 | if (pType != nullptr) 49 | *pType = QbValueType::TypeUndefined; 50 | return false; 51 | } 52 | 53 | //Crude way for setting values or doing horrible things the hashmap structure 54 | HashMapNode * GlobalMap::GetNode(QbKey key) 55 | { 56 | HashMapNode *node = GetEntry(key); 57 | 58 | while (node != nullptr) 59 | { 60 | if (node->key == key) 61 | { 62 | return node; 63 | } 64 | node = node->nextItem; 65 | } 66 | 67 | return nullptr; 68 | } 69 | 70 | bool GlobalMap::GetInt(QbKey qbKey, int32_t &value) 71 | { 72 | return GetTypedValue(qbKey, QbValueType::TypeInt, &value); 73 | } 74 | 75 | bool GlobalMap::GetUInt(QbKey qbKey, uint32_t &value) 76 | { 77 | return GetTypedValue(qbKey, QbValueType::TypeInt, &value); 78 | } 79 | 80 | bool GlobalMap::GetFloat(QbKey qbKey, float &value) 81 | { 82 | return GetTypedValue(qbKey, QbValueType::TypeFloat, &value); 83 | } 84 | 85 | bool GlobalMap::GetDouble(QbKey qbKey, double &value) 86 | { 87 | float fValue; 88 | return GetTypedValue(qbKey, QbValueType::TypeFloat, &fValue); 89 | value = fValue; 90 | } 91 | 92 | bool GlobalMap::GetString(QbKey qbKey, char *&value) 93 | { 94 | return GetTypedValue(qbKey, QbValueType::TypeCString, &value); 95 | } 96 | 97 | bool GlobalMap::GetWString(QbKey qbKey, wchar_t *&value) 98 | { 99 | return GetTypedValue(qbKey, QbValueType::TypeWString, &value); 100 | } 101 | 102 | bool GlobalMap::GetPair(QbKey qbKey, QbPair *&value) 103 | { 104 | return GetTypedValue(qbKey, QbValueType::TypePair, &value); 105 | } 106 | 107 | bool GlobalMap::GetPair(QbKey qbKey, float & x, float & y) 108 | { 109 | QbPair *value; 110 | if (GetPair(qbKey, value)) 111 | { 112 | x = value->X; 113 | y = value->Y; 114 | return true; 115 | } 116 | return false; 117 | } 118 | 119 | bool GlobalMap::GetVector(QbKey qbKey, QbVector *&value) 120 | { 121 | return GetTypedValue(qbKey, QbValueType::TypeVector, &value); 122 | } 123 | 124 | bool GlobalMap::GetVector(QbKey qbKey, float & x, float & y, float & z) 125 | { 126 | QbVector *value; 127 | if (GetVector(qbKey, value)) 128 | { 129 | x = value->X; 130 | y = value->Y; 131 | z = value->Z; 132 | return true; 133 | } 134 | return false; 135 | } 136 | 137 | bool GlobalMap::GetStruct(QbKey qbKey, QbStruct *&value) 138 | { 139 | return GetTypedValue(qbKey, QbValueType::TypeQbStruct, &value); 140 | } 141 | 142 | bool GlobalMap::GetArray(QbKey qbKey, QbArray *&value) 143 | { 144 | return GetTypedValue(qbKey, QbValueType::TypeQbArray, &value); 145 | } 146 | 147 | bool GlobalMap::GetQbKey(QbKey qbKey, QbKey &value) 148 | { 149 | return GetTypedValue(qbKey, QbValueType::TypeQbKey, &value); 150 | } 151 | 152 | } -------------------------------------------------------------------------------- /src/gh3/GlobalMap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "QbMap.h" 4 | 5 | namespace GH3 6 | { 7 | /// A node of the GlobalMap class 8 | struct __declspec(align(4)) HashMapNode 9 | { 10 | uint8_t byte0; 11 | uint8_t byte1; 12 | QbValueType itemType; 13 | uint8_t byte3; 14 | QbKey key; 15 | uint32_t dword8; 16 | uint32_t value; 17 | HashMapNode *nextItem; 18 | }; 19 | 20 | /// A static class that essentially stores almost everything to do with game state that is accessible by scripts. 21 | class GH3P_API GlobalMap final 22 | { 23 | private: 24 | GlobalMap() = delete; 25 | ~GlobalMap() = delete; 26 | public: 27 | inline static constexpr uint32_t Size() { return 15; } 28 | inline static constexpr uint32_t Length() { return 1 << Size(); } 29 | inline static constexpr uint32_t IndexMask() { return Length() - 1; } 30 | 31 | inline static HashMapNode ** Nodes() { return reinterpret_cast(0x00C03AA8); }; 32 | 33 | inline static HashMapNode * GetEntry(QbKey key) { return Nodes()[key & IndexMask()]; }; 34 | 35 | static bool GetTypedValue(QbKey key, QbValueType type, void *pValue); 36 | static bool GetValue(QbKey key, void *pValue, QbValueType *pType); 37 | static HashMapNode * GetNode(QbKey key); 38 | static bool GetInt(QbKey qbKey, int32_t &value); 39 | static bool GetUInt(QbKey qbKey, uint32_t &value); 40 | static bool GetFloat(QbKey qbKey, float &value); 41 | static bool GetDouble(QbKey qbKey, double &value); 42 | static bool GetString(QbKey qbKey, char *&value); 43 | static bool GetWString(QbKey qbKey, wchar_t *&value); 44 | static bool GetPair(QbKey qbKey, QbPair *&value); 45 | static bool GetPair(QbKey qbKey, float &x, float &y); 46 | static bool GetVector(QbKey qbKey, QbVector *&value); 47 | static bool GetVector(QbKey qbKey, float &x, float &y, float &z); 48 | static bool GetStruct(QbKey qbKey, QbStruct *&value); 49 | static bool GetArray(QbKey qbKey, QbArray *&value); 50 | static bool GetQbKey(QbKey qbKey, QbKey &value); 51 | 52 | static uint32_t Insert(uint32_t key, QbValueType type, uint32_t value); //TODO 53 | 54 | }; 55 | 56 | } -------------------------------------------------------------------------------- /src/gh3/List.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "core\GH3Plus.h" 4 | 5 | namespace GH3 6 | { 7 | namespace Lst 8 | { 9 | /// Node of Neversoft's templated linked list 10 | template 11 | class GH3P_API Node 12 | { 13 | public: 14 | struct VFTable 15 | { 16 | Node *(__thiscall *dtor)(bool onHeap); 17 | }; 18 | void *vftable; 19 | T *data; 20 | uint32_t dword8; 21 | Node *prev; 22 | Node *next; 23 | }; 24 | 25 | /// Head node of Neversoft's templated linked list 26 | template 27 | class GH3P_API Head : Node 28 | { 29 | public: 30 | struct VFTable 31 | { 32 | Head *(__thiscall *dtor)(bool onHeap); 33 | }; 34 | }; 35 | 36 | 37 | } 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/gh3/QbArray.cpp: -------------------------------------------------------------------------------- 1 | #include "QbArray.h" 2 | 3 | namespace GH3 4 | { 5 | 6 | int * QbArray::Initialize(int size, int type) 7 | { 8 | static const void *function = (void *)0x0055DF00; 9 | __asm jmp function; 10 | } 11 | 12 | void QbArray::Clear() 13 | { 14 | SetType(QbValueType::TypeUndefined); 15 | m_arr = nullptr; 16 | m_length = 0; 17 | unk1 = 0; 18 | } 19 | 20 | uint32_t QbArray::operator[](int index) const 21 | { 22 | if (m_length != 1) 23 | return m_arr[index]; 24 | else 25 | return reinterpret_cast(m_arr); 26 | } 27 | 28 | uint32_t & QbArray::operator[](int index) 29 | { 30 | if (Length() == 1) 31 | return reinterpret_cast(m_arr); 32 | else 33 | return m_arr[index]; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/gh3/QbArray.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core\GH3Plus.h" 4 | 5 | #include "QbValueType.h" 6 | #include 7 | 8 | namespace GH3 9 | { 10 | /// Neversoft's array class that is used by the game's scripting engine. Also known as CArray. 11 | struct GH3P_API QbArray final 12 | { 13 | 14 | private: 15 | uint8_t unk0; 16 | uint8_t unk1; 17 | QbValueType m_type; 18 | uint8_t unk3; 19 | uint32_t m_length; 20 | uint32_t *m_arr; 21 | 22 | public: 23 | int * __thiscall Initialize(int size, int type); 24 | 25 | void Clear(); 26 | 27 | uint32_t operator [](int index) const; 28 | uint32_t & operator [](int index); 29 | 30 | inline void Set(int index, uint32_t value) { (*this)[index] = value; } 31 | inline uint32_t Get(int index) const { return (*this)[index]; } 32 | 33 | inline void SetType(QbValueType type) { m_type = type; } 34 | inline QbValueType Type() const { return m_type;} 35 | inline uint32_t Length() const { return m_length;} 36 | }; 37 | 38 | } -------------------------------------------------------------------------------- /src/gh3/QbImage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core\GH3Plus.h" 4 | #include "QbKey.h" 5 | #include "TextureMetadata.h" 6 | #include 7 | 8 | 9 | namespace GH3 10 | { 11 | struct QbImage_VTABLE 12 | { 13 | //QbImage *(__thiscall *SetVtable)(char flags); 14 | //QbKey (__thiscall *GetQbKey)(); 15 | int (__thiscall *GetStretchWidth)(); 16 | int (__thiscall *anonymous_0)(); 17 | bool (__thiscall *CreateFromImgFile)(const char *fileName); 18 | bool (__thiscall *CreateTextureFromMetadata)(TextureMetadata *textureMetadata, int a3, int a4); 19 | bool (__thiscall *CreateNewTexture)(QbKey aKey, int cullWidth, int cullHeight, int a5, int a6, int a7, TextureMetadataFormat format); 20 | }; 21 | 22 | struct GH3P_API __declspec(align(4)) QbImage 23 | { 24 | QbImage_VTABLE *vtable; 25 | QbKey key; 26 | uint32_t flags; 27 | uint8_t MipLevels; 28 | uint8_t byteD; 29 | TextureMetadata *textureMetadata; 30 | }; 31 | } -------------------------------------------------------------------------------- /src/gh3/QbKey.cpp: -------------------------------------------------------------------------------- 1 | #include "QbKey.h" 2 | 3 | namespace GH3 4 | { 5 | static constexpr uint32_t crc32tab[] = { 6 | 0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x76DC419, 0x706AF48F, 7 | 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 8 | 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 9 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 10 | 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 11 | 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 12 | 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 13 | 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 14 | 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 15 | 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 16 | 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 17 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 18 | 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 19 | 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 20 | 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 21 | 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 22 | 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 23 | 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 24 | 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 25 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 26 | 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 27 | 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 28 | 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 29 | 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 30 | 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 31 | 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 32 | 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 33 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 34 | 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 35 | 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 36 | 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 37 | 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 38 | 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 39 | 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 40 | 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 41 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 42 | 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 43 | 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 44 | 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 45 | 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 46 | 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 47 | 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 48 | 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 49 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 50 | 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 51 | 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 52 | 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 53 | 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 54 | 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 55 | 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 56 | 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, 57 | }; 58 | } -------------------------------------------------------------------------------- /src/gh3/QbKey.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "core\GH3Plus.h" 3 | #include 4 | 5 | namespace GH3 6 | { 7 | namespace crc32 8 | { 9 | constexpr uint32_t tab[] = { 10 | 0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x76DC419, 0x706AF48F, 11 | 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 12 | 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 13 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 14 | 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 15 | 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 16 | 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 17 | 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 18 | 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 19 | 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 20 | 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 21 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 22 | 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 23 | 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 24 | 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 25 | 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 26 | 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 27 | 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 28 | 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 29 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 30 | 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 31 | 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 32 | 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 33 | 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 34 | 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 35 | 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 36 | 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 37 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 38 | 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 39 | 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 40 | 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 41 | 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 42 | 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 43 | 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 44 | 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 45 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 46 | 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 47 | 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 48 | 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 49 | 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 50 | 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 51 | 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 52 | 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 53 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 54 | 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 55 | 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 56 | 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 57 | 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 58 | 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 59 | 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 60 | 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, 61 | }; 62 | 63 | char constexpr fixChar(char c) 64 | { 65 | return (c >= 'A' && c <= 'Z') ? (c + 32) : 66 | (c == '/') ? '\\' : 67 | c; 68 | } 69 | 70 | uint32_t constexpr hashChar(char c, uint32_t crc) 71 | { 72 | return tab[(crc ^ fixChar(c)) & 0xFF] ^ (crc >> 8); 73 | } 74 | 75 | uint32_t constexpr hash(const char *key, uint32_t previousKey = 0xFFFFFFFF) 76 | { 77 | return (!key) ? 0 : 78 | (*key == '\0') ? previousKey : 79 | (hash(key + 1, hashChar(*key, previousKey))); 80 | } 81 | 82 | } 83 | 84 | 85 | 86 | 87 | 88 | /// A crc32 hash that is often used as a key in the Guitar Hero engine. 89 | struct GH3P_API QbKey final 90 | { 91 | private: 92 | /// The internal representation of the QbKey. 93 | uint32_t m_key; 94 | 95 | public: 96 | /// Initializes a QbKey with a value of 0 97 | constexpr QbKey() : m_key(0) {}; 98 | 99 | constexpr QbKey(const QbKey &rhs) : m_key(rhs.m_key) {}; 100 | 101 | /// Initializes a QbKey using an integer 102 | constexpr QbKey(const uint32_t key) : m_key(key) {}; 103 | 104 | /// Initializes a QbKey using a crc32 hash of the input string 105 | constexpr QbKey(const char *key) : m_key(crc32::hash(key)) {}; 106 | 107 | /// Allow integer conversion 108 | inline constexpr operator uint32_t() const { return m_key; } 109 | 110 | inline QbKey& operator=(const uint32_t rhs) { m_key = rhs; return *this; }; 111 | 112 | }; 113 | 114 | constexpr QbKey operator+(const QbKey & lhs, const char * rhs) 115 | { 116 | return QbKey(crc32::hash(rhs, static_cast(lhs))); 117 | } 118 | } -------------------------------------------------------------------------------- /src/gh3/QbMap.cpp: -------------------------------------------------------------------------------- 1 | #include "QbMap.h" 2 | #include 3 | 4 | namespace GH3 5 | { 6 | 7 | uint32_t QbMap::operator[](QbKey key) const 8 | { 9 | if (m_nodes == nullptr) 10 | return 0; 11 | 12 | QbMapNode *node = &m_nodes[key & IndexMask()]; 13 | 14 | while (node->key != key || !this->m_boolFlag && !node->value) 15 | { 16 | node = node->nextNode; 17 | if (node == nullptr) 18 | return 0; 19 | } 20 | return node->value; 21 | } 22 | 23 | uint32_t & QbMap::operator[](QbKey key) 24 | { 25 | static uint32_t &nullref = *reinterpret_cast(0); 26 | 27 | if (m_nodes == nullptr) 28 | return nullref; 29 | 30 | uint32_t index = key & IndexMask(); 31 | 32 | //Attempt insertion if the node doesn't exist 33 | QbMapNode *node = &m_nodes[index]; 34 | if (node->key == 0 && node->nextNode == nullptr) 35 | { 36 | node->key = key; 37 | return node->value; 38 | } 39 | 40 | while (node->key != key || !this->m_boolFlag && !node->value) 41 | { 42 | if (node->nextNode == nullptr) 43 | { 44 | QbMapNode *nextNode = static_cast(malloc(sizeof(QbMapNode))); //TODO: Use GH3's malloc. THIS WILL PROBABLY CRASH 45 | node->nextNode = nextNode; 46 | nextNode->key = key; 47 | nextNode->nextNode = nullptr; 48 | return nextNode->value; 49 | } 50 | } 51 | return node->value; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /src/gh3/QbMap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core\GH3Plus.h" 4 | #include "QbValueType.h" 5 | #include "QbKey.h" 6 | #include "QbStruct.h" 7 | #include 8 | 9 | 10 | namespace GH3 11 | { 12 | /// A GH3 map/dictionary structure. Only stores other types, not native structures. 13 | struct GH3P_API QbMap 14 | { 15 | private: 16 | 17 | struct QbMapNode 18 | { 19 | QbKey key; 20 | uint32_t value; 21 | QbMapNode *nextNode; 22 | }; 23 | 24 | uint32_t m_size; 25 | QbMapNode *m_nodes; 26 | QbNodeFlags m_typeFlags; 27 | uint32_t unkC; 28 | uint32_t unk10; 29 | uint8_t unk14; 30 | uint8_t m_boolFlag; 31 | uint8_t m_keepAliveFlag; 32 | uint8_t unk17; 33 | 34 | public: 35 | uint32_t operator[] (QbKey key) const; 36 | uint32_t & operator[] (QbKey key); 37 | 38 | inline uint32_t Get(QbKey key) const { return (*this)[key]; }; 39 | inline void Insert(QbKey key, uint32_t value) { this->operator[](key) = value; }; 40 | 41 | inline uint32_t Size() const { return m_size; } 42 | inline QbValueType Type() const { return static_cast(m_typeFlags >> 1); } 43 | inline uint32_t IndexMask() const { return ( (1 << m_size) - 1); } 44 | }; 45 | 46 | } -------------------------------------------------------------------------------- /src/gh3/QbPair.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core\GH3Plus.h" 4 | #include "QbKey.h" 5 | #include 6 | 7 | namespace GH3 8 | { 9 | /// Neversoft's pair class that is referenced by the scripting engine. A pair of two floats. Also known as CPair 10 | struct GH3P_API QbPair 11 | { 12 | uint8_t gap0[1]; 13 | uint8_t byte1; 14 | float X; 15 | float Y; 16 | }; 17 | } -------------------------------------------------------------------------------- /src/gh3/QbScript.cpp: -------------------------------------------------------------------------------- 1 | #include "QbScript.h" 2 | 3 | // Currently there are no QbScript methods that aren't bound to the native GH3 counterparts -------------------------------------------------------------------------------- /src/gh3/QbScript.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core\GH3Plus.h" 4 | #include "QbStruct.h" 5 | #include "QbKey.h" 6 | #include 7 | 8 | namespace GH3 9 | { 10 | /// Neversoft's script class. Most of the contents of the script class are unknown. Also known as CScript 11 | struct GH3P_API QbScript 12 | { 13 | uint8_t gap0[16]; 14 | uint8_t *instructionPointer; 15 | QbStruct *qbStruct14; 16 | uint32_t dword18; 17 | QbStruct *qbStruct1C; 18 | uint8_t gap20[16]; 19 | uint8_t gap30[16]; 20 | uint8_t gap40[16]; 21 | uint8_t gap50[16]; 22 | uint8_t gap60[16]; 23 | uint8_t gap70[16]; 24 | uint8_t gap80[16]; 25 | uint8_t gap90[16]; 26 | uint32_t dwordA0; 27 | uint32_t dwordA4; 28 | uint32_t unkStructPtrA8; 29 | uint32_t dwordAC; 30 | uint32_t unkB0; 31 | uint32_t dwordB4; 32 | uint32_t dwordB8; 33 | uint8_t unkBC; 34 | uint8_t unkBD; 35 | uint8_t unkBE; 36 | uint8_t unkBF; 37 | uint8_t *nextIP; 38 | uint8_t unkC4; 39 | uint8_t unkC5; 40 | uint8_t unkC6; 41 | uint8_t unkC7; 42 | uint32_t dwordC8; 43 | uint32_t dwordCC; 44 | uint32_t dwordD0; 45 | uint32_t dwordD4; 46 | QbKey type; 47 | }; 48 | 49 | ///used for struct items? 50 | static void (__cdecl * const SpawnScript)(QbStruct *aStruct, QbScript *parentScript) = reinterpret_cast(0x00534100); 51 | static void (__cdecl * const SpawnScriptNow)(QbStruct *aStruct, QbScript *parentScript) = reinterpret_cast(0x00534140); 52 | static void (__cdecl * const SpawnScriptLater)(QbStruct *aStruct, QbScript *parentScript) = reinterpret_cast(0x00534160); 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/gh3/QbStruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core\GH3Plus.h" 4 | #include "QbValueType.h" 5 | #include "QbKey.h" 6 | #include "QbPair.h" 7 | #include "QbVector.h" 8 | #include "QbArray.h" 9 | #include 10 | 11 | namespace GH3 12 | { 13 | 14 | enum GH3P_API QbNodeFlags : __int8 15 | { 16 | QFlagStructItem = 0x1, 17 | QTypeInt = 0x2, 18 | QTypeFloat = 0x4, 19 | QTypeCString = 0x6, 20 | QTypeWString = 0x8, 21 | QTypePair = 0xA, 22 | QTypeVector = 0xC, 23 | QTypeScript = 0xE, 24 | QTypeCFunc = 0x10, 25 | QTypeUnk9 = 0x12, 26 | QTypeQbStruct = 0x14, 27 | QTypeQbArray = 0x18, 28 | QTypeQbKey = 0x1A, 29 | QTypeUnk20 = 0x28, 30 | QTypeUnk21 = 0x2A, 31 | QTypeBinaryTree1 = 0x2C, 32 | QTypeBinaryTree2 = 0x2E, 33 | QTypeStringPointer = 0x34, 34 | QTypeMap = 0x36, 35 | }; 36 | 37 | /// A node in the QbStruct "linked list" 38 | struct GH3P_API QbStructItem 39 | { 40 | uint8_t unkFlag0; 41 | QbNodeFlags flags; 42 | uint16_t word2; 43 | uint32_t key; 44 | uint32_t value; 45 | QbStructItem *next; 46 | 47 | inline QbValueType Type() const { return static_cast(flags >> 1); } 48 | 49 | QbStructItem(QbNodeFlags aFlags, QbKey aKey, uint32_t aValue); 50 | }; 51 | 52 | /// Neversoft's struct class that is referenced by the scripting engine. Implemented like a linked list of the items it contains. Also known as CStruct 53 | struct GH3P_API QbStruct 54 | { 55 | 56 | private: 57 | uint16_t unk0; 58 | uint8_t unk2; //might be a debug flag to not free or something 59 | uint8_t unk3; 60 | QbStructItem *first; 61 | 62 | public: 63 | QbStruct(); 64 | QbStruct(QbStructItem *itemChain); //Use with care 65 | ~QbStruct(); 66 | 67 | ///Untested. Get a value from the QbStruct, traversing its children if necessary 68 | bool GetTypedValue(QbKey qbKey, QbValueType valueType, void *outValue); 69 | bool GetInt(QbKey qbKey, int32_t &value); 70 | bool GetUInt(QbKey qbKey, uint32_t &value); 71 | bool GetFloat(QbKey qbKey, float &value); 72 | bool GetDouble(QbKey qbKey, double &value); 73 | bool GetString(QbKey qbKey, char *&value); 74 | bool GetWString(QbKey qbKey, wchar_t *&value); 75 | bool GetPair(QbKey qbKey, QbPair &value); 76 | bool GetVector(QbKey qbKey, QbVector &value); 77 | bool GetStruct(QbKey qbKey, QbStruct &value); 78 | bool GetArray(QbKey qbKey, QbArray &value); 79 | bool GetQbKey(QbKey qbKey, QbKey &value); 80 | 81 | ///Gets an item in the immediate item chain of the struct (it will not recursively traverse nested structs, maps, or binary trees) 82 | QbStructItem * GetItem(QbKey key); 83 | QbStructItem * GetItem(QbKey qbKey, QbValueType type); 84 | bool ContainsItem(QbKey qbKey); 85 | bool ContainsItem(QbKey qbKey, QbValueType type); 86 | 87 | void __thiscall InsertCStringItem(QbKey qbKey, char *item); 88 | void __thiscall InsertWStringItem(QbKey qbKey, wchar_t *item); 89 | void __thiscall InsertStringPointerItem(QbKey qbKey, uint32_t item); 90 | void __thiscall InsertIntItem(QbKey qbKey, int32_t item); 91 | void __thiscall InsertUIntItem(QbKey qbKey, uint32_t item); 92 | void __thiscall InsertFloatItem(QbKey qbKey, float item); 93 | void __thiscall InsertQbKeyItem(QbKey qbKey, QbKey item); 94 | void __thiscall InsertVectorItem(QbKey qbKey, QbVector *item); 95 | void __thiscall InsertPairItem(QbKey qbKey, QbPair *item); 96 | void __thiscall InsertQbArrayItem(QbKey qbKey, QbArray *item); 97 | void __thiscall InsertQbStructItem(QbKey qbKey, QbStruct *item); 98 | 99 | }; 100 | 101 | } -------------------------------------------------------------------------------- /src/gh3/QbValueType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace GH3 4 | { 5 | /// Represents any value that can be referenced by GH3's storage system such as the GlobalMap, QbArrays, and QbStructs. 6 | enum GH3P_API QbValueType : __int8 7 | { 8 | TypeUndefined = 0x0, 9 | TypeInt = 0x1, 10 | TypeFloat = 0x2, 11 | TypeCString = 0x3, 12 | TypeWString = 0x4, 13 | TypePair = 0x5, 14 | TypeVector = 0x6, 15 | TypeScript = 0x7, 16 | TypeCFunc = 0x8, 17 | TypeUnk9 = 0x9, 18 | TypeQbStruct = 0xA, 19 | TypeQbArray = 0xC, 20 | TypeQbKey = 0xD, 21 | TypeUnk20 = 0x14, 22 | TypeUnk21 = 0x15, 23 | TypeBinaryTree1 = 0x16, 24 | TypeBinaryTree2 = 0x17, 25 | TypeStringPointer = 0x1A, 26 | TypeQbMap = 0x1B, 27 | TypeQbKeyStringQs = 0x1C, 28 | }; 29 | 30 | } -------------------------------------------------------------------------------- /src/gh3/QbVector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core\GH3Plus.h" 4 | #include "QbKey.h" 5 | #include 6 | 7 | namespace GH3 8 | { 9 | /// Neversoft's vector class that is referenced by the scripting engine. A vector of three floats. Also known as CVector 10 | struct GH3P_API QbVector 11 | { 12 | uint8_t gap0[1]; 13 | uint8_t byte1; 14 | float X; 15 | float Y; 16 | float Z; 17 | }; 18 | } -------------------------------------------------------------------------------- /src/gh3/SDraw2D.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //Empty class. All members live in SText currently 4 | 5 | namespace GH3 6 | { 7 | enum class BlendModeEnum 8 | { 9 | DIFFUSE = 0x0, 10 | ADD = 0x1, 11 | SUBTRACT = 0x2, 12 | BLEND = 0x3, 13 | MODULATE = 0x4, 14 | UNK = 0x5, 15 | }; 16 | 17 | /// Class representing something that can get drawn to the screen. Currently this class is empty because the only subclass GH3+ uses is SText. 18 | class SDraw2D 19 | { 20 | }; 21 | } -------------------------------------------------------------------------------- /src/gh3/SText.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gh3\SDraw2D.h" 4 | #include 5 | 6 | namespace GH3 7 | { 8 | /// A class representing a 2D text object about to be drawn to the screen. Unknown if this is Neversoft's, Aspyr's, or someone else's. 9 | class SText : SDraw2D 10 | { 11 | public: 12 | struct VFTable 13 | { 14 | SText *(__thiscall *dtor)(SText *this_, bool onHeap); 15 | int(__thiscall *vmethod1)(SText *this_); 16 | int(__thiscall *vmethod2)(SText *this_); 17 | int(__thiscall *vmethod3)(SText *this_); 18 | int(__thiscall *vmethod4)(SText *this_); 19 | int(__thiscall *vmethod5)(SText *this_); 20 | }; 21 | VFTable *vftable; 22 | SText *stext4; 23 | bool flag8; 24 | bool flag9; 25 | float floatC; 26 | float float10; 27 | BlendModeEnum mode; 28 | uint32_t dword18; 29 | uint32_t funcPtr; 30 | uint32_t *xboxWindow2D; 31 | uint32_t *memory24; 32 | uint32_t dword28; 33 | wchar_t *text; 34 | float float30; 35 | float float34; 36 | float float38; 37 | float float3C; 38 | float float40; 39 | float float44; 40 | uint32_t dword48; 41 | uint32_t unk4C; 42 | uint8_t flag50; 43 | uint8_t flag51; 44 | uint32_t dword54; 45 | }; 46 | } -------------------------------------------------------------------------------- /src/gh3/TextureMetadata.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core\GH3Plus.h" 4 | #include "QbKey.h" 5 | #include 6 | #include 7 | 8 | 9 | namespace GH3 10 | { 11 | enum GH3P_API TextureMetadataFormat : __int8 12 | { 13 | TM_DXT1 = 0x1, 14 | TM_DXT2 = 0x2, 15 | TM_DXT3 = 0x3, 16 | TM_DXT4 = 0x4, 17 | TM_DXT5_1 = 0x5, 18 | TM_DXT5_2 = 0x6, 19 | TM_A8R8G8B8 = 0x0, 20 | }; 21 | 22 | enum GH3P_API TextureMetadataType : __int8 23 | { 24 | TM_CubeTexture = 0x4, 25 | TM_VolumeTexture = 0x5, 26 | }; 27 | 28 | /// A structure representing texture metadata, containing information about the texture such as the width, height, and format in addition 29 | /// to a pointer to the actual texture itself. 30 | struct GH3P_API __declspec(align(4)) TextureMetadata 31 | { 32 | uint8_t byte0; 33 | uint8_t byte1; 34 | uint8_t unkFlags; 35 | TextureMetadataType type; 36 | QbKey key; 37 | uint16_t stretchWidth; 38 | uint16_t stretchHeight; 39 | uint16_t unk1; 40 | uint16_t cullWidth; 41 | uint16_t cullHeight; 42 | uint16_t unk2; 43 | uint8_t MipLevels; 44 | __declspec(align(2)) TextureMetadataFormat textureFormat; 45 | uint8_t *texFile1; 46 | IDirect3DTexture9 *texture; 47 | uint32_t Length; 48 | uint8_t *texFile2; 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /src/gh3/malloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace GH3 4 | { 5 | // Various memory allocation calls used by classes in the game. Since the game's memory management is different than ours, any game class created 6 | // that uses dynamic memory allocation should be using these calls so that the game cleans them up properly. 7 | 8 | ///used for struct items? 9 | static void * (__cdecl * const qbItemMalloc)(size_t size, int unused) = reinterpret_cast(0x00437410); 10 | 11 | ///Used for qbstructs 12 | static void * (__cdecl * const qbMalloc)(size_t size, int unused) = reinterpret_cast(0x00402370); 13 | } -------------------------------------------------------------------------------- /src/plugins/alwaysDoubleNotes/AlwaysDoubleNotes.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {5F7C4B1C-C85B-46E9-8171-D6B2FAE90A14} 15 | Win32Proj 16 | AlwaysDoubleNotes 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;ALWAYSDOUBLENOTES_EXPORTS;%(PreprocessorDefinitions) 58 | true 59 | ..\..\;%(AdditionalIncludeDirectories) 60 | MultiThreadedDebug 61 | 62 | 63 | Windows 64 | true 65 | 0.5 66 | 67 | 68 | 69 | 70 | Level3 71 | 72 | 73 | MaxSpeed 74 | true 75 | true 76 | WIN32;NDEBUG;_WINDOWS;_USRDLL;ALWAYSDOUBLENOTES_EXPORTS;%(PreprocessorDefinitions) 77 | true 78 | ..\..\;%(AdditionalIncludeDirectories) 79 | MultiThreaded 80 | 81 | 82 | Windows 83 | true 84 | true 85 | true 86 | 0.5 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/plugins/alwaysDoubleNotes/AlwaysDoubleNotes.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/plugins/alwaysDoubleNotes/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include 3 | #include "doubleNotes.h" 4 | 5 | BOOL APIENTRY DllMain(HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | ApplyHack(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/alwaysDoubleNotes/doubleNotes.cpp: -------------------------------------------------------------------------------- 1 | #include "gh3\GH3Keys.h" 2 | #include "gh3\GH3GlobalAddresses.h" 3 | #include "core\Patcher.h" 4 | #include "doubleNotes.h" 5 | #include 6 | 7 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 8 | 9 | __declspec(naked) void tinyJump() 10 | { 11 | static const uint32_t returnAddress = 0x0041D298; 12 | __asm 13 | { 14 | mov ecx, ebp; 15 | jmp returnAddress; 16 | } 17 | } 18 | 19 | static void * hopoCheckDetour = (void *)0x0041D1D2; 20 | static void * GetFretmaskFromNoteQbArray = (void *)0x0041B090; 21 | static void * GetFretmaskFromTrackArray = (void *)0x0041B100; 22 | __declspec (naked) void hopoCheckNaked() 23 | { 24 | static const uint32_t returnAddress = 0x0041D1E4; 25 | 26 | __asm 27 | { 28 | //Only use the old method if we're literally on the first note. 29 | sub esi, 3 30 | cmp esi, 0 31 | jge NEW_METHOD 32 | 33 | //Old method 34 | add esi, 3 //correct ESI 35 | mov ecx, edi; //this 36 | call GetFretmaskFromNoteQbArray; 37 | mov ebp, eax; 38 | jmp GET_FRETMASK; 39 | 40 | NEW_METHOD: 41 | mov ecx, [esp + 58h]; 42 | call GetFretmaskFromTrackArray 43 | mov ebp, eax; 44 | add esi, 3 //correct ESI 45 | 46 | GET_FRETMASK: 47 | mov ecx, [esp + 58h]; 48 | call GetFretmaskFromTrackArray; 49 | mov ecx, eax; 50 | 51 | jmp returnAddress; 52 | } 53 | } 54 | 55 | void ApplyHack() 56 | { 57 | g_patcher.WriteJmp((void *)0x0041D288, &tinyJump); 58 | g_patcher.WriteJmp(hopoCheckDetour, hopoCheckNaked); 59 | } -------------------------------------------------------------------------------- /src/plugins/alwaysDoubleNotes/doubleNotes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | void ApplyHack(); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/plugins/doubleNotesHopo/DoubleNotesHopo.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {117EDA36-1197-4908-AACD-3E4F4006347D} 15 | Win32Proj 16 | DoubleNotesHopo 17 | 18 | 19 | 20 | DynamicLibrary 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | DynamicLibrary 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;_DEBUG;_WINDOWS;_USRDLL;DOUBLENOTESHOPO_EXPORTS;%(PreprocessorDefinitions) 55 | true 56 | 57 | 58 | Windows 59 | true 60 | 61 | 62 | 63 | 64 | Level3 65 | 66 | 67 | MaxSpeed 68 | true 69 | true 70 | WIN32;NDEBUG;_WINDOWS;_USRDLL;DOUBLENOTESHOPO_EXPORTS;%(PreprocessorDefinitions) 71 | true 72 | 73 | 74 | Windows 75 | true 76 | true 77 | true 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/plugins/doubleNotesHopo/DoubleNotesHopo.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/plugins/forceStrumNotes/ForceStrumNotes.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {6CF035F3-C8E4-40AD-A992-D07C31BA79FC} 15 | Win32Proj 16 | ForceStrumNotes 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;FORCESTRUMNOTES_EXPORTS;%(PreprocessorDefinitions) 58 | true 59 | ..\..\;%(AdditionalIncludeDirectories) 60 | MultiThreadedDebug 61 | 62 | 63 | Windows 64 | true 65 | 0.5 66 | 67 | 68 | 69 | 70 | Level3 71 | 72 | 73 | MaxSpeed 74 | true 75 | true 76 | WIN32;NDEBUG;_WINDOWS;_USRDLL;FORCESTRUMNOTES_EXPORTS;%(PreprocessorDefinitions) 77 | true 78 | ..\..\;%(AdditionalIncludeDirectories) 79 | MultiThreaded 80 | 81 | 82 | Windows 83 | true 84 | true 85 | true 86 | 0.5 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/plugins/forceStrumNotes/ForceStrumNotes.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/plugins/forceStrumNotes/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include 3 | #include "forceStrumNotes.h" 4 | 5 | BOOL APIENTRY DllMain(HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | ApplyHack(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/forceStrumNotes/forceStrumNotes.cpp: -------------------------------------------------------------------------------- 1 | #include "forceStrumNotes.h" 2 | #include "core\Patcher.h" 3 | #include "gh3\GH3Keys.h" 4 | #include "gh3\GH3GlobalAddresses.h" 5 | 6 | 7 | 8 | static void *setHopoFlagDetour = (void *)0x0041D22A; 9 | static void *setHopoFlagDetour2 =(void *)0x0041D41B; 10 | 11 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 12 | 13 | __declspec(naked) void forceTapFlagNaked() 14 | { 15 | static const uint32_t returnAddress = 0x0041D233; 16 | __asm 17 | { 18 | mov [esp + 20h], 0 //Tapping flag 19 | mov eax, KEY_PLAYER; 20 | jmp returnAddress; 21 | } 22 | } 23 | 24 | __declspec(naked) void forceTapFlagNaked2() 25 | { 26 | static const uint32_t returnAddress = 0x0041D423; 27 | __asm 28 | { 29 | mov edx, 0; 30 | mov ecx, [esp + 14h]; 31 | jmp returnAddress; 32 | } 33 | } 34 | 35 | void ApplyHack() 36 | { 37 | g_patcher.WriteJmp(setHopoFlagDetour2, &forceTapFlagNaked2); 38 | } -------------------------------------------------------------------------------- /src/plugins/forceStrumNotes/forceStrumNotes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | void ApplyHack(); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/plugins/forceTapNotes/ForceTapNotes.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {32615C85-50B5-48DB-B611-C8046783FB9B} 15 | Win32Proj 16 | ForceTapNotes 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;FORCETAPNOTES_EXPORTS;%(PreprocessorDefinitions) 58 | true 59 | ..\..\;%(AdditionalIncludeDirectories) 60 | MultiThreadedDebug 61 | 62 | 63 | Windows 64 | true 65 | 0.5 66 | 67 | 68 | 69 | 70 | Level3 71 | 72 | 73 | MaxSpeed 74 | true 75 | true 76 | WIN32;NDEBUG;_WINDOWS;_USRDLL;FORCETAPNOTES_EXPORTS;%(PreprocessorDefinitions) 77 | true 78 | ..\..\;%(AdditionalIncludeDirectories) 79 | MultiThreaded 80 | 81 | 82 | Windows 83 | true 84 | true 85 | true 86 | 0.5 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/plugins/forceTapNotes/ForceTapNotes.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/plugins/forceTapNotes/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include 3 | #include "forceTapNotes.h" 4 | 5 | BOOL APIENTRY DllMain(HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | ApplyHack(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/forceTapNotes/forceTapNotes.cpp: -------------------------------------------------------------------------------- 1 | #include "core\Patcher.h" 2 | #include "gh3\GH3Keys.h" 3 | #include "gh3\GH3GlobalAddresses.h" 4 | #include "forceTapNotes.h" 5 | 6 | static void *setHopoFlagDetour = (void *)0x0041D22A; 7 | static void *setHopoFlagDetour2 = (void *)0x0041D41B; 8 | 9 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 10 | 11 | __declspec(naked) void forceTapFlagNaked() 12 | { 13 | static const uint32_t returnAddress = 0x0041D233; 14 | __asm 15 | { 16 | mov [esp+20h], 2 //Tapping flag 17 | mov eax, KEY_PLAYER 18 | jmp returnAddress; 19 | } 20 | } 21 | 22 | __declspec(naked) void forceTapFlagNaked2() 23 | { 24 | static const uint32_t returnAddress = 0x0041D423; 25 | __asm 26 | { 27 | mov edx, 2 28 | mov ecx, [esp+14h] 29 | jmp returnAddress 30 | } 31 | } 32 | 33 | void ApplyHack() 34 | { 35 | g_patcher.WriteJmp(setHopoFlagDetour2, &forceTapFlagNaked2); 36 | } -------------------------------------------------------------------------------- /src/plugins/forceTapNotes/forceTapNotes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | void ApplyHack(); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/plugins/gemShuffle/GemShuffle.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {4D606C3E-242C-4413-87C5-155D35824206} 15 | Win32Proj 16 | GemShuffle 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;GEMSHUFFLE_EXPORTS;%(PreprocessorDefinitions) 58 | true 59 | ..\..\;%(AdditionalIncludeDirectories) 60 | MultiThreadedDebug 61 | 62 | 63 | Windows 64 | true 65 | 0.5 66 | 67 | 68 | 69 | 70 | Level3 71 | 72 | 73 | MaxSpeed 74 | true 75 | true 76 | WIN32;NDEBUG;_WINDOWS;_USRDLL;GEMSHUFFLE_EXPORTS;%(PreprocessorDefinitions) 77 | true 78 | ..\..\;%(AdditionalIncludeDirectories) 79 | MultiThreaded 80 | 81 | 82 | Windows 83 | true 84 | true 85 | true 86 | 0.5 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/plugins/gemShuffle/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include 3 | #include "gemShuffle.h" 4 | 5 | BOOL APIENTRY DllMain(HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | ApplyHack(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/gemShuffle/gemShuffle.cpp: -------------------------------------------------------------------------------- 1 | #include "core\Patcher.h" 2 | #include "gh3\GH3Keys.h" 3 | #include "gh3\GH3GlobalAddresses.h" 4 | 5 | #include "gemShuffle.h" 6 | #include 7 | 8 | static void * const fruityDetour = (void *)0x00432887; //0x004327D2; // 0x00432733; 9 | 10 | static void * const overstrumDetour1 = (void *)0x004320F0; //overstrum 11 | 12 | static uint32_t g_randomIndex; 13 | 14 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 15 | 16 | void randomizeIndex() 17 | { 18 | g_randomIndex = rand() % 5; 19 | } 20 | 21 | __declspec (naked) void fruityNaked() 22 | { 23 | static const uint32_t returnAddress = 0x0043288F; 24 | 25 | __asm 26 | { 27 | pushad; 28 | call randomizeIndex; 29 | popad; 30 | mov eax, g_randomIndex; 31 | 32 | test ecx, ecx 33 | movss [esp + 34h], xmm0 34 | 35 | jmp returnAddress; 36 | } 37 | } 38 | 39 | 40 | 41 | void ApplyHack() 42 | { 43 | g_patcher.WriteJmp(fruityDetour, (void *)fruityNaked); 44 | 45 | } -------------------------------------------------------------------------------- /src/plugins/gemShuffle/gemShuffle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | void ApplyHack(); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/plugins/keyHijacker/KeyHijacker.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExileLord/GH3-Plus/309aebb6bc4c3fa82d92617403c17d9585a63f34/src/plugins/keyHijacker/KeyHijacker.rc -------------------------------------------------------------------------------- /src/plugins/keyHijacker/KeyHijacker.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {252C9FE0-3AF1-42D4-BA15-CBC4C26176A8} 15 | Win32Proj 16 | KeyHijacker 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;KEYHIJACKER_EXPORTS;%(PreprocessorDefinitions) 58 | ..\..\;%(AdditionalIncludeDirectories) 59 | MultiThreadedDebug 60 | AssemblyAndSourceCode 61 | 62 | 63 | Windows 64 | true 65 | 0.5 66 | 67 | 68 | 69 | 70 | Level3 71 | 72 | 73 | MaxSpeed 74 | true 75 | true 76 | WIN32;NDEBUG;_WINDOWS;_USRDLL;KEYHIJACKER_EXPORTS;%(PreprocessorDefinitions) 77 | ..\..\;%(AdditionalIncludeDirectories) 78 | MultiThreaded 79 | 80 | 81 | Windows 82 | true 83 | true 84 | true 85 | 0.5 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/plugins/keyHijacker/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include 3 | #include "keyHijacker.h" 4 | 5 | BOOL APIENTRY DllMain(HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | ApplyHack(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/keyHijacker/keyHijacker.cpp: -------------------------------------------------------------------------------- 1 | #include "keyHijacker.h" 2 | #include "resource.h" 3 | #include "core\Patcher.h" 4 | #include "gh3\GH3Keys.h" 5 | #include "gh3\GH3GlobalAddresses.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #pragma comment(lib,"Winmm.lib") 11 | 12 | static const LPVOID changeDetour = (LPVOID)0x00538EF0; 13 | static const LPVOID gameFrameDetour = (LPVOID)0x005B0C50; 14 | static uint32_t changeSpeedStruct[] = { 0x00010000, 0xCDCDCDCD, 15 | 0x00000500, 0x16D91BC1, 0x3F800000, 0x00000000 }; 16 | #ifdef PITCHSHIFT 17 | static uint32_t changePitchStruct[] = { 0x00010000, 0xCDCDCDCD, 18 | 0x00001B00, 0xFD2C9E38, 0x3370A847, 0xCDCDCDCD, 19 | 0x00000500, 0xD8604126, 0x3F800000, 0x00000000 }; 20 | #endif 21 | 22 | static float g_hackedSpeed = 1.0f; 23 | static float g_hackedPitch = 1.0f; 24 | static int32_t g_currentInt = 100; 25 | static int32_t g_multiplier = 0; 26 | static bool g_keyHeld = false; 27 | static int g_speedUpdated = 0; 28 | 29 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 30 | 31 | BOOL PlayResource(LPCWSTR lpName) 32 | { 33 | BOOL bRtn; 34 | LPWSTR lpRes; 35 | HRSRC hResInfo; 36 | HGLOBAL hRes; 37 | 38 | // Find the WAVE resource. 39 | 40 | hResInfo = FindResource(NULL, lpName, L"WAVE"); 41 | if (hResInfo == NULL) 42 | return FALSE; 43 | 44 | // Load the WAVE resource. 45 | 46 | hRes = LoadResource(NULL, hResInfo); 47 | if (hRes == NULL) 48 | return FALSE; 49 | 50 | // Lock the WAVE resource and play it. 51 | 52 | lpRes = (LPWSTR)LockResource(hRes); 53 | if (lpRes != NULL) { 54 | bRtn = sndPlaySound(lpRes, SND_MEMORY | SND_SYNC | SND_NODEFAULT); 55 | UnlockResource(hRes); 56 | } 57 | else 58 | bRtn = 0; 59 | 60 | // Free the WAVE resource and return success or failure. 61 | 62 | FreeResource(hRes); 63 | return bRtn; 64 | } 65 | 66 | __declspec(naked) void changeOverrideNaked() 67 | { 68 | static const uint32_t returnAddress = 0x538EFA; 69 | static const uint32_t speedFactorKey = 0x16D91BC1; 70 | static const uint32_t structureNameKey = 0xFD2C9E38; 71 | static const uint32_t pitchStructKey = 0x3370A847; 72 | static const uint32_t pitchKey = 0xD8604126; 73 | 74 | __asm 75 | { 76 | CHANGE: 77 | // Copied start of "change" 78 | sub esp, 1Ch 79 | push ebp; 80 | mov ebp, [esp + 36]; // aList 81 | push esi; 82 | push edi; 83 | 84 | // If the hacked values need to be changed, call change recursively to set them 85 | pushad; 86 | mov eax, g_speedUpdated; 87 | test eax, eax; 88 | jz NORECURSE; 89 | lea eax, g_speedUpdated; 90 | mov [eax], 0; 91 | lea eax, changeSpeedStruct; 92 | push eax; 93 | call CHANGE; 94 | pop eax; // remove the stack item that change didn't clean up 95 | #ifdef PITCHSHIFT 96 | lea eax, changePitchStruct; 97 | push eax; 98 | call CHANGE; 99 | pop eax; // remove the stack item that change didn't clean up 100 | #endif 101 | NORECURSE: 102 | popad; 103 | // Check for current_speedfactor 104 | mov ecx, dword ptr[ebp + 4]; // Using edi and ecx because they are overwritten by 105 | mov edi, dword ptr[ecx + 4]; // existing code immediately after jumping back 106 | cmp edi, speedFactorKey; 107 | je OVERWRITESPEED; 108 | #ifdef PITCHSHIFT 109 | // Check for structurename 110 | cmp edi, structureNameKey; 111 | je CHECKPITCHSTRUCT; 112 | jmp returnAddress; 113 | 114 | CHECKPITCHSTRUCT: 115 | mov edi, dword ptr[ecx + 8]; 116 | cmp edi, pitchStructKey; 117 | je CHECKPITCH; 118 | jmp returnAddress; 119 | 120 | CHECKPITCH: 121 | mov edi, dword ptr[ecx + 12]; // Next node of the linked list 122 | mov ecx, dword ptr[edi + 4]; 123 | cmp ecx, pitchKey; 124 | je OVERWRITEPITCH; 125 | jmp returnAddress; 126 | #else 127 | jmp returnAddress 128 | #endif 129 | OVERWRITESPEED: 130 | mov edi, g_hackedSpeed; 131 | mov dword ptr[ecx + 8], edi; 132 | jmp returnAddress; 133 | #ifdef PITCHSHIFT 134 | OVERWRITEPITCH: 135 | mov ecx, g_hackedPitch; 136 | mov dword ptr[edi + 8], ecx; 137 | jmp returnAddress; 138 | #endif 139 | } 140 | } 141 | 142 | int32_t getKeypadNumber(); 143 | 144 | void applyNewSpeed(int32_t newSpeed) 145 | { 146 | if (newSpeed <= 0) 147 | return; 148 | g_hackedSpeed = (float)(newSpeed / 100.0f); 149 | g_hackedPitch = 1.0f / g_hackedSpeed; 150 | 151 | g_speedUpdated = 1; 152 | } 153 | 154 | void resetKeys() 155 | { 156 | g_currentInt = 100; 157 | g_multiplier = 0; 158 | } 159 | 160 | void checkKeys() 161 | { 162 | int number = getKeypadNumber(); 163 | 164 | if (!g_keyHeld && number >= 0) 165 | { 166 | g_keyHeld = true; 167 | g_multiplier += (g_currentInt * number); 168 | g_currentInt /= 10; 169 | 170 | if (g_currentInt == 0) 171 | { 172 | applyNewSpeed(g_multiplier); 173 | resetKeys(); 174 | 175 | PlaySound(TEXT("quack.wav"), NULL, SND_FILENAME | SND_ASYNC); 176 | } 177 | } 178 | 179 | if (g_keyHeld && number == -1) 180 | { 181 | g_keyHeld = false; 182 | } 183 | } 184 | 185 | int32_t getKeypadNumber() 186 | { 187 | static uint8_t keys[256]; 188 | memset(keys, 0, sizeof(keys)); 189 | GetKeyboardState(keys); 190 | 191 | for (int i = 0; i < 10; ++i) 192 | { 193 | if ( (keys[VK_NUMPAD0 + i] & 0x80) || (keys['0' + i] & 0x80) ) 194 | return i; 195 | } 196 | 197 | return -1; 198 | } 199 | 200 | _declspec(naked) void checkKeysNaked() 201 | { 202 | static const uint32_t returnAddress = 0x005B0C59; 203 | 204 | __asm 205 | { 206 | pushad; 207 | call checkKeys; 208 | popad; 209 | 210 | //Displaced code 211 | mov eax, [ecx + 8]; 212 | and eax, 0Fh; 213 | add eax, 0FFFFFFFFh; 214 | 215 | jmp returnAddress; 216 | } 217 | } 218 | 219 | void ApplyHack() 220 | { 221 | // set up pointers within the changeX structs 222 | changeSpeedStruct[1] = (uint32_t) &changeSpeedStruct[2]; 223 | #ifdef PITCHSHIFT 224 | changePitchStruct[1] = (uint32_t) &changePitchStruct[2]; 225 | changePitchStruct[5] = (uint32_t) &changePitchStruct[6]; 226 | #endif 227 | 228 | g_patcher.WriteJmp(changeDetour, &changeOverrideNaked); 229 | g_patcher.WriteJmp(gameFrameDetour, &checkKeysNaked); 230 | } 231 | -------------------------------------------------------------------------------- /src/plugins/keyHijacker/keyHijacker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | void ApplyHack(); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/plugins/keyHijacker/quack.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExileLord/GH3-Plus/309aebb6bc4c3fa82d92617403c17d9585a63f34/src/plugins/keyHijacker/quack.wav -------------------------------------------------------------------------------- /src/plugins/keyHijacker/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExileLord/GH3-Plus/309aebb6bc4c3fa82d92617403c17d9585a63f34/src/plugins/keyHijacker/resource.h -------------------------------------------------------------------------------- /src/plugins/mirrorMode/MirrorMode.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {e32b6d2d-e3d7-4b20-bda6-953eecc50247} 15 | Win32Proj 16 | MirrorMode 17 | 8.1 18 | MirrorMode 19 | 20 | 21 | 22 | DynamicLibrary 23 | true 24 | v140 25 | Unicode 26 | 27 | 28 | DynamicLibrary 29 | false 30 | v140 31 | true 32 | Unicode 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | true 46 | $(SolutionDir)bin\$(Configuration)\ 47 | 48 | 49 | false 50 | $(SolutionDir)bin\$(Configuration)\ 51 | 52 | 53 | 54 | 55 | 56 | Level3 57 | Disabled 58 | WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 59 | true 60 | ..\..\;%(AdditionalIncludeDirectories) 61 | MultiThreadedDebug 62 | 63 | 64 | Windows 65 | true 66 | 0.5 67 | 68 | 69 | 70 | 71 | Level3 72 | 73 | 74 | MaxSpeed 75 | true 76 | true 77 | WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 78 | true 79 | ..\..\;%(AdditionalIncludeDirectories) 80 | MultiThreaded 81 | 82 | 83 | Windows 84 | true 85 | true 86 | true 87 | 0.5 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/plugins/mirrorMode/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include 3 | #include "MirrorMode.h" 4 | 5 | BOOL APIENTRY DllMain(HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | ApplyHack(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/mirrorMode/mirrorMode.cpp: -------------------------------------------------------------------------------- 1 | #include "gh3\GH3Keys.h" 2 | #include "core\Patcher.h" 3 | #include "mirrorMode.h" 4 | #include 5 | 6 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 7 | 8 | enum class FretMask : uint32_t 9 | { 10 | ORANGE = 0x00001, 11 | BLUE = 0x00010, 12 | YELLOW = 0x00100, 13 | RED = 0x01000, 14 | GREEN = 0x10000, 15 | }; 16 | 17 | struct QbArray 18 | { 19 | uint32_t flags; 20 | uint32_t size; 21 | uint32_t *arr; 22 | }; 23 | 24 | // Reverse the parameter order for the CreateNote call 25 | static void * const createNoteDetour = (void *)0x0041D41B; 26 | 27 | __declspec(naked) void createNoteReversedNaked() 28 | { 29 | static void * const returnAddress = (void *)0x0041D449; 30 | __asm 31 | { 32 | mov edx, [esp + 20h]; // [esp+48h+hopoRaw] 33 | mov ecx, [esp + 18h]; // [esp+48h+redSustainLength] 34 | mov esi, [esp + 30h]; // [esp+48h+currentStartTime] 35 | push eax; // nextNoteTime 36 | mov eax, [esp + 28h]; // [esp+4Ch+greenSustainLength] 37 | push edx; // hopoFlag 38 | mov edx, [esp + 18h]; // [esp+50h+yellowSustainLength] 39 | push eax; // greenLength 40 | mov eax, [esp + 20h]; // [esp+54h+blueSustainLength] 41 | push ecx; // redLength 42 | mov ecx, [esp + 2Ch]; // [esp+58h+orangeSustainLength] 43 | push edx; // yellowLength 44 | mov edx, [esp + 40h]; // [esp+5Ch+noteTime2] 45 | push eax; // blueLength 46 | mov eax, [esp + 4Ch]; // [esp+60h+noteArray] ; noteArray 47 | push ecx; // greenLength 48 | push edx; // noteTime 49 | mov ecx, esi; // noteIndex 50 | jmp returnAddress; 51 | } 52 | } 53 | 54 | 55 | static void * const GetFretmaskFromNoteQbArrayDetour = (void *)0x0041B090; 56 | 57 | uint32_t __fastcall GetMirroredFretmaskFromNoteQbArray(QbArray *qbArr) 58 | { 59 | uint32_t size = qbArr->size; 60 | uint32_t *frets = qbArr->arr; 61 | uint32_t fretMask = 0; 62 | uint32_t fret = reinterpret_cast(frets); //Please don't ask me the reasoning behind this insanity. The neversoft devs are mad 63 | 64 | if (size != 1) 65 | fret = frets[1]; 66 | if (fret > 0) 67 | fretMask |= (uint32_t)FretMask::ORANGE; 68 | 69 | if (size != 1) 70 | fret = frets[2]; 71 | if (fret > 0) 72 | fretMask |= (uint32_t)FretMask::BLUE; 73 | 74 | if (size != 1) 75 | fret = frets[3]; 76 | if (fret > 0) 77 | fretMask |= (uint32_t)FretMask::YELLOW; 78 | 79 | if (size != 1) 80 | fret = frets[4]; 81 | if (fret > 0) 82 | fretMask |= (uint32_t)FretMask::RED; 83 | 84 | if (size != 1) 85 | fret = frets[5]; 86 | if (fret > 0) 87 | fretMask |= (uint32_t)FretMask::GREEN; 88 | 89 | return fretMask; 90 | } 91 | 92 | void ApplyHack() 93 | { 94 | if (!g_patcher.WriteJmp(createNoteDetour, createNoteReversedNaked) || 95 | !g_patcher.WriteJmp(GetFretmaskFromNoteQbArrayDetour, GetMirroredFretmaskFromNoteQbArray)) 96 | g_patcher.RemoveAllChanges(); 97 | } -------------------------------------------------------------------------------- /src/plugins/mirrorMode/mirrorMode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | void ApplyHack(); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/plugins/noteLimit/NoteLimitFix.cpp: -------------------------------------------------------------------------------- 1 | // GH3Hack.cpp : Defines the exported functions for the DLL application. 2 | // 3 | 4 | #include "noteLimitFix.h" 5 | #include "core\Patcher.h" 6 | #include 7 | 8 | const uint32_t MAX_NOTES = 0x110000; //?1,048,576? 9 | const uint32_t GH3_MAX_PLAYERS = 2; 10 | 11 | void * const SIZEOP_NOTE_ALLOCATION = (void *)0x0041AA78; 12 | 13 | void * const ADDROP_SUSTAINARRAY_1 = (void *)0x0041EE33; 14 | void * const ADDROP_SUSTAINARRAY_2 = (void *)0x00423CD4; 15 | void * const ADDROP_SUSTAINARRAY_3 = (void *)0x00423D02; 16 | void * const ADDROP_FCARRAY = (void *)0x00423D14; 17 | void * const ADDROP_NOTEOFFSETARRAY = (void *)0x00423D22; 18 | 19 | static float *fixedSustainArray = nullptr; 20 | static float *fixedFcArray = nullptr; 21 | static uint32_t *fixedOffsetArray = nullptr; 22 | 23 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 24 | 25 | // Writes to the code segment of GH3, overwriting the operands responsible for creating or pointing 26 | // towards the fixed 4000 size note arrays with its own allocated arrays 27 | void FixNoteLimit() 28 | { 29 | if (fixedSustainArray == nullptr) 30 | fixedSustainArray = new float[MAX_NOTES * GH3_MAX_PLAYERS]; 31 | 32 | if (fixedFcArray == nullptr) 33 | fixedFcArray = new float[MAX_NOTES * GH3_MAX_PLAYERS]; 34 | 35 | if (fixedOffsetArray == nullptr) 36 | fixedOffsetArray = new uint32_t[MAX_NOTES * GH3_MAX_PLAYERS]; 37 | 38 | // Fix dynamic allocations 39 | g_patcher.WriteInt32(SIZEOP_NOTE_ALLOCATION, MAX_NOTES); 40 | 41 | // Fix static references 42 | g_patcher.WriteInt32(ADDROP_SUSTAINARRAY_1, reinterpret_cast(fixedSustainArray)); 43 | g_patcher.WriteInt32(ADDROP_SUSTAINARRAY_2, reinterpret_cast(fixedSustainArray)); 44 | g_patcher.WriteInt32(ADDROP_SUSTAINARRAY_3, reinterpret_cast(fixedSustainArray)); 45 | g_patcher.WriteInt32(ADDROP_FCARRAY, reinterpret_cast(fixedFcArray)); 46 | g_patcher.WriteInt32(ADDROP_NOTEOFFSETARRAY, reinterpret_cast(fixedOffsetArray)); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/plugins/noteLimit/NoteLimitFix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void FixNoteLimit(); -------------------------------------------------------------------------------- /src/plugins/noteLimit/NoteLimitFix.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {AD3A956F-41C3-4493-9C88-8A000167BE8D} 15 | Win32Proj 16 | NoteLimitFix 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;NOTELIMITFIX_EXPORTS;%(PreprocessorDefinitions) 58 | ..\..\;%(AdditionalIncludeDirectories) 59 | MultiThreadedDebug 60 | AssemblyAndSourceCode 61 | 62 | 63 | Windows 64 | true 65 | 0.5 66 | 67 | 68 | 69 | 70 | Level3 71 | 72 | 73 | MaxSpeed 74 | true 75 | true 76 | WIN32;NDEBUG;_WINDOWS;_USRDLL;NOTELIMITFIX_EXPORTS;%(PreprocessorDefinitions) 77 | ..\..\;%(AdditionalIncludeDirectories) 78 | MultiThreaded 79 | 80 | 81 | Windows 82 | true 83 | true 84 | true 85 | 0.5 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /src/plugins/noteLimit/NoteLimitFix.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/plugins/noteLimit/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "NoteLimitFix.h" 3 | #include 4 | 5 | BOOL APIENTRY DllMain( HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | FixNoteLimit(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/songLimit/SongLimitFix.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {9A18518C-38BF-48CA-88F8-206DEAE220FD} 15 | Win32Proj 16 | SongLimitFix 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;SONGLIMITFIX_EXPORTS;%(PreprocessorDefinitions) 58 | ..\..\;%(AdditionalIncludeDirectories) 59 | MultiThreadedDebug 60 | AssemblyAndSourceCode 61 | 62 | 63 | Windows 64 | true 65 | 0.5 66 | 67 | 68 | 69 | 70 | Level3 71 | 72 | 73 | MaxSpeed 74 | true 75 | true 76 | WIN32;NDEBUG;_WINDOWS;_USRDLL;SONGLIMITFIX_EXPORTS;%(PreprocessorDefinitions) 77 | ..\..\;%(AdditionalIncludeDirectories) 78 | MultiThreaded 79 | 80 | 81 | Windows 82 | true 83 | true 84 | true 85 | 0.5 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /src/plugins/songLimit/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "SongLimitFix.h" 3 | #include 4 | 5 | BOOL APIENTRY DllMain( HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | FixSongLimit(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/songLimit/songLimitFix.cpp: -------------------------------------------------------------------------------- 1 | // GH3Hack.cpp : Defines the exported functions for the DLL application. 2 | // 3 | 4 | #include "songLimitFix.h" 5 | #include "core\Patcher.h" 6 | #include 7 | 8 | const uint32_t MAX_TIME = 2140283648; //Roughly 24 days. Trying to get close to INT_MAX without running the risk of overflowing 9 | 10 | void * const TIME_LOC_1 = (void *)0x0041AAE8; 11 | void * const TIME_LOC_2 = (void *)0x0041D417; 12 | void * const TIME_LOC_3 = (void *)0x0043043E; 13 | void * const TIME_LOC_4 = (void *)0x00431463; 14 | 15 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 16 | 17 | void FixSongLimit() 18 | { 19 | g_patcher.WriteInt32(TIME_LOC_1, MAX_TIME); 20 | g_patcher.WriteInt32(TIME_LOC_2, MAX_TIME); 21 | g_patcher.WriteInt32(TIME_LOC_3, MAX_TIME); 22 | g_patcher.WriteInt32(TIME_LOC_4, MAX_TIME); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/plugins/songLimit/songLimitFix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void FixSongLimit(); -------------------------------------------------------------------------------- /src/plugins/spooky/Spooky.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {6176FF08-5AA8-41B5-836A-7F8E647B91E0} 15 | Win32Proj 16 | Spooky 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;SPOOKY_EXPORTS;%(PreprocessorDefinitions) 58 | ..\..\;%(AdditionalIncludeDirectories) 59 | MultiThreadedDebug 60 | AssemblyAndSourceCode 61 | 62 | 63 | Windows 64 | true 65 | 0.5 66 | 67 | 68 | Winmm.lib;%(AdditionalDependencies) 69 | 70 | 71 | 72 | 73 | Level3 74 | 75 | 76 | MaxSpeed 77 | true 78 | true 79 | WIN32;NDEBUG;_WINDOWS;_USRDLL;SPOOKY_EXPORTS;%(PreprocessorDefinitions) 80 | ..\..\;%(AdditionalIncludeDirectories) 81 | MultiThreaded 82 | 83 | 84 | Windows 85 | true 86 | true 87 | true 88 | 0.5 89 | Winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /src/plugins/spooky/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "spooky.h" 3 | #include 4 | 5 | BOOL APIENTRY DllMain( HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | HauntMyGame(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/spooky/garbagetext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | static const wchar_t defaultGarbageText[] = L"ZGRBG000GENERICZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; 6 | //const std::size_t defaultGarbageTextLength = wcslen() 7 | 8 | class GarbageText 9 | { 10 | private: 11 | std::wstring str_; 12 | std::wstring spookyStr_; 13 | GarbageText(); 14 | static GarbageText &Instance(); 15 | public: 16 | const static wchar_t * GetString(std::size_t offset); 17 | const static wchar_t * GetSpookyString(std::size_t offset); 18 | 19 | }; -------------------------------------------------------------------------------- /src/plugins/spooky/keydebugging.cpp: -------------------------------------------------------------------------------- 1 | #include "keydebugging.h" 2 | #include 3 | #include 4 | #include 5 | 6 | //Debugging 7 | bool g_enabled = true; 8 | bool g_forceColorStrings = false; 9 | bool g_forceNoInstances = false; 10 | bool g_forceNoDraw = false; 11 | bool g_forceNoDraw2D = false; 12 | bool g_forceNoWorld = false; 13 | bool g_forcedJitter = false; 14 | 15 | int getKeypadNumber() 16 | { 17 | static uint8_t keys[256]; 18 | memset(keys, 0, sizeof(keys)); 19 | GetKeyboardState(keys); 20 | 21 | for (int i = 0; i < 10; ++i) 22 | { 23 | if ((keys[VK_NUMPAD0 + i] & 0x80) || (keys['0' + i] & 0x80)) 24 | return i; 25 | } 26 | 27 | return -1; 28 | } 29 | 30 | 31 | void debugCheckKeys() 32 | { 33 | static bool keyHeld = false; 34 | 35 | int number = getKeypadNumber(); 36 | 37 | if (!keyHeld && number >= 0) 38 | { 39 | keyHeld = true; 40 | 41 | switch (number) 42 | { 43 | case 0: 44 | PlaySound(TEXT("quack.wav"), NULL, SND_FILENAME | SND_ASYNC); 45 | g_enabled = !g_enabled; 46 | break; 47 | case 1: 48 | PlaySound(TEXT("quack.wav"), NULL, SND_FILENAME | SND_ASYNC); 49 | g_forceColorStrings = !g_forceColorStrings; 50 | break; 51 | case 2: 52 | PlaySound(TEXT("quack.wav"), NULL, SND_FILENAME | SND_ASYNC); 53 | g_forceNoInstances = !g_forceNoInstances; 54 | break; 55 | case 5: 56 | PlaySound(TEXT("quack.wav"), NULL, SND_FILENAME | SND_ASYNC); 57 | g_forceNoDraw = !g_forceNoDraw; 58 | break; 59 | case 4: 60 | PlaySound(TEXT("quack.wav"), NULL, SND_FILENAME | SND_ASYNC); 61 | g_forceNoDraw2D = !g_forceNoDraw2D; 62 | break; 63 | case 3: 64 | PlaySound(TEXT("quack.wav"), NULL, SND_FILENAME | SND_ASYNC); 65 | g_forceNoWorld = !g_forceNoWorld; 66 | case 6: 67 | PlaySound(TEXT("quack.wav"), NULL, SND_FILENAME | SND_ASYNC); 68 | g_forcedJitter = !g_forcedJitter; 69 | break; 70 | default: 71 | return; 72 | } 73 | } 74 | else if (keyHeld && number < 0) 75 | { 76 | keyHeld = false; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/plugins/spooky/keydebugging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | extern bool g_enabled; 5 | extern bool g_forceColorStrings; 6 | extern bool g_forceNoInstances; 7 | extern bool g_forceNoDraw; 8 | extern bool g_forceNoDraw2D; 9 | extern bool g_forceNoWorld; 10 | extern bool g_forcedJitter; 11 | 12 | void debugCheckKeys(); -------------------------------------------------------------------------------- /src/plugins/spooky/spooky.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void HauntMyGame(); -------------------------------------------------------------------------------- /src/plugins/spooky/stringscramble.cpp: -------------------------------------------------------------------------------- 1 | #include "stringscramble.h" 2 | #include "weakrand.h" 3 | #include "garbagetext.h" 4 | #include 5 | 6 | 7 | 8 | wchar_t RandomCharacter() 9 | { 10 | return static_cast(32 + (rand() % (123 - 32))); 11 | } 12 | 13 | void ScrambleString(wchar_t *str) 14 | { 15 | if (str == nullptr) 16 | return; 17 | 18 | for (wchar_t *c = str; *c != L'\0'; ++c) 19 | { 20 | *c = RandomCharacter(); 21 | } 22 | } 23 | 24 | 25 | ///Side effect: sets seed 26 | void WeakScrambleString(wchar_t *str, float weight, float sequenceWeight, float buttonWeight) 27 | { 28 | if (str == nullptr) 29 | return; 30 | 31 | static uint32_t seed = 0; 32 | ++seed; 33 | srand(seed); 34 | 35 | for (wchar_t *c = str; *c != L'\0'; ++c) 36 | { 37 | // Only insert random characters if we hit the random threshold 38 | if (!FlipCoin(weight)) 39 | continue; 40 | 41 | // If we don't hit the threshold for a sequence insertion, just put in a random character 42 | if (!FlipCoin(sequenceWeight)) 43 | { 44 | *c = RandomCharacter(); 45 | continue; 46 | } 47 | 48 | // We hit the threshold for a sequence insertion so we will insert either a button or color sequence 49 | if (FlipCoin(buttonWeight)) 50 | InsertRandomEscapeSequence(c); //button 51 | else 52 | InsertRandomEscapeSequence(c); //color 53 | } 54 | 55 | 56 | } 57 | 58 | void GarbifyString(wchar_t *str) 59 | { 60 | if (str == nullptr) 61 | return; 62 | 63 | const wchar_t * garbageString = GarbageText::GetString(rand2()); 64 | 65 | for (wchar_t *c = str; *c != L'\0'; ++c) 66 | { 67 | *c = *garbageString; 68 | ++garbageString; 69 | } 70 | } -------------------------------------------------------------------------------- /src/plugins/spooky/stringscramble.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void GarbifyString(wchar_t *str); 6 | wchar_t RandomCharacter(); 7 | void ScrambleString(wchar_t *str); 8 | void WeakScrambleString(wchar_t *str, float weight = 0.05f, float sequenceWeight = 0.1f, float buttonWeight = 0.8); 9 | 10 | template 11 | bool InsertRandomEscapeSequence(wchar_t *str) 12 | { 13 | if (str == nullptr) 14 | return false; 15 | 16 | if (str[0] == L'\0' || str[1] == L'\0' || str[2] == L'\0') 17 | return false; 18 | 19 | uint32_t index = rand() % Limit; 20 | wchar_t randomChar; 21 | if (index < 10) 22 | randomChar = L'0' + index; 23 | else 24 | randomChar = L'a' + index - 10; 25 | 26 | str[0] = L'\\'; 27 | str[1] = C; 28 | str[2] = randomChar; 29 | return true; 30 | } -------------------------------------------------------------------------------- /src/plugins/spooky/weakrand.cpp: -------------------------------------------------------------------------------- 1 | #include "weakrand.h" 2 | #include 3 | #include 4 | 5 | void RandomizeSeed() 6 | { 7 | static uint32_t seed = 236147403; 8 | seed += (clock() & 0x7FFF); 9 | seed ^= (seed << 13); 10 | seed ^= (seed >> 17); 11 | seed ^= (seed << 5); 12 | seed += 541; 13 | srand(seed); 14 | }; 15 | 16 | uint32_t rand2() 17 | { 18 | return (rand() << 15) | (rand()); 19 | } 20 | 21 | bool FlipCoin(float weight) 22 | { 23 | return (rand2() / static_cast(RAND2_MAX)) < weight; 24 | } -------------------------------------------------------------------------------- /src/plugins/spooky/weakrand.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | //This is wrong if RAND_MAX is anything other than 0x7FFF 6 | #define RAND2_MAX 0x3FFFFFFF 7 | 8 | ///Randomizes the seed since it is being manipulated frequently. Call before using a random function if a "random" number is actually desired. 9 | void RandomizeSeed(); 10 | 11 | uint32_t rand2(); 12 | 13 | bool FlipCoin(float weight = 0.5f); -------------------------------------------------------------------------------- /src/plugins/tapHopoChord/TapHopoChord.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {ECC8A22B-8DA2-4D50-9679-0DA29AC7D4FF} 15 | Win32Proj 16 | TapHopoChord 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(VC_IncludePath);$(WindowsSDK_IncludePath); 46 | $(SolutionDir)bin\$(Configuration)\ 47 | 48 | 49 | false 50 | $(SolutionDir)bin\$(Configuration)\ 51 | 52 | 53 | 54 | 55 | 56 | Level4 57 | Disabled 58 | WIN32;_DEBUG;_WINDOWS;_USRDLL;TAPHOPOCHORD_EXPORTS;%(PreprocessorDefinitions) 59 | ..\..\;%(AdditionalIncludeDirectories) 60 | true 61 | false 62 | 4Bytes 63 | false 64 | AssemblyAndSourceCode 65 | 66 | Neither 67 | EditAndContinue 68 | 69 | 70 | MultiThreadedDebug 71 | 72 | 73 | Windows 74 | true 75 | C:\Users\Dan\Documents\Visual Studio 2015\Projects\GH3Hack\bin\Debug;%(AdditionalLibraryDirectories) 76 | 0.5 77 | 78 | 79 | 80 | 81 | Level3 82 | 83 | 84 | MaxSpeed 85 | true 86 | true 87 | WIN32;NDEBUG;_WINDOWS;_USRDLL;TAPHOPOCHORD_EXPORTS;%(PreprocessorDefinitions) 88 | ..\..\;%(AdditionalIncludeDirectories) 89 | MultiThreaded 90 | AssemblyAndSourceCode 91 | 92 | 93 | Windows 94 | true 95 | true 96 | true 97 | 0.5 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /src/plugins/tapHopoChord/TapHopoChord.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | 23 | 24 | Source Files 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/plugins/tapHopoChord/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include 3 | #include "tapHopoChord.h" 4 | 5 | BOOL APIENTRY DllMain(HMODULE, DWORD ul_reason_for_call, LPVOID) 6 | { 7 | switch (ul_reason_for_call) 8 | { 9 | case DLL_PROCESS_ATTACH: 10 | ApplyHack(); 11 | break; 12 | case DLL_THREAD_ATTACH: 13 | case DLL_THREAD_DETACH: 14 | case DLL_PROCESS_DETACH: 15 | break; 16 | } 17 | return TRUE; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/plugins/tapHopoChord/gemConstants.cpp: -------------------------------------------------------------------------------- 1 | #include "core\Patcher.h" 2 | #include "gh3\GH3Keys.h" 3 | #include "gh3\GH3GlobalAddresses.h" 4 | #include "tapHopoChord.h" 5 | 6 | float g_gemStartPosX[6] = { 0 }; 7 | float g_gemStartPosY[6] = { 0 }; 8 | float g_gemEndPosX[6] = { 0 }; 9 | float g_gemEndPosY[6] = { 0 }; 10 | 11 | float g_gemLeftStartPosX[6] = { 0 }; 12 | float g_gemLeftStartPosY[6] = { 0 }; 13 | float g_gemLeftEndPosX[6] = { 0 }; 14 | float g_gemLeftEndPosY[6] = { 0 }; 15 | 16 | float g_gemLeftAngle[6] = { 0 }; 17 | float g_gemAngle[6] = { 0 }; 18 | 19 | uint32_t g_gemMatBattle[6] = { 0 }; 20 | uint32_t g_gemMatHammerBattle[6] = { 0 }; 21 | 22 | uint32_t g_gemMatStar[6] = { 0 }; 23 | uint32_t g_gemMatHammerStar[6] = { 0 }; 24 | 25 | uint32_t g_gemMatNormal[6] = { 0 }; 26 | uint32_t g_gemMatHammer[6] = { 0 }; 27 | 28 | uint32_t g_gemMatSp[6] = { 0 }; 29 | uint32_t g_gemMatHammerSp[6] = { 0 }; 30 | 31 | uint32_t g_gemMatWhammy[6] = { 0 }; 32 | uint32_t g_gemMatSpWhammy[6] = { 0 }; 33 | 34 | 35 | 36 | void __declspec(naked) setupOpenNote() 37 | { 38 | __asm pushad; 39 | 40 | //Copy most of the yellow yellow note properties 41 | g_gemStartPosX[5] = g_gemStartPosX[2]; 42 | g_gemStartPosY[5] = g_gemStartPosY[2]; 43 | g_gemEndPosX[5] = g_gemEndPosX[2]; 44 | g_gemEndPosY[5] = g_gemEndPosY[2]; 45 | g_gemLeftStartPosX[5] = g_gemLeftStartPosX[2]; 46 | g_gemLeftStartPosY[5] = g_gemLeftStartPosY[2]; 47 | g_gemLeftEndPosX[5] = g_gemLeftEndPosX[2]; 48 | g_gemLeftEndPosY[5] = g_gemLeftEndPosY[2]; 49 | g_gemLeftAngle[5] = g_gemLeftAngle[2]; 50 | g_gemAngle[5] = g_gemAngle[2]; 51 | 52 | g_gemMatBattle[5] = OpenStarTextureKey; 53 | g_gemMatHammerBattle[5] = OpenStarHammerTextureKey; 54 | g_gemMatStar[5] = OpenStarTextureKey; 55 | g_gemMatHammerStar[5] = OpenStarHammerTextureKey; 56 | g_gemMatNormal[5] = OpenTextureKey; 57 | g_gemMatHammer[5] = OpenHammerTextureKey; 58 | g_gemMatSp[5] = OpenStarpowerTextureKey; 59 | g_gemMatHammerSp[5] = OpenStarpowerHammerTextureKey; 60 | g_gemMatWhammy[5] = g_gemMatWhammy[2]; 61 | g_gemMatSpWhammy[5] = g_gemMatSpWhammy[2]; 62 | 63 | __asm popad; 64 | __asm retn; 65 | } 66 | 67 | static void * const gemConstantFixingDetour = (void *)0x0041BB91; 68 | void __declspec(naked) gemConstantFixingNaked() 69 | { 70 | static void * const loopAddress = (void *)0x0041B954; 71 | static void * const returnAddress = (void *)0x0041BC62; 72 | __asm 73 | { 74 | fstp [g_gemLeftStartPosX + esi]; 75 | mov ecx, [esp + 48h]; 76 | fld dword ptr[eax + 8]; 77 | mov eax, [esp + 18h]; 78 | fstp [g_gemLeftStartPosY + esi]; 79 | movss xmm0, dword ptr[esp + 1Ch]; 80 | fld dword ptr[eax + 4]; 81 | fstp [g_gemLeftEndPosX + esi]; 82 | fld dword ptr[eax + 8]; 83 | mov eax, [esp + 44h]; 84 | fstp [g_gemLeftEndPosY + esi]; 85 | fld dword ptr[ebp + 4]; 86 | fstp [g_gemStartPosX + esi]; 87 | fld dword ptr[ebp + 8]; 88 | fstp [g_gemStartPosY + esi]; 89 | fld dword ptr[ebx + 4]; 90 | fstp [g_gemEndPosX + esi]; 91 | fld dword ptr[ebx + 8]; 92 | mov [g_gemMatHammerSp + esi], edx; 93 | mov edx, [esp + 4Ch]; 94 | fstp [g_gemEndPosY + esi]; 95 | mov [g_gemMatSp + esi], eax; 96 | mov eax, [esp + 50h]; 97 | mov [g_gemMatHammerBattle + esi], ecx; 98 | mov ecx, [esp + 54h]; 99 | mov [g_gemMatBattle + esi], edx; 100 | mov edx, [esp + 58h]; 101 | mov [g_gemMatHammerStar + esi], eax; 102 | mov eax, [esp + 5Ch]; 103 | mov [g_gemMatStar + esi], ecx; 104 | mov ecx, [esp + 60h]; 105 | mov [g_gemMatHammer + esi], edx; 106 | mov edx, [esp + 64h]; 107 | movss [g_gemLeftAngle + esi], xmm0; 108 | movss xmm0, dword ptr[esp + 20h]; 109 | mov [g_gemMatNormal + esi], eax; 110 | movss [g_gemAngle + esi], xmm0; 111 | mov [g_gemMatSpWhammy + esi], ecx; 112 | mov [g_gemMatWhammy + esi], edx; 113 | 114 | add esi, 4; 115 | cmp esi, 20; 116 | jl LOOP_ADDRESS; 117 | call setupOpenNote; // 118 | jmp returnAddress; 119 | LOOP_ADDRESS: 120 | jmp loopAddress; 121 | } 122 | } 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | bool TryApplyGemConstantsPatches() 132 | { 133 | return g_patcher.WriteJmp(gemConstantFixingDetour, gemConstantFixingNaked); 134 | } -------------------------------------------------------------------------------- /src/plugins/tapHopoChord/tapHopoChord.cpp: -------------------------------------------------------------------------------- 1 | #include "core\Patcher.h" 2 | #include "gh3\GH3Keys.h" 3 | #include "gh3\GH3GlobalAddresses.h" 4 | #include "tapHopoChord.h" 5 | 6 | GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 7 | 8 | 9 | void ApplyHack() 10 | { 11 | if (!TryApplyGlobalArrayPatches() || 12 | !TryApplyGemLoadingPatches() || 13 | !TryApplyGemMutationPatches() || 14 | !TryApplyNoteLoadingPatches() || 15 | !TryApplyNoteLogicPatches() || 16 | !TryApplyGemConstantsPatches() || 17 | !TryApplyTextureTakeoverPatches() 18 | ) 19 | { 20 | g_patcher.RemoveAllChanges(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/plugins/tapHopoChord/tapHopoChord.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core\Patcher.h" 4 | #include "gh3\QbArray.h" 5 | 6 | 7 | ///Determines which tapping gem sprite to use under starpower since we don't have a starpower texture 8 | //Set this to 0 to use the green note texture 9 | // 1 to use the red note texture 10 | // 2 to use the yellow note texture 11 | // 3 to use the blue note texture 12 | // 4 to use the orange note texture 13 | #define SP_TAP_NOTE_GEM_INDEX 3 14 | 15 | #define PUSH_ALL_BUT_EDX \ 16 | __asm push esp \ 17 | __asm push ebp \ 18 | __asm push eax \ 19 | __asm push ebx \ 20 | __asm push ecx \ 21 | __asm push esi \ 22 | __asm push edi \ 23 | 24 | #define POP_ALL_BUT_EDX \ 25 | __asm pop edi \ 26 | __asm pop esi \ 27 | __asm pop ecx \ 28 | __asm pop ebx \ 29 | __asm pop eax \ 30 | __asm pop ebp \ 31 | __asm pop esp \ 32 | 33 | enum HopoFlag : uint32_t 34 | { 35 | STRUMMED = 0, 36 | HOPO = 1, 37 | TAPPING = 2 38 | }; 39 | 40 | struct Note 41 | { 42 | uint32_t noteTime; 43 | uint32_t fretLength[5]; 44 | HopoFlag hopoFlag; 45 | uint32_t nextNoteTime; 46 | uint32_t noteLength; 47 | }; 48 | 49 | 50 | enum FretMask : uint32_t 51 | { 52 | ORANGE = 0x00001, 53 | BLUE = 0x00010, 54 | YELLOW = 0x00100, 55 | RED = 0x01000, 56 | GREEN = 0x10000, 57 | OPEN = 0x22222, 58 | }; 59 | 60 | enum QbFretMask : uint32_t 61 | { 62 | QbGreen = 0x1, 63 | QbRed = 0x2, 64 | QbYellow = 0x4, 65 | QbBlue = 0x8, 66 | QbOrange = 0x10, 67 | QbHopoflip = 0x20, 68 | QbTapping = 0x40, 69 | QbOpen = 0x80 70 | }; 71 | 72 | bool __fastcall IsSingleNote(FretMask fretMask); 73 | FretMask __fastcall GetFretmaskFromTrackArray(GH3::QbArray *trackArray, int currentNote); 74 | FretMask __fastcall GetFretmaskFromNoteQbArray(GH3::QbArray *noteArr); 75 | 76 | constexpr GH3::QbKey RawOpenTextureKey = "images\\highway\\gem2d_open.img"; 77 | constexpr GH3::QbKey RawOpenHammerTextureKey = "images\\highway\\gem2d_open_hammer.img"; 78 | constexpr GH3::QbKey RawOpenStarTextureKey = "images\\highway\\star2d_open.img"; 79 | constexpr GH3::QbKey RawOpenStarHammerTextureKey = "images\\highway\\star2d_open_hammer.img"; 80 | constexpr GH3::QbKey RawOpenStarpowerTextureKey = "images\\highway\\gem2d_open_starpower.img"; 81 | constexpr GH3::QbKey RawOpenStarpowerHammerTextureKey = "images\\highway\\gem2d_open_hammer_starpower.img"; 82 | 83 | constexpr GH3::QbKey OpenTextureKey = "sys_gem2d_open_sys_gem2d_open"; 84 | constexpr GH3::QbKey OpenHammerTextureKey = "sys_gem2d_open_hammer_sys_gem2d_open_hammer"; 85 | constexpr GH3::QbKey OpenStarTextureKey = "sys_star2d_open_sys_gem2d_open"; 86 | constexpr GH3::QbKey OpenStarHammerTextureKey = "sys_star2d_open_hammer_sys_gem2d_open_hammer"; 87 | constexpr GH3::QbKey OpenStarpowerTextureKey = "sys_gem2d_open_starpower_sys_gem2d_open_starpower"; 88 | constexpr GH3::QbKey OpenStarpowerHammerTextureKey = "sys_gem2d_open_starpower_hammer_sys_gem2d_open_starpower_hammer"; 89 | 90 | constexpr GH3::QbKey YellowTextureKey = "sys_gem2d_yellow_sys_gem2d_yellow"; 91 | constexpr GH3::QbKey YellowHammerTextureKey = "sys_gem2d_yellow_hammer_sys_gem2d_yellow_hammer"; 92 | constexpr GH3::QbKey YellowStarTextureKey = "sys_star2d_yellow_sys_star2d_yellow"; 93 | constexpr GH3::QbKey YellowStarHammerTextureKey = "sys_star2d_yellow_hammer_sys_star2d_yellow_hammer"; 94 | constexpr GH3::QbKey YellowStarpowerTextureKey = "sys_gem2d_starpower_sys_gem2d_starpower"; 95 | constexpr GH3::QbKey YellowStarpowerHammerTextureKey = "sys_gem2d_starpower_hammer_sys_gem2d_starpower_hammer"; 96 | 97 | extern GH3P::Patcher g_patcher; 98 | 99 | extern float g_gemStartPosX[6]; 100 | extern float g_gemStartPosY[6]; 101 | extern float g_gemEndPosX[6]; 102 | extern float g_gemEndPosY[6]; 103 | 104 | extern float g_gemLeftStartPosX[6]; 105 | extern float g_gemLeftStartPosY[6]; 106 | extern float g_gemLeftEndPosX[6]; 107 | extern float g_gemLeftEndPosY[6]; 108 | 109 | extern float g_gemLeftAngle[6]; 110 | extern float g_gemAngle[6]; 111 | 112 | extern uint32_t g_gemMatBattle[6]; 113 | extern uint32_t g_gemMatHammerBattle[6]; 114 | 115 | extern uint32_t g_gemMatStar[6]; 116 | extern uint32_t g_gemMatHammerStar[6]; 117 | 118 | extern uint32_t g_gemMatNormal[6]; 119 | extern uint32_t g_gemMatHammer[6]; 120 | 121 | extern uint32_t g_gemMatSp[6]; 122 | extern uint32_t g_gemMatHammerSp[6]; 123 | 124 | extern uint32_t g_gemMatWhammy[6]; 125 | extern uint32_t g_gemMatSpWhammy[6]; 126 | 127 | 128 | void ApplyHack(); 129 | 130 | bool TryApplyNoteLogicPatches(); 131 | bool TryApplyNoteLoadingPatches(); 132 | bool TryApplyGemLoadingPatches(); 133 | bool TryApplyGemMutationPatches(); 134 | bool TryApplyGemConstantsPatches(); 135 | bool TryApplyGlobalArrayPatches(); 136 | bool TryApplyTextureTakeoverPatches(); 137 | 138 | FretMask getHighFret(FretMask fretMask); -------------------------------------------------------------------------------- /src/plugins/tapHopoChord/textureTakeover.cpp: -------------------------------------------------------------------------------- 1 | #include "core\Patcher.h" 2 | #include "gh3\GH3Keys.h" 3 | #include "gh3\GH3GlobalAddresses.h" 4 | #include "gh3\QbKey.h" 5 | #include "gh3\QbImage.h" 6 | #include "gh3\QbMap.h" 7 | #include "gh3\TextureMetadata.h" 8 | #include "tapHopoChord.h" 9 | #include 10 | 11 | #define ArrayLength(x) (sizeof(x)/sizeof(*(x))) 12 | 13 | static GH3::QbKey tmpTextureKey; 14 | static GH3::TextureMetadata *tmpMetadata; 15 | static GH3::QbImage *tmpQbImage; 16 | 17 | 18 | 19 | // Probably don't need to understand what's in here as long as we have it 20 | struct WeirdTextureStruct 21 | { 22 | GH3::QbKey key; 23 | uint32_t unk4_0; 24 | GH3::TextureMetadata *metadata; 25 | uint32_t unkC_0; 26 | 27 | uint32_t unk10_0; 28 | uint32_t unk14_0; 29 | uint32_t unk18_0; 30 | uint32_t unk1C_0; 31 | uint32_t unk20_0; 32 | uint32_t unk24_0; 33 | uint32_t unk28_0; 34 | uint32_t unk2C_0; 35 | uint32_t unk30_0; 36 | uint32_t unk34_0; 37 | uint32_t unk38_0; 38 | uint32_t unk3C_0; 39 | uint32_t unk40_0; 40 | uint32_t unk44_0; 41 | uint32_t unk48_0; 42 | uint32_t unk4C_0; 43 | uint32_t unk50_0; 44 | uint32_t unk54_0; 45 | void * unk58; 46 | uint32_t unk5C_0; 47 | 48 | uint32_t unk60_0; 49 | uint32_t unk64_0; 50 | uint32_t unk68_0; 51 | uint32_t unk6C_0; 52 | 53 | uint32_t unk70_0; 54 | uint32_t unk74_0; 55 | uint32_t unk78_0; 56 | uint32_t unk7C_0; 57 | 58 | uint32_t unk80_0; 59 | uint32_t unk84_0; 60 | uint32_t unk88_0; 61 | uint32_t unk8C_0; 62 | 63 | uint32_t unk90_0; 64 | uint32_t unk94_0; 65 | uint32_t unk98_0; 66 | uint32_t unk9C_0; 67 | 68 | uint32_t unkA0_weird; 69 | void * unkA4_boolCountOrStruct; 70 | 71 | uint32_t unkA8_2; 72 | float * unkAC_PTR; 73 | 74 | uint32_t unkB0_1; 75 | float * unkB4_PTR; 76 | 77 | uint32_t unkB8_1; 78 | float * unkBC_PTR; 79 | 80 | uint32_t unkC0_0; 81 | GH3::QbKey * unkC4_PTR; 82 | 83 | uint32_t unkC8_0; 84 | uint32_t unkCC_4; 85 | 86 | uint32_t unkD0_0; 87 | uint32_t unkD4_0; 88 | uint32_t unkD8_3; 89 | uint32_t unkDC_0; 90 | 91 | uint32_t unkF0_0; 92 | uint32_t unkF4_maybeHeight320; 93 | uint32_t unkF8_maybeWidth512; 94 | uint32_t unkFC_0; 95 | 96 | uint32_t unk100_0; 97 | uint32_t unk104_0; 98 | uint32_t unk108_0; 99 | uint32_t unk10C_0; 100 | uint32_t unk110_0; //float 101 | uint32_t unk114_0; 102 | uint32_t unk118_0; 103 | uint32_t unk11C_0; 104 | uint32_t unk120_0; //float 105 | uint32_t unk124_0; 106 | uint32_t unk128_0; 107 | uint32_t unk12C_0; 108 | }; 109 | 110 | 111 | 112 | 113 | 114 | 115 | static std::map g_imageMap; 116 | static std::map g_metadataMap; 117 | static std::map g_weirdMap; 118 | 119 | static constexpr GH3::QbKey g_rawKeys[] = { 120 | RawOpenTextureKey, 121 | RawOpenHammerTextureKey, 122 | RawOpenStarTextureKey, 123 | RawOpenStarHammerTextureKey, 124 | RawOpenStarpowerTextureKey, 125 | RawOpenStarpowerHammerTextureKey, 126 | }; 127 | 128 | static constexpr GH3::QbKey g_textureKeys[] = { 129 | OpenTextureKey, 130 | OpenHammerTextureKey, 131 | OpenStarTextureKey, 132 | OpenStarHammerTextureKey, 133 | OpenStarpowerTextureKey, 134 | OpenStarpowerHammerTextureKey, 135 | }; 136 | 137 | 138 | /////////////////////////// 139 | // Retrieve our textures // 140 | /////////////////////////// 141 | 142 | 143 | static GH3::QbKey getYellowEquivalent(GH3::QbKey openKey) 144 | { 145 | switch (openKey) 146 | { 147 | case static_cast(OpenTextureKey): 148 | return YellowTextureKey; 149 | 150 | case static_cast(OpenHammerTextureKey): 151 | return YellowHammerTextureKey; 152 | 153 | case static_cast(OpenStarTextureKey): 154 | return YellowStarTextureKey; 155 | 156 | case static_cast(OpenStarHammerTextureKey): 157 | return YellowStarHammerTextureKey; 158 | 159 | case static_cast(OpenStarpowerTextureKey): 160 | return YellowStarpowerTextureKey; 161 | 162 | case static_cast(OpenStarpowerHammerTextureKey): 163 | return YellowStarpowerHammerTextureKey; 164 | 165 | default: 166 | return GH3::QbKey(); 167 | } 168 | } 169 | 170 | bool constexpr isTextureKey(GH3::QbKey key) 171 | { 172 | return key == OpenTextureKey || 173 | key == OpenHammerTextureKey || 174 | key == OpenStarTextureKey || 175 | key == OpenStarHammerTextureKey || 176 | key == OpenStarpowerTextureKey || 177 | key == OpenStarpowerHammerTextureKey; 178 | } 179 | 180 | 181 | void CopyExistingWeirdStruct(WeirdTextureStruct *dest, const WeirdTextureStruct *src, GH3::QbKey newKey, GH3::TextureMetadata *newMetadata) 182 | { 183 | memcpy(dest, src, sizeof(WeirdTextureStruct)); 184 | dest->key = newKey; 185 | dest->metadata = newMetadata; 186 | } 187 | 188 | WeirdTextureStruct * __stdcall frankerzFix(GH3::QbMap *map, GH3::QbKey *key) 189 | { 190 | WeirdTextureStruct * node = reinterpret_cast(map->Get(*key)); 191 | if (node == nullptr && isTextureKey(*key)) 192 | { 193 | GH3::QbKey yellowKey = getYellowEquivalent(*key); 194 | WeirdTextureStruct *yellowWeird = reinterpret_cast(map->Get(yellowKey)); 195 | WeirdTextureStruct *openWeird = &g_weirdMap[*key]; 196 | 197 | GH3::TextureMetadata *metadata = g_metadataMap[*key]; 198 | CopyExistingWeirdStruct(openWeird, yellowWeird, *key, metadata); 199 | 200 | map->Insert(*key, reinterpret_cast(openWeird)); 201 | node = reinterpret_cast(map->Get(*key)); 202 | } 203 | return node; 204 | } 205 | 206 | static void * const frankerzDetour = (void *)0x0062D9A1; 207 | void __declspec(naked) frankerzFixNaked() 208 | { 209 | static const void * const returnAddress = (void *)0x0062D9A6; 210 | __asm 211 | { 212 | push ecx; 213 | call frankerzFix; 214 | add esp, 4; //normal map call has an extra argument we're not using 215 | jmp returnAddress; 216 | } 217 | } 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | //////////////////////// 230 | // Store our textures // 231 | //////////////////////// 232 | 233 | bool isRawTextureKey(GH3::QbKey key, int &i) 234 | { 235 | for (i = 0; i < ArrayLength(g_rawKeys); ++i) 236 | { 237 | if (key == g_rawKeys[i]) 238 | return true; 239 | } 240 | 241 | return false; 242 | } 243 | 244 | bool __stdcall storeSpecialTextures(GH3::QbImage *img, GH3::TextureMetadata *metadata) 245 | { 246 | int index; 247 | 248 | if (isRawTextureKey(metadata->key, index)) 249 | { 250 | GH3::QbKey textureKey = g_textureKeys[index]; 251 | g_metadataMap[textureKey] = metadata; 252 | g_imageMap[textureKey] = img; 253 | g_weirdMap[textureKey] = WeirdTextureStruct(); 254 | } 255 | 256 | return false; 257 | } 258 | 259 | 260 | static void * const storeSpecialTexturesDetour = (void *)0x005F8AA2; 261 | void __declspec(naked) storeSpecialTexturesNaked() 262 | { 263 | static const void * const returnAddress = (void *)0x005F8AA8; 264 | __asm 265 | { 266 | pushad; 267 | push esi; //metadata 268 | push eax; //QbImage 269 | call storeSpecialTextures; 270 | popad; 271 | 272 | mov [eax + 10h], esi; 273 | mov edx, [esi + 4]; 274 | jmp returnAddress; 275 | } 276 | } 277 | 278 | bool TryApplyTextureTakeoverPatches() 279 | { 280 | if (!g_patcher.WriteJmp(storeSpecialTexturesDetour, storeSpecialTexturesNaked) || 281 | !g_patcher.WriteJmp(frankerzDetour, frankerzFixNaked)) 282 | return false; 283 | 284 | return true; 285 | } -------------------------------------------------------------------------------- /src/plugins/textureHelper/TextureHelper.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {7033409A-E1C1-4759-A519-F508EBFF1114} 15 | Win32Proj 16 | TextureHelper 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;FORCETAPNOTES_EXPORTS;%(PreprocessorDefinitions) 58 | true 59 | ..\..\;%(AdditionalIncludeDirectories) 60 | MultiThreadedDebug 61 | 62 | 63 | Windows 64 | true 65 | 0.5 66 | 67 | 68 | 69 | 70 | Level3 71 | 72 | 73 | MaxSpeed 74 | true 75 | true 76 | WIN32;NDEBUG;_WINDOWS;_USRDLL;TEXTUREHELPER_EXPORTS;%(PreprocessorDefinitions) 77 | true 78 | ..\..\;%(AdditionalIncludeDirectories) 79 | MultiThreaded 80 | 81 | 82 | Windows 83 | true 84 | true 85 | true 86 | 0.5 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/plugins/textureHelper/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include 3 | #include "textureHelper.h" 4 | 5 | BOOL APIENTRY DllMain(HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | ApplyHack(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/textureHelper/textureHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "core\Patcher.h" 2 | #include "gh3\GH3Keys.h" 3 | #include "gh3\GH3GlobalAddresses.h" 4 | 5 | #include "textureHelper.h" 6 | #include 7 | #include 8 | 9 | //static void * guitarInputDetour = (void *)0x00431D65; ////0x00431CCE; //0x0043190D; 10 | //static void * guitarInputDetour2 = (void *)0x0043226B; // 0x004320EC; //overstrum 11 | 12 | static void * const textureKeyDetour = (void *)0x004FAC60; //0x004327D2; // 0x00432733; 13 | 14 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 15 | 16 | static uint32_t g_newTexture = 0; 17 | 18 | static uint32_t ignoredKeys[] 19 | { 20 | 0x0, //error 21 | 22 | 0x02EC4A8A, //nowbar 23 | 0x0B7DDD3A, 24 | 0x1FB8EE56, 25 | 0x3BEEDF17, 26 | 0x488A30D9, 27 | 0x53A29CF3, 28 | 0x541C5B42, 29 | 0x55173AC7, 30 | 0x5E62E0F2, 31 | 0x62442C5A, 32 | 0x76FFFD01, 33 | 0x89657E48, 34 | 0x8A5CBE09, 35 | 0x901A7B90, 36 | 0x9C1D32A6, 37 | 0xA3ABE406, 38 | 0xA57BFEF9, 39 | 0xA6461323, 40 | 0xAAE08B99, 41 | 0xAE3F6FBD, 42 | 0xCADD3843, 43 | 0xD4C574A7, 44 | 0xE4A7C8B6, 45 | 0xE92CFF13, 46 | 0xEF5FAC20, 47 | 0xF0B602EB, 48 | 49 | 0xE0D86413, //fretbar 50 | 0x3F7CAAE1, 51 | 0x82ADD9D0, 52 | 53 | 0xC5C51FEE, //sparks 54 | 0x3A9A5D3E, 55 | 56 | 0x3E4F70B3, //sys_string01_sys_string01 57 | 58 | 59 | }; 60 | 61 | int __stdcall textureManipulator(uint32_t key); 62 | 63 | __declspec (naked) void textureHelperNaked() 64 | { 65 | static const uint32_t returnAddress = 0x004FAC68; 66 | 67 | __asm 68 | { 69 | mov eax, [esp+4] 70 | 71 | pushad 72 | push eax 73 | call textureManipulator 74 | mov g_newTexture, eax 75 | popad 76 | 77 | mov eax, g_newTexture 78 | 79 | push esi 80 | push edi 81 | xor edi, edi 82 | 83 | jmp returnAddress; 84 | } 85 | } 86 | 87 | int __stdcall textureManipulator(uint32_t key) 88 | { 89 | for (int i = 0; i < (sizeof(ignoredKeys) / 4); ++i) 90 | { 91 | if (key == ignoredKeys[i]) 92 | return key; 93 | } 94 | 95 | std::cout << key << "\n"; 96 | 97 | return 0x58C6A27F;// 0x1FB75CA1; //lightning 98 | } 99 | 100 | 101 | void ApplyHack() 102 | { 103 | 104 | g_patcher.WriteJmp(textureKeyDetour, (void *)textureHelperNaked); 105 | 106 | } -------------------------------------------------------------------------------- /src/plugins/textureHelper/textureHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | void ApplyHack(); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/plugins/tiltFix/TiltFix.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {8F562B97-5D1F-4E3C-9447-E01604AF9662} 15 | Win32Proj 16 | TiltFix 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;TILTFIX_EXPORTS;%(PreprocessorDefinitions) 58 | ..\..\;%(AdditionalIncludeDirectories) 59 | MultiThreadedDebug 60 | AssemblyAndSourceCode 61 | 62 | 63 | Windows 64 | true 65 | 0.5 66 | 67 | 68 | 69 | 70 | Level3 71 | 72 | 73 | Disabled 74 | true 75 | true 76 | WIN32;NDEBUG;_WINDOWS;_USRDLL;TILTFIX_EXPORTS;%(PreprocessorDefinitions) 77 | ..\..\;%(AdditionalIncludeDirectories) 78 | MultiThreaded 79 | true 80 | 81 | 82 | Windows 83 | true 84 | true 85 | true 86 | 0.5 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/plugins/tiltFix/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include 3 | #include "tiltFix.h" 4 | 5 | BOOL APIENTRY DllMain(HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | ApplyHack(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/tiltFix/tiltFix.cpp: -------------------------------------------------------------------------------- 1 | #include "tiltFix.h" 2 | #include "core\Patcher.h" 3 | #include "gh3\GH3Keys.h" 4 | #include "gh3\GH3GlobalAddresses.h" 5 | #include 6 | #include 7 | 8 | static const uint32_t GH3_MAX_PLAYERS = 2; 9 | 10 | //Detours 11 | static void * const starPowerCheckDetour = (void *)0x0042E194; 12 | 13 | // Static variables used by hack 14 | static bool g_isTilting[GH3_MAX_PLAYERS] = { false }; 15 | static uint32_t g_tiltStart[GH3_MAX_PLAYERS] = { 0 }; 16 | 17 | static uint32_t g_timeMinThreshold = 266; //266 the equivalent of 16 frames at 60fps which is the default tilt threshold. 18 | static uint32_t g_timeMaxThreshold = 1000; //If the time difference is over 1000ms we must assume it is because of a bug. 19 | 20 | static float g_tiltAngleThreshold = -1.0f; //-1.0 is the highest the controller can be tilted with 1.0 being the lowest. Set this to a value less than -1.0 to never activate by tilting. 21 | 22 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 23 | 24 | 25 | 26 | bool __stdcall tiltFix(float tilt); 27 | 28 | __declspec(naked) void tiltFixNaked() 29 | { 30 | static const uint32_t returnAddressActivate = 0x0042E1B7; 31 | static const uint32_t returnAddressDontActivate = 0x0042E1DE; 32 | 33 | _asm 34 | { 35 | mov eax, [esp + 0x24]; // tilt 36 | pushad; 37 | 38 | push eax; 39 | call tiltFix; 40 | 41 | cmp eax, 0; 42 | jz DONT_ACTIVATE; 43 | jmp DONT_ACTIVATE; //remove later 44 | 45 | //ACTIVATE: 46 | popad; 47 | jmp returnAddressActivate; 48 | 49 | DONT_ACTIVATE: 50 | popad; 51 | jmp returnAddressDontActivate; 52 | }; 53 | } 54 | 55 | bool __stdcall tiltFix(float tilt) 56 | { 57 | uint32_t pIdx = 0; //temporary 58 | uint32_t currentTime; 59 | uint32_t timeDiff; 60 | 61 | currentTime = static_cast(GetTickCount64()); 62 | timeDiff = static_cast(currentTime - g_tiltStart[pIdx]); 63 | 64 | if (tilt > g_tiltAngleThreshold) 65 | { 66 | g_isTilting[pIdx] = false; 67 | g_tiltStart[pIdx] = currentTime; 68 | } 69 | else if (!g_isTilting[pIdx]) 70 | { 71 | g_isTilting[pIdx] = true; 72 | g_tiltStart[pIdx] = currentTime; 73 | } 74 | else if (timeDiff > g_timeMinThreshold && timeDiff < g_timeMaxThreshold) 75 | { 76 | return true; 77 | } 78 | 79 | return false; 80 | } 81 | 82 | 83 | void ApplyHack() 84 | { 85 | g_patcher.WriteJmp(starPowerCheckDetour, tiltFixNaked); 86 | } -------------------------------------------------------------------------------- /src/plugins/tiltFix/tiltFix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | void ApplyHack(); 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/plugins/whammyFix/WhammyFix.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {3F3D0ABE-56CE-47CE-AFC4-D069E0CDE09A} 15 | Win32Proj 16 | WhammyFix 17 | 8.1 18 | 19 | 20 | 21 | DynamicLibrary 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | DynamicLibrary 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)bin\$(Configuration)\ 46 | 47 | 48 | false 49 | $(SolutionDir)bin\$(Configuration)\ 50 | 51 | 52 | 53 | 54 | 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;WHAMMYFIX_EXPORTS;%(PreprocessorDefinitions) 58 | ..\..\;%(AdditionalIncludeDirectories) 59 | MultiThreadedDebug 60 | 61 | 62 | Windows 63 | true 64 | 0.5 65 | 66 | 67 | 68 | 69 | Level3 70 | 71 | 72 | MaxSpeed 73 | true 74 | true 75 | WIN32;NDEBUG;_WINDOWS;_USRDLL;WHAMMYFIX_EXPORTS;%(PreprocessorDefinitions) 76 | ..\..\;%(AdditionalIncludeDirectories) 77 | MultiThreaded 78 | 79 | 80 | Windows 81 | true 82 | true 83 | true 84 | 0.5 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | {3ecb28cb-cdca-4193-b4bf-1f7ec67c9e03} 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/plugins/whammyFix/WhammyFix.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/plugins/whammyFix/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include 3 | #include "whammyFix.h" 4 | 5 | BOOL APIENTRY DllMain(HMODULE hModule, 6 | DWORD ul_reason_for_call, 7 | LPVOID lpReserved 8 | ) 9 | { 10 | switch (ul_reason_for_call) 11 | { 12 | case DLL_PROCESS_ATTACH: 13 | ApplyHack(); 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/plugins/whammyFix/whammyFix.cpp: -------------------------------------------------------------------------------- 1 | #include "whammyFix.h" 2 | #include "core\Patcher.h" 3 | #include "gh3\GH3Keys.h" 4 | #include "gh3\GH3GlobalAddresses.h" 5 | #include 6 | 7 | static const uint32_t GH3_MAX_PLAYERS = 2; 8 | 9 | 10 | //Static variables for hack functionality 11 | static uint32_t g_clock[GH3_MAX_PLAYERS] = { 0 }; 12 | static uint8_t g_prevWhammy[GH3_MAX_PLAYERS] = { 0 }; 13 | static uint8_t g_prevRealWhammy[GH3_MAX_PLAYERS] = { 0 }; 14 | static uint64_t g_lastChange[GH3_MAX_PLAYERS] = { 0 }; 15 | 16 | static uint32_t controllerStructBuffer=0xDEADC0DE; 17 | 18 | static uint32_t g_structure[GH3_MAX_PLAYERS] = { 0 }; 19 | static uint32_t g_player[GH3_MAX_PLAYERS] = { 0 }; 20 | 21 | static const uint32_t whammyThreshold = 200; 22 | static const uint8_t minWibble = 24; 23 | 24 | uint8_t __stdcall modifyWhammyInput(uint32_t controllerStruct, uint32_t rawInput); 25 | 26 | static GH3P::Patcher g_patcher = GH3P::Patcher(__FILE__); 27 | 28 | 29 | 30 | 31 | static void * const controllerRelatedStart = (void *)0x00522CD0; 32 | __declspec(naked) void storeControllerStructNaked() 33 | { 34 | static const uint32_t returnAddress = 0x00522CD6; 35 | __asm 36 | { 37 | mov controllerStructBuffer, ecx; 38 | sub esp, 118h 39 | jmp returnAddress; 40 | } 41 | } 42 | 43 | 44 | 45 | 46 | static void * const controllerInputDetour = (void *)0x005249C5; 47 | __declspec(naked) void modifyWhammyInputNaked() 48 | { 49 | static const uint32_t returnAddress = 0x005249CF; 50 | __asm 51 | { 52 | pushad; 53 | 54 | push esi; 55 | push eax; //rawInput 56 | mov eax, controllerStructBuffer; 57 | mov eax, [eax]; 58 | push eax; //controllerStruct 59 | call modifyWhammyInput 60 | pop esi 61 | mov[esi + 1Dh], al; 62 | popad; 63 | 64 | mov eax, ADDR_byteDebugController; 65 | cmp [eax], 0; 66 | 67 | jmp returnAddress; 68 | } 69 | } 70 | 71 | uint32_t getPlayerIndex(uint32_t controllerStructPtr) 72 | { 73 | 74 | static uint32_t newestPlayer = 0; 75 | 76 | //use the controllerStruct 77 | 78 | for (uint32_t i = 0; i < GH3_MAX_PLAYERS; ++i) 79 | { 80 | if (controllerStructPtr == g_structure[i]) 81 | return g_player[i]; 82 | } 83 | 84 | //shift existing cells right and push current at 0 85 | 86 | for (uint32_t i = GH3_MAX_PLAYERS - 1; i > 0; --i) 87 | { 88 | g_structure[i] = g_structure[i - 1]; 89 | g_player[i] = g_player[i - 1]; 90 | } 91 | 92 | g_structure[0] = controllerStructPtr; 93 | g_player[0] = newestPlayer; 94 | newestPlayer = (newestPlayer + 1) % GH3_MAX_PLAYERS; 95 | 96 | return g_player[0]; 97 | } 98 | 99 | 100 | uint8_t __stdcall modifyWhammyInput(uint32_t controllerStruct, uint32_t rawInput) 101 | { 102 | rawInput &= 0xFF; 103 | uint32_t pIdx = getPlayerIndex(controllerStruct); 104 | 105 | ++g_clock[pIdx]; 106 | 107 | uint64_t curTime = GetTickCount64(); 108 | 109 | 110 | if (g_prevRealWhammy[pIdx] != rawInput) 111 | g_lastChange[pIdx] = curTime; 112 | g_prevRealWhammy[pIdx] = rawInput; 113 | 114 | uint8_t whammy = (uint8_t)rawInput; 115 | 116 | if ( (curTime - g_lastChange[pIdx]) < whammyThreshold) 117 | { 118 | if (g_clock[pIdx] % 2 == 0) 119 | { 120 | if (whammy > 100) 121 | whammy -= 100; 122 | else 123 | whammy = 0; 124 | } 125 | else 126 | { 127 | if (whammy == 0) 128 | whammy = minWibble; 129 | } 130 | } 131 | 132 | g_prevWhammy[pIdx] = whammy; 133 | 134 | return whammy; 135 | } 136 | 137 | 138 | void ApplyHack() 139 | { 140 | for (int i = 0; i < GH3_MAX_PLAYERS; ++i) 141 | { 142 | g_structure[i] = 0xD15EA5ED; 143 | g_player[i] = 0xDEADFACE; 144 | } 145 | g_patcher.WriteJmp(controllerRelatedStart, &storeControllerStructNaked); 146 | g_patcher.WriteJmp(controllerInputDetour, &modifyWhammyInputNaked); 147 | } -------------------------------------------------------------------------------- /src/plugins/whammyFix/whammyFix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | void ApplyHack(); 5 | 6 | 7 | -------------------------------------------------------------------------------- /templates/GH3+ Plugin Project.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExileLord/GH3-Plus/309aebb6bc4c3fa82d92617403c17d9585a63f34/templates/GH3+ Plugin Project.zip --------------------------------------------------------------------------------