forked from Raytwo/ARCropolis
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfixes.rs
239 lines (208 loc) · 9.96 KB
/
fixes.rs
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
use crate::offsets;
use skyline::{from_offset, hook, hooks::InlineCtx, install_hooks, patching::{Patch, BranchBuilder}};
// Patches to get Inkling c08+ working
fn install_inkling_patches() {
#[skyline::hook(offset = offsets::clear_ink_patch(), inline)]
unsafe fn clear_ink_patch(ctx: &mut InlineCtx) {
let res = (*ctx.registers[24].w.as_ref() as u32) % 8;
*ctx.registers[24].w.as_mut() = res;
}
// Inkling Patches here nop some branches so it can work with more than c08+
Patch::in_text(offsets::inkling_patch())
.nop()
.expect("Failed to patch inkling 1 cmp");
Patch::in_text(offsets::inkling_patch() + 4)
.nop()
.expect("Failed to patch inkling 1 b.cs");
BranchBuilder::branch()
.branch_offset(offsets::inkling_c10plus())
.branch_to_offset(offsets::inkling_c10plus() + 0x38)
.replace();
install_hooks!(clear_ink_patch);
}
/*
Patches for:
- Aegis c08+ working
- Some issues reported with some other characters
- Crashes in Classic Mode with colors greater than c08+
- Crashes in Tourney Mode when selecting a c08+ color
*/
fn install_added_color_patches() {
// Install inkling patches here since they're related to added color issues
install_inkling_patches();
#[hook(offset = offsets::set_global_color_for_classic_mode(), inline)]
pub unsafe fn set_global_color_for_classic_mode(ctx: &mut InlineCtx) {
*(ctx.registers[9].w.as_mut()) = *(ctx.registers[9].w.as_ref()) % 8;
}
skyline::install_hook!(set_global_color_for_classic_mode);
/*
Offsets and Instructions that need to be patched in array so we don't repeat
same code with minor changes over and over.
Format: (offset, instruction)
*/
// OFFSETS ARE CURRENTLY HARDCODED TO VERSION 13.0.1
static ADDED_COLOR_PATCHES: &[(usize, u32)] = &[
(0x18355dc, 0xF104027F), // cmp x19, #256 (Issue related to Aegis)
(0x183529c, 0xF104027F), // cmp x19, #256 (Issue related to Aegis)
(0x1835608, 0xF104011F), // cmp x8, #256 (Issue related to Aegis)
(0x18359d8, 0xF10402FF), // cmp x23, #256 (Issue related to Aegis)
(0x1835e6c, 0xF104011F), // cmp x8, #256 (Issue related to Aegis)
(0x18365c4, 0xF104027F), // cmp x19, #256 (Issue related to Aegis)
(0x18368e0, 0xF104013F), // cmp x9, #256 (Issue related to Aegis)
(0x1a1cdd0, 0xF104011F), // cmp x8, #256 (Issue related to Aegis)
(0x1a1ce14, 0xF104011F), // cmp x8, #256 (Issue related to Aegis)
(0x14dee20, 0x7104013F), // cmp w9, #256 (Issue related to Terry)
(0x14e1ef0, 0x710402FF), // cmp w23, #256 (Issue related to Terry)
(0x14e207c, 0x7104011F), // cmp w8, #256 (Issue related to Terry)
(0x1a56064, 0x52800020), // mov w0, #1 (Issue related to Tourney Mode Crash)
(0x1a56194, 0xF104011F), // cmp x8, #256 (Issue related to Tourney Mode Crash)
(0x1a55a54, 0x7104015F), // cmp w10, #256 (Issue related to Tourney Mode Crash)
(0x1a55aec, 0x7104001F), // cmp w0, #256 (Issue related to Tourney Mode Crash)
(0x1a55b18, 0xF104001F), // cmp x0, #256 (Issue related to Tourney Mode Crash)
(0x1a55a80, 0xF104001F), // cmp x0, #256 (Issue related to Tourney Mode Crash)
(0x1a55ab4, 0x7104017F), // cmp w11, #256 (Issue related to Tourney Mode Crash)
];
for entry in ADDED_COLOR_PATCHES {
let (offset, value) = entry;
Patch::in_text(*offset)
.data(*value)
.expect(&format!("Failed to run Aegis Patch! Offset: {:#x} - Data: {:#x}", offset, value));
}
}
fn install_lazy_loading_patches() {
#[repr(C)]
struct ParametersCache {
pub vtable: *const u64,
pub databases: *const ParameterDatabaseTable,
}
#[repr(C)]
struct ParameterDatabaseTable {
pub unk1: [u8; 360],
pub character: *const u64, // ParameterDatabase
}
impl ParametersCache {
pub unsafe fn get_chara_db(&self) -> *const u64 {
(*(self.databases)).character
}
}
// Cache of variables we reuse later for loading UI + getting the character database
static mut PARAM_1: u64 = 0x0;
static mut PARAM_4: u64 = 0x0;
// This function is what's responsible for loading the UI File.
#[from_offset(offsets::load_ui_file())]
pub fn load_ui_file(param_1: *const u64, ui_path_hash: *const u64, unk1: u64, unk2: u64);
/*
This function is the function that takes the ui_chara_hash, color_slot, and
the type of UI to load and converts them to a hash40 that represents the path
it needs to load
*/
#[from_offset(offsets::get_ui_chara_path_from_hash())]
pub fn get_ui_chara_path_from_hash_color_and_type(ui_chara_hash: u64, color_slot: u32, ui_type: u32) -> u64;
// This takes the character_database and the ui_chara_hash to get the color_num
#[from_offset(0x3262110)]
pub fn get_color_num_from_hash(character_database: u64, ui_chara_hash: u64) -> u8;
// This takes the character_database and the ui_chara_hash to get the chara's respective echo (for loading it at the same time)
#[from_offset(offsets::get_echo_from_hash())]
pub fn get_ui_chara_echo(character_database: u64, ui_chara_hash: u64) -> u64;
#[hook(offset = offsets::load_chara_1_for_all_costumes(), inline)]
pub unsafe fn original_load_chara_1_ui_for_all_colors(ctx: &mut InlineCtx) {
// Save the first and fourth parameter for reference when we load the file ourselves
PARAM_1 = *ctx.registers[0].x.as_ref();
PARAM_4 = *ctx.registers[3].x.as_ref();
}
#[hook(offset = offsets::load_stock_icon_for_portrait_menu(), inline)]
pub unsafe fn load_stock_icon_for_portrait_menu(ctx: &mut InlineCtx) {
/*
If both of these params are valid, then most likely we're in the
CharaSelectMenu, which means we should be pretty safe loading the CSPs
*/
if PARAM_1 != 0 && PARAM_4 != 0 {
let ui_chara_hash = *ctx.registers[1].x.as_ref();
let color = *ctx.registers[2].w.as_ref();
let path = get_ui_chara_path_from_hash_color_and_type(ui_chara_hash, color, 1);
load_ui_file(PARAM_1 as *const u64, &path, 0, PARAM_4);
}
}
pub unsafe fn load_chara_1_for_ui_chara_hash_and_num(ui_chara_hash: u64, color: u32) {
/*
If we have the first and fourth param in our cache, then we're in the
character select screen and can load the files manually
*/
if PARAM_1 != 0 && PARAM_4 != 0 {
// Get the color_num for smooth loading between different CSPs
// Get the character database for the color num function
let max_color: u32 = get_color_num_from_hash(
(*(*(offsets::offset_to_addr(offsets::parameters_cache()) as *const u64) as *const ParametersCache)).get_chara_db() as u64,
ui_chara_hash,
) as u32;
let path = get_ui_chara_path_from_hash_color_and_type(ui_chara_hash, color, 1);
load_ui_file(PARAM_1 as *const u64, &path, 0, PARAM_4);
/*
Set next color to 0 if it's going to end up past the max, else just be
the current color + 1
*/
let next_color = {
let mut res = color + 1;
if res >= max_color {
res = 0;
}
res
};
/*
Set the previous color to max_color - 1 (so 8 - 1 = 7) if it's gonna be
the u32::MAX (aka underflowed to max), else just be the current color - 1
*/
let prev_color = {
let mut res = color - 1;
if res == u32::MAX {
res = max_color - 1;
}
res
};
// Load both next and previous color paths
let next_color_path = get_ui_chara_path_from_hash_color_and_type(ui_chara_hash, next_color, 1);
load_ui_file(PARAM_1 as *const u64, &next_color_path, 0, PARAM_4);
let prev_color_path = get_ui_chara_path_from_hash_color_and_type(ui_chara_hash, prev_color, 1);
load_ui_file(PARAM_1 as *const u64, &prev_color_path, 0, PARAM_4);
}
}
#[hook(offset = offsets::css_set_selected_character_ui())]
pub unsafe fn css_set_selected_character_ui(param_1: *const u64, chara_hash_1: u64, chara_hash_2: u64, color: u32, unk1: u32, unk2: u32) {
let echo = get_ui_chara_echo(
(*(*(offsets::offset_to_addr(offsets::parameters_cache()) as *const u64) as *const ParametersCache)).get_chara_db() as u64,
chara_hash_1,
);
load_chara_1_for_ui_chara_hash_and_num(chara_hash_1, color);
load_chara_1_for_ui_chara_hash_and_num(echo, color);
call_original!(param_1, chara_hash_1, chara_hash_2, color, unk1, unk2);
}
#[hook(offset = offsets::chara_select_scene_destructor())]
pub unsafe fn chara_select_scene_destructor(param_1: u64) {
// Clear the first and fourth param in our cache so we don't load outside of the chara select
PARAM_1 = 0;
PARAM_4 = 0;
call_original!(param_1);
}
// Prevent the game from loading all chara_1 colors at once for all characters
Patch::in_text(offsets::load_chara_1_for_all_costumes())
.nop()
.expect("Failed to patch chara_1 load");
// Install the hooks for everything necessary to properly load the chara_1s
install_hooks!(
original_load_chara_1_ui_for_all_colors,
css_set_selected_character_ui,
load_stock_icon_for_portrait_menu,
chara_select_scene_destructor
);
}
// Patch to allow running uncompiled lua scripts
fn install_lua_magic_patch() {
Patch::in_text(offsets::lua_magic_check())
.nop()
.expect("Failed to patch lua magic check cbnz");
}
pub fn install() {
install_added_color_patches();
install_lazy_loading_patches();
install_lua_magic_patch();
}