Skip to content

Commit cccae0a

Browse files
author
Kalle Fagerberg
committed
Replace protobuf with encoding/binary implementation
1 parent 82266b6 commit cccae0a

8 files changed

Lines changed: 239 additions & 693 deletions

File tree

REUSE.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ version = 1
77
[[annotations]]
88
path = [
99
"**/*.go",
10-
"**/*.proto",
1110
"assets/*.png",
1211
"assets/*.pxo",
1312
]

go.mod

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,7 @@ module github.com/applejag/epic-wizard-firefly-gladiators
33
go 1.25.5
44

55
require (
6-
github.com/aperturerobotics/protobuf-go-lite v0.11.0
76
github.com/applejag/firefly-go-math v0.2.0
87
github.com/firefly-zero/firefly-go v0.10.0
98
github.com/orsinium-labs/tinymath v1.1.0
109
)
11-
12-
require google.golang.org/protobuf v1.36.11 // indirect
13-
14-
tool (
15-
github.com/aperturerobotics/protobuf-go-lite/cmd/protoc-gen-go-lite
16-
google.golang.org/protobuf/cmd/protoc-gen-go
17-
)

go.sum

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
github.com/aperturerobotics/protobuf-go-lite v0.11.0 h1:IAaZISqrEpodqECYxk0yKWgROEbZtMhs7bErP+Zma9o=
2-
github.com/aperturerobotics/protobuf-go-lite v0.11.0/go.mod h1:c4kGy7Dkfz6B1m0t4QBIMQoNeQ7m+nYj3Qxxnlwhygo=
31
github.com/applejag/firefly-go-math v0.2.0 h1:IiDXTbHpLDU8LR8LP3RKGpyUA59mQp2HwAdkDyLLask=
42
github.com/applejag/firefly-go-math v0.2.0/go.mod h1:XbmMPAO9vDIYvwAJIPlY6HE0m1RZ3tXgn3GP9agFXos=
53
github.com/firefly-zero/firefly-go v0.10.0 h1:CFEVPrXdLCZYgMna2DMncZ+lR01xg3danlXtIw+dJkE=
64
github.com/firefly-zero/firefly-go v0.10.0/go.mod h1:+X/XGyPdES51OESkV8NSf1mszEBZionoROM7x2pBofw=
7-
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
8-
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
95
github.com/orsinium-labs/tinymath v1.1.0 h1:KomdsyLHB7vE3f1nRAJF2dyf1m/gnM2HxfTeV1vS5UA=
106
github.com/orsinium-labs/tinymath v1.1.0/go.mod h1:WPXX6ei3KSXG7JfA03a+ekCYaY9SWN4I+JRl2p6ck+A=
11-
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
12-
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=

mise.toml

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,15 @@
55
[tools]
66
uv = "latest"
77
"pipx:reuse" = "latest"
8-
protoc = "33.4"
9-
protoc-gen-go = "1.36.11"
108
"aqua:tinygo-org/tinygo" = "0.40.1"
119
"github:firefly-zero/firefly-cli"= { version = "0.15.8", rename_exe = "ff" }
1210
"github:firefly-zero/firefly-emulator" = "0.9.8"
1311
"github:wwwg/wasmdec" = "latest"
1412
golangci-lint = "2.8.0"
1513

16-
[tasks."install:tools"]
17-
description = "Install protoc plugins"
18-
run = "go install tool"
19-
20-
[tasks."build:generate"]
21-
# using https://github.com/aperturerobotics/protobuf-go-lite
22-
description = "Generate protobuf files"
23-
run = """
24-
: "${GOBIN:="$(go env GOBIN)"}"
25-
: "${GOBIN:="$(go env GOPATH)/bin"}"
26-
protoc \
27-
--go-lite_out=proto --plugin protoc-gen-go-lite="${GOBIN}/protoc-gen-go-lite" \
28-
--go-lite_opt=features=size+marshal+unmarshal \
29-
proto/game/v1/gamestate.proto
30-
"""
31-
sources = ['proto/game/v1/*.proto']
32-
outputs = ['proto/game/v1/*.go']
33-
depends = ['install:tools']
34-
3514
[tasks.build]
3615
description = "Build the game using firefly CLI"
3716
run = "ff build"
38-
depends = ['build:generate']
3917

4018
[tasks."debug:print-allocs"]
4119
description = "Build with tinygo and print allocations"

pkg/state/state.go

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"strconv"
55

66
"github.com/applejag/epic-wizard-firefly-gladiators/pkg/util"
7-
gamev1 "github.com/applejag/epic-wizard-firefly-gladiators/proto/game/v1"
87
"github.com/applejag/firefly-go-math/ffrand"
98

109
"github.com/firefly-zero/firefly-go/firefly"
@@ -73,34 +72,19 @@ func (g *GameState) RemoveMyFireflyFromRaceBattle() {
7372
}
7473

7574
func (g *GameState) Save() {
76-
state := gamev1.Save{
77-
Fireflies: make([]*gamev1.Firefly, len(g.Fireflies)),
78-
BattlesWonTotal: int32(g.BattlesWonTotal),
79-
BattlesPlayedTotal: int32(g.BattlesPlayedTotal),
80-
Money: int32(g.Money),
81-
}
82-
for i, f := range g.Fireflies {
83-
state.Fireflies[i] = &gamev1.Firefly{
84-
Id: int32(f.ID),
85-
Name: int32(f.Name),
86-
Speed: int32(f.Speed),
87-
Nimbleness: int32(f.Nimbleness),
88-
BattlesWon: int32(f.BattlesWon),
89-
BattlesPlayed: int32(f.BattlesPlayed),
90-
}
91-
}
92-
b, err := state.MarshalVT()
75+
var saveBuf [100]byte
76+
save, err := g.AppendBinary(saveBuf[:0])
9377
if err != nil {
94-
panic("failed to marshal save file")
78+
firefly.LogError("failed to save: " + err.Error())
79+
return
9580
}
96-
firefly.DumpFile("save", b)
81+
firefly.DumpFile("save", save)
9782

9883
var buf [len("saved game, size: ") + 10 + len(" B")]byte
9984
index := copy(buf[0:], "saved game, size: ")
100-
index += util.FormatIntInto(buf[index:], len(b))
85+
index += util.FormatIntInto(buf[index:], len(save))
10186
index += copy(buf[index:], " B")
10287
util.LogDebugBytes(buf[:index])
103-
panic(12345678)
10488
}
10589

10690
func (g *GameState) HasSave() bool {
@@ -112,28 +96,12 @@ func (g *GameState) LoadSave() bool {
11296
if !file.Exists() {
11397
return false
11498
}
115-
var state gamev1.Save
116-
if err := state.UnmarshalVT(file.Raw); err != nil {
99+
g.Reset()
100+
if err := g.UnmarshalBinary(file.Raw); err != nil {
117101
firefly.LogError("failed to load save: " + err.Error())
118102
return false
119103
}
120104

121-
g.Reset()
122-
g.BattlesPlayedTotal = int(state.BattlesPlayedTotal)
123-
g.BattlesWonTotal = int(state.BattlesWonTotal)
124-
g.Money = int(state.Money)
125-
g.Fireflies = make([]Firefly, len(state.Fireflies))
126-
for i, f := range state.Fireflies {
127-
g.Fireflies[i] = Firefly{
128-
ID: int(f.Id),
129-
Name: util.Name(f.Name),
130-
Speed: int(f.Speed),
131-
Nimbleness: int(f.Nimbleness),
132-
BattlesWon: int(f.BattlesWon),
133-
BattlesPlayed: int(f.BattlesPlayed),
134-
}
135-
}
136-
137105
firefly.LogDebug("loaded saved game, size: " + strconv.Itoa(len(file.Raw)) + " B")
138106
return true
139107
}

pkg/state/state_marshal.go

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
package state
2+
3+
import (
4+
"bytes"
5+
"encoding"
6+
"encoding/binary"
7+
"errors"
8+
"io"
9+
"strconv"
10+
11+
"github.com/applejag/epic-wizard-firefly-gladiators/pkg/util"
12+
)
13+
14+
type FieldError struct {
15+
Field string
16+
Err error
17+
}
18+
19+
func (err FieldError) Error() string {
20+
return err.Field + ": " + err.Err.Error()
21+
}
22+
23+
func (err FieldError) Unwrap() error {
24+
return err.Err
25+
}
26+
27+
type IndexedFieldError struct {
28+
Field string
29+
Index int
30+
Err error
31+
}
32+
33+
func (err IndexedFieldError) Error() string {
34+
return err.Field + "[" + strconv.Itoa(err.Index) + "]: " + err.Err.Error()
35+
}
36+
37+
func (err IndexedFieldError) Unwrap() error {
38+
return err.Err
39+
}
40+
41+
// Arbitrary number, mostly for future-proofing
42+
const FileMarker byte = 0x37
43+
44+
type FieldState byte
45+
46+
const (
47+
FieldStateUnknown FieldState = 0
48+
FieldStateFireflies FieldState = 1
49+
FieldStateBattlesWonTotal FieldState = 2
50+
FieldStateBattlesPlayedTotal FieldState = 3
51+
FieldStateMoney FieldState = 4
52+
)
53+
54+
var (
55+
_ encoding.BinaryAppender = &GameState{}
56+
_ encoding.BinaryUnmarshaler = &GameState{}
57+
)
58+
59+
// UnmarshalBinary implements [encoding.BinaryUnmarshaler].
60+
func (g *GameState) UnmarshalBinary(data []byte) error {
61+
buf := bytes.NewBuffer(data)
62+
63+
if marker, err := buf.ReadByte(); err != nil || marker != FileMarker {
64+
return errors.New("invalid save file marker")
65+
}
66+
67+
for {
68+
next, err := buf.ReadByte()
69+
if err != nil {
70+
if err == io.EOF {
71+
return nil
72+
}
73+
return err
74+
}
75+
76+
switch FieldState(next) {
77+
case FieldStateBattlesPlayedTotal:
78+
val, err := binary.ReadUvarint(buf)
79+
if err != nil {
80+
return FieldError{Field: "GameState.BattlesPlayedTotal", Err: err}
81+
}
82+
g.BattlesPlayedTotal = int(val)
83+
case FieldStateBattlesWonTotal:
84+
val, err := binary.ReadUvarint(buf)
85+
if err != nil {
86+
return FieldError{Field: "GameState.BattlesWonTotal", Err: err}
87+
}
88+
g.BattlesWonTotal = int(val)
89+
case FieldStateMoney:
90+
val, err := binary.ReadUvarint(buf)
91+
if err != nil {
92+
return FieldError{Field: "GameState.Money", Err: err}
93+
}
94+
g.Money = int(val)
95+
case FieldStateFireflies:
96+
val, err := binary.ReadUvarint(buf)
97+
if err != nil {
98+
return FieldError{Field: "GameState.Fireflies.len", Err: err}
99+
}
100+
if val > 99 {
101+
return FieldError{Field: "GameState.Fireflies.len", Err: errors.New("too many fireflies")}
102+
}
103+
g.Fireflies = make([]Firefly, val)
104+
for i := range int(val) {
105+
if err := g.Fireflies[i].UnmarshalBinaryBuf(buf); err != nil {
106+
return IndexedFieldError{Field: "GameState.Fireflies", Index: i, Err: err}
107+
}
108+
}
109+
default:
110+
return errors.New("unexpected game state field")
111+
}
112+
}
113+
}
114+
115+
// AppendBinary implements [encoding.BinaryAppender].
116+
func (g *GameState) AppendBinary(b []byte) ([]byte, error) {
117+
b = append(b, FileMarker)
118+
119+
b = append(b, byte(FieldStateFireflies))
120+
b = binary.AppendUvarint(b, uint64(len(g.Fireflies)))
121+
for i := range g.Fireflies {
122+
var err error
123+
b, err = g.Fireflies[i].AppendBinary(b)
124+
if err != nil {
125+
return b, IndexedFieldError{Field: "GameState.Fireflies", Index: i, Err: err}
126+
}
127+
}
128+
129+
b = append(b, byte(FieldStateBattlesWonTotal))
130+
b = binary.AppendUvarint(b, uint64(g.BattlesWonTotal))
131+
b = append(b, byte(FieldStateBattlesPlayedTotal))
132+
b = binary.AppendUvarint(b, uint64(g.BattlesPlayedTotal))
133+
b = append(b, byte(FieldStateMoney))
134+
b = binary.AppendUvarint(b, uint64(g.Money))
135+
136+
return b, nil
137+
}
138+
139+
type FieldFirefly byte
140+
141+
const (
142+
FieldFireflyEOF FieldFirefly = 0
143+
FieldFireflyID FieldFirefly = 1
144+
FieldFireflyName FieldFirefly = 2
145+
FieldFireflySpeed FieldFirefly = 3
146+
FieldFireflyNimbleness FieldFirefly = 4
147+
FieldFireflyBattlesPlayed FieldFirefly = 5
148+
FieldFireflyBattlesWon FieldFirefly = 6
149+
FieldFireflyHat FieldFirefly = 7
150+
)
151+
152+
func (f *Firefly) UnmarshalBinaryBuf(buf *bytes.Buffer) error {
153+
for {
154+
next, err := buf.ReadByte()
155+
if err != nil {
156+
if err == io.EOF {
157+
return nil
158+
}
159+
return err
160+
}
161+
162+
switch FieldFirefly(next) {
163+
case FieldFireflyID:
164+
val, err := binary.ReadUvarint(buf)
165+
if err != nil {
166+
return FieldError{Field: "Firefly.ID", Err: err}
167+
}
168+
f.ID = int(val)
169+
case FieldFireflyName:
170+
val, err := binary.ReadUvarint(buf)
171+
if err != nil {
172+
return FieldError{Field: "Firefly.Name", Err: err}
173+
}
174+
f.Name = util.Name(val)
175+
case FieldFireflySpeed:
176+
val, err := binary.ReadUvarint(buf)
177+
if err != nil {
178+
return FieldError{Field: "Firefly.Speed", Err: err}
179+
}
180+
f.Speed = int(val)
181+
case FieldFireflyNimbleness:
182+
val, err := binary.ReadUvarint(buf)
183+
if err != nil {
184+
return FieldError{Field: "Firefly.Nimbleness", Err: err}
185+
}
186+
f.Nimbleness = int(val)
187+
case FieldFireflyBattlesPlayed:
188+
val, err := binary.ReadUvarint(buf)
189+
if err != nil {
190+
return FieldError{Field: "Firefly.BattlesPlayed", Err: err}
191+
}
192+
f.BattlesPlayed = int(val)
193+
case FieldFireflyBattlesWon:
194+
val, err := binary.ReadUvarint(buf)
195+
if err != nil {
196+
return FieldError{Field: "Firefly.BattlesWon", Err: err}
197+
}
198+
f.BattlesWon = int(val)
199+
case FieldFireflyHat:
200+
val, err := binary.ReadUvarint(buf)
201+
if err != nil {
202+
return FieldError{Field: "Firefly.Hat", Err: err}
203+
}
204+
f.Hat = int(val)
205+
case FieldFireflyEOF:
206+
return nil
207+
default:
208+
return errors.New("unexpected firefly field")
209+
}
210+
}
211+
}
212+
213+
// AppendBinary implements [encoding.BinaryAppender].
214+
func (f *Firefly) AppendBinary(b []byte) ([]byte, error) {
215+
b = append(b, byte(FieldFireflyID))
216+
b = binary.AppendUvarint(b, uint64(f.ID))
217+
b = append(b, byte(FieldFireflyName))
218+
b = binary.AppendUvarint(b, uint64(f.Name))
219+
b = append(b, byte(FieldFireflySpeed))
220+
b = binary.AppendUvarint(b, uint64(f.Speed))
221+
b = append(b, byte(FieldFireflyNimbleness))
222+
b = binary.AppendUvarint(b, uint64(f.Nimbleness))
223+
b = append(b, byte(FieldFireflyBattlesPlayed))
224+
b = binary.AppendUvarint(b, uint64(f.BattlesPlayed))
225+
b = append(b, byte(FieldFireflyBattlesWon))
226+
b = binary.AppendUvarint(b, uint64(f.BattlesWon))
227+
b = append(b, byte(FieldFireflyHat))
228+
b = binary.AppendUvarint(b, uint64(f.Hat))
229+
230+
return append(b, byte(FieldFireflyEOF)), nil
231+
}

0 commit comments

Comments
 (0)