]> git.lizzy.rs Git - mt.git/blob - toolcaps_json.go
Add WaitGroup to SerializePkt
[mt.git] / toolcaps_json.go
1 package mt
2
3 import (
4         "bytes"
5         "encoding/json"
6         "errors"
7         "fmt"
8         "strconv"
9 )
10
11 func (tc ToolCaps) String() string {
12         b, err := tc.MarshalJSON()
13         if err != nil {
14                 panic(err)
15         }
16
17         return string(b)
18 }
19
20 func (tc ToolCaps) MarshalJSON() ([]byte, error) {
21         if !tc.NonNil {
22                 return []byte("null"), nil
23         }
24
25         var dgs bytes.Buffer
26         dgs.WriteByte('{')
27         e := json.NewEncoder(&dgs)
28         for i, dg := range tc.DmgGroups {
29                 e.Encode(dg.Name)
30                 dgs.WriteByte(':')
31                 e.Encode(dg.Rating)
32                 if i < len(tc.DmgGroups)-1 {
33                         dgs.WriteByte(',')
34                 }
35         }
36         dgs.WriteByte('}')
37
38         var gcs bytes.Buffer
39         gcs.WriteByte('{')
40         e = json.NewEncoder(&gcs)
41         for i, gc := range tc.GroupCaps {
42                 var maxRating int16
43                 for _, t := range gc.Times {
44                         if t.Rating >= maxRating {
45                                 maxRating = t.Rating + 1
46                         }
47                 }
48
49                 times := make([]interface{}, maxRating)
50                 for _, t := range gc.Times {
51                         times[t.Rating] = fmtFloat(t.Time)
52                 }
53
54                 e.Encode(gc.Name)
55                 gcs.WriteByte(':')
56                 e.Encode(map[string]interface{}{
57                         "uses":     gc.Uses,
58                         "maxlevel": gc.MaxLvl,
59                         "times":    times,
60                 })
61                 if i < len(tc.GroupCaps)-1 {
62                         gcs.WriteByte(',')
63                 }
64         }
65         gcs.WriteByte('}')
66
67         return json.Marshal(map[string]interface{}{
68                 "damage_groups":       json.RawMessage(dgs.Bytes()),
69                 "full_punch_interval": fmtFloat(tc.AttackCooldown),
70                 "groupcaps":           json.RawMessage(gcs.Bytes()),
71                 "max_drop_level":      tc.MaxDropLvl,
72                 "punch_attack_uses":   tc.PunchUses,
73         })
74 }
75
76 func (tc *ToolCaps) UnmarshalJSON(data []byte) error {
77         d := json.NewDecoder(bytes.NewReader(data))
78
79         t, err := d.Token()
80         if err != nil {
81                 return err
82         }
83         if t == nil {
84                 *tc = ToolCaps{}
85                 return nil
86         }
87         if d, ok := t.(json.Delim); !ok || d != '{' {
88                 return errors.New("not an object")
89         }
90         for d.More() {
91                 t, err := d.Token()
92                 if err != nil {
93                         return err
94                 }
95                 key := t.(string)
96
97                 err = nil
98                 switch key {
99                 case "full_punch_interval":
100                         err = d.Decode(&tc.AttackCooldown)
101                 case "max_drop_level":
102                         err = d.Decode(&tc.MaxDropLvl)
103                 case "groupcaps":
104                         tc.GroupCaps = nil
105
106                         t, err := d.Token()
107                         if err != nil {
108                                 return fmt.Errorf("groupcaps: %w", err)
109                         }
110                         if d, ok := t.(json.Delim); !ok || d != '{' {
111                                 return errors.New("groupcaps: not an object")
112                         }
113                         for d.More() {
114                                 var gc ToolGroupCap
115
116                                 t, err := d.Token()
117                                 if err != nil {
118                                         return fmt.Errorf("groupcaps: %w", err)
119                                 }
120                                 gc.Name = t.(string)
121
122                                 t, err = d.Token()
123                                 if err != nil {
124                                         return fmt.Errorf("groupcaps: %w", err)
125                                 }
126                                 if d, ok := t.(json.Delim); !ok || d != '{' {
127                                         return errors.New("groupcaps: not an object")
128                                 }
129                                 for d.More() {
130                                         t, err := d.Token()
131                                         if err != nil {
132                                                 return fmt.Errorf("groupcaps: %w", err)
133                                         }
134                                         key := t.(string)
135
136                                         err = nil
137                                         switch key {
138                                         case "uses":
139                                                 err = d.Decode(&gc.Uses)
140                                         case "maxlevel":
141                                                 err = d.Decode(&gc.MaxLvl)
142                                         case "times":
143                                                 gc.Times = nil
144
145                                                 t, err := d.Token()
146                                                 if err != nil {
147                                                         return fmt.Errorf("groupcaps: times: %w", err)
148                                                 }
149                                                 if d, ok := t.(json.Delim); !ok || d != '[' {
150                                                         return errors.New("groupcaps: times: not an array")
151                                                 }
152                                                 for i := int16(0); d.More(); i++ {
153                                                         t, err := d.Token()
154                                                         if err != nil {
155                                                                 return fmt.Errorf("groupcaps: times: %w", err)
156                                                         }
157                                                         switch t := t.(type) {
158                                                         case nil:
159                                                         case float64:
160                                                                 gc.Times = append(gc.Times, DigTime{i, float32(t)})
161                                                         default:
162                                                                 return errors.New("groupcaps: times: not null or a number")
163                                                         }
164                                                 }
165                                                 _, err = d.Token()
166                                         }
167                                         if err != nil {
168                                                 return fmt.Errorf("groupcaps: %s: %w", key, err)
169                                         }
170                                 }
171                                 if _, err := d.Token(); err != nil {
172                                         return err
173                                 }
174                                 tc.GroupCaps = append(tc.GroupCaps, gc)
175                         }
176                         _, err = d.Token()
177                 case "damage_groups":
178                         tc.DmgGroups = nil
179
180                         t, err := d.Token()
181                         if err != nil {
182                                 return fmt.Errorf("damage_groups: %w", err)
183                         }
184                         if d, ok := t.(json.Delim); !ok || d != '{' {
185                                 return errors.New("damage_groups: not an object")
186                         }
187                         for d.More() {
188                                 var g Group
189
190                                 t, err := d.Token()
191                                 if err != nil {
192                                         return err
193                                 }
194                                 g.Name = t.(string)
195
196                                 if err := d.Decode(&g.Rating); err != nil {
197                                         return fmt.Errorf("damage_groups: %w", err)
198                                 }
199
200                                 tc.DmgGroups = append(tc.DmgGroups, g)
201                         }
202                         _, err = d.Token()
203                 case "punch_attack_uses":
204                         err = d.Decode(&tc.PunchUses)
205                 }
206                 if err != nil {
207                         return fmt.Errorf("%s: %w", key, err)
208                 }
209         }
210         if _, err := d.Token(); err != nil {
211                 return err
212         }
213
214         tc.NonNil = true
215         return nil
216 }
217
218 func fmtFloat(f float32) json.Number {
219         buf := make([]byte, 0, 24)
220         buf = strconv.AppendFloat(buf, float64(f), 'g', 17, 32)
221         if !bytes.ContainsRune(buf, '.') {
222                 buf = append(buf, '.', '0')
223         }
224         return json.Number(buf)
225 }