generated from SokuDev/ModTemplate
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7f5b70e
Showing
10 changed files
with
359 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Prerequisites | ||
*.d | ||
|
||
# Compiled Object files | ||
*.slo | ||
*.lo | ||
*.o | ||
*.obj | ||
|
||
# Precompiled Headers | ||
*.gch | ||
*.pch | ||
|
||
# Compiled Dynamic libraries | ||
*.so | ||
*.dylib | ||
*.dll | ||
|
||
# Fortran module files | ||
*.mod | ||
*.smod | ||
|
||
# Compiled Static libraries | ||
*.lai | ||
*.la | ||
*.a | ||
*.lib | ||
|
||
# Executables | ||
*.exe | ||
*.out | ||
*.app | ||
|
||
# IDE stuff | ||
.idea | ||
.vs | ||
|
||
# Build directories | ||
cmake-build-* | ||
build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "SokuLib"] | ||
path = SokuLib | ||
url = https://github.com/SokuDev/SokuLib |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
cmake_minimum_required(VERSION 3.15) | ||
cmake_policy(SET CMP0091 NEW) | ||
set(PROJECT_NAME SaveRep) | ||
project("${PROJECT_NAME}" C CXX) | ||
|
||
set(CMAKE_C_STANDARD 11) | ||
set(CMAKE_CXX_STANDARD 17) | ||
|
||
set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/install") | ||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") | ||
|
||
add_definitions(-DWINVER=0x0501 -D_WIN32_WINNT=0x0501) | ||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC") | ||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++11-narrowing -Wno-microsoft-cast") | ||
endif () | ||
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /Brepro") | ||
SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /Brepro") | ||
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /Brepro") | ||
|
||
# SokuLib | ||
add_subdirectory(SokuLib) | ||
|
||
# Module | ||
add_library( | ||
"${PROJECT_NAME}" | ||
MODULE | ||
src/main.cpp | ||
src/version.rc | ||
) | ||
target_compile_options("${PROJECT_NAME}" PRIVATE /Zi) | ||
target_compile_definitions("${PROJECT_NAME}" PRIVATE DIRECTINPUT_VERSION=0x0800 CURL_STATICLIB _CRT_SECURE_NO_WARNINGS $<$<CONFIG:Debug>:_DEBUG>) | ||
target_link_directories("${PROJECT_NAME}" PRIVATE lib) | ||
target_link_libraries( | ||
"${PROJECT_NAME}" | ||
SokuLib | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2023 SokuDev | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# SaveRep mod for Touhou Hisoutensoku | ||
|
||
This mod is to save replay when in one of the following situations: | ||
|
||
- the user is p1 or p2 in network battle, and: | ||
- p1 or p2 presses ESC to end the game, or | ||
- the game ends before one of the players wins because of desync, or | ||
- the connection is lost | ||
- the user is spectating, and: | ||
- the user presses ESC to stop spectating, or | ||
- the connection is lost | ||
|
||
## Build | ||
Requires CMake, git and the VisualStudio compiler (MSVC). | ||
Both git and cmake needs to be in the PATH environment variable. | ||
|
||
All the following commands are to be run inside the visual studio 32bits compiler | ||
command prompt (called `x86 Native Tools Command Prompt for VS 20XX` in the start menu), unless stated otherwise. | ||
|
||
## Initialization | ||
First go inside the folder you want the repository to be in. | ||
In this example it will be C:\Users\PinkySmile\SokuProjects but remember to replace this | ||
with the path for your machine. If you don't want to type the full path, you can drag and | ||
drop the folder onto the console. | ||
|
||
`cd C:\Users\PinkySmile\SokuProjects` | ||
|
||
Now let's download the repository and initialize it for the first time | ||
``` | ||
git clone https://github.com/Hagb/SaveRep | ||
cd SaveRep | ||
git submodule init | ||
git submodule update | ||
mkdir build | ||
cd build | ||
cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Debug | ||
``` | ||
Note that if you want to build in Release, you should replace `-DCMAKE_BUILD_TYPE=Debug` with `-DCMAKE_BUILD_TYPE=Release`. | ||
|
||
## Compiling | ||
Now, to build the mod, go to the build directory (if you did the previous step you already are) | ||
`cd C:\Users\PinkySmile\SokuProjects\SaveRep\build` and invoke the compiler by running `cmake --build . --target SaveRep`. If you change the name of the mod (in the add_library statement in CMakeLists.txt), you will need to replace 'SaveRep' by the name of your mod in the previous command. | ||
|
||
You should find the resulting SaveRep.dll mod inside the build folder that can be to SWRSToys.ini. | ||
In my case, I would add this line to it `SaveRep=C:/Users/PinkySmile/SokuProjects/SaveRep/build/SaveRep.dll`. |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// | ||
// Created by PinkySmile on 31/10/2020 | ||
// | ||
|
||
// #include <SokuLib.hpp> | ||
// clang-format off | ||
|
||
#include <string> | ||
#include <type_traits> | ||
// clang-format on | ||
#include "BattleManager.hpp" | ||
#include "BattleMode.hpp" | ||
#include "InputManager.hpp" | ||
#include <iostream> | ||
// #include "Net" | ||
#include "Hash.hpp" | ||
#include "NetObject.hpp" | ||
#include "Scenes.hpp" | ||
#include "Tamper.hpp" | ||
#include "VTables.hpp" | ||
|
||
static int /*SokuLib::Scene*/ (SokuLib::BattleWatch::*ogBattleWatchOnProcess)(); | ||
static int /*SokuLib::Scene*/ (SokuLib::BattleClient::*ogBattleClientOnProcess)(); | ||
static int /*SokuLib::Scene*/ (SokuLib::BattleServer::*ogBattleServerOnProcess)(); | ||
static const auto spectatingSaveReplayIfAllow = (void(__thiscall *)(SokuLib::NetObject *))(0x454240); | ||
static const auto battleSaveReplay = (void (*)())(0x43ebe0); | ||
static const auto get00899840 = (char *(*)())(0x0043df40); | ||
// static const auto getReplayPath | ||
// = (void(__thiscall *)(SokuLib::InputManager *, char *replay_path, const char *profile1name, const char *profile2name))(0x42cb30); | ||
// static const auto writeReplay = (void(__thiscall *)(SokuLib::InputManager *, const char *path))(0x42b2d0); | ||
|
||
static int /*SokuLib::Scene*/ __fastcall CBattleWatch_OnProcess(SokuLib::BattleWatch *This) { | ||
int ret = (This->*ogBattleWatchOnProcess)(); | ||
if (ret == SokuLib::SCENE_TITLE) { | ||
std::cout << "Disconnect when spectating. Save replay if allowed." << std::endl; | ||
spectatingSaveReplayIfAllow(&SokuLib::getNetObject()); | ||
} | ||
return ret; | ||
} | ||
|
||
static void battleSaveReplayIfAllow() { | ||
std::cout << "Save replay if allowed." << std::endl; | ||
switch (get00899840()[0x73]) { | ||
case 0: // always save replay | ||
case 1: // save replay when as player | ||
battleSaveReplay(); | ||
case 2: // save replay when as spectator | ||
case 3: // never save replay | ||
case 4: // always ask | ||
break; | ||
} | ||
} | ||
|
||
template<typename T, int (T::**ogBattlePlayOnProcess)()> static int /*SokuLib::Scene*/ __fastcall CBattlePlay_OnProcess(T *This) { | ||
int ret = (This->**ogBattlePlayOnProcess)(); | ||
if (ret == SokuLib::SCENE_TITLE) { | ||
std::cout << "Disconnect. "; | ||
battleSaveReplayIfAllow(); | ||
} | ||
return ret; | ||
} | ||
|
||
template<SokuLib::Scene retcode> static void __declspec(naked) gameEndTooEarly() { | ||
static const SokuLib::Scene retcode_ = retcode; // workaround for the template parameter is unusable in inline asm (why?) | ||
std::cout << "Esc or desync causes the game ends too early. "; | ||
battleSaveReplayIfAllow(); | ||
__asm { | ||
pop edi; | ||
mov eax, retcode_; | ||
pop esi; | ||
ret; | ||
} | ||
} | ||
|
||
static void __declspec(naked) gameEndTooEarly2() { | ||
static auto gameEndTooEarlyAddr = gameEndTooEarly<SokuLib::SCENE_SELECTSV>; | ||
static const void *fun004282d0 = (void *)0x004282d0; | ||
__asm { | ||
call fun004282d0; | ||
jmp gameEndTooEarlyAddr; | ||
} | ||
} | ||
static void __declspec(naked) gameEndTooEarly3() { | ||
static const void *addr004283a2 = (void *)0x004283a2; | ||
__asm { | ||
push esi; | ||
} | ||
std::cout << "Esc or desync causes the game ends too early. "; | ||
battleSaveReplayIfAllow(); | ||
__asm { | ||
pop esi; | ||
cmp [esi+0x6c8], 0; | ||
jmp addr004283a2; | ||
} | ||
} | ||
|
||
// We check if the game version is what we target (in our case, Soku 1.10a). | ||
extern "C" __declspec(dllexport) bool CheckVersion(const BYTE hash[16]) { | ||
return memcmp(hash, SokuLib::targetHash, sizeof(SokuLib::targetHash)) == 0; | ||
} | ||
|
||
// Called when the mod loader is ready to initialize this module. | ||
// All hooks should be placed here. It's also a good moment to load settings | ||
// from the ini. | ||
extern "C" __declspec(dllexport) bool Initialize(HMODULE hMyModule, HMODULE hParentModule) { | ||
DWORD old; | ||
|
||
#ifdef _DEBUG | ||
FILE *_; | ||
|
||
AllocConsole(); | ||
freopen_s(&_, "CONOUT$", "w", stdout); | ||
freopen_s(&_, "CONOUT$", "w", stderr); | ||
#endif | ||
VirtualProtect((PVOID)RDATA_SECTION_OFFSET, RDATA_SECTION_SIZE, PAGE_EXECUTE_WRITECOPY, &old); | ||
ogBattleWatchOnProcess = SokuLib::TamperDword(&SokuLib::VTable_BattleWatch.onProcess, CBattleWatch_OnProcess); | ||
ogBattleServerOnProcess | ||
= SokuLib::TamperDword(&SokuLib::VTable_BattleServer.onProcess, CBattlePlay_OnProcess<SokuLib::BattleServer, &ogBattleServerOnProcess>); | ||
ogBattleClientOnProcess | ||
= SokuLib::TamperDword(&SokuLib::VTable_BattleClient.onProcess, CBattlePlay_OnProcess<SokuLib::BattleClient, &ogBattleClientOnProcess>); | ||
VirtualProtect((PVOID)RDATA_SECTION_OFFSET, RDATA_SECTION_SIZE, old, &old); | ||
VirtualProtect((PVOID)TEXT_SECTION_OFFSET, TEXT_SECTION_SIZE, PAGE_EXECUTE_WRITECOPY, &old); | ||
SokuLib::TamperNearJmp(0x428663, gameEndTooEarly<SokuLib::SCENE_SELECTCL>); | ||
SokuLib::TamperNearJmp(0x428680, gameEndTooEarly<SokuLib::SCENE_SELECTCL>); | ||
SokuLib::TamperNearJmp(0x4283b0, gameEndTooEarly<SokuLib::SCENE_SELECTSV>); | ||
SokuLib::TamperNearJmp(0x42838e, gameEndTooEarly2); | ||
VirtualProtect((PVOID)TEXT_SECTION_OFFSET, TEXT_SECTION_SIZE, old, &old); | ||
|
||
FlushInstructionCache(GetCurrentProcess(), nullptr, 0); | ||
return true; | ||
} | ||
|
||
extern "C" int APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) { | ||
return TRUE; | ||
} | ||
|
||
// New mod loader functions | ||
// Loading priority. Mods are loaded in order by ascending level of priority | ||
// (the highest first). When 2 mods define the same loading priority the loading | ||
// order is undefined. | ||
extern "C" __declspec(dllexport) int getPriority() { | ||
return 0; | ||
} | ||
|
||
// Not yet implemented in the mod loader, subject to change | ||
// SokuModLoader::IValue **getConfig(); | ||
// void freeConfig(SokuModLoader::IValue **v); | ||
// bool commitConfig(SokuModLoader::IValue *); | ||
// const char *getFailureReason(); | ||
// bool hasChainedHooks(); | ||
// void unHook(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#include <windows.h> | ||
#define VER_FILEVERSION 0,1,0,0 | ||
#define VER_FILEVERSION_STR "0.1\0" | ||
|
||
#define VER_PRODUCTVERSION 0,1,0,0 | ||
#define VER_PRODUCTVERSION_STR "0.1\0" | ||
|
||
#define VER_COMPANYNAME_STR "SokuDev\0" | ||
#define VER_FILEDESCRIPTION_STR "Mod for Touhou 12.3 to save replay when the battle ends too early (such as esc or desync)\0" | ||
#define VER_INTERNALNAME_STR "SaveRep\0" | ||
#define VER_LEGALCOPYRIGHT_STR "Hagb\0" | ||
#define VER_LEGALTRADEMARKS1_STR "\0" | ||
#define VER_LEGALTRADEMARKS2_STR "\0" | ||
#define VER_ORIGINALFILENAME_STR "SaveRep.dll\0" | ||
#define VER_PRODUCTNAME_STR "SaveRep\0" | ||
|
||
// Define this to 0 if not a pre release | ||
#define VER_PRERELEASE VS_FF_PRERELEASE | ||
|
||
#ifndef DEBUG | ||
#define VER_DEBUG 0 | ||
#else | ||
#define VER_DEBUG VS_FF_DEBUG | ||
#endif | ||
|
||
VS_VERSION_INFO VERSIONINFO | ||
FILEVERSION VER_FILEVERSION | ||
PRODUCTVERSION VER_PRODUCTVERSION | ||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK | ||
FILEFLAGS (VER_PRERELEASE|VER_DEBUG) | ||
FILEOS VOS__WINDOWS32 | ||
FILETYPE VFT_DLL | ||
FILESUBTYPE VFT2_UNKNOWN | ||
BEGIN | ||
BLOCK "StringFileInfo" | ||
BEGIN | ||
BLOCK "040904E4" | ||
BEGIN | ||
VALUE "CompanyName", VER_COMPANYNAME_STR | ||
VALUE "FileDescription", VER_FILEDESCRIPTION_STR | ||
VALUE "FileVersion", VER_FILEVERSION_STR | ||
VALUE "InternalName", VER_INTERNALNAME_STR | ||
VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR | ||
VALUE "LegalTrademarks1", VER_LEGALTRADEMARKS1_STR | ||
VALUE "LegalTrademarks2", VER_LEGALTRADEMARKS2_STR | ||
VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR | ||
VALUE "ProductName", VER_PRODUCTNAME_STR | ||
VALUE "ProductVersion", VER_PRODUCTVERSION_STR | ||
END | ||
END | ||
|
||
BLOCK "VarFileInfo" | ||
BEGIN | ||
/* The following line should only be modified for localized versions. */ | ||
/* It consists of any number of WORD,WORD pairs, with each pair */ | ||
/* describing a language,codepage combination supported by the file. */ | ||
/* */ | ||
/* For example, a file might have values "0x409,1252" indicating that it */ | ||
/* supports English language (0x409) in the Windows ANSI codepage (1252). */ | ||
VALUE "Translation", 0x409, 1252 | ||
END | ||
END |