Skip to content

Commit 67530db

Browse files
committed
Add asset config, move libast, formatting
1 parent aff3994 commit 67530db

File tree

9 files changed

+590
-681
lines changed

9 files changed

+590
-681
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,9 @@ docs/doxygen/
3232
__pycache__/
3333
venv/
3434

35+
# m2ctx files
3536
m2ctx.py
3637
ctx.c
38+
39+
# Asset Config
40+
asset_config.json

Makefile

+9-5
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,11 @@ tools: dirs $(ELF2DOL) $(YAZ0)
156156

157157
assets:
158158
@mkdir -p game
159-
$(PYTHON) tools/extract_game_assets.py $(IMAGENAME) game
159+
$(PYTHON) tools/extract_game_assets.py $(IMAGENAME) game native asset_config.json
160+
161+
assets-fast:
162+
@mkdir -p game
163+
$(PYTHON) tools/extract_game_assets.py $(IMAGENAME) game oead asset_config.json
160164

161165
docs:
162166
$(DOXYGEN) Doxyfile
@@ -189,19 +193,19 @@ shiftedrels: shift $(RELS)
189193

190194
game: shiftedrels
191195
@mkdir -p game
192-
@$(PYTHON) tools/package_game_assets.py ./game $(BUILD_PATH) copyCode native
196+
@$(PYTHON) tools/package_game_assets.py ./game $(BUILD_PATH) copyCode native asset_config.json
193197

194198
game-fast: shiftedrels
195199
@mkdir -p game
196-
@$(PYTHON) tools/package_game_assets.py ./game $(BUILD_PATH) copyCode oead
200+
@$(PYTHON) tools/package_game_assets.py ./game $(BUILD_PATH) copyCode oead asset_config.json
197201

198202
game-nocompile:
199203
@mkdir -p game
200-
@$(PYTHON) tools/package_game_assets.py ./game $(BUILD_PATH) noCopyCode native
204+
@$(PYTHON) tools/package_game_assets.py ./game $(BUILD_PATH) noCopyCode native asset_config.json
201205

202206
game-nocompile-fast:
203207
@mkdir -p game
204-
@$(PYTHON) tools/package_game_assets.py ./game $(BUILD_PATH) noCopyCode oead
208+
@$(PYTHON) tools/package_game_assets.py ./game $(BUILD_PATH) noCopyCode oead asset_config.json
205209

206210
rungame-nocompile: game-nocompile
207211
@echo If you are playing on a shifted game make sure Hyrule Field Speed hack is disabled in dolphin!

tools/assets_config.py

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import curses
2+
from sys import argv
3+
import json
4+
from os import path
5+
6+
CONFIG_DESCRIPTIONS = {
7+
"decompress_assets": "Decompress Yaz0 compressed assets (appends .c to the filename)",
8+
"extract_arc": "Extract archive (.arc) files",
9+
"convert_stages": "Convert Stage Files (.dzs and .dzr) to json",
10+
"convert_textures": "Convert Textures (.bti) to png",
11+
"update_copydate": "Update COPYDATE on build",
12+
"package_maps": "Package Symbol Map (.map) files on build",
13+
}
14+
15+
CONFIG_DEFAULTS = {
16+
"decompress_assets": True,
17+
"extract_arc": True,
18+
"convert_stages": True,
19+
"convert_textures": False,
20+
"update_copydate": True,
21+
"package_maps": True,
22+
}
23+
24+
CONFIGFILE_DEFAULT = "asset_config.json"
25+
26+
27+
def printMenu(stdscr, selected_idx, options):
28+
stdscr.clear()
29+
height, width = stdscr.getmaxyx()
30+
31+
left = min([(width // 2) - (len(option) // 2) for option in options])
32+
top = (height // 2) - (len(options) // 2)
33+
34+
stdscr.addstr(top - 2, left, "Configure Asset Extraction/Packaging (q to save):")
35+
36+
for idx, option in enumerate(options):
37+
x = left
38+
y = top + idx
39+
40+
if idx == selected_idx:
41+
stdscr.attron(curses.color_pair(1))
42+
stdscr.addstr(y, x, option)
43+
stdscr.attroff(curses.color_pair(1))
44+
else:
45+
stdscr.addstr(y, x, option)
46+
47+
stdscr.refresh()
48+
49+
50+
def cursesMenu(stdscr, values):
51+
curses.curs_set(0)
52+
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
53+
54+
keys = list(values.keys())
55+
options = [
56+
f"{CONFIG_DESCRIPTIONS[key]}: ({"X" if values[key] else " "})" for key in keys
57+
]
58+
bool_values = [values[key] for key in keys]
59+
60+
selected_idx = 0
61+
62+
while True:
63+
printMenu(stdscr, selected_idx, options)
64+
65+
key = stdscr.getch()
66+
67+
if key == curses.KEY_UP and selected_idx > 0:
68+
selected_idx -= 1
69+
elif key == curses.KEY_DOWN and selected_idx < len(options) - 1:
70+
selected_idx += 1
71+
elif key in (curses.KEY_ENTER, ord("\n"), 13):
72+
bool_values[selected_idx] = not bool_values[selected_idx]
73+
options[selected_idx] = (
74+
f"{CONFIG_DESCRIPTIONS[keys[selected_idx]]}: ({"X" if bool_values[selected_idx] else " "})"
75+
)
76+
elif key in (27, ord("q")): # Escape, q
77+
break
78+
79+
return {key: value for key, value in zip(keys, bool_values)}
80+
81+
82+
def saveConfig(values, configfile=CONFIGFILE_DEFAULT):
83+
with open(configfile, "w") as f:
84+
json.dump(values, f)
85+
86+
87+
def updateConfig(configfile=CONFIGFILE_DEFAULT):
88+
values = getConfig(configfile)
89+
90+
values = curses.wrapper(cursesMenu, values)
91+
saveConfig(values, configfile)
92+
return values
93+
94+
95+
def getConfig(configfile=CONFIGFILE_DEFAULT, update=False):
96+
values = CONFIG_DEFAULTS
97+
98+
if path.exists(configfile):
99+
with open(configfile, "r") as f:
100+
config = json.load(f)
101+
for key, value in config.items():
102+
if key in CONFIG_DEFAULTS:
103+
values[key] = value
104+
elif update == True:
105+
values = updateConfig(configfile)
106+
107+
return values
108+
109+
110+
def main():
111+
if len(argv) < 2:
112+
print(f"{argv[0]} Usage: python3 {argv[0]} asset_config.json")
113+
exit(1)
114+
115+
updateConfig(argv[1])
116+
117+
118+
if __name__ == "__main__":
119+
main()

tools/extract_game_assets.py

+17-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import libyaz0
66
import libstage
77
import libbti
8+
import assets_config
89

910
"""
1011
Extracts the game assets and stores them in the game folder
@@ -139,20 +140,24 @@ def writeFolder(parsedFstBin, i):
139140
".arc": {
140141
"function": libarc.extract_to_directory,
141142
"exceptions": ["archive/dat/speakerse.arc"],
143+
"config_key": "extract_arc"
142144
},
143145
".dzs": {
144-
"function": libstage.extract_to_json
146+
"function": libstage.extract_to_json,
147+
"config_key": "convert_stages"
145148
},
146149
".dzr": {
147-
"function": libstage.extract_to_json
150+
"function": libstage.extract_to_json,
151+
"config_key": "convert_stages"
148152
},
149153
".bti": {
150-
"function": libbti.bti_to_png
154+
"function": libbti.bti_to_png,
155+
"config_key": "convert_textures"
151156
}
152157
}
153158

154159
def writeFile(name, data):
155-
if data[0:4] == bytes("Yaz0", "ascii"):
160+
if data[0:4] == bytes("Yaz0", "ascii") and config["decompress_assets"]:
156161
splitName = os.path.splitext(name)
157162
name = splitName[0] + ".c" + splitName[1]
158163
data = libyaz0.decompress(data)
@@ -162,9 +167,12 @@ def writeFile(name, data):
162167
ext = splitName[1]
163168
if ext in convertDefinitions:
164169
extractDef = convertDefinitions[ext]
165-
if "exceptions" in extractDef and str(name) in extractDef["exceptions"]:
170+
if ("exceptions" in extractDef and str(name) in extractDef["exceptions"]) or ("config_key" in extractDef and config[extractDef["config_key"]] == False):
166171
extractDef = None
167172

173+
if config["decompress_assets"] == None:
174+
extractDef = None # If assets aren't being decompressed, just write the raw file
175+
168176
if extractDef == None:
169177
file = open(name, "wb")
170178
file.write(data)
@@ -237,15 +245,16 @@ def getDolInfo(disc):
237245

238246
return dolOffset, dolSize
239247

240-
241-
def extract(isoPath: Path, gamePath: Path, yaz0Encoder):
248+
def extract(isoPath: Path, gamePath: Path, yaz0Encoder: str, config_file: str):
242249
if yaz0Encoder == "oead":
243250
try:
244251
from oead import yaz0
245252
global yaz0DecompressFunction
246253
yaz0DecompressFunction = yaz0.decompress
247254
except:
248255
print("Extract: oead isn't installed, falling back to native yaz0")
256+
global config
257+
config = assets_config.getConfig(config_file,update=True)
249258
isoPath = isoPath.absolute()
250259
cwd = os.getcwd()
251260
os.chdir(gamePath)
@@ -293,7 +302,7 @@ def extract(isoPath: Path, gamePath: Path, yaz0Encoder):
293302

294303

295304
def main():
296-
extract(Path(sys.argv[1]), Path(sys.argv[2]), "native")
305+
extract(Path(sys.argv[1]), Path(sys.argv[2]), sys.argv[3], sys.argv[4])
297306

298307

299308
if __name__ == "__main__":

tools/libast/__init__.py

-1
This file was deleted.

0 commit comments

Comments
 (0)