-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
83 lines (69 loc) · 3.33 KB
/
main.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
import argparse
import os
import shutil
import subprocess
import sys
SAVE_TOOL = 'Fire.Emblem.Save.Tool.exe'
SEARCH_STR = b'\xAD\x55\x0A\x19\x01'
SEARCH_STR_LEN = len(SEARCH_STR)
SPOTPASS_DATA = (b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
b'\x0A\x10\xDE\x34\x01\xFF\x0F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
b'\x00\x00\x00\x00\x00\x04\xD0\x46\xA5\x01\xFF\xFF\x3F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0C\xFB\xFC\x41\x01\x3F\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\xC0\x60\x65\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'
b'\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0A\x10\xDE\x34\x01\xFF\x0F')
SPOTPASS_DATA_LEN = len(SPOTPASS_DATA)
def find_insert_pos(contents):
# Need to find the forth instance of the search string
pos = contents.find(SEARCH_STR)
pos = contents.find(SEARCH_STR, pos + SEARCH_STR_LEN)
pos = contents.find(SEARCH_STR, pos + SEARCH_STR_LEN)
pos = contents.find(SEARCH_STR, pos + SEARCH_STR_LEN)
return pos + SEARCH_STR_LEN
def add_spotpass_data(filepath):
print(f'Backing up {filepath} to {filepath}.bak')
shutil.copy(filepath, f'{filepath}.bak')
print(f'Decompressing {filepath}')
decompress_process = subprocess.Popen(f'{SAVE_TOOL} {filepath}', stdout=subprocess.PIPE)
decompress_process.wait()
decompressed_path = f'{filepath}_dec'
print(f'Modifying {decompressed_path}')
with open(decompressed_path, 'rb') as decompressed_file:
contents = decompressed_file.read()
insert_pos = find_insert_pos(contents)
new_contents = contents[:insert_pos] + SPOTPASS_DATA + contents[insert_pos + SPOTPASS_DATA_LEN:]
print(f'Overwriting {decompressed_path}')
with open(decompressed_path, 'wb') as save_file:
save_file.write(new_contents)
print(f'Recompressing {decompressed_path}')
recompress_process = subprocess.Popen(f'{SAVE_TOOL} {decompressed_path}', stdout=subprocess.PIPE)
recompress_process.wait()
os.remove(decompressed_path)
print(f'Save written to {filepath}')
def main():
parser = argparse.ArgumentParser(description='Fire Emblem Awakening SpotPass Unlocker')
parser.add_argument('saves', metavar='save', type=str, nargs='+', help='Path to save file(s)')
args = parser.parse_args()
# Check if PyInstaller executable to know where to check for SAVE_TOOL
is_executable = getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS')
if is_executable:
working_dir = os.getcwd()
executable_dir = os.path.split(sys.executable)[0]
if working_dir != executable_dir:
os.chdir(executable_dir)
if not os.path.exists(SAVE_TOOL):
print(f'Please ensure {SAVE_TOOL} is in this directory')
if is_executable:
input('Press <Enter> to close')
sys.exit(1)
for save in args.saves:
if not os.path.exists(save):
print(f'Couldn\'t find {save}')
if is_executable:
input('Press <Enter> to close')
sys.exit(1)
else:
add_spotpass_data(save)
print('---')
if __name__ == '__main__':
main()