From ecba7f726f70b37126d852c38c7e3eec7b04d730 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Thu, 9 Jul 2026 22:15:54 -0400 Subject: feat: old standalone trigger systems completely unified into trigger->condition->action system --- cmd/migrate-messages/main.go | 245 ------------------------------------------- 1 file changed, 245 deletions(-) delete mode 100644 cmd/migrate-messages/main.go (limited to 'cmd/migrate-messages') 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 -} -- cgit v1.2.3