-
Notifications
You must be signed in to change notification settings - Fork 2
/
patch.py
executable file
·156 lines (115 loc) · 4.57 KB
/
patch.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import argparse
from os import environ
from pathlib import Path
from run import run_game
import shutil
import subprocess
import sys
import urllib.request
from utils import run_command, run_exe, get_nerts_path, remove_existing_path
import zipfile
DE4DOT_URL = "https://github.com/ViRb3/de4dot-cex/releases/download/v4.0.0/de4dot-cex.zip"
def download_de4dot(bin_dir: Path) -> None:
"""
Downloads de4dot to the bin dir and extracts it.
"""
# Download de4dot to the bin dir
urllib.request.urlretrieve(DE4DOT_URL, bin_dir / "de4dot-cex.zip")
# Extract de4dot
with zipfile.ZipFile(bin_dir / "de4dot-cex.zip", "r") as zip:
zip.extractall(bin_dir)
# Attempt to remove zip file
(bin_dir / "de4dot-cex.zip").unlink()
def run_de4dot(bin_dir: Path, nerts_path: Path, cleaned_name: str) -> None:
"""
Runs de4dot to deobfuscate the Nerts game executable.
"""
run_exe(bin_dir / "de4dot-x64.exe", [str(nerts_path)])
shutil.copyfile(nerts_path.parent / cleaned_name, bin_dir / "NertsOnline-cleaned.exe")
def build_patcher() -> None:
"""
Builds the patcher and copies it to the Nerts game folder.
"""
patcher_dir = Path().cwd() / "Patcher"
subprocess.call("dotnet build", cwd=patcher_dir, shell=True)
def run_patcher(bin_dir: Path, nerts_path: Path) -> None:
"""
Runs the patcher to patch the Nerts game executable, and then copies it to the Nerts game folder.
"""
patcher_dir = Path().cwd() / "Patcher"
run_exe(Path("bin") / "Debug/net452/NertsPlusPatcher.exe", cwd=patcher_dir)
shutil.copyfile(patcher_dir / "bin/Debug/net452/NertsPlusPatcher.exe", nerts_path.parent / "NertsPlusPatcher.exe")
# Copy patcher output back to Steam directory
shutil.copyfile(bin_dir / "NertsOnline-patched.exe", nerts_path.parent / "NertsOnline-patched.exe")
def build_plugin(nerts_path: Path) -> None:
plugin_dir = Path().cwd() / "Plugin"
# Build and copy plugin
run_command("dotnet", ["build"], cwd=plugin_dir)
shutil.copyfile(plugin_dir / "bin/Debug/net452/NertsPlus.dll", nerts_path.parent / "NertsPlus.dll")
shutil.copyfile(plugin_dir / "bin/Debug/net452/0Harmony.dll", nerts_path.parent / "0Harmony.dll")
shutil.copyfile(plugin_dir / "bin/Debug/net452/Newtonsoft.Json.dll", nerts_path.parent / "Newtonsoft.Json.dll")
def write_steam_appid(nerts_path: Path) -> None:
"""
Writes the steam_appid.txt file to the Nerts game folder.
"""
NERTS_STEAM_ID = "1131190"
with open(nerts_path.parent / "steam_appid.txt", "w") as file:
file.write(NERTS_STEAM_ID)
def copy_textures(nerts_path: Path) -> None:
"""
Copies the textures to the Nerts game folder.
"""
shutil.copyfile("textures/logo_button.tex", nerts_path.parent / "Content/Packed/logo_button.tex")
shutil.copyfile("textures/logo_button_hover.tex", nerts_path.parent / "Content/Packed/logo_button_hover.tex")
def main():
# Parse arguments
parser = argparse.ArgumentParser(description="NertsPlus patcher")
parser.add_argument(
"--skip-download",
action=argparse.BooleanOptionalAction,
default=False,
help="Skip downloading and extracting de4dot")
parser.add_argument(
"-b",
"--bin-dir",
type=Path,
default=Path("bin"),
help="Directory to store de4dot and patched binaries")
parser.add_argument(
"-n",
"--nerts-path",
type=Path,
help="Path to Nerts game executable")
parser.add_argument(
"-r",
"--run",
action=argparse.BooleanOptionalAction,
default=False,
help="Run the game")
args = parser.parse_args()
# If a nerts path is not provided, try to find it automatically
# or ask for user input
if args.nerts_path is None:
nerts_path = get_nerts_path()
else:
nerts_path = args.nerts_path
cleaned_name = f"{nerts_path.stem}-cleaned.exe"
if args.run:
run_game(nerts_path)
sys.exit(0)
if not (args.skip_download or environ.get("SKIP_DOWNLOAD")):
if not remove_existing_path(args.bin_dir):
print("Unable to clear the bin directory, aborting 🛑!")
sys.exit(1)
args.bin_dir.mkdir()
# Download de4dot
download_de4dot(args.bin_dir)
run_de4dot(args.bin_dir, nerts_path, cleaned_name)
build_patcher()
run_patcher(args.bin_dir, nerts_path)
build_plugin(nerts_path)
copy_textures(nerts_path)
write_steam_appid(nerts_path)
print("🎉 All done! Now re-run with the --run flag to run the game.")
if __name__ == "__main__":
main()