-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgof2Installation.py
145 lines (106 loc) · 4.68 KB
/
gof2Installation.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
from AEPi import AEI
from typing import Dict, Iterable, List, Optional
import os
from os.path import join
from enum import Enum
class ItemIconResolution(Enum):
SD = 0
IPhone4 = 1
IPad = 2
IPad_1440 = 3
IPad_large = 4
# A list of file name segments. See the item_icons_aei_file_name function for usage.
ITEM_ICONS_AEI_RESOLUTIONS = {
ItemIconResolution.SD: ("", ""),
ItemIconResolution.IPhone4: ("iphone4", ""),
ItemIconResolution.IPad: ("ipad", ""),
ItemIconResolution.IPad_1440: ("ipad", "1440"),
ItemIconResolution.IPad_large: ("ipad", "large")
}
# Directory scanning sanity check
MAX_ITEM_ICONS_AEIS_PER_RESOLUTION = 99
# 176 items per AEI
# This is needed because the first 'items' AEI contains more than just items!
ITEM_ICONS_AEI_CHUNK_SIZE = 176
def _underscoreTruthy(s):
return f"_{s}" if s else ""
def item_icons_aei_file_name(resolution: ItemIconResolution, aei_index: int):
prefix, suffix = ITEM_ICONS_AEI_RESOLUTIONS[resolution]
return "".join((
"gof2_items",
_underscoreTruthy(prefix),
'' if aei_index == 1 else f"_{aei_index}",
_underscoreTruthy(suffix),
".aei"))
class Gof2ItemIcons:
def __init__(self, aei_paths: Iterable[str]) -> None:
self.aei_paths = list(aei_paths)
self._lazy_aeis: List[Optional[AEI]] = [None] * len(self.aei_paths)
def _get_aei(self, aei_index: int):
if existing := self._lazy_aeis[aei_index]:
return existing
aei = AEI.read(self.aei_paths[aei_index])
self._lazy_aeis[aei_index] = aei
return aei
def get_aei(self, item_id: int):
aei_index = int(item_id / ITEM_ICONS_AEI_CHUNK_SIZE)
if aei_index >= len(self._lazy_aeis):
raise KeyError(f"No AEI is stored for item with id {item_id}")
return self._get_aei(aei_index)
def get_image(self, item_id: int):
aei = self.get_aei(item_id)
texture_index = item_id % ITEM_ICONS_AEI_CHUNK_SIZE
texture = aei.textures[texture_index]
return aei.getTexture(texture)
def close(self):
for aei in self._lazy_aeis:
if aei:
aei.close()
def __del__(self):
self.close()
class Gof2Installation:
def __init__(self, base_path: str) -> None:
self.base_path = base_path
self._item_icon_resolutions: Dict[ItemIconResolution, Optional[Gof2ItemIcons]] = {
resolution: None for resolution in ItemIconResolution
}
self._discover_textures()
@property
def data_folder(self):
return join(self.base_path, "data")
def _discover_textures(self):
textures_folder = join(self.data_folder, "textures")
for resolution in ItemIconResolution:
aei_path = join(textures_folder, item_icons_aei_file_name(resolution, 1))
if not os.path.isfile(aei_path):
self._item_icon_resolutions[resolution] = None
continue
resolution_paths = [aei_path]
for aei_index in range(2, MAX_ITEM_ICONS_AEIS_PER_RESOLUTION):
current_path = join(textures_folder, item_icons_aei_file_name(resolution, aei_index))
if not os.path.isfile(current_path):
break
resolution_paths.append(current_path)
self._item_icon_resolutions[resolution] = Gof2ItemIcons(resolution_paths)
def item_icons(self, resolution: Optional[ItemIconResolution] = None):
"""Get the item icons AEI(s) in the installation, at a particular resolution.
If no resolution is specified, the highest available resolution is returned.
:param resolution: The item icon resolution to get, defaults to maximum available resolution
:type resolution: Optional[ItemIconResolution], optional
:raises ValueError: If `resolution` was not given, but no item icons AEIs exist in the installation
:raises KeyError: If `resolution` does not exist in the installation
"""
if resolution is None:
resolution = max(self._item_icon_resolutions.keys(), key=lambda r: r.value, default=None)
if resolution is None:
raise ValueError("No item icons AEIs were found in the installation")
icons = self._item_icon_resolutions.get(resolution, None)
if icons is None:
raise KeyError(f"The resolution was not found in the installation: {resolution}")
return icons
def close(self):
for item_icons in self._item_icon_resolutions.values():
if item_icons:
item_icons.close()
def __del__(self):
self.close()