104 lines
2.8 KiB
Go
104 lines
2.8 KiB
Go
package common
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// Commands are separate from the run revision. The live game session applies
|
|
// them only during Preparation, so a web command cannot invalidate settlement.
|
|
type CurrencyWarsCommand struct {
|
|
ID string `json:"id"`
|
|
UID uint32 `json:"uid"`
|
|
RunID uint32 `json:"run_id"`
|
|
Field string `json:"field"`
|
|
Value uint32 `json:"value"`
|
|
Quantity uint32 `json:"quantity,omitempty"`
|
|
Star uint32 `json:"star,omitempty"`
|
|
}
|
|
|
|
func ReadCurrencyWarsCommands() ([]CurrencyWarsCommand, error) {
|
|
root, err := readCurrencyWarsPersistentRoot()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var commands []CurrencyWarsCommand
|
|
if raw, ok := root["currency_wars_commands"]; ok {
|
|
err = json.Unmarshal(raw, &commands)
|
|
}
|
|
return commands, err
|
|
}
|
|
|
|
func QueueCurrencyWarsCommand(uid, runID uint32, field string, value uint32) (string, error) {
|
|
return QueueCurrencyWarsGrant(uid, runID, field, value, 1, 0)
|
|
}
|
|
|
|
func QueueCurrencyWarsGrant(uid, runID uint32, field string, value, quantity, star uint32) (string, error) {
|
|
if uid == 0 || runID == 0 || quantity == 0 || (field != "gold" && field != "hp" && field != "exp" && field != "equip" && field != "role" && field != "orb" && field != "consumable" && field != "forge") {
|
|
return "", fmt.Errorf("invalid CW command")
|
|
}
|
|
var nonce [16]byte
|
|
if _, err := rand.Read(nonce[:]); err != nil {
|
|
return "", err
|
|
}
|
|
id := hex.EncodeToString(nonce[:])
|
|
persistentWriteMu.Lock()
|
|
defer persistentWriteMu.Unlock()
|
|
unlock, err := lockPersistentFile()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer unlock()
|
|
root, err := readCurrencyWarsPersistentRoot()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
var commands []CurrencyWarsCommand
|
|
if raw, ok := root["currency_wars_commands"]; ok {
|
|
if err = json.Unmarshal(raw, &commands); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
commands = append(commands, CurrencyWarsCommand{ID: id, UID: uid, RunID: runID, Field: field, Value: value, Quantity: quantity, Star: star})
|
|
raw, err := json.Marshal(commands)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
root["currency_wars_commands"] = raw
|
|
return id, writeJSONAtomic("persistent", root)
|
|
}
|
|
|
|
func AcknowledgeCurrencyWarsCommand(id string) error {
|
|
persistentWriteMu.Lock()
|
|
defer persistentWriteMu.Unlock()
|
|
unlock, err := lockPersistentFile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer unlock()
|
|
root, err := readCurrencyWarsPersistentRoot()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var commands []CurrencyWarsCommand
|
|
if raw, ok := root["currency_wars_commands"]; ok {
|
|
if err = json.Unmarshal(raw, &commands); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
remaining := commands[:0]
|
|
for _, c := range commands {
|
|
if c.ID != id {
|
|
remaining = append(remaining, c)
|
|
}
|
|
}
|
|
raw, err := json.Marshal(remaining)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
root["currency_wars_commands"] = raw
|
|
return writeJSONAtomic("persistent", root)
|
|
}
|