mirror of
https://gitee.com/anod/open_agb_firm.git
synced 2025-05-06 05:44:11 +08:00
添加go版本的代码,测试比aot后的C#要慢,大概是2*native
This commit is contained in:
parent
91548c067e
commit
4d952f6a82
672
tools/cheat-builder/make-acl.go
Normal file
672
tools/cheat-builder/make-acl.go
Normal file
@ -0,0 +1,672 @@
|
||||
package main;
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"encoding/json"
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
"bytes"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type Serial struct {
|
||||
order string
|
||||
serial string
|
||||
}
|
||||
|
||||
type Packed struct {
|
||||
code uint32
|
||||
data []byte
|
||||
}
|
||||
|
||||
type Cheat struct {
|
||||
serial string
|
||||
cheats []Packed
|
||||
}
|
||||
|
||||
type LockKey = []string
|
||||
|
||||
type LockHole struct {
|
||||
name string
|
||||
keys []LockKey
|
||||
}
|
||||
|
||||
type Lock struct {
|
||||
name string
|
||||
holes []LockHole
|
||||
}
|
||||
|
||||
type EntData struct {
|
||||
id uint32
|
||||
t uint
|
||||
strs [](*string)
|
||||
cmds *[]LockKey
|
||||
}
|
||||
|
||||
const (
|
||||
WaitLock = iota
|
||||
ReadLock
|
||||
WaitHole
|
||||
ReadHole
|
||||
ReadKey
|
||||
WaitPart
|
||||
NeedPart
|
||||
)
|
||||
|
||||
const (
|
||||
EntNames = iota
|
||||
EntCmds
|
||||
)
|
||||
|
||||
func align(n uint32, basic uint32) uint32 {
|
||||
ext := n % basic
|
||||
if ext == 0 {
|
||||
return n
|
||||
} else {
|
||||
return n + basic - ext
|
||||
}
|
||||
}
|
||||
|
||||
func find_index(t []byte, tr []byte) int {
|
||||
rlen, tlen := len(tr), len(t)
|
||||
limit := tlen - rlen
|
||||
for i := 0; i < limit; i++ {
|
||||
if t[i+rlen] != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
eq := true
|
||||
for j := 0; j < rlen; j++ {
|
||||
if tr[j] != t[i+j] {
|
||||
eq = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if eq {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func assemble_cheat(list *[]LockKey, dup map[uint32]uint16, hole uint16) []uint32 {
|
||||
var atoi = func(t string) uint32 {
|
||||
var n uint32
|
||||
fmt.Sscanf(t, "%x", &n)
|
||||
return n
|
||||
}
|
||||
var from_taddr = func(taddr string) uint32 {
|
||||
n := atoi(taddr)
|
||||
if n == 0 || n > 0x41fffff {
|
||||
panic(fmt.Sprintf("invalid taddr %s", taddr))
|
||||
}
|
||||
|
||||
if n <= 0x3ffff {
|
||||
return n | 0x2000000
|
||||
}else if 0 == (n&0xf000000) {
|
||||
return (n & 0xffff) | 0x3000000
|
||||
}else { return n }
|
||||
}
|
||||
|
||||
addrval := make(map[uint32]uint32, 0)
|
||||
for _, command := range *list {
|
||||
if len(command) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
addr := from_taddr(command[0])
|
||||
len := len(command) - 1
|
||||
for i := 0; i < len; i++ {
|
||||
addrval[addr + uint32(i)] = atoi(command[i+1])
|
||||
}
|
||||
}
|
||||
|
||||
ordered := make([][2]uint32, 0)
|
||||
for addr, val := range addrval {
|
||||
ordered = append(ordered, [2]uint32{addr, val})
|
||||
}
|
||||
sort.Slice(ordered, func(i, j int) bool {
|
||||
return ordered[i][0] < ordered[j][0]
|
||||
})
|
||||
blocks, curr := make([]uint32, 0), [3]uint32{0, 0, 0}
|
||||
for _, addrval := range ordered {
|
||||
addr, value := addrval[0], addrval[1]
|
||||
dup[addr] = hole
|
||||
|
||||
if 0 == curr[2] {
|
||||
curr = [3]uint32{addr, value, 1}
|
||||
}else if curr[1] == value && curr[0] + curr[2] == addr {
|
||||
curr[2]++
|
||||
}else {
|
||||
blocks = append(blocks, curr[0], curr[2]<<8 | curr[1])
|
||||
curr = [3]uint32{addr, value, 1}
|
||||
}
|
||||
}
|
||||
if curr[2] > 0 {
|
||||
blocks = append(blocks, curr[0], curr[2]<<8 | curr[1])
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
|
||||
func loadlist() ([]Serial, error) {
|
||||
bytes, err := os.ReadFile("./serial.json")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var jsonData map[string]string
|
||||
err = json.Unmarshal(bytes, &jsonData)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var serials []Serial
|
||||
for k, v := range jsonData {
|
||||
if v != "????" {
|
||||
serials = append(serials, Serial{order: k, serial: v})
|
||||
}
|
||||
}
|
||||
return serials, nil
|
||||
}
|
||||
|
||||
func lade(locks []Lock, serial string, order string) Packed {
|
||||
rootstr, names := make([]*string, 0), make([]*string, 0)
|
||||
enttable := make([]EntData, 0)
|
||||
|
||||
var make_id = func(a uint32, b uint32) uint32 {
|
||||
return a | b<<16
|
||||
};
|
||||
|
||||
for i, lock := range locks {
|
||||
rootstr = append(rootstr, &lock.name)
|
||||
names = append(names, &lock.name)
|
||||
|
||||
holestr := make([]*string, 0)
|
||||
colname := len(lock.holes) > 1
|
||||
for idx, hole := range lock.holes {
|
||||
holestr = append(holestr, &hole.name)
|
||||
if colname {
|
||||
names = append(names, &hole.name)
|
||||
}
|
||||
id := make_id(uint32(i+1), uint32(idx+1))
|
||||
enttable = append( enttable, EntData{
|
||||
id, EntCmds, make([]*string, 0), &hole.keys,
|
||||
})
|
||||
}
|
||||
enttable = append(enttable, EntData{
|
||||
make_id(uint32(i+1), 0),
|
||||
EntNames, holestr, nil,
|
||||
})
|
||||
}
|
||||
enttable = append(enttable, EntData{
|
||||
make_id(0, 0), EntNames, rootstr, nil,
|
||||
})
|
||||
|
||||
if len(enttable) > 0xffff {
|
||||
panic("too many entries")
|
||||
}
|
||||
|
||||
sort.Slice(enttable, func(i, j int) bool {
|
||||
return enttable[i].id < enttable[j].id
|
||||
})
|
||||
sort.Slice(names, func(i, j int) bool {
|
||||
if len(*names[i]) == len(*names[j]) {
|
||||
return *names[i] < *names[j]
|
||||
}else {
|
||||
return len(*names[j]) < len(*names[i])
|
||||
}
|
||||
})
|
||||
|
||||
strtable, idxtable, cmdtable := make([]byte, 0), make([]uint16, 0), make([]uint32, 0)
|
||||
strcache := make(map[string]uint16, 0)
|
||||
|
||||
var ut_push = func(tr []byte) uint16 {
|
||||
off := len(strtable)
|
||||
for _, v := range tr {
|
||||
strtable = append(strtable, v)
|
||||
}
|
||||
strtable = append(strtable, 0)
|
||||
return uint16(off)
|
||||
}
|
||||
var ut_addr = func(tr string) uint16 {
|
||||
if v, ok := strcache[tr]; ok {
|
||||
return v
|
||||
}
|
||||
idx := find_index(strtable, []byte(tr))
|
||||
var off uint16
|
||||
if idx < 0 { off = ut_push([]byte(tr)) } else { off = uint16(idx) }
|
||||
//uint16(idx < 0 ? ut_push([]byte(tr)) : idx)
|
||||
strcache[tr] = off
|
||||
return off
|
||||
}
|
||||
var add_string = func(list []*string) []uint16 {
|
||||
retval := make([]uint16, len(list))
|
||||
for i, v := range list {
|
||||
retval[i] = ut_addr(*v)
|
||||
}
|
||||
return retval
|
||||
}
|
||||
var add_str_index = func(list []uint16) uint16 {
|
||||
if len(list) == 0 {
|
||||
return 0
|
||||
}
|
||||
if len(strtable) > 0xffff {
|
||||
panic("too many strings")
|
||||
}
|
||||
|
||||
retval := uint16(len(idxtable))
|
||||
for _, v := range list {
|
||||
idxtable = append(idxtable, v)
|
||||
}
|
||||
return retval*2
|
||||
}
|
||||
var add_command = func(list []uint32) uint32 {
|
||||
retval := len(cmdtable)
|
||||
for _, v := range list {
|
||||
cmdtable = append(cmdtable, v)
|
||||
}
|
||||
return uint32(retval*4)
|
||||
}
|
||||
|
||||
add_string(names)
|
||||
|
||||
entbytelist, emptylist, holedup := make([][3]uint32, 0), make([]*string, 0), make(map[uint32]uint16, 0)
|
||||
for _, entry := range enttable {
|
||||
if entry.t == EntNames {
|
||||
var idxlist []uint16
|
||||
if entry.id == 0 {
|
||||
idxlist = add_string( entry.strs )
|
||||
}else if len(entry.strs) > 1 {
|
||||
idxlist = add_string( entry.strs )
|
||||
}else {
|
||||
idxlist = add_string( emptylist )
|
||||
}
|
||||
location := add_str_index(idxlist)
|
||||
entbytelist = append(entbytelist, [3]uint32{
|
||||
entry.id, uint32(location), uint32(len(idxlist)),
|
||||
})
|
||||
} else {
|
||||
armbytecode := assemble_cheat( entry.cmds, holedup, uint16(entry.id & 0xffff) )
|
||||
location := add_command(armbytecode)
|
||||
entbytelist = append(entbytelist, [3]uint32{
|
||||
entry.id, uint32(location), uint32(len(armbytecode)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var code uint32 = 0
|
||||
for _, c := range []byte(serial) {
|
||||
code = (code << 8) | uint32(c & 0xff)
|
||||
}
|
||||
for _, cmd := range cmdtable {
|
||||
code = code ^ cmd
|
||||
}
|
||||
return Packed{code, pack(entbytelist, strtable, idxtable, cmdtable) }
|
||||
}
|
||||
|
||||
func pack(entlist [][3]uint32, strlist []byte, idxlist []uint16, cmdlist []uint32) []byte {
|
||||
entrysize := 12
|
||||
strbase := 2 + len(entlist) * entrysize
|
||||
idxbase := strbase + len(strlist)
|
||||
cmdbase := idxbase + len(idxlist) * 2
|
||||
nonalign_size := cmdbase + len(cmdlist) * 4
|
||||
size := align(uint32(nonalign_size), 32)
|
||||
|
||||
result := make([]byte, size)
|
||||
binary.Encode(result, binary.LittleEndian, uint32(len(entlist)))
|
||||
|
||||
for i, entry := range entlist {
|
||||
offset := i * entrysize + 2
|
||||
locbase := idxbase
|
||||
if entry[0] > 0xffff {
|
||||
locbase = cmdbase
|
||||
}
|
||||
|
||||
binary.Encode(result[offset:], binary.LittleEndian, entry[0])
|
||||
binary.Encode(result[offset+4:], binary.LittleEndian, entry[1] + uint32(locbase))
|
||||
binary.Encode(result[offset+8:], binary.LittleEndian, entry[2])
|
||||
}
|
||||
|
||||
copy(result[strbase:], strlist)
|
||||
|
||||
for i, v := range idxlist {
|
||||
binary.Encode(result[idxbase + i*2:], binary.LittleEndian, v)
|
||||
}
|
||||
|
||||
for i, v := range cmdlist {
|
||||
binary.Encode(result[cmdbase + i*4:], binary.LittleEndian, v)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func parse(datas []byte, serial string, order string) ([]Packed, error) {
|
||||
var retval []Packed
|
||||
var token []byte
|
||||
state, line, locks := WaitLock, 1, make([]Lock, 0)
|
||||
var currlock *Lock
|
||||
var currhole *LockHole
|
||||
|
||||
var token_str = func() string {
|
||||
var r = string( token );
|
||||
token = make([]byte, 0)
|
||||
return r;
|
||||
};
|
||||
|
||||
var error = func(msg string) {
|
||||
panicmsg := fmt.Sprintf("error occur %s on line %d", msg, line)
|
||||
panic(panicmsg)
|
||||
};
|
||||
|
||||
// incr
|
||||
var incr = func(ch byte) {
|
||||
switch ch {
|
||||
case '[':
|
||||
if state == WaitLock || state == ReadHole || state == NeedPart {
|
||||
state = ReadLock;
|
||||
if currlock != nil {
|
||||
locks = append(locks, *currlock );
|
||||
}
|
||||
currlock = &Lock{"", make([]LockHole, 0)};
|
||||
}else if state == WaitPart {
|
||||
}else { error(fmt.Sprintf("error occur [ on %d", state) ) }
|
||||
case ']':
|
||||
if state == ReadLock {
|
||||
state = WaitHole
|
||||
name := token_str()
|
||||
if strings.ToLower(name) == "gameinfo" {
|
||||
retval = append(retval, lade(locks, serial, order))
|
||||
state = WaitPart
|
||||
locks = make([]Lock, 0)
|
||||
currlock = nil
|
||||
currhole = nil
|
||||
}else if len(name) > 0 {
|
||||
currlock = &Lock{name, make([]LockHole, 0)}
|
||||
currhole = nil
|
||||
}else { error(fmt.Sprintf("empty lock name in %s", order) ) }
|
||||
}else if state == WaitPart {
|
||||
}else if state == NeedPart{
|
||||
state = WaitPart
|
||||
}else { error(fmt.Sprintf("error occur ] on %d", state) ) }
|
||||
case '\r', '\n':
|
||||
if state == WaitHole {
|
||||
state = ReadHole
|
||||
}else if state == ReadKey {
|
||||
t, pass := token_str(), false
|
||||
if currhole != nil {
|
||||
if len(t) > 0 {
|
||||
idx := len(currhole.keys) - 1
|
||||
currhole.keys[idx] = append(currhole.keys[idx], t)
|
||||
}
|
||||
|
||||
t = strings.ToLower(currhole.name)
|
||||
if t == "text" || t == "off" {
|
||||
pass = true
|
||||
}
|
||||
}
|
||||
if !pass {
|
||||
if currlock != nil {
|
||||
if currhole == nil { error("unreachable for pass") }
|
||||
currlock.holes = append(currlock.holes, *currhole)
|
||||
//LockHole{name: currhole.name, keys: currhole.keys})
|
||||
}
|
||||
currhole = nil
|
||||
}
|
||||
state = ReadHole
|
||||
}else if state == ReadLock {
|
||||
error(fmt.Sprintf("error occur newline on %d", state))
|
||||
}else if state == ReadHole {
|
||||
if len(token) > 0 && bytes.ContainsFunc(token, func(r rune) bool { return r != ' ' && r != '\t' }) {
|
||||
error(fmt.Sprintf("error occur space on %d", state))
|
||||
} else {
|
||||
token = make([]byte, 0)
|
||||
}
|
||||
}else if state == WaitPart {
|
||||
state = NeedPart
|
||||
} else {}
|
||||
if ch == '\n' { line++ }
|
||||
case '=':
|
||||
if state == ReadHole {
|
||||
state = ReadKey
|
||||
currhole = &LockHole{name: token_str(), keys: make([]LockKey, 1)}
|
||||
}else if state == ReadLock {
|
||||
token = append(token, ch)
|
||||
}else if state == WaitPart {
|
||||
}else if state == NeedPart {
|
||||
state = WaitPart
|
||||
}else { error(fmt.Sprintf("error occur = on %d", state)) }
|
||||
case ',':
|
||||
if state == ReadKey {
|
||||
if currhole == nil { error("unreachable for currhole") }
|
||||
|
||||
if len(token) > 0 {
|
||||
idx := len(currhole.keys) - 1
|
||||
currhole.keys[idx] = append(currhole.keys[idx], token_str())
|
||||
}
|
||||
}else if state == ReadHole {
|
||||
if currlock == nil { error("unreachable for currlock") }
|
||||
|
||||
idx := len(currlock.holes) - 1
|
||||
tmp := currlock.holes[idx]
|
||||
currlock.holes = currlock.holes[:idx]
|
||||
if len(token) > 0 {
|
||||
pos := len(tmp.keys) - 1
|
||||
tmp.keys[pos] = append(tmp.keys[pos], token_str())
|
||||
}
|
||||
currhole = &LockHole{name: tmp.name, keys: tmp.keys}
|
||||
state = ReadKey
|
||||
}else if state == ReadLock {
|
||||
token = append(token, ch)
|
||||
}else if state == WaitPart {
|
||||
}else if state == NeedPart {
|
||||
state = WaitPart
|
||||
}else { error(fmt.Sprintf("error occur , on %d", state)) }
|
||||
case ';':
|
||||
if state == ReadKey {
|
||||
if currhole == nil { error("unreachable for currhole") }
|
||||
|
||||
if len(token) > 0 {
|
||||
idx := len(currhole.keys) - 1
|
||||
currhole.keys[idx] = append(currhole.keys[idx], token_str())
|
||||
}
|
||||
if currhole != nil {
|
||||
currhole.keys = append(currhole.keys, make([]string, 0))
|
||||
}
|
||||
}else if state == ReadLock {
|
||||
token = append(token, ch)
|
||||
}else if state == ReadHole {
|
||||
if currlock == nil { error("unreachable for currlock") }
|
||||
|
||||
idx := len(currlock.holes) - 1
|
||||
tmp := currlock.holes[idx]
|
||||
currlock.holes = currlock.holes[:idx]
|
||||
if len(token) > 0 {
|
||||
pos := len(tmp.keys) - 1
|
||||
tmp.keys[pos] = append(tmp.keys[pos], token_str())
|
||||
}
|
||||
tmp.keys = append(tmp.keys, make([]string, 0))
|
||||
currhole = &LockHole{name: tmp.name, keys: tmp.keys}
|
||||
state = ReadKey
|
||||
}else if state == WaitPart {
|
||||
}else if state == NeedPart {
|
||||
state = WaitPart
|
||||
}else { error(fmt.Sprintf("error occur ; on %d", state)) }
|
||||
case ' ':
|
||||
if state == ReadLock || state == ReadHole {
|
||||
token = append(token, ch)
|
||||
}else if state == NeedPart {
|
||||
state = WaitPart
|
||||
}else {}
|
||||
default:
|
||||
if state == ReadLock || state == ReadHole {
|
||||
token = append(token, ch)
|
||||
}else if state == ReadKey {
|
||||
if strings.Contains("0123456789abcdefABCDEF", string(ch)) {
|
||||
token = append(token, ch)
|
||||
} else if currhole != nil {
|
||||
if strings.ToLower(currhole.name) == "text" {
|
||||
token = append(token, ch)
|
||||
}
|
||||
} else { error(fmt.Sprintf("error occur %c on %d", ch, state)) }
|
||||
}else if state == WaitPart {
|
||||
}else if state == NeedPart {
|
||||
state = WaitPart
|
||||
} else { error(fmt.Sprintf("error occur %c on %d", ch, state))}
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
var done = func() {
|
||||
if state != WaitPart && state != NeedPart {
|
||||
error(fmt.Sprintf("unexpected end of file %d in %s", state, order))
|
||||
}
|
||||
}
|
||||
|
||||
for _, ch := range datas {
|
||||
incr(ch)
|
||||
}
|
||||
done()
|
||||
return retval, nil
|
||||
}
|
||||
|
||||
func transform(list []Serial) []Cheat {
|
||||
var retval []Cheat
|
||||
for _, game := range list {
|
||||
file := fmt.Sprintf("./gba/%s.u8", game.order)
|
||||
if _, err := os.Stat(file); os.IsNotExist(err) {
|
||||
// fmt.Println(file, " not found")
|
||||
retval = append( retval, Cheat{ game.serial, make([]Packed, 0) } )
|
||||
continue
|
||||
}
|
||||
|
||||
bytes, err := os.ReadFile(file)
|
||||
if err != nil || len(bytes) == 0 {
|
||||
retval = append( retval, Cheat{ game.serial, make([]Packed, 0) } )
|
||||
} else {
|
||||
cheats, err := parse(bytes, game.serial, game.order)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
retval = append( retval, Cheat{ game.serial, make([]Packed, 0) } )
|
||||
} else {
|
||||
retval = append( retval, Cheat{ game.serial, cheats } )
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval
|
||||
}
|
||||
|
||||
func format( cheats []Cheat ) []byte {
|
||||
sort.Slice( cheats, func(i, j int) bool {
|
||||
return cheats[i].serial < cheats[j].serial
|
||||
})
|
||||
fmt.Println("valid rom has", len(cheats))
|
||||
|
||||
var step1 = func() ([]byte, []uint16, uint32, uint32) {
|
||||
item1, item2 := make([]byte, 0), make([]uint16, 0)
|
||||
item3, item4, item5, last := uint32(0), uint32(0), "", uint32(0)
|
||||
for _, ch := range cheats {
|
||||
serial, cheat := ch.serial, ch.cheats
|
||||
val := serial[0:3]
|
||||
if item5 != val {
|
||||
if len(item2) > 0 && item3 - last > item4 {
|
||||
item4 = item3 - last
|
||||
}
|
||||
item1 = append(item1, []byte(val)...)
|
||||
item2 = append(item2, uint16(item3))
|
||||
last = item3
|
||||
item5 = val
|
||||
}
|
||||
item3 += uint32(len(cheat))
|
||||
}
|
||||
if len(item2) > 0 {
|
||||
if item3 - last > item4 {
|
||||
item4 = item3 - last
|
||||
}
|
||||
item2 = append(item2, uint16(item3))
|
||||
}
|
||||
return item1, item2, item3, item4
|
||||
}
|
||||
sers, offs, chtc, maxl := step1()
|
||||
|
||||
var step2 = func() ([]uint32, []byte) {
|
||||
item1, item2 := make([]uint32, 0), make([]byte, 0)
|
||||
item3 := align(uint32(8 + len(sers) + len(offs)*2 + int(chtc) * 8), 32)
|
||||
for _, ch := range cheats {
|
||||
serial, cheat := ch.serial, ch.cheats
|
||||
val := serial[3]
|
||||
|
||||
for _, cht := range cheat {
|
||||
id, bin := cht.code, cht.data
|
||||
off := item3 + uint32(len(item2))
|
||||
item1 = append(item1, uint32(val) | (off<<3), id)
|
||||
item2 = append(item2, bin...)
|
||||
}
|
||||
}
|
||||
return item1, item2
|
||||
}
|
||||
chts, expanded := step2()
|
||||
fmt.Printf("name: %d cheats: %d maxl: %d", len(sers), chtc, maxl)
|
||||
|
||||
serialbase := 8
|
||||
offsetbase := serialbase + len(sers)
|
||||
cheatbase := offsetbase + len(offs) * 2
|
||||
cheatend := cheatbase + len(chts) * 4
|
||||
expandbase := align(uint32(cheatend), 32)
|
||||
total := int(expandbase) + len(expanded)
|
||||
|
||||
retval := make([]byte, total)
|
||||
retval[0] = 'A'
|
||||
retval[1] = 'C'
|
||||
retval[2] = 'L'
|
||||
retval[3] = 1
|
||||
|
||||
binary.Encode(retval[4:], binary.LittleEndian, uint16(len(sers)/3))
|
||||
binary.Encode(retval[6:], binary.LittleEndian, uint16(maxl))
|
||||
|
||||
copy(retval[serialbase:], sers)
|
||||
|
||||
for i, off := range offs {
|
||||
binary.Encode(retval[offsetbase+i*2:], binary.LittleEndian, off)
|
||||
}
|
||||
for i, ch := range chts {
|
||||
binary.Encode(retval[cheatbase+i*4:], binary.LittleEndian, ch)
|
||||
}
|
||||
copy(retval[cheatbase:], expanded)
|
||||
|
||||
return retval
|
||||
}
|
||||
|
||||
func main() {
|
||||
list, err := loadlist()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
roms := transform(list)
|
||||
fmt.Println("all rom has", len(roms))
|
||||
|
||||
idx := make(map[string][]Packed, 0)
|
||||
for _, rom := range roms {
|
||||
if len(rom.cheats) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := idx[rom.serial]; !ok {
|
||||
idx[rom.serial] = make([]Packed, 0)
|
||||
}
|
||||
|
||||
idx[rom.serial] = append(idx[rom.serial], rom.cheats...)
|
||||
}
|
||||
|
||||
cheats := make([]Cheat, 0)
|
||||
for serial, chts := range idx {
|
||||
cheats = append(cheats, Cheat{ serial, chts })
|
||||
}
|
||||
|
||||
content := format( cheats )
|
||||
os.WriteFile("gba.acl", content, 0644)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user