-
Notifications
You must be signed in to change notification settings - Fork 0
/
deck.go
116 lines (108 loc) · 3.45 KB
/
deck.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package gathering
import (
"encoding/json"
"strconv"
)
// ArenaDeck is our format for an Arena Deck
// Arena has changed the deck format, sometimes it has
// the old version of json objects for cards, sometimes it now contains
// a list of `ints`, pairs of card number and quantity.
// We handle both
type ArenaDeck struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Format string `json:"format"`
DeckTileID int `json:"deckTileId"`
MainDeck []ArenaDeckCard `json:"mainDeck"`
Sideboard []ArenaDeckCard `json:"sideboard"`
CardSkins []*ArenaDeckCardSkin `json:"cardSkins"`
CardBack string `json:"cardBack"`
}
// ArenaDeckCardSkin contains which cards have which skins
type ArenaDeckCardSkin struct {
GrpID int `json:"grpId"`
CCV string `json:"ccv"` // No idea what this is
}
// ArenaDeckCard is our representation of the card
// This is not always what the log has, but we normalize it to
// this structure when we parse the JSON
type ArenaDeckCard struct {
ID int `json:"id"`
Quantity int `json:"quantity"`
}
// UnmarshalJSON handles both strange cases of the deck format
// and normalizes it to what we expect
func (d *ArenaDeck) UnmarshalJSON(data []byte) error {
var deck map[string]interface{}
if err := json.Unmarshal(data, &deck); err != nil {
return err
}
if _, ok := deck["id"]; !ok {
return nil
}
d.ID = deck["id"].(string)
if name, ok := deck["name"].(string); ok {
d.Name = name
}
if description, ok := deck["description"].(string); ok {
d.Description = description
}
if format, ok := deck["format"].(string); ok {
d.Format = format
}
if deckTile, ok := deck["deckTileId"].(float64); ok {
d.DeckTileID = int(deckTile)
}
if cardBack, ok := deck["cardBack"].(string); ok {
d.CardBack = cardBack
}
d.MainDeck = getCards(deck["mainDeck"])
d.Sideboard = getCards(deck["sideboard"])
return nil
}
// getCards takes an ambiguous array from the log and
// turns it into our ArenaDeckCard. This is a little ugly, but the format is
// either: [int, int, int, int] (id, quantity) or,
// { id: "id", quantity: num }
func getCards(cards interface{}) []ArenaDeckCard {
final := []ArenaDeckCard{}
if array, ok := cards.([]interface{}); ok {
for i := 0; i < len(array); i++ {
val := array[i]
switch val.(type) {
case float64:
final = append(final, ArenaDeckCard{
ID: int(val.(float64)),
Quantity: int(array[i+1].(float64)),
})
i++
case map[string]interface{}:
var id int
switch val.(map[string]interface{})["id"].(type) {
case string:
id, _ = strconv.Atoi(val.(map[string]interface{})["id"].(string))
case float64:
id = int(val.(map[string]interface{})["id"].(float64))
}
final = append(final, ArenaDeckCard{
ID: id,
Quantity: int(val.(map[string]interface{})["quantity"].(float64)),
})
}
}
}
return final
}
// IsArenaDecks checks if a segment contains Arena Decks
func (s *Segment) IsArenaDecks() bool {
return s.SegmentType == DeckGetDeckLists
}
// ParseArenaDecks parses out arena decks from a segment if present.
// Note, it is the caller's responsibility to check if this segment contains
// ArenaDecks by calling `IsArenaDecks()`
func (s *Segment) ParseArenaDecks() ([]ArenaDeck, error) {
var decks []ArenaDeck
err := json.Unmarshal(stripNonJSON(s.Text), &decks)
return decks, err
}