aboutsummaryrefslogtreecommitdiff
path: root/cmd/migrate-messages
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/migrate-messages')
-rw-r--r--cmd/migrate-messages/main.go245
1 files changed, 0 insertions, 245 deletions
diff --git a/cmd/migrate-messages/main.go b/cmd/migrate-messages/main.go
deleted file mode 100644
index 81400a4..0000000
--- a/cmd/migrate-messages/main.go
+++ /dev/null
@@ -1,245 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "sort"
- "strings"
-
- "gopkg.in/yaml.v3"
-)
-
-func main() {
- dataDir := os.Getenv("DATA_DIR")
- if dataDir == "" {
- dataDir = "data"
- }
-
- var changed []string
- err := filepath.WalkDir(dataDir, func(path string, d os.DirEntry, err error) error {
- if err != nil {
- return err
- }
- if d.IsDir() || (!strings.HasSuffix(path, ".yaml") && !strings.HasSuffix(path, ".yml")) {
- return nil
- }
- if migrated(path) {
- changed = append(changed, path)
- }
- return nil
- })
- if err != nil {
- fmt.Fprintf(os.Stderr, "walk error: %v\n", err)
- os.Exit(1)
- }
-
- sort.Strings(changed)
- if len(changed) == 0 {
- fmt.Println("No files needed migration.")
- } else {
- fmt.Printf("Migrated %d file(s):\n", len(changed))
- for _, f := range changed {
- fmt.Printf(" %s\n", f)
- }
- }
-}
-
-func migrated(path string) bool {
- data, err := os.ReadFile(path)
- if err != nil {
- fmt.Fprintf(os.Stderr, "read %s: %v\n", path, err)
- return false
- }
-
- var root any
- if err := yaml.Unmarshal(data, &root); err != nil {
- fmt.Fprintf(os.Stderr, "parse %s: %v\n", path, err)
- return false
- }
-
- modified := false
- root = walk(root, "", &modified)
-
- if !modified {
- return false
- }
-
- out, err := yaml.Marshal(root)
- if err != nil {
- fmt.Fprintf(os.Stderr, "marshal %s: %v\n", path, err)
- return false
- }
- if err := os.WriteFile(path, out, 0644); err != nil {
- fmt.Fprintf(os.Stderr, "write %s: %v\n", path, err)
- return false
- }
- return true
-}
-
-// walk recursively walks a YAML tree with a parent-key context.
-// The context tells us what array type we're inside (on_enter, on_use, sequences, etc.)
-func walk(v any, parentKey string, modified *bool) any {
- switch val := v.(type) {
- case map[string]any:
- return migrateMap(val, parentKey, modified)
- case []any:
- return migrateSlice(val, parentKey, modified)
- }
- return v
-}
-
-func migrateSlice(arr []any, parentKey string, modified *bool) any {
- for i, el := range arr {
- arr[i] = walk(el, parentKey, modified)
- }
- return arr
-}
-
-// stepActionKeys are fields unique to StepAction that are NOT found on
-// ModTriggerStep or Interaction. A map with any of these is definitely a
-// StepAction, regardless of context.
-var stepActionKeys = map[string]bool{
- "broadcast": true,
- "broadcast_global": true,
- "spawn_mob": true,
- "despawn_mob": true,
- "give_item": true,
- "take_item": true,
- "teleport": true,
- "heal": true,
- "credits": true,
- "aps_node": true,
- "set_global_flags": true,
- "set_player_flags": true,
-}
-
-func hasStepActionKey(m map[string]any) bool {
- for k := range m {
- if stepActionKeys[k] {
- return true
- }
- }
- return false
-}
-
-// contextIsStepAction returns true when the parent key indicates this array
-// contains StepAction entries (as opposed to ModTriggerStep or Interaction).
-func contextIsStepAction(parentKey string) bool {
- switch parentKey {
- case "on_enter":
- return true
- case "action":
- return true
- case "on_traverse":
- // on_traverse entries have action: but entries themselves are Interactions.
- // The action: inside them is a StepAction, handled by the "action" case above.
- // The top-level entry message is handled by interaction logic.
- return false
- }
- return false
-}
-
-// isSequenceArray returns true for keys whose array entries are ModTriggerStep
-// (which keeps the legacy message field — do not migrate).
-func isSequenceArray(key string) bool {
- return key == "sequence"
-}
-
-// isInteractionArray returns true for keys that contain Interaction entries.
-func isInteractionArray(key string) bool {
- switch key {
- case "on_use", "on_look", "on_kill", "on_traverse":
- return true
- }
- return false
-}
-
-func migrateMap(m map[string]any, parentKey string, modified *bool) any {
- _, hasMsg := m["message"].(string)
-
- // --- Step 1: migrate legacy message: on StepAction maps ---
- // A map is a StepAction if:
- // a) It has a unique StepAction key (set_player_flags, broadcast, etc.), OR
- // b) The parent array is on_enter or action (our context tells us)
- // We exclude sequence arrays (ModTriggerStep keeps its message field).
- if hasMsg && (hasStepActionKey(m) || contextIsStepAction(parentKey)) && !isSequenceArray(parentKey) {
- m["messages"] = []any{map[string]any{"message": m["message"], "delay": 0}}
- delete(m, "message")
- *modified = true
- }
-
- // --- Step 2: recurse into children ---
- // For map values, recurse with the key as context. For arrays under a key,
- // the child will use that key.
- for k, v := range m {
- m[k] = walk(v, k, modified)
- }
-
- // --- Step 3: interaction-level migration ---
- // If this is an interaction entry (identified by being an element of an
- // on_use/on_look/on_kill/on_traverse array) that still has a top-level
- // message: string, fold it into the action's messages list.
- if hasMsg && isInteractionArray(parentKey) {
- topMsg := m["message"].(string)
- delete(m, "message")
- *modified = true
-
- act, ok := m["action"].(map[string]any)
- if !ok {
- act = map[string]any{}
- m["action"] = act
- }
-
- var msgs []any
- if existing, ok2 := act["messages"].([]any); ok2 {
- msgs = existing
- } else if existingMsg, ok2 := act["message"].(string); ok2 {
- msgs = []any{map[string]any{"message": existingMsg, "delay": 0}}
- delete(act, "message")
- }
- msgs = append([]any{map[string]any{"message": topMsg, "delay": 0}}, msgs...)
- act["messages"] = msgs
- *modified = true
- }
-
- // --- Step 4: trigger steps under "steps" key ---
- // TriggerDef.Steps is []StepAction. But the key "steps" could also be
- // ItemDef.CraftStep (craft items). We detect trigger steps by looking for
- // trigger-specific parent fields (on_player_flag, on_global_flag, room, id).
- // Actually we already recursed into children and migrated individual entries
- // if they had stepActionKeys. The remaining case: a trigger step with only
- // delay+message. We detect this after the children walk: if we're under
- // a "steps" key and the parent map has trigger-specific keys, migrate the
- // step's message. Since we've already recursed into the array entries,
- // this step handles the case where individual step entries had only
- // delay+message and weren't caught by hasStepActionKey.
- // We detect this case in step 1 already: contextIsStepAction returns false
- // for "steps". But if the parent map itself has trigger-like fields, we
- // should treat "steps" as StepAction context.
- // This is handled below.
-
- // --- Step 5: "steps" key whose parent is a trigger ---
- // If this map has a "steps" key AND has trigger-specific fields, re-walk
- // the steps array with StepAction context. This is done via the recursive
- // walk already — but contextIsStepAction("steps") returns false. We need
- // to detect trigger-def parentage and treat steps as StepAction context.
- //
- // TriggerDef keys: id, on_player_flag, on_global_flag, value, room, steps
- // CraftDef keys: type, level, skill, ingredients, success, output_qty, fail,
- // success_message, fail_message, start_message, end_message, steps
- //
- // If this map has trigger-specific keys, treat "steps" as StepAction context.
- if hasTriggerLikeKeys(m) {
- if stepsArr, ok := m["steps"].([]any); ok {
- m["steps"] = walk(stepsArr, "on_enter", modified)
- }
- }
-
- return m
-}
-
-func hasTriggerLikeKeys(m map[string]any) bool {
- return m["on_player_flag"] != nil || m["on_global_flag"] != nil ||
- m["room"] != nil
-}