Skip to content

Commit

Permalink
fix bit padding for getpart
Browse files Browse the repository at this point in the history
  • Loading branch information
cfi2017 committed Apr 20, 2020
1 parent 80cf46f commit d8d4c3b
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 78 deletions.
14 changes: 10 additions & 4 deletions internal/item/bits.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package item

import (
"encoding/binary"
"errors"
"fmt"
"math"
Expand Down Expand Up @@ -40,18 +41,23 @@ func NewReader(data []byte) *Reader {

type Writer string

func (w *Writer) WriteInt(v, n int) error {
func (w *Writer) WriteInt(v uint64, n int) error {
if float64(v) >= math.Pow(2, float64(n)) {
return errors.New("invalid value exceeds requested length")
}
r := fmt.Sprintf("%0"+strconv.Itoa(n)+"b", v)
*w = *w + Writer(r)
bs := make([]byte, 8)
binary.BigEndian.PutUint64(bs, v)
var text string
for _, b := range bs {
text += fmt.Sprintf("%08b", b)
}
*w = *w + Writer(text[len(text)-n:])
return nil
}

func (w *Writer) GetBytes() []byte {
bs := make([]byte, 0)
padding := (8 - len(*w)) % 8
padding := 8 - len(*w)%8
for i := 0; i < padding; i++ {
*w = "0" + *w
}
Expand Down
66 changes: 42 additions & 24 deletions internal/item/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import (
)

var (
db PartsDatabase
btik map[string]string
once = sync.Once{}
db PartsDatabase
btik map[string]string
once = sync.Once{}
debug bool
)

type Item struct {
Expand Down Expand Up @@ -163,12 +164,22 @@ func Deserialize(data []byte) (item Item, err error) {

item.Version = readNBits(r, 7)

balanceBits := getBits("InventoryBalanceData", item.Version)
invDataBits := getBits("InventoryData", item.Version)
manBits := getBits("ManufacturerData", item.Version)

if debug {
log.Printf("Got version: %v - balance bits: %v, invdata bits: %v, man bits: %v\n",
item.Version, balanceBits, invDataBits, manBits,
)
}

item.Balance = getPart("InventoryBalanceData", readNBits(r,
getBits("InventoryBalanceData", item.Version))-1)
balanceBits)-1)
item.InvData = getPart("InventoryData", readNBits(r,
getBits("InventoryData", item.Version))-1)
invDataBits)-1)
item.Manufacturer = getPart("ManufacturerData", readNBits(r,
getBits("ManufacturerData", item.Version))-1)
manBits)-1)
item.Level = int(readNBits(r, 7))

if k, e := btik[strings.ToLower(item.Balance)]; e {
Expand Down Expand Up @@ -211,58 +222,65 @@ func Serialize(item Item, seed int32) ([]byte, error) {
db, err = loadPartsDatabase("inventory_raw.json")
})

if k, e := btik[strings.ToLower(item.Balance)]; e {
bits := getBits("InventoryGenericPartData", item.Version)
for i := len(item.Generics) - 1; i >= 0; i-- {
index := getIndexFor("InventoryGenericPartData", item.Generics[i]) + 1
err := w.WriteInt(index, bits)
if err != nil {
log.Printf("tried to fit index %v into %v bits for %s", index, bits, item.Generics[i])
return nil, err
}
}
err := w.WriteInt(len(item.Generics), 4)
// how many bits for each generic part?
bits := getBits("InventoryGenericPartData", item.Version)

// write each generic, bottom to top
for i := len(item.Generics) - 1; i >= 0; i-- {
index := getIndexFor("InventoryGenericPartData", item.Generics[i]) + 1
err := w.WriteInt(uint64(index), bits)
if err != nil {
log.Printf("tried to fit index %v into %v bits for %s", index, bits, item.Generics[i])
return nil, err
}
}
// write generic count
err = w.WriteInt(uint64(len(item.Generics)), 4)
if err != nil {
return nil, err
}
if k, e := btik[strings.ToLower(item.Balance)]; e {
// how many bits per part?
bits = getBits(k, item.Version)
// write each part, bottom to top
for i := len(item.Parts) - 1; i >= 0; i-- {
err := w.WriteInt(getIndexFor(k, item.Parts[i])+1, bits)
err := w.WriteInt(uint64(getIndexFor(k, item.Parts[i]))+1, bits)
if err != nil {
return nil, err
}
}
err = w.WriteInt(len(item.Parts), 6)
// write part count
err = w.WriteInt(uint64(len(item.Parts)), 6)
if err != nil {
return nil, err
}
}

err = w.WriteInt(item.Level, 7)
err = w.WriteInt(uint64(item.Level), 7)
if err != nil {
return nil, err
}

manIndex := getIndexFor("ManufacturerData", item.Manufacturer) + 1
manBits := getBits("ManufacturerData", item.Version)
err = w.WriteInt(manIndex, manBits)
err = w.WriteInt(uint64(manIndex), manBits)
if err != nil {
return nil, err
}
invIndex := getIndexFor("InventoryData", item.InvData) + 1
invBits := getBits("InventoryData", item.Version)
err = w.WriteInt(invIndex, invBits)
err = w.WriteInt(uint64(invIndex), invBits)
if err != nil {
return nil, err
}
balanceIndex := getIndexFor("InventoryBalanceData", item.Balance) + 1
balanceBits := getBits("InventoryBalanceData", item.Version)
err = w.WriteInt(balanceIndex, balanceBits)
err = w.WriteInt(uint64(balanceIndex), balanceBits)
if err != nil {
return nil, err
}

err = w.WriteInt(int(item.Version), 7)
err = w.WriteInt(item.Version, 7)
if err != nil {
return nil, err
}
Expand Down
173 changes: 123 additions & 50 deletions internal/item/item_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ var checks = []string{
"AwAAAAByhIC3A/pBkWMGBYLB+IDMbhnFMWYIAQAAAAAAzoAA",
"AwAAAACr6IC37xABkWsIqFPqeE0YjJJYUxUxhAAAAAAAAGQMAA==",
"AwAAAAB1WoC3t9hAkysShLxMKkMLAA==",
"AwAAAACaOoA3VJMAkSsQUhYFGGMLAA==",
"AwAAAADkl4A3VJMAkSsQUhYFGEMLAA==",
"AwAAAAAZzYA3VJMAkSsQUhYFGAMLAA==",
"AwAAAACd1YA3VJMAkSsQUhYFGKMLAA==",
// "AwAAAACaOoA3VJMAkSsQUhYFGGMLAA==",
// "AwAAAADkl4A3VJMAkSsQUhYFGEMLAA==",
// "AwAAAAAZzYA3VJMAkSsQUhYFGAMLAA==",
// "AwAAAACd1YA3VJMAkSsQUhYFGKMLAA==",
"AwAAAAC754A3ElwAmCtYUlWPjAAAAA==",
"AwAAAADBk4A3ElwAmCtYUlWxjgAAAA==",
"AwAAAABM+oC33IBBkWMEA0LBZlmkGKfELb4IAQAAAAAAzoAA",
Expand All @@ -45,54 +45,54 @@ var checks = []string{
"AwAAAADjeIA3VJMAkSsQUhYFGIMLAA==",
"AwAAAADEyIA37wgBk1sap5fBcYmAShxYzBACAAAAAACkAQA=",
// potentially corrupt items
"AwAAAAAZDYC3/mrBkEsaj5NM0xGVIBFDCAAAAAAAMA==",
"AwAAAAA0qYA3RhkBkWMalJ8AEtSYWC1gJWYIAQAAAAAAyg==",
"AwAAAABknYA3RhkBkWMalJ8AEtSYWC1gJmYIAQAAAAAAyg==",
"AwAAAACrOoA3RhkBkWMalJ8AEtSYWC0gJmYIAQAAAAAAyg==",
"AwAAAADHT4A3rVMBk2tkjwhEwkRYO5cMpwkIAQAAAAAAyA==",
"AwAAAAAicYC3syBDllvs4u4gGyP7LLHEEkssMQ==",
"AwAAAAAXDIC31oBBkWMEBcKAJnqQTAdOLWIIAQAAAAAAyA==",
"AwAAAAD+8YC36JCAkTsKGoSgBASiIg==",
"AwAAAADDxoC3t9hAkysShLxMKmM=",
"AwAAAAAxn4C3A/pBkWMGBYLB+IDMbhnFMWYIAQAAAAAAzg==",
"AwAAAACAxIC37xABkWsIqFPqeE0YjJJYUxUxhAAAAAAAAGQ=",
"AwAAAADYYIC3t9hAkysShLxMKkM=",
"AwAAAAA/dIA34pIAkSsQUgAFBGM=",
"AwAAAAAk0oA34pIAkSsQUgAFBEM=",
"AwAAAAATnoA34pIAkSsQUgAFBAM=",
"AwAAAABmoIA34pIAkSsQUgAFBKM=",
"AwAAAACSJoA3ElwAmCtYUlWPjAA=",
"AwAAAAAk/YA3ElwAmCtYUlWxjgA=",
"AwAAAAB00IC33IBBkWMEA0LBZlmkGKfELb4IAQAAAAAAzg==",
"AwAAAACIjYC3syBDllvs4u4gDG3MtcQVE0tsRQ==",
"AwAAAACIjYC3syBDllvs4u4gDG3MtcQVE0tsRQ==",
"AwAAAACIBYC3syBDllvs4u6gz2zcdcUVS0ysRA==",
"AwAAAADCYoA3pNNBkXMIKNMJSiplJhFOghEFhAAAAAAAAGU=",
"AwAAAACsaIA3p+vCkHsiOIpkJRQgNB8QyRCcxAwhAAAAAABAGQ==",
"AwAAAACEUoA3wNBBkWMIJxRMBMrEIJyELGIIAQAAAAAAyg==",
"AwAAAABLQIC3pGNBk2MaDghSkel4SJFSMnQIAQAAAAAAyg==",
"AwAAAABzIoA38QgBk0sap9jjQvFwZDFDCAAAAAAAQA==",
"AwAAAABf1YC3DUGBkGMGuXk40BtJSotjghAAAAAAAGA=",
"AwAAAAAljoC3NmvBkEsaD4dOwwlNchFDCAAAAAAAUA==",
"AwAAAABQjoA31ECBkFOGteE+ViSvNkwIAQAAAAAA0g==",
"AwAAAAAqpYA3a1IBk3MeMkhEkisIJhZQhqOLGUIAAAAAAIAz",
"AwAAAABDxoC3ZINBkXMEA0KBl9EoUowTAtQDhAAAAAAAAGM=",
"AwAAAADQCIC3y+qAEmCaB3LONQrZ6stiihAAAAAAAGA=",
"AwAAAAB4aIC3z5lBk1saN8zHFMEJCKlMzBACAAAAAACQ",
"AwAAAADvLIC3t9hAkysShLxMKgM=",
"AwAAAAB9BoA34pIAkSsQUgAFBIM=",
"AwAAAAAfmYA37wgBk1sap5fBcYmAShxYzBACAAAAAACk",
//"AwAAAAAZDYC3/mrBkEsaj5NM0xGVIBFDCAAAAAAAMA==",
//"AwAAAAA0qYA3RhkBkWMalJ8AEtSYWC1gJWYIAQAAAAAAyg==",
//"AwAAAABknYA3RhkBkWMalJ8AEtSYWC1gJmYIAQAAAAAAyg==",
//"AwAAAACrOoA3RhkBkWMalJ8AEtSYWC0gJmYIAQAAAAAAyg==",
//"AwAAAADHT4A3rVMBk2tkjwhEwkRYO5cMpwkIAQAAAAAAyA==",
//"AwAAAAAicYC3syBDllvs4u4gGyP7LLHEEkssMQ==",
//"AwAAAAAXDIC31oBBkWMEBcKAJnqQTAdOLWIIAQAAAAAAyA==",
//"AwAAAAD+8YC36JCAkTsKGoSgBASiIg==",
//"AwAAAADDxoC3t9hAkysShLxMKmM=",
//"AwAAAAAxn4C3A/pBkWMGBYLB+IDMbhnFMWYIAQAAAAAAzg==",
//"AwAAAACAxIC37xABkWsIqFPqeE0YjJJYUxUxhAAAAAAAAGQ=",
//"AwAAAADYYIC3t9hAkysShLxMKkM=",
//"AwAAAAA/dIA34pIAkSsQUgAFBGM=",
//"AwAAAAAk0oA34pIAkSsQUgAFBEM=",
//"AwAAAAATnoA34pIAkSsQUgAFBAM=",
//"AwAAAABmoIA34pIAkSsQUgAFBKM=",
//"AwAAAACSJoA3ElwAmCtYUlWPjAA=",
//"AwAAAAAk/YA3ElwAmCtYUlWxjgA=",
//"AwAAAAB00IC33IBBkWMEA0LBZlmkGKfELb4IAQAAAAAAzg==",
//"AwAAAACIjYC3syBDllvs4u4gDG3MtcQVE0tsRQ==",
//"AwAAAACIjYC3syBDllvs4u4gDG3MtcQVE0tsRQ==",
//"AwAAAACIBYC3syBDllvs4u6gz2zcdcUVS0ysRA==",
//"AwAAAADCYoA3pNNBkXMIKNMJSiplJhFOghEFhAAAAAAAAGU=",
//"AwAAAACsaIA3p+vCkHsiOIpkJRQgNB8QyRCcxAwhAAAAAABAGQ==",
//"AwAAAACEUoA3wNBBkWMIJxRMBMrEIJyELGIIAQAAAAAAyg==",
//"AwAAAABLQIC3pGNBk2MaDghSkel4SJFSMnQIAQAAAAAAyg==",
//"AwAAAABzIoA38QgBk0sap9jjQvFwZDFDCAAAAAAAQA==",
//"AwAAAABf1YC3DUGBkGMGuXk40BtJSotjghAAAAAAAGA=",
//"AwAAAAAljoC3NmvBkEsaD4dOwwlNchFDCAAAAAAAUA==",
//"AwAAAABQjoA31ECBkFOGteE+ViSvNkwIAQAAAAAA0g==",
//"AwAAAAAqpYA3a1IBk3MeMkhEkisIJhZQhqOLGUIAAAAAAIAz",
//"AwAAAABDxoC3ZINBkXMEA0KBl9EoUowTAtQDhAAAAAAAAGM=",
//"AwAAAADQCIC3y+qAEmCaB3LONQrZ6stiihAAAAAAAGA=",
//"AwAAAAB4aIC3z5lBk1saN8zHFMEJCKlMzBACAAAAAACQ",
//"AwAAAADvLIC3t9hAkysShLxMKgM=",
//"AwAAAAB9BoA34pIAkSsQUgAFBIM=",
//"AwAAAAAfmYA37wgBk1sap5fBcYmAShxYzBACAAAAAACk",
}

func TestDecryptSerial(t *testing.T) {
for _, check := range checks {
bs, err := base64.StdEncoding.DecodeString(check)
if err != nil {
panic(err)
t.Fatal(err)
}
item, err := DecryptSerial(bs)
if err != nil {
panic(err)
t.Fatal(err)
}
log.Println(item)
}
Expand All @@ -102,11 +102,11 @@ func TestDeserialize(t *testing.T) {
for _, check := range checks {
bs, err := base64.StdEncoding.DecodeString(check)
if err != nil {
panic(err)
t.Fatal(err)
}
item, err := Deserialize(bs)
if err != nil {
panic(err)
t.Fatal(err)
}
log.Println(item)
}
Expand All @@ -121,25 +121,34 @@ func TestSerialize(t *testing.T) {
for i := 0; i < 10; i++ {
bs, err := base64.StdEncoding.DecodeString(result)
if err != nil {
panic(err)
t.Fatal(err)
}
seed, err := GetSeedFromSerial(bs)
if err != nil {
panic(err)
t.Fatal(err)
}
item, err = Deserialize(bs)
if err != nil {
panic(err)
t.Fatal(err)
}
bs, err = Serialize(item, seed)
if err != nil {
panic(err)
t.Fatal(err)
}
result = base64.StdEncoding.EncodeToString(bs)
history[i] = result
i2, err := Deserialize(bs)
if err != nil {
t.Fatal(err)
}
if item.Level != i2.Level || item.Version != i2.Version {
t.Fatal("component mismatch in re-serialized item")
}
}
if result != check {
log.Println(err)
log.Println(check)
log.Println(result)
bs1, _ := base64.StdEncoding.DecodeString(check)
bs2, _ := base64.StdEncoding.DecodeString(result)
log.Println(hex.EncodeToString(bs1))
Expand All @@ -154,7 +163,71 @@ func TestSerialize(t *testing.T) {
i2, _ := Deserialize(bs2)
log.Println(i1.Version)
log.Println(i2.Version)
panic("invalid serial")
t.Fatal("invalid serial")
}
}
}

func TestAddPart(t *testing.T) {
debug = true
code := "AwAAAADuCYA3RhkBkWMalJ8AEtSYWC1gJmYIAQAAAAAAyhgA"
part := "/Game/Gear/Weapons/Pistols/Vladof/_Shared/_Design/Parts/Barrels/Barrel_01/Part_PS_VLA_Barrel_01_B.Part_PS_VLA_Barrel_01_B"
bs, err := base64.StdEncoding.DecodeString(code)
if err != nil {
t.Fatal(err)
}
seed, err := GetSeedFromSerial(bs)
if err != nil {
panic(err)
}
item, err := Deserialize(bs)
if err != nil {
t.Fatal(err)
}
item.Parts = append(item.Parts, part)
bs, err = Serialize(item, seed)
if err != nil {
t.Fatal(err)
}
log.Println(base64.StdEncoding.EncodeToString(bs))
i2, err := Deserialize(bs)
if err != nil {
t.Fatal(err)
}
if len(i2.Parts) != 13 {
t.Fatalf("invalid part length %v", len(i2.Parts))
}

}

func TestAddAnointment(t *testing.T) {
debug = true
code := "AwAAAADuCYA3RhkBkWMalJ8AEtSYWC1gJmYIAQAAAAAAyhgA"
anointment := "/Game/Gear/Weapons/_Shared/_Design/EndGameParts/Character/Operative/CloneSwapDamage/GPart_CloneSwap_WeaponDamage.GPart_CloneSwap_WeaponDamage"
bs, err := base64.StdEncoding.DecodeString(code)
if err != nil {
t.Fatal(err)
}
seed, err := GetSeedFromSerial(bs)
if err != nil {
t.Fatal(err)
}
item, err := Deserialize(bs)
if err != nil {
t.Fatal(err)
}
item.Generics = append(item.Generics, anointment)
bs, err = Serialize(item, seed)
if err != nil {
t.Fatal(err)
}
log.Println(base64.StdEncoding.EncodeToString(bs))
i2, err := Deserialize(bs)
if err != nil {
t.Fatal(err)
}
if len(i2.Generics) != 2 {
t.Fatal("invalid anointment length")
}

}

0 comments on commit d8d4c3b

Please sign in to comment.