Files
GaCy-GO/internal/common/currency_wars_commands.go
T
2026-10-28 18:54:43 +07:00

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)
}