Skip to content

Commit 0679b45

Browse files
authored
Add silksong suport (#196)
1 parent deabf2a commit 0679b45

1 file changed

Lines changed: 121 additions & 0 deletions

File tree

games/game_silksong.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
from __future__ import annotations
2+
3+
from pathlib import Path
4+
5+
from PyQt6.QtCore import QDir
6+
7+
import mobase
8+
9+
from ..basic_features import BasicModDataChecker, GlobPatterns
10+
from ..basic_features.basic_save_game_info import BasicGameSaveGame
11+
from ..basic_game import BasicGame
12+
13+
14+
class SilksongModDataChecker(BasicModDataChecker):
15+
def __init__(self, patterns: GlobPatterns | None = None):
16+
super().__init__(
17+
GlobPatterns(
18+
valid=[
19+
# BepInEx files go to root
20+
"BepInEx",
21+
"doorstop_config.ini",
22+
"winhttp.dll",
23+
".doorstop_version",
24+
],
25+
delete=[
26+
"*.txt",
27+
"*.md",
28+
"manifest.json",
29+
"icon.png",
30+
],
31+
).merge(patterns or GlobPatterns()),
32+
)
33+
34+
def dataLooksValid(
35+
self, filetree: mobase.IFileTree
36+
) -> mobase.ModDataChecker.CheckReturn:
37+
# Check if it contains BepInEx folders/files - if so, keep structure
38+
if self._has_bepinex_structure(filetree):
39+
return self.VALID
40+
41+
# Everything else needs to go to BepInEx/plugins/
42+
return self.FIXABLE
43+
44+
def _has_bepinex_structure(self, filetree: mobase.IFileTree) -> bool:
45+
"""Check if the mod has BepInEx folder structure"""
46+
for entry in filetree:
47+
name = entry.name().lower()
48+
if name in [
49+
"bepinex",
50+
"doorstop_config.ini",
51+
"winhttp.dll",
52+
".doorstop_version",
53+
]:
54+
return True
55+
return False
56+
57+
def fix(self, filetree: mobase.IFileTree) -> mobase.IFileTree:
58+
# First apply the basic fix (handles delete patterns)
59+
filetree = super().fix(filetree)
60+
61+
# If no BepInEx structure, move everything to BepInEx/plugins/
62+
if not self._has_bepinex_structure(filetree):
63+
# Move all top-level items to BepInEx/plugins/
64+
items_to_move = list(filetree)
65+
for item in items_to_move:
66+
filetree.move(item, f"BepInEx/plugins/{item.name()}")
67+
68+
return filetree
69+
70+
71+
class SilksongGame(BasicGame):
72+
Name = "Hollow Knight: Silksong Support Plugin"
73+
Author = "Nikirack"
74+
Version = "1.0.0"
75+
76+
GameName = "Hollow Knight: Silksong"
77+
GameShortName = "hollowknightsilksong" # Match the error message
78+
GameNexusName = "hollowknightsilksong"
79+
GameSteamId = 1030300
80+
GameBinary = r"Hollow Knight Silksong.exe"
81+
GameDataPath = ""
82+
GameSavesDirectory = (
83+
r"%USERPROFILE%\AppData\LocalLow\Team Cherry\Hollow Knight Silksong"
84+
)
85+
GameSupportURL = (
86+
r"https://github.com/ModOrganizer2/modorganizer-basic_games/wiki/"
87+
"Game:-Hollow-Knight-Silksong"
88+
)
89+
90+
_forced_libraries = ["winhttp.dll"]
91+
92+
def init(self, organizer: mobase.IOrganizer) -> bool:
93+
super().init(organizer)
94+
self._register_feature(SilksongModDataChecker())
95+
return True
96+
97+
def listSaves(self, folder: QDir) -> list[mobase.ISaveGame]:
98+
saves: list[mobase.ISaveGame] = []
99+
save_dir = Path(folder.absolutePath())
100+
101+
if save_dir.exists():
102+
# Look for common save file patterns
103+
for pattern in ["*.save", "user*.dat"]:
104+
for save_file in save_dir.rglob(pattern):
105+
saves.append(BasicGameSaveGame(save_file))
106+
107+
return saves
108+
109+
def executables(self) -> list[mobase.ExecutableInfo]:
110+
return [
111+
mobase.ExecutableInfo(
112+
self.gameName(),
113+
self.gameDirectory().absoluteFilePath(self.binaryName()),
114+
)
115+
]
116+
117+
def executableForcedLoads(self) -> list[mobase.ExecutableForcedLoadSetting]:
118+
return [
119+
mobase.ExecutableForcedLoadSetting(self.binaryName(), lib).withEnabled(True)
120+
for lib in self._forced_libraries
121+
]

0 commit comments

Comments
 (0)