作为一个又菜又爱玩的音游手残玩家,ap 一个曲子总是一个遥不可及的梦想,每天对着 1good 1miss 等等发呆,这样下去也不是办法,于是想调整一下判定,使得某梦想手游能够打到 phigros 的手感,提高一下游戏体验,满足一下联机 ap 的虚荣心。
另外,这是刚开始接触逆向的菜鸡的第一次发帖,肯定会有很多疏漏与不合适的地方,希望各位大大能指点指点。
对于音游来说,过度修改会丧失游戏的乐趣,因此并不是很建议大改,折中方案在文末有所提及。
首先拆一下包,发现是 unity
游戏的 il2cpp
方式,看一下 libil2cpp.so
发现没有加密,在 assets\bin\Data\Managed\Metadata
中取出 global-metadata.dat
尝试用 il2cppdumper 直接 dump 下来
比较意外,没有出什么岔子。拿到了 dump.cs
与 script.json
,那接下来就好办了。
搜索关键词 Perfect
,分析关联项,得到 Note
的判定信息。
那么对于判定函数来说,返回值应该是一种 NoteResultType
的类型。搜索具有相关返回值的函数,得到:
用 ida 打开 libil2cpp.so ,执行脚本导入函数信息。按 G 跳转到 0xCEA5E4,得到:
那么 v5 所存的应该就是判定结果,根据前面的 NoteResultType
枚举类型,一般思路是改为 return 4
,但是在音游里这样改,反而会出现一个降低游戏体验的问题。
在此游戏中,由于 public const NoteResultType None = -1
的设定,你在距离待判定 Note
具有很长一段距离时,如果继续返回 Perfect(4)
,那么在此 Note
之前的 Note
都会被 miss 掉。
那么我们只需要将 0x0CEA66C
到 0x0CEA69C
处的 MOV R1, #X
改为 MOV R1, #4
即可。
用 AndroidKiller
重新打包,进入游戏后体验直线上升。但还存在一些小问题,如下。
在游戏过程中,普通 Note 碰到都是 perfect,但是绿条的起点经常爆 Great,这让强迫症的我有些无法忍受,重新分析 dump.cs,查找有关 slideNote
的信息,终于功夫不负有心人,在 SlideNoteManager
找到了对应的判定函数。
ida 跳过去看了一下,是个极其复杂的函数(我改了些变量名以便分析)
同样的,如果对上述函数直接返回 Perfect(4)
,会出现同上文提到的同样的尴尬局面,滑条会提前判定,体验很难受,因此我们需要对这个函数进行分析。
阅读完代码后,我们发现,该函数的前半部分有对绿条是否结束进行判定,这个是不应该修改的,此时 NoteResult 为 -1,应该是标志着一个滑条的结束。
之后的代码猜测是对手指是否在滑条处的一个判定,结果保存在 NoteResult
中,这也是我们需要修改的地方。
转到汇编,这里 R6 保存了 NoteResult。
那么很显然,我们只需要把这条语句改为一般的赋值即可
将 0C6096E5 改为 0460A0E3 后,可以看到修改成功。
打包后进入游戏,喝!大功告成!(虽然手残还是手残,26 级以上还是按不完所有的 Note 呜呜呜)
(为了游戏体验,可以适当的更改难度,比如只将前面的 3 改成 4,这样的话,只有 Great 会变成 Perfect,good bad 依旧,相当于永久判卡)
/
/
Namespace:
public enum NoteResultType
/
/
TypeDefIndex:
7514
{
/
/
Fields
public
int
value__;
/
/
0x0
public const NoteResultType
None
=
-
1
;
public const NoteResultType Miss
=
0
;
public const NoteResultType Bad
=
1
;
public const NoteResultType Good
=
2
;
public const NoteResultType Great
=
3
;
public const NoteResultType Perfect
=
4
;
}
/
/
Namespace:
public enum NoteResultType
/
/
TypeDefIndex:
7514
{
/
/
Fields
public
int
value__;
/
/
0x0
public const NoteResultType
None
=
-
1
;
public const NoteResultType Miss
=
0
;
public const NoteResultType Bad
=
1
;
public const NoteResultType Good
=
2
;
public const NoteResultType Great
=
3
;
public const NoteResultType Perfect
=
4
;
}
/
/
RVA:
0xCEA5E4
Offset:
0xCEA5E4
VA:
0xCEA5E4
public static NoteResultType GetResult(
float
diffSecond,
int
sweetFrame
=
0
) { }
/
/
RVA:
0xCEA5E4
Offset:
0xCEA5E4
VA:
0xCEA5E4
public static NoteResultType GetResult(
float
diffSecond,
int
sweetFrame
=
0
) { }
/
/
RVA:
0xD14E10
Offset:
0xD14E10
VA:
0xD14E10
public NoteResultType Judge(
float
posY, out
int
outCursor) { }
/
/
RVA:
0xD14E10
Offset:
0xD14E10
VA:
0xD14E10
public NoteResultType Judge(
float
posY, out
int
outCursor) { }
int
__fastcall SlideNoteManager__Judge(
int
a1,
float
posY,
int
*
outCursor)
{
int32_t bpm;
/
/
r0
System_Collections_Generic_Dictionary_int__TerrainUtility_TerrainMap__o
*
music_map;
/
/
r6
float
v8;
/
/
s16
UnityEngine_Experimental_TerrainAPI_TerrainUtility_TerrainMap_o
*
v9;
/
/
r5
int32_t init_cont;
/
/
r6
int
v11;
/
/
r9
int
counter;
/
/
r7
System_TypeSpec_o
*
v13;
/
/
r0
float
v14;
/
/
s18
System_TypeSpec_o
*
v15;
/
/
r0
float
v16;
/
/
s0
__int64 v17;
/
/
r0
int32_t v18;
/
/
r0
System_TypeSpec_o
*
v19;
/
/
r0
float
v20;
/
/
s18
int32_t v21;
/
/
r0
System_TypeSpec_o
*
v22;
/
/
r0
int
NoteResult;
/
/
r6
System_TypeSpec_o
*
v24;
/
/
r6
System_TypeSpec_o
*
v25;
/
/
r0
int32_t v26;
/
/
r0
int32_t v27;
/
/
kr04_4
int
v28;
/
/
r0
if
(!byte_2ECE7FD)
{
sub_659480(
35551
);
byte_2ECE7FD
=
1
;
}
if
(!
*
(_DWORD
*
)(a1
+
16
))
sub_684BE8(
0
);
bpm
=
NoteManager__get_CurrentBpm(
*
(_DWORD
*
)(a1
+
16
),
0
);
music_map
=
*
(System_Collections_Generic_Dictionary_int__TerrainUtility_TerrainMap__o
*
*
)(a1
+
24
);
if
(!music_map)
sub_684BE8(
0
);
v8
=
posY;
v9
=
System_Collections_Generic_Dictionary_int__TerrainUtility_TerrainMap___get_Item(
music_map,
bpm,
(const MethodInfo_1431
*
)Method_System_Collections_Generic_Dictionary_int__List_SlideNoteManager_SlideResultData___get_Item__);
init_cont
=
1
;
v11
=
-
2
;
while
(
1
)
{
counter
=
init_cont
-
1
;
if
(!v9)
sub_684BE8(
0
);
if
(counter >
=
System_Collections_Generic_List________get_Count(
(System_Collections_Generic_List_______o
*
)v9,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Count__)
/
2
)
{
NoteResult
=
-
1
;
counter
=
0
;
goto LABEL_34;
}
v13
=
System_Collections_Generic_List_TypeSpec___get_Item(
(System_Collections_Generic_List_TypeSpec__o
*
)v9,
init_cont
-
1
,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Item__);
if
(!v13)
sub_684BE8(
0
);
v14
=
*
(
float
*
)&v13
-
>fields.name;
v15
=
System_Collections_Generic_List_TypeSpec___get_Item(
(System_Collections_Generic_List_TypeSpec__o
*
)v9,
init_cont,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Item__);
if
(!v15)
sub_684BE8(
0
);
v16
=
*
(
float
*
)&v15
-
>fields.name;
v17
=
0LL
;
if
(v14 < v8)
LODWORD(v17)
=
1
;
if
(v16 >
=
v8)
HIDWORD(v17)
=
1
;
if
(!v17)
break
;
v18
=
System_Collections_Generic_List________get_Count(
(System_Collections_Generic_List_______o
*
)v9,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Count__);
v19
=
System_Collections_Generic_List_TypeSpec___get_Item(
(System_Collections_Generic_List_TypeSpec__o
*
)v9,
v18
+
v11
+
1
,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Item__);
if
(!v19)
sub_684BE8(
0
);
v20
=
*
(
float
*
)&v19
-
>fields.name;
v21
=
System_Collections_Generic_List________get_Count(
(System_Collections_Generic_List_______o
*
)v9,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Count__);
v22
=
System_Collections_Generic_List_TypeSpec___get_Item(
(System_Collections_Generic_List_TypeSpec__o
*
)v9,
v21
+
v11,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Item__);
if
(!v22)
sub_684BE8(
0
);
-
-
v11;
+
+
init_cont;
if
(v20 <
=
v8 &&
*
(
float
*
)&v22
-
>fields.name > v8)
{
counter
=
System_Collections_Generic_List________get_Count(
(System_Collections_Generic_List_______o
*
)v9,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Count__)
+
v11
+
2
;
v25
=
System_Collections_Generic_List_TypeSpec___get_Item(
(System_Collections_Generic_List_TypeSpec__o
*
)v9,
counter,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Item__);
v24
=
v25;
if
(!v25)
sub_684BE8(
0
);
goto LABEL_33;
}
}
v24
=
System_Collections_Generic_List_TypeSpec___get_Item(
(System_Collections_Generic_List_TypeSpec__o
*
)v9,
init_cont
-
1
,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Item__);
if
(!v24)
sub_684BE8(
0
);
LABEL_33:
NoteResult
=
(
int
)v24
-
>fields.assembly_name;
LABEL_34:
v26
=
System_Collections_Generic_List________get_Count(
(System_Collections_Generic_List_______o
*
)v9,
(const MethodInfo_1470
*
)Method_System_Collections_Generic_List_SlideNoteManager_SlideResultData__get_Count__);
if
(NoteResult
=
=
-
1
)
{
v28
=
0
;
}
else
{
v27
=
v26;
v28
=
v26
/
2
-
counter;
if
(v27
/
2
<
=
counter)
-
-
v28;
}
*
outCursor
=
v28;
return
NoteResult;
}
int
__fastcall SlideNoteManager__Judge(
int
a1,
float
posY,
int
*
outCursor)
{
int32_t bpm;
/
/
r0
System_Collections_Generic_Dictionary_int__TerrainUtility_TerrainMap__o
*
music_map;
/
/
r6
float
v8;
/
/
s16
UnityEngine_Experimental_TerrainAPI_TerrainUtility_TerrainMap_o
*
v9;
/
/
r5
int32_t init_cont;
/
/
r6
int
v11;
/
/
r9
int
counter;
/
/
r7
System_TypeSpec_o
*
v13;
/
/
r0
float
v14;
/
/
s18
System_TypeSpec_o
*
v15;
/
/
r0
float
v16;
/
/
s0
__int64 v17;
/
/
r0
int32_t v18;
/
/
r0
System_TypeSpec_o
*
v19;
/
/
r0
float
v20;
/
/
s18
int32_t v21;
/
/
r0
System_TypeSpec_o
*
v22;
/
/
r0
int
NoteResult;
/
/
r6
System_TypeSpec_o
*
v24;
/
/
r6
System_TypeSpec_o
*
v25;
/
/
r0
int32_t v26;
/
/
r0
int32_t v27;
/
/
kr04_4
int
v28;
/
/
r0
if
(!byte_2ECE7FD)
{
sub_659480(
35551
);
byte_2ECE7FD
=
1
;
}
if
(!
*
(_DWORD
*
)(a1
+
16
))
sub_684BE8(
0
);
bpm
=
NoteManager__get_CurrentBpm(
*
(_DWORD
*
)(a1
+
16
),
0
);
music_map
=
*
(System_Collections_Generic_Dictionary_int__TerrainUtility_TerrainMap__o
*
*
)(a1
+
24
);
if
(!music_map)
sub_684BE8(
0
);
v8
=
posY;
v9
=
System_Collections_Generic_Dictionary_int__TerrainUtility_TerrainMap___get_Item(
music_map,
bpm,
(const MethodInfo_1431
*
)Method_System_Collections_Generic_Dictionary_int__List_SlideNoteManager_SlideResultData___get_Item__);
init_cont
=
1
;
v11
=
-
2
;
while
(
1
)
{
counter
=
init_cont
-
1
;
if
(!v9)
sub_684BE8(
0
);
if
(counter >
=
System_Collections_Generic_List________get_Count(
(System_Collections_Generic_List_______o
*
)v9,
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)