pre cw with probe and a bunch script to read game behavior
This commit is contained in:
1 parent
5120219ae2
commit
da8a32f60d
310 files changed
+219693
-872
No files matched your search
@@ -0,0 +1,104 @@
|
||||
package sdkserver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"gac-hkrpg-go/internal/common"
|
||||
)
|
||||
|
||||
// POST patches fields; PUT explicitly replaces a complete player document.
|
||||
// Keep raw JSON values so unrelated IDs and numeric values are not rounded.
|
||||
func preparePlayerDataUpdate(existing, payload []byte, replace bool) ([]byte, error) {
|
||||
var patch map[string]json.RawMessage
|
||||
if err := json.Unmarshal(payload, &patch); err != nil || patch == nil {
|
||||
return nil, fmt.Errorf("player data must be a JSON object")
|
||||
}
|
||||
result := make(map[string]json.RawMessage)
|
||||
if replace {
|
||||
for _, key := range []string{"avatars", "lightcones", "relics", "battle_config"} {
|
||||
if _, present := patch[key]; !present {
|
||||
return nil, fmt.Errorf("full replacement is missing %s; use POST for a partial update", key)
|
||||
}
|
||||
}
|
||||
// FreeSR exports do not necessarily include the inventory editor's
|
||||
// material overrides. Omission preserves them; an explicit materials
|
||||
// object (including zero counts or {}) still replaces that field.
|
||||
if _, present := patch["materials"]; !present && len(existing) != 0 {
|
||||
var current map[string]json.RawMessage
|
||||
if err := json.Unmarshal(existing, ¤t); err != nil || current == nil {
|
||||
return nil, fmt.Errorf("existing player data is invalid; restore it before applying updates")
|
||||
}
|
||||
if value, present := current["materials"]; present {
|
||||
result["materials"] = value
|
||||
}
|
||||
}
|
||||
} else if err := json.Unmarshal(existing, &result); err != nil || result == nil {
|
||||
return nil, fmt.Errorf("existing player data is invalid; restore it before applying updates")
|
||||
}
|
||||
for key, value := range patch {
|
||||
if key == "avatars" && !replace {
|
||||
var incoming map[string]json.RawMessage
|
||||
if err := json.Unmarshal(value, &incoming); err != nil || len(incoming) == 0 {
|
||||
return nil, fmt.Errorf("avatars update must be a non-empty object")
|
||||
}
|
||||
current := make(map[string]json.RawMessage)
|
||||
if raw, found := result[key]; found {
|
||||
if err := json.Unmarshal(raw, ¤t); err != nil || current == nil {
|
||||
return nil, fmt.Errorf("existing avatars data is invalid")
|
||||
}
|
||||
}
|
||||
for id, avatar := range incoming {
|
||||
current[id] = avatar
|
||||
}
|
||||
merged, err := json.Marshal(current)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[key] = merged
|
||||
} else {
|
||||
result[key] = value
|
||||
}
|
||||
}
|
||||
out, err := json.MarshalIndent(result, "", " ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var data common.FreesrData
|
||||
if err := json.Unmarshal(out, &data); err != nil {
|
||||
return nil, fmt.Errorf("invalid player data: %w", err)
|
||||
}
|
||||
if err := common.ValidateAvatarRoster(data.Avatars); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if saved, err := common.ReadPersistent(); err == nil {
|
||||
if err := common.ValidateAdventureLineup(data.Avatars, saved.Lineups); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("cannot validate active lineup: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func writePlayerDataAtomic(data []byte) error {
|
||||
file, err := os.CreateTemp(".", ".gac-freesr-*.tmp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := file.Name()
|
||||
defer os.Remove(name)
|
||||
if _, err := file.Write(data); err != nil {
|
||||
file.Close()
|
||||
return err
|
||||
}
|
||||
if err := file.Sync(); err != nil {
|
||||
file.Close()
|
||||
return err
|
||||
}
|
||||
if err := file.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(name, "freesr-data.json")
|
||||
}
|
||||
Reference in new issue
Block a user