package topdata import ( "encoding/json" "os" "path/filepath" ) func importLegacyCreaturespeed(referenceBuilderDir, dataDir string, legacyTLK *legacyTLKData) (int, error) { _ = legacyTLK legacyDir := filepath.Join(referenceBuilderDir, "data", "creaturespeed") if _, err := os.Stat(legacyDir); err != nil { if os.IsNotExist(err) { return 0, nil } return 0, err } targetDir := filepath.Join(dataDir, "creaturespeed") targetPath := filepath.Join(targetDir, "creaturespeed.json") if _, err := os.Stat(targetPath); err == nil { obj, err := loadJSONObject(targetPath) if err == nil && countLegacyTLKRefsInValue(obj) == 0 { return 0, nil } } baseObj, err := loadJSONObject(filepath.Join(legacyDir, "base.json")) if err != nil { return 0, err } rows, err := mergeCreaturespeedRows(baseObj, filepath.Join(legacyDir, "modules")) if err != nil { return 0, err } if err := os.MkdirAll(targetDir, 0o755); err != nil { return 0, err } if err := removePathIfExists(filepath.Join(targetDir, "base.json")); err != nil { return 0, err } if err := removePathIfExists(filepath.Join(targetDir, "lock.json")); err != nil { return 0, err } if err := removePathIfExists(filepath.Join(targetDir, "modules")); err != nil { return 0, err } out := map[string]any{ "output": "creaturespeed.2da", "columns": baseObj["columns"], "rows": rows, } raw, err := json.MarshalIndent(out, "", " ") if err != nil { return 0, err } raw = append(raw, '\n') if err := os.WriteFile(targetPath, raw, 0o644); err != nil { return 0, err } return 1, nil } func mergeCreaturespeedRows(baseObj map[string]any, modulesDir string) ([]any, error) { rawRows, ok := baseObj["rows"].([]any) if !ok { return nil, nil } rows := make([]map[string]any, 0, len(rawRows)) byID := map[int]map[string]any{} for _, raw := range rawRows { row, ok := deepCopyValue(raw).(map[string]any) if !ok { continue } delete(row, "key") rows = append(rows, row) if rawID, ok := row["id"]; ok { id, err := asInt(rawID) if err != nil { return nil, err } byID[id] = row } } modulePaths, err := collectModulePaths(modulesDir) if err != nil { return nil, err } for _, path := range modulePaths { obj, err := loadJSONObject(path) if err != nil { return nil, err } overrideList, ok := obj["overrides"].([]any) if !ok { continue } for _, raw := range overrideList { override, ok := raw.(map[string]any) if !ok { continue } rawID, ok := override["id"] if !ok { continue } id, err := asInt(rawID) if err != nil { return nil, err } row := byID[id] if row == nil { continue } for key, value := range override { if key == "id" || key == "key" || key == "_tlk" { continue } row[key] = deepCopyValue(value) } } } out := make([]any, 0, len(rows)) for _, row := range rows { out = append(out, row) } return out, nil } func removePathIfExists(path string) error { if _, err := os.Stat(path); err != nil { if os.IsNotExist(err) { return nil } return err } return os.RemoveAll(path) }