Skip to content

Commit d7e0c5a

Browse files
authored
Plugin for Silent Hill 2 Remake (#201)
1 parent 80dc114 commit d7e0c5a

1 file changed

Lines changed: 113 additions & 0 deletions

File tree

games/game_silenthill2remake.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
from typing import Tuple
2+
3+
import mobase
4+
5+
from ..basic_features import BasicModDataChecker, GlobPatterns
6+
from ..basic_game import BasicGame
7+
8+
9+
class SilentHill2RemakeModDataChecker(BasicModDataChecker):
10+
def __init__(self):
11+
super().__init__(
12+
GlobPatterns(
13+
delete=[
14+
"*.txt",
15+
"*.md",
16+
"manifest.json",
17+
"icon.png",
18+
],
19+
)
20+
)
21+
self.mod_path = ["SHProto", "Content", "Paks", "~mod"]
22+
self.mod_path_lower = [name.lower() for name in self.mod_path]
23+
24+
def _find_tree(
25+
self, filetree: mobase.IFileTree
26+
) -> Tuple[str | None, mobase.FileTreeEntry | None]:
27+
"""
28+
Search the given filetree for a directory name that matches any component
29+
of self.mod_path (case-insensitive).
30+
31+
Returns:
32+
(prefix, entry)
33+
prefix: The missing part before the match (e.g. 'SHProto/Content/')
34+
entry: The IFileTree entry that matched (e.g. the 'Paks' directory)
35+
(None, None) if nothing matches.
36+
"""
37+
for entry in filetree:
38+
if not entry.isDir():
39+
continue
40+
41+
name_lower = entry.name().lower()
42+
for i, component in enumerate(self.mod_path_lower):
43+
if name_lower == component:
44+
# Build the prefix string for everything *before* this match
45+
prefix_parts = self.mod_path[:i]
46+
prefix = "/".join(prefix_parts) + ("/" if prefix_parts else "")
47+
return (prefix, entry)
48+
# No matches found
49+
return (None, None)
50+
51+
def dataLooksValid(
52+
self, filetree: mobase.IFileTree
53+
) -> mobase.ModDataChecker.CheckReturn:
54+
# Check for fully valid layout
55+
has_entry, _ = self._find_tree(filetree)
56+
if has_entry is None:
57+
# in this case we check to make sure there's a .pak file
58+
for entry in filetree:
59+
if entry.name().lower().endswith(".pak") and entry.isFile():
60+
return mobase.ModDataChecker.FIXABLE
61+
elif has_entry == "":
62+
return mobase.ModDataChecker.VALID
63+
else:
64+
return mobase.ModDataChecker.FIXABLE
65+
66+
# Otherwise, not recognizable
67+
return mobase.ModDataChecker.INVALID
68+
69+
def fix(self, filetree: mobase.IFileTree) -> mobase.IFileTree:
70+
filetree = super().fix(filetree)
71+
prefix, item = self._find_tree(filetree)
72+
if prefix is None:
73+
foundAPak = False
74+
# Move all top-level items to BepInEx/plugins/
75+
items_to_move = list(filetree)
76+
for cur_item in items_to_move:
77+
if cur_item.name().lower().endswith(".pak"):
78+
foundAPak = True
79+
filetree.move(cur_item, f"SHProto/Content/Paks/~mod/{cur_item.name()}")
80+
# foundAPack MUST be true because if 'prefix' returned None then
81+
# there must be a .pak file or dataLooksValid wouldn't have returned
82+
# a FIXABLE. This is therefore just a sanity check
83+
assert foundAPak
84+
return filetree
85+
elif prefix == "":
86+
return filetree
87+
else:
88+
# if prefix is not None then item cannot be None
89+
assert item is not None
90+
filetree.move(item, f"{prefix}{item.name()}")
91+
return filetree
92+
93+
94+
class SilentHill2RemakeGame(BasicGame):
95+
def init(self, organizer: mobase.IOrganizer) -> bool:
96+
super().init(organizer)
97+
self._register_feature(SilentHill2RemakeModDataChecker())
98+
return True
99+
100+
Name = "Silent Hill 2 Remake Support Plugin"
101+
Author = "HomerSimpleton Returns"
102+
Version = "1.0"
103+
104+
GameName = "Silent Hill 2 Remake"
105+
GameShortName = "silenthill2"
106+
GameNexusName = "silenthill2"
107+
108+
GameBinary = "SHProto/Binaries/Win64/SHProto-Win64-Shipping.exe"
109+
GameLauncher = "SHProto.exe"
110+
GameDataPath = "%GAME_PATH%"
111+
GameSupportURL = "https://github.com/ModOrganizer2/modorganizer-basic_games/wiki/Game:-Silent-Hill-2-Remake"
112+
113+
GameGogId = [1225972913, 2051029707]

0 commit comments

Comments
 (0)