aboutsummaryrefslogtreecommitdiff
path: root/libs/basic_games/games/game_silenthill2remake.py
blob: 4683a5d1b1efb72066716d578e8f46a7691cd4bc (plain)
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
from typing import Tuple

import mobase

from ..basic_features import BasicModDataChecker, GlobPatterns
from ..basic_game import BasicGame


class SilentHill2RemakeModDataChecker(BasicModDataChecker):
    def __init__(self):
        super().__init__(
            GlobPatterns(
                delete=[
                    "*.txt",
                    "*.md",
                    "manifest.json",
                    "icon.png",
                ],
            )
        )
        self.mod_path = ["SHProto", "Content", "Paks", "~mod"]
        self.mod_path_lower = [name.lower() for name in self.mod_path]

    def _find_tree(
        self, filetree: mobase.IFileTree
    ) -> Tuple[str | None, mobase.FileTreeEntry | None]:
        """
        Search the given filetree for a directory name that matches any component
        of self.mod_path (case-insensitive).

        Returns:
            (prefix, entry)
            prefix: The missing part before the match (e.g. 'SHProto/Content/')
            entry:  The IFileTree entry that matched (e.g. the 'Paks' directory)
            (None, None) if nothing matches.
        """
        for entry in filetree:
            if not entry.isDir():
                continue

            name_lower = entry.name().lower()
            for i, component in enumerate(self.mod_path_lower):
                if name_lower == component:
                    # Build the prefix string for everything *before* this match
                    prefix_parts = self.mod_path[:i]
                    prefix = "/".join(prefix_parts) + ("/" if prefix_parts else "")
                    return (prefix, entry)
        # No matches found
        return (None, None)

    def dataLooksValid(
        self, filetree: mobase.IFileTree
    ) -> mobase.ModDataChecker.CheckReturn:
        # Check for fully valid layout
        has_entry, _ = self._find_tree(filetree)
        if has_entry is None:
            # in this case we check to make sure there's a .pak file
            for entry in filetree:
                if entry.name().lower().endswith(".pak") and entry.isFile():
                    return mobase.ModDataChecker.FIXABLE
        elif has_entry == "":
            return mobase.ModDataChecker.VALID
        else:
            return mobase.ModDataChecker.FIXABLE

        # Otherwise, not recognizable
        return mobase.ModDataChecker.INVALID

    def fix(self, filetree: mobase.IFileTree) -> mobase.IFileTree:
        filetree = super().fix(filetree)
        prefix, item = self._find_tree(filetree)
        if prefix is None:
            foundAPak = False
            # Move all top-level items to BepInEx/plugins/
            items_to_move = list(filetree)
            for cur_item in items_to_move:
                if cur_item.name().lower().endswith(".pak"):
                    foundAPak = True
                filetree.move(cur_item, f"SHProto/Content/Paks/~mod/{cur_item.name()}")
            # foundAPack MUST be true because if 'prefix' returned None then
            # there must be a .pak file or dataLooksValid wouldn't have returned
            # a FIXABLE. This is therefore just a sanity check
            assert foundAPak
            return filetree
        elif prefix == "":
            return filetree
        else:
            # if prefix is not None then item cannot be None
            assert item is not None
            filetree.move(item, f"{prefix}{item.name()}")
            return filetree


class SilentHill2RemakeGame(BasicGame):
    def init(self, organizer: mobase.IOrganizer) -> bool:
        super().init(organizer)
        self._register_feature(SilentHill2RemakeModDataChecker())
        return True

    Name = "Silent Hill 2 Remake Support Plugin"
    Author = "HomerSimpleton Returns"
    Version = "1.0"

    GameName = "Silent Hill 2 Remake"
    GameShortName = "silenthill2"
    GameNexusName = "silenthill2"

    GameBinary = "SHProto/Binaries/Win64/SHProto-Win64-Shipping.exe"
    GameLauncher = "SHProto.exe"
    GameDataPath = "%GAME_PATH%"
    GameSupportURL = "https://github.com/ModOrganizer2/modorganizer-basic_games/wiki/Game:-Silent-Hill-2-Remake"

    GameGogId = [1225972913, 2051029707]