项目说明:和多插件项目结构类似
打包说明build.sh
debug {
//写死,测试使用
target0:com.iplay.gba
}
release{
}
intputGBA:gba插件项目的基础库包括:金手指
intputNDS:nds插件项目的基础库包括:金手指
ndsNDKLibrary:nds的native库,写好之后会打包成so,然后关闭掉
gbaNDKLibrary:nds的native库,写好之后会打包成so,然后关闭掉
frankpi-orange:插件ui界面
controller:悬浮摇杆按钮模块 单独写项目 EmuController
引用顺序 app->dep/xxx->inputGBA || inputNDS->frankpi-orange
操作内容:deps+properties
properties:看例子,
hash:表示rom的md5
Emulator=com.iplay.gba
Emulator0=90048
dep:包含各个插件的项目内容
assets/cheats.xml 配置文件说明:
重点:<!-- --->中内容
<?xml version='1.0' encoding='UTF-8' ?>
<cheats>
<!--nativeId是个位 1-8 是菜单栏的标志使用 1功能互斥、6是物品、7是nds金手指、8是火焰纹章预留 使用 2,3,4,5,-->
<cheat cheatCode="" cheatName="拓展模式" commodityId="" isSwitch="0" menuId="0" nativeId="2" />
<!--nativeId是两位数 9-299 是功能位 -->
<cheat cheatCode="02037274:0000" cheatName="不遇敌" commodityId="17" isSwitch="1" menuId="2"
nativeId="17" />
<!--nativeId 300-400 400-500 500-600 grideView 物品列表的-->
<cheat cheatCode="" cheatName="全收集" commodityId="" isSwitch="0" menuId="0" nativeId="3" />
<cheat cheatCode="" cheatName="全道具" commodityId="500" isSwitch="0" menuId="3" nativeId="500" />
</cheats>
<cheat />含义:
isSwitch="0" :按钮
1:开关
2:移速二倍,四倍 关
3:快捷键按钮(一般都不用)
4:快捷键开关(一般都不用)
5:拓展标签,二级标签
6:-+1
menuId:对应菜单cheat的nativeId
nativeId:唯一,不可重复,当isSwitch="0" 且menuId="0“,是一级菜单,nativeId就是菜单id
commodityId:唯一,不可重复,1级菜单的时候不用,二级菜单用的话,二级菜单子功能都不需要用。
u = "1" 直接解锁
isSupportSave = "1" 功能记忆保存
<cheat logic />含义:
configManager.xxxxx.xxxx.xxx.xx
configManager.getHashMapCodes().get(a1):获取金手指
configManager.cheatManager.parseCheatCode();
configManager.nativeProcessCheat(a1, a2, a3);
金手指EmuCheat EC 说明:
[速度]
ON=44E2C,60,EA
说明:0200442C 60;0200442D EA
[钱]
ON=44770,9F,86,1
说明:02044770 9F;02044771 86;02044772 01
vba GBA模拟器常用
02044770:9F
GameShark1 来自gameboid
2XXXXXXX YYYYYYYY 把 4 byte 数据 YYYYYYYY 写入到位址 XXXXXXX 上。
1XXXXXXX 0000YYYY 把 2 byte 数据 YYYY 写入到位址 XXXXXXX 上。
0XXXXXXX 000000YY 把 1 byte 数据 YY 写入到位址 XXXXXXX 上。
case 0x3:
{
u32 num_addresses = address & 0xFFFF;
u32 address1, address2;
u32 i2;
for(i2 = 0; i2 < num_addresses; i2++)
{
address1 = code_ptr[0];
address2 = code_ptr[1];
code_ptr += 2;
i++;
write_memory32(address1, value);
if(address2 != 0)
write_memory32(address2, value);
}
break;
}
Gameshark 来自GBA-Emulator-android
AF7B768C7 DB18B104或者AF7B768C7DB18B104 是加密过的gs码
解密算法
void cheatsDecryptGSACode(u32& address, u32& value, bool v3)
{
u32 rollingseed = 0xC6EF3720;
u32 seeds_v1[] = { 0x09F4FBBD, 0x9681884A, 0x352027E9, 0xF3DEE5A7 };
u32 seeds_v3[] = { 0x7AA9648F, 0x7FAE6994, 0xC0EFAAD5, 0x42712C57 };
u32 *seeds = v3 ? seeds_v3 : seeds_v1;
int bitsleft = 32;
while (bitsleft > 0) {
value -= ((((address << 4) + seeds[2]) ^ (address + rollingseed)) ^
((address >> 5) + seeds[3]));
address -= ((((value << 4) + seeds[0]) ^ (value + rollingseed)) ^
((value >> 5) + seeds[1]));
rollingseed -= 0x9E3779B9;
bitsleft--;
}
}
/**
* Gameshark code types:
*
* NNNNNNNN 001DC0DE - ID code for the game (game 4 character name) from ROM
* DEADFACE XXXXXXXX - changes decryption seeds
* 0AAAAAAA 000000YY - 8-bit constant write
* 1AAAAAAA 0000YYYY - 16-bit constant write
* 2AAAAAAA YYYYYYYY - 32-bit constant write
* 3AAAAAAA YYYYYYYY - ??
* 6AAAAAAA 0000YYYY - 16-bit ROM Patch (address >> 1)
* 6AAAAAAA 1000YYYY - 16-bit ROM Patch ? (address >> 1)
* 6AAAAAAA 2000YYYY - 16-bit ROM Patch ? (address >> 1)
* 8A1AAAAA 000000YY - 8-bit button write
* 8A2AAAAA 0000YYYY - 16-bit button write
* 8A3AAAAA YYYYYYYY - 32-bit button write
* 80F00000 0000YYYY - button slow motion
* DAAAAAAA 0000YYYY - if address contains 16-bit value enable next code
* FAAAAAAA 0000YYYY - Master code function
*/
CodeBreaker:8200510a0001 来自GBA-Emulator-android
/**
* CodeBreaker codes types:
*
* 0000AAAA 000Y - Game CRC (Y are flags: 8 - CRC, 2 - DI)
* 1AAAAAAA YYYY - Master Code function (store address at ((YYYY << 0x16)
* + 0x08000100))
* 2AAAAAAA YYYY - 16-bit or
* 3AAAAAAA YYYY - 8-bit constant write
* 4AAAAAAA YYYY - Slide code
* XXXXCCCC IIII (C is count and I is address increment, X is value incr.)
* 5AAAAAAA CCCC - Super code (Write bytes to address, CCCC is count)
* BBBBBBBB BBBB
* 6AAAAAAA YYYY - 16-bit and
* 7AAAAAAA YYYY - if address contains 16-bit value enable next code
* 8AAAAAAA YYYY - 16-bit constant write
* 9AAAAAAA YYYY - change decryption (when first code only?)
* AAAAAAAA YYYY - if address does not contain 16-bit value enable next code
* BAAAAAAA YYYY - if 16-bit < YYYY
* CAAAAAAA YYYY - if 16-bit > YYYY
* D0000020 YYYY - if button keys equal value enable next code
* EAAAAAAA YYYY - increase value stored in address
*/
Action Replay 金手指R4 nds主用来自github OpenEmu/DeSmuME-Core 版本1.54
D6000000 0XXXXXXX YYYYYYYY 把 4 byte 数据 YYYYYYYY 写入到位址 XXXXXXX 上。
D7000000 1XXXXXXX 0000YYYY 把 2 byte 数据 YYYY 写入到位址 XXXXXXX 上。
D8000000 2XXXXXXX 000000YY 把 1 byte 数据 YY 写入到位址 XXXXXXX 上。
DA000000 021121AE //控制血量
D7000000 021121AC
D2000000 00000000
021121AC:021121AE的值
D2000000 00000000
是结束符
94000130 FFFB0000
按住select键
D5000000 00000099 value
C0000000 0000004E size
D8000000 02107206 addr
D2000000 00000000
for(int i=0x02107206; i<=i+0x4E; i++){
i:00000099 BYTE
}
C0000000 00000003 size
020BB028 270F270F addr:value
120BB02C 0000270F addr:value
DC000000 00000148 offset
D2000000 00000000
for(int i=0x020BB028; i<=i+0x3*0x148; i=i+0x148){
i:270F270F INT
i+4:0000270F SHORT
}
void CHEATS::ARparser(CHEATS_LIST& list)
{
u8 type = 0;
u8 subtype = 0;
u32 hi = 0;
u32 lo = 0;
u32 addr = 0;
u32 val = 0;
// AR temporary vars & flags
u32 offset = 0;
u32 datareg = 0;
u32 loopcount = 0;
u32 counter = 0;
u32 if_flag = 0;
s32 loopbackline = 0;
u32 loop_flag = 0;
for (int i=0; i < list.num; i++)
{
type = list.code[i][0] >> 28;
subtype = (list.code[i][0] >> 24) & 0x0F;
hi = list.code[i][0] & 0x0FFFFFFF;
lo = list.code[i][1];
if (if_flag > 0)
{
if ((type == 0x0E)) i += ((lo + 7) / 8);
if ( (type == 0x0D) && (subtype == 0)) if_flag--; // ENDIF
if ( (type == 0x0D) && (subtype == 2)) // NEXT & Flush
{
if (loop_flag)
i = (loopbackline-1);
else
{
offset = 0;
datareg = 0;
loopcount = 0;
counter = 0;
if_flag = 0;
loop_flag = 0;
}
}
continue;
}
switch (type)
{
case 0x00:
{
if (hi==0)
{
//manual hook
}
else
if ((hi==0x0000AA99) && (lo==0)) // 0000AA99 00000000 parameter bytes 9..10 for above code (padded with 00s)
{
//parameter bytes 9..10 for above code (padded with 00s)
}
else // 0XXXXXXX YYYYYYYY word[XXXXXXX+offset] = YYYYYYYY
{
addr = hi + offset;
_MMU_write32<ARMCPU_ARM9,MMU_AT_DEBUG>(addr, lo);
}
}
break;
case 0x01: // 1XXXXXXX 0000YYYY half[XXXXXXX+offset] = YYYY
addr = hi + offset;
_MMU_write16<ARMCPU_ARM9,MMU_AT_DEBUG>(addr, lo);
break;
case 0x02: // 2XXXXXXX 000000YY byte[XXXXXXX+offset] = YY
addr = hi + offset;
_MMU_write08<ARMCPU_ARM9,MMU_AT_DEBUG>(addr, lo);
break;
case 0x03: // 3XXXXXXX YYYYYYYY IF YYYYYYYY > word[XXXXXXX] ;unsigned
if (hi == 0) hi = offset; // V1.54+
val = _MMU_read32<ARMCPU_ARM9,MMU_AT_DEBUG>(hi);
if ( lo > val )
{
if (if_flag > 0) if_flag--;
}
else
{
if_flag++;
}
break;
case 0x04: // 4XXXXXXX YYYYYYYY IF YYYYYYYY < word[XXXXXXX] ;unsigned
if ((hi == 0x04332211) && (lo == 88776655)) //44332211 88776655 parameter bytes 1..8 for above code (example)
{
break;
}
if (hi == 0) hi = offset; // V1.54+
val = _MMU_read32<ARMCPU_ARM9,MMU_AT_DEBUG>(hi);
if ( lo < val )
{
if (if_flag > 0) if_flag--;
}
else
{
if_flag++;
}
break;
case 0x05: // 5XXXXXXX YYYYYYYY IF YYYYYYYY = word[XXXXXXX]
if (hi == 0) hi = offset; // V1.54+
val = _MMU_read32<ARMCPU_ARM9,MMU_AT_DEBUG>(hi);
if ( lo == val )
{
if (if_flag > 0) if_flag--;
}
else
{
if_flag++;
}
break;
case 0x06: // 6XXXXXXX YYYYYYYY IF YYYYYYYY <> word[XXXXXXX]
if (hi == 0) hi = offset; // V1.54+
val = _MMU_read32<ARMCPU_ARM9,MMU_AT_DEBUG>(hi);
if ( lo != val )
{
if (if_flag > 0) if_flag--;
}
else
{
if_flag++;
}
break;
case 0x07: // 7XXXXXXX ZZZZYYYY IF YYYY > ((not ZZZZ) AND half[XXXXXXX])
if (hi == 0) hi = offset; // V1.54+
val = _MMU_read16<ARMCPU_ARM9,MMU_AT_DEBUG>(hi);
if ( (lo & 0xFFFF) > ( (~(lo >> 16)) & val) )
{
if (if_flag > 0) if_flag--;
}
else
{
if_flag++;
}
break;
case 0x08: // 8XXXXXXX ZZZZYYYY IF YYYY < ((not ZZZZ) AND half[XXXXXXX])
if (hi == 0) hi = offset; // V1.54+
val = _MMU_read16<ARMCPU_ARM9,MMU_AT_DEBUG>(hi);
if ( (lo & 0xFFFF) < ( (~(lo >> 16)) & val) )
{
if (if_flag > 0) if_flag--;
}
else
{
if_flag++;
}
break;
case 0x09: // 9XXXXXXX ZZZZYYYY IF YYYY = ((not ZZZZ) AND half[XXXXXXX])
if (hi == 0) hi = offset; // V1.54+
val = _MMU_read16<ARMCPU_ARM9,MMU_AT_DEBUG>(hi);
if ( (lo & 0xFFFF) == ( (~(lo >> 16)) & val) )
{
if (if_flag > 0) if_flag--;
}
else
{
if_flag++;
}
break;
case 0x0A: // AXXXXXXX ZZZZYYYY IF YYYY <> ((not ZZZZ) AND half[XXXXXXX])
if (hi == 0) hi = offset; // V1.54+
val = _MMU_read16<ARMCPU_ARM9,MMU_AT_DEBUG>(hi);
if ( (lo & 0xFFFF) != ( (~(lo >> 16)) & val) )
{
if (if_flag > 0) if_flag--;
}
else
{
if_flag++;
}
break;
case 0x0B: // BXXXXXXX 00000000 offset = word[XXXXXXX+offset]
addr = hi + offset;
offset = _MMU_read32<ARMCPU_ARM9,MMU_AT_DEBUG>(addr);;
break;
case 0x0C:
switch (subtype)
{
case 0x0: // C0000000 YYYYYYYY FOR loopcount=0 to YYYYYYYY ;execute Y+1 times
if (loopcount < (lo+1))
loop_flag = 1;
else
loop_flag = 0;
loopcount++;
loopbackline = i;
break;
case 0x4: // C4000000 00000000 offset = address of the C4000000 code ; V1.54
printf("AR: untested code C4\n");
break;
case 0x5: // C5000000 XXXXYYYY counter=counter+1, IF (counter AND YYYY) = XXXX ; V1.54
counter++;
if ( (counter & (lo & 0xFFFF)) == ((lo >> 8) & 0xFFFF) )
{
if (if_flag > 0) if_flag--;
}
else
{
if_flag++;
}
break;
case 0x6: // C6000000 XXXXXXXX [XXXXXXXX]=offset ; V1.54
_MMU_write32<ARMCPU_ARM9,MMU_AT_DEBUG>(lo, offset);
break;
}
break;
case 0x0D:
{
switch (subtype)
{
case 0x0: // D0000000 00000000 ENDIF
break;
case 0x1: // D1000000 00000000 NEXT loopcount
if (loop_flag)
i = (loopbackline-1);
break;
case 0x2: // D2000000 00000000 NEXT loopcount, and then FLUSH everything
if (loop_flag)
i = (loopbackline-1);
else
{
offset = 0;
datareg = 0;
loopcount = 0;
counter = 0;
if_flag = 0;
loop_flag = 0;
}
break;
case 0x3: // D3000000 XXXXXXXX offset = XXXXXXXX
offset = lo;
break;
case 0x4: // D4000000 XXXXXXXX datareg = datareg + XXXXXXXX
datareg += lo;
break;
case 0x5: // D5000000 XXXXXXXX datareg = XXXXXXXX
datareg = lo;
break;
case 0x6: // D6000000 XXXXXXXX word[XXXXXXXX+offset]=datareg, offset=offset+4
addr = lo + offset;
_MMU_write32<ARMCPU_ARM9,MMU_AT_DEBUG>(addr, datareg);
offset += 4;
break;
case 0x7: // D7000000 XXXXXXXX half[XXXXXXXX+offset]=datareg, offset=offset+2
addr = lo + offset;
_MMU_write16<ARMCPU_ARM9,MMU_AT_DEBUG>(addr, datareg);
offset += 2;
break;
case 0x8: // D8000000 XXXXXXXX byte[XXXXXXXX+offset]=datareg, offset=offset+1
addr = lo + offset;
_MMU_write08<ARMCPU_ARM9,MMU_AT_DEBUG>(addr, datareg);
offset += 1;
break;
case 0x9: // D9000000 XXXXXXXX datareg = word[XXXXXXXX+offset]
addr = lo + offset;
datareg = _MMU_read32<ARMCPU_ARM9,MMU_AT_DEBUG>(addr);
break;
case 0xA: // DA000000 XXXXXXXX datareg = half[XXXXXXXX+offset]
addr = lo + offset;
datareg = _MMU_read16<ARMCPU_ARM9,MMU_AT_DEBUG>(addr);
break;
case 0xB: // DB000000 XXXXXXXX datareg = byte[XXXXXXXX+offset] ;bugged on pre-v1.54
addr = lo + offset;
datareg = _MMU_read08<ARMCPU_ARM9,MMU_AT_DEBUG>(addr);
break;
case 0xC: // DC000000 XXXXXXXX offset = offset + XXXXXXXX
offset += lo;
break;
}
}
break;
case 0xE: // EXXXXXXX YYYYYYYY Copy YYYYYYYY parameter bytes to [XXXXXXXX+offset...]
{
u8 *tmp_code = (u8*)(list.code[i+1]);
u32 addr = hi+offset;
u32 maxByteReadLocation = ((2 * 4) * (MAX_XX_CODE - i - 1)) - 1; // 2 = 2 array dimensions, 4 = 4 bytes per array element
if (lo <= maxByteReadLocation)
{
for (u32 t = 0; t < lo; t++)
{
u8 tmp = tmp_code[t];
_MMU_write08<ARMCPU_ARM9,MMU_AT_DEBUG>(addr, tmp);
addr++;
}
}
i += ((lo + 7) / 8);
}
break;
case 0xF: // FXXXXXXX YYYYYYYY Copy YYYYYYYY bytes from [offset..] to [XXXXXXX...]
for (u32 t = 0; t < lo; t++)
{
u8 tmp = _MMU_read08<ARMCPU_ARM9,MMU_AT_DEBUG>(offset+t);
_MMU_write08<ARMCPU_ARM9,MMU_AT_DEBUG>(hi+t, tmp);
}
break;
default: PROGINFO("AR: ERROR unknown command 0x%2X at %08X:%08X\n", type, hi, lo); break;
}
}
}
网友评论