forked from SnowWolfRoy/HackerOoT
-
Notifications
You must be signed in to change notification settings - Fork 0
/
install_mod_assets.py
146 lines (118 loc) · 5.36 KB
/
install_mod_assets.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
146
#!/usr/bin/env python3
"""
copies mod_assets into assets. assumes file is located at project root
"""
import os
import shutil
import time
import glob
import typing as T
from pathlib import Path
def log(msg: str):
print(f"[{__file__}]: {msg}")
def remove_stale_assets(root: str, copied_files: T.List[str], last_cache_time: int):
modified_times: T.Dict[str, int] = { file: int(os.path.getmtime(file)) for file in copied_files }
stale = [file for file, ts in modified_times.items() if ts > last_cache_time]
if len(stale) == 0:
log(f"No stale assets since last build")
return
removed_count = 0
for file in stale:
rel = os.path.relpath(file, root)
pattern = os.path.join(root, "build", os.path.dirname(rel), "*")
for match in glob.glob(pattern, recursive=True):
os.remove(match)
removed_count += 1
log(f"Removed {removed_count} stale asset(s) from {root}")
def copy_all(root: str) -> T.List[str]:
src_root = os.path.join(root, "mod_assets")
dst_root = os.path.join(root, "assets")
copied_files: T.List[str] = []
for src_dir, _, file_names in os.walk(src_root):
dst_dir = src_dir.replace(src_root, dst_root, 1)
Path(dst_dir).mkdir(parents=True, exist_ok=True)
for file_name in file_names:
src_file = os.path.join(src_dir, file_name)
dst_file = os.path.join(dst_dir, file_name)
shutil.copy2(src_file, dst_file)
copied_files.append(dst_file)
build_anim_files(dst_dir, file_names, copied_files)
log(f"Copied {len(copied_files)} file(s) from mod_assets")
return copied_files
def build_anim_files(dst_dir: str, file_names: T.List[str], copied_files: T.List[str]):
# We need to build 3 files:
# - [AllAnimData.c]: One that includes all the animation data definitions (*AnimData.c)
# - [AllAnim.h]: One that includes all the animation headers (*Anim.h)
# - [AllAnim.c]: One that includes all the animation definitions (*Anim.c)
ALL_ANIM_DATA_C: str = "AllAnimData.c"
ALL_ANIM_H: str = "AllAnim.h"
ALL_ANIM_C: str = "AllAnim.c"
anim_data_defns: T.List[str] = []
anim_headers: T.List[str] = []
anim_defns: T.List[str] = []
for file_name in file_names:
if file_name.endswith("AnimData.c") and file_name != ALL_ANIM_DATA_C:
anim_data_defns.append(file_name)
if file_name.endswith("Anim.h") and file_name != ALL_ANIM_H:
anim_headers.append(file_name)
if file_name.endswith("Anim.c") and file_name != ALL_ANIM_C:
anim_defns.append(file_name)
if anim_data_defns and anim_headers and anim_defns:
build_anim_file(dst_dir, ALL_ANIM_DATA_C, sorted(anim_data_defns), copied_files)
build_anim_file(dst_dir, ALL_ANIM_H, sorted(anim_headers), copied_files)
build_anim_file(dst_dir, ALL_ANIM_C, sorted(anim_defns), copied_files)
log(f"Created 'AllAnim' files in {dst_dir}.")
def build_anim_file(dst_dir: str, dst_file_name: str, file_names: T.List[str], copied_files: T.List[str]):
dst_file: str = os.path.join(dst_dir, dst_file_name)
dst_timestamps: T.List[int] = []
with open(dst_file, "w") as f:
f.write("// This file was generated by install_mod_assets.py.\n")
for file_name in file_names:
f.write(f'#include "{file_name}"\n')
dst_timestamps.append(int(os.path.getmtime(os.path.join(dst_dir, file_name))))
os.utime(dst_file, (max(dst_timestamps), max(dst_timestamps)))
copied_files.append(dst_file)
def remove_stale_actors(root: str, last_cache_time: int):
actors_src_dir = os.path.join(root, "src", "overlays", "actors")
actors_build_dir = os.path.join(root, "build", "src", "overlays", "actors")
stale_directories = set()
for actor_dir, _, actor_files in os.walk(actors_src_dir):
for actor_file in actor_files:
modified_time = os.path.getmtime(os.path.join(actor_dir, actor_file))
if modified_time > last_cache_time:
stale_directories.add(actor_dir)
removed = 0
for actor_dir in stale_directories:
overlay_name = os.path.split(actor_dir)[1]
build_path = os.path.join(actors_build_dir, overlay_name)
if os.path.exists(build_path):
log(f"Removing stale actor {overlay_name}")
shutil.rmtree(build_path)
removed += 1
if removed == 0:
log("No stale actors since last build")
else:
log(f"Removed {removed} total stale actors")
def update_cache_time(root: str) -> int:
build_dir = os.path.join(root, "build")
if not os.path.exists(build_dir):
os.mkdir(build_dir)
cache_file = os.path.join(build_dir, ".mod_assets_cache")
if os.path.exists(cache_file):
with open(cache_file) as fd:
last_time = int(fd.read().strip())
else:
last_time = 0
with open(cache_file, "w") as fd:
fd.write(f"{int(time.time())}")
log(f"Updated {cache_file}")
return last_time
def main():
root = os.path.dirname(os.path.realpath(__file__))
last_cache_time = update_cache_time(root)
copied_files = copy_all(root)
remove_stale_assets(root, copied_files, last_cache_time)
# check actor overlays for stale include dependencies i.e. "*.inc.c"
remove_stale_actors(root, last_cache_time)
if __name__ == "__main__":
main()