]> git.lizzy.rs Git - mt.git/blob - inv.go
Add WaitGroup to SerializePkt
[mt.git] / inv.go
1 package mt
2
3 import (
4         "fmt"
5         "io"
6         "reflect"
7 )
8
9 type Inv []NamedInvList
10
11 type NamedInvList struct {
12         Name string
13         InvList
14 }
15
16 func (inv Inv) List(name string) *NamedInvList {
17         for i, l := range inv {
18                 if l.Name == name {
19                         return &inv[i]
20                 }
21         }
22         return nil
23 }
24
25 func (i Inv) Serialize(w io.Writer) error {
26         return i.SerializeKeep(w, nil)
27 }
28
29 func (i Inv) SerializeKeep(w io.Writer, old Inv) error {
30         ew := &errWriter{w: w}
31
32         for _, l := range i {
33                 var oldList InvList
34                 if l := old.List(l.Name); l != nil {
35                         oldList = l.InvList
36                 }
37
38                 if reflect.DeepEqual(&i, oldList) {
39                         fmt.Fprintln(ew, "KeepList", l.Name)
40                         continue
41                 }
42
43                 fmt.Fprintln(ew, "List", l.Name, len(l.Stacks))
44                 l.SerializeKeep(ew, oldList)
45         }
46         fmt.Fprintln(ew, "EndInventory")
47
48         return ew.err
49 }
50
51 func (i *Inv) Deserialize(r io.Reader) (err error) {
52         s := new(sentinel)
53         defer s.recover(&err)
54
55         old := *i
56         *i = nil
57
58         for {
59                 if err := readCmdLn(r, map[string]interface{}{
60                         "List": func(name string, size int) {
61                                 l := old.List(name)
62                                 if l == nil {
63                                         l = &NamedInvList{Name: name}
64                                 }
65
66                                 if err := l.Deserialize(r); err != nil {
67                                         s.ret(fmt.Errorf("List %s %d: %w", name, size, err))
68                                 }
69                                 if len(l.Stacks) != size {
70                                         s.ret(fmt.Errorf("List %s %d: contains %d stacks", name, size, len(l.Stacks)))
71                                 }
72
73                                 *i = append(*i, *l)
74                         },
75                         "KeepList": func(name string) {
76                                 l := old.List(name)
77                                 if l == nil {
78                                         s.ret(fmt.Errorf("KeepList %s: list does not exist", name))
79                                 }
80
81                                 *i = append(*i, *l)
82                         },
83                         "EndInventory": func() {
84                                 s.ret(nil)
85                         },
86                 }); err != nil {
87                         if err == io.EOF {
88                                 return io.ErrUnexpectedEOF
89                         }
90                         return err
91                 }
92         }
93 }
94
95 type InvList struct {
96         Width  int
97         Stacks []Stack
98 }
99
100 func (l InvList) Serialize(w io.Writer) error {
101         return l.SerializeKeep(w, InvList{})
102 }
103
104 func (l InvList) SerializeKeep(w io.Writer, old InvList) error {
105         ew := &errWriter{w: w}
106
107         fmt.Fprintln(ew, "Width", l.Width)
108         for i, s := range l.Stacks {
109                 if i < len(old.Stacks) && s == old.Stacks[i] {
110                         fmt.Fprintln(ew, "Keep")
111                         continue
112                 }
113
114                 if s.Count > 0 {
115                         fmt.Fprintln(ew, "Item", s)
116                 } else {
117                         fmt.Fprintln(ew, "Empty")
118                 }
119         }
120         fmt.Fprintln(ew, "EndInventoryList")
121
122         return ew.err
123 }
124
125 func (l *InvList) Deserialize(r io.Reader) (err error) {
126         s := new(sentinel)
127         defer s.recover(&err)
128
129         if _, err := fmt.Fscanf(r, "Width %d\n", &l.Width); err != nil {
130                 return err
131         }
132
133         old := l.Stacks
134         l.Stacks = nil
135
136         for {
137                 if err := readCmdLn(r, map[string]interface{}{
138                         "Empty": func() {
139                                 l.Stacks = append(l.Stacks, Stack{})
140                         },
141                         "Item": func(stk Stack) {
142                                 l.Stacks = append(l.Stacks, stk)
143                         },
144                         "Keep": func() {
145                                 if i := len(l.Stacks); i < len(old) {
146                                         l.Stacks = append(l.Stacks, old[i])
147                                 } else {
148                                         l.Stacks = append(l.Stacks, Stack{})
149                                 }
150                         },
151                         "EndInventoryList": func() {
152                                 s.ret(nil)
153                         },
154                 }); err != nil {
155                         if err == io.EOF {
156                                 return io.ErrUnexpectedEOF
157                         }
158                         return err
159                 }
160         }
161 }
162
163 func readCmdLn(r io.Reader, cmds map[string]interface{}) error {
164         if _, ok := r.(io.RuneScanner); !ok {
165                 r = &readRune{Reader: r, peekRune: -1}
166         }
167
168         var cmd string
169         if _, err := fmt.Fscan(r, &cmd); err != nil {
170                 return err
171         }
172
173         f, ok := cmds[cmd]
174         if !ok {
175                 return fmt.Errorf("unsupported line type: %+q", cmd)
176         }
177
178         t := reflect.TypeOf(f)
179
180         a := make([]interface{}, t.NumIn())
181         for i := range a {
182                 a[i] = reflect.New(t.In(i)).Interface()
183         }
184         fmt.Fscanln(r, a...)
185
186         args := make([]reflect.Value, t.NumIn())
187         for i := range args {
188                 args[i] = reflect.ValueOf(a[i]).Elem()
189         }
190         reflect.ValueOf(f).Call(args)
191
192         return nil
193 }
194
195 type sentinel struct {
196         err error
197 }
198
199 func (s *sentinel) ret(err error) {
200         s.err = err
201         panic(s)
202 }
203
204 func (s *sentinel) recover(p *error) {
205         if r := recover(); r != nil {
206                 if r == s {
207                         *p = s.err
208                 } else {
209                         panic(r)
210                 }
211         }
212 }
213
214 type errWriter struct {
215         w   io.Writer
216         err error
217 }
218
219 func (ew *errWriter) Write(p []byte) (int, error) {
220         if ew.err != nil {
221                 return 0, ew.err
222         }
223
224         n, err := ew.w.Write(p)
225         if err != nil {
226                 ew.err = err
227         }
228         return n, err
229 }