Update GaCy-GO
This commit is contained in:
1 parent
da8a32f60d
commit
0cbe460e49
345 files changed
+98202
-77559
No files matched your search
@@ -17,12 +17,20 @@ var ErrCurrencyWarsSaveConflict = errors.New("CW save changed in another session
|
||||
// WireData is a serialized GridFightGetDataScRsp, retaining unknown protocol
|
||||
// fields. UID and Client identity prevent restoring a different account/schema.
|
||||
type CurrencyWarsSnapshot struct {
|
||||
FormatVersion uint32 `json:"format_version"`
|
||||
UID uint32 `json:"uid"`
|
||||
ClientVersion string `json:"client_version"`
|
||||
AssemblySHA256 string `json:"assembly_sha256"`
|
||||
Revision uint64 `json:"revision"`
|
||||
WireData []byte `json:"wire_data"`
|
||||
FormatVersion uint32 `json:"format_version"`
|
||||
UID uint32 `json:"uid"`
|
||||
ClientVersion string `json:"client_version"`
|
||||
AssemblySHA256 string `json:"assembly_sha256"`
|
||||
Revision uint64 `json:"revision"`
|
||||
WireData []byte `json:"wire_data"`
|
||||
Runtime *CurrencyWarsRuntimeState `json:"runtime,omitempty"`
|
||||
}
|
||||
|
||||
// Server-side rules are kept beside, never smuggled into, the Client protocol.
|
||||
// RunID prevents a rule from a finished run leaking into a later challenge.
|
||||
type CurrencyWarsRuntimeState struct {
|
||||
RunID uint32 `json:"run_id"`
|
||||
Rules map[string]uint32 `json:"rules,omitempty"`
|
||||
}
|
||||
|
||||
func (s *CurrencyWarsSnapshot) validate() error {
|
||||
@@ -85,6 +93,19 @@ func readCurrencyWarsPersistentRoot() (map[string]json.RawMessage, error) {
|
||||
// stale game session from overwriting a later run. The caller must validate
|
||||
// the protocol payload before committing; reads do not perform migration.
|
||||
func CommitCurrencyWarsSnapshot(expectedRevision uint64, next CurrencyWarsSnapshot) (uint64, error) {
|
||||
return commitCurrencyWarsSnapshot(expectedRevision, next, "")
|
||||
}
|
||||
|
||||
// A grant and its queue acknowledgement share one atomic file replacement.
|
||||
// A crash or disconnect cannot replay an already committed additive grant.
|
||||
func CommitCurrencyWarsCommand(expectedRevision uint64, next CurrencyWarsSnapshot, commandID string) (uint64, error) {
|
||||
if commandID == "" {
|
||||
return 0, fmt.Errorf("CW command ID missing")
|
||||
}
|
||||
return commitCurrencyWarsSnapshot(expectedRevision, next, commandID)
|
||||
}
|
||||
|
||||
func commitCurrencyWarsSnapshot(expectedRevision uint64, next CurrencyWarsSnapshot, commandID string) (uint64, error) {
|
||||
if err := next.validate(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -107,7 +128,11 @@ func CommitCurrencyWarsSnapshot(expectedRevision uint64, next CurrencyWarsSnapsh
|
||||
}
|
||||
key := strconv.FormatUint(uint64(next.UID), 10)
|
||||
var revision uint64
|
||||
var previousFields map[string]json.RawMessage
|
||||
if raw, exists := accounts[key]; exists {
|
||||
if err := json.Unmarshal(raw, &previousFields); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var previous CurrencyWarsSnapshot
|
||||
if err := json.Unmarshal(raw, &previous); err != nil {
|
||||
return 0, err
|
||||
@@ -119,6 +144,9 @@ func CommitCurrencyWarsSnapshot(expectedRevision uint64, next CurrencyWarsSnapsh
|
||||
return 0, fmt.Errorf("CW snapshot source differs; migration is required")
|
||||
}
|
||||
revision = previous.Revision
|
||||
if next.Runtime != nil && previous.Runtime != nil && next.Runtime.RunID == previous.Runtime.RunID && next.Runtime.Rules == nil {
|
||||
next.Runtime.Rules = previous.Runtime.Rules
|
||||
}
|
||||
}
|
||||
if revision != expectedRevision {
|
||||
return 0, ErrCurrencyWarsSaveConflict
|
||||
@@ -127,7 +155,48 @@ func CommitCurrencyWarsSnapshot(expectedRevision uint64, next CurrencyWarsSnapsh
|
||||
return 0, fmt.Errorf("CW snapshot revision exhausted")
|
||||
}
|
||||
next.Revision = revision + 1
|
||||
accounts[key], err = json.Marshal(next)
|
||||
// Retain unrelated envelope fields added by tools or a newer writer.
|
||||
encoded, err := json.Marshal(next)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var nextFields map[string]json.RawMessage
|
||||
if err = json.Unmarshal(encoded, &nextFields); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if next.Runtime != nil && previousFields != nil {
|
||||
var oldRuntime map[string]json.RawMessage
|
||||
var oldRunID uint32
|
||||
if raw := previousFields["runtime"]; len(raw) != 0 && json.Unmarshal(raw, &oldRuntime) == nil {
|
||||
_ = json.Unmarshal(oldRuntime["run_id"], &oldRunID)
|
||||
if oldRunID == next.Runtime.RunID {
|
||||
var runtimeFields map[string]json.RawMessage
|
||||
if err = json.Unmarshal(nextFields["runtime"], &runtimeFields); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for name, value := range runtimeFields {
|
||||
oldRuntime[name] = value
|
||||
}
|
||||
if next.Runtime.Rules != nil && len(next.Runtime.Rules) == 0 {
|
||||
delete(oldRuntime, "rules")
|
||||
}
|
||||
nextFields["runtime"], err = json.Marshal(oldRuntime)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if previousFields == nil {
|
||||
previousFields = map[string]json.RawMessage{}
|
||||
}
|
||||
for name, value := range nextFields {
|
||||
previousFields[name] = value
|
||||
}
|
||||
if next.Runtime == nil {
|
||||
delete(previousFields, "runtime")
|
||||
}
|
||||
accounts[key], err = json.Marshal(previousFields)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -135,6 +204,34 @@ func CommitCurrencyWarsSnapshot(expectedRevision uint64, next CurrencyWarsSnapsh
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if commandID != "" {
|
||||
var commands []CurrencyWarsCommand
|
||||
if raw, ok := root["currency_wars_commands"]; ok {
|
||||
if err := json.Unmarshal(raw, &commands); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
found := false
|
||||
remaining := make([]CurrencyWarsCommand, 0, len(commands))
|
||||
for _, cmd := range commands {
|
||||
if cmd.ID == commandID {
|
||||
if found || cmd.UID != next.UID {
|
||||
return 0, fmt.Errorf("CW command identity differs")
|
||||
}
|
||||
found = true
|
||||
} else {
|
||||
remaining = append(remaining, cmd)
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return 0, fmt.Errorf("CW command no longer queued")
|
||||
}
|
||||
raw, err := json.Marshal(remaining)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
root["currency_wars_commands"] = raw
|
||||
}
|
||||
if err := writeJSONAtomic("persistent", root); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user