diff options
Diffstat (limited to 'internal/admin/api_rooms.go')
| -rw-r--r-- | internal/admin/api_rooms.go | 177 |
1 files changed, 128 insertions, 49 deletions
diff --git a/internal/admin/api_rooms.go b/internal/admin/api_rooms.go index 4075534..b60aefc 100644 --- a/internal/admin/api_rooms.go +++ b/internal/admin/api_rooms.go @@ -228,8 +228,36 @@ func (s *AdminServer) handleRoomByID(w http.ResponseWriter, r *http.Request) { s.world.RebuildRoomIndex(s.dataDir) s.world.ClearRoomState(id) + allIDs, _ := listRoomIDs(s.dataDir) + var exitCleaned int + for _, otherID := range allIDs { + if otherID == id { + continue + } + otherRoom, loadErr := s.world.LoadRoom(otherID) + if loadErr != nil { + continue + } + changed := false + for _, dir := range world.ExitOrder { + exit, exists := otherRoom.Exits[dir] + if !exists || exit.Room != id { + continue + } + delete(otherRoom.Exits, dir) + changed = true + } + if changed { + otherPath, pathOk := s.world.GetRoomPath(otherID) + if pathOk { + writeYAMLFile(otherPath, otherRoom) + exitCleaned++ + } + } + } + s.undoStack.Push(ChangeDesc{ - Description: fmt.Sprintf("delete room %d", id), + Description: fmt.Sprintf("delete room %d (cleaned %d exits)", id, exitCleaned), FilePath: path, OldContent: oldContent, IsDelete: true, @@ -477,25 +505,29 @@ func (s *AdminServer) handleRoomLink(w http.ResponseWriter, r *http.Request) { roomA, errA := s.world.LoadRoom(body.From) roomB, errB := s.world.LoadRoom(body.To) - if errA != nil || errB != nil { - writeJSON(w, map[string]any{"error": "one or both rooms not found"}) + + if errA != nil && errB != nil { + writeJSON(w, map[string]any{"error": "both rooms not found"}) return } - if roomA == nil || roomB == nil { - writeJSON(w, map[string]any{"error": "one or both rooms not found"}) - return + if (errA != nil && roomA == nil) { + roomA = nil + } + if (errB != nil && roomB == nil) { + roomB = nil } var dir, oppDir world.ExitDir - for _, d := range world.ExitOrder { - if exit, ok := roomA.Exits[d]; ok && exit.Room == body.To { - dir = d - break + if roomA != nil { + for _, d := range world.ExitOrder { + if exit, ok := roomA.Exits[d]; ok && exit.Room == body.To { + dir = d + oppDir = world.OppositeExit[d] + break + } } } - if dir != "" { - oppDir = world.OppositeExit[dir] - } else { + if dir == "" && roomB != nil { for _, d := range world.ExitOrder { if exit, ok := roomB.Exits[d]; ok && exit.Room == body.From { oppDir = d @@ -505,49 +537,58 @@ func (s *AdminServer) handleRoomLink(w http.ResponseWriter, r *http.Request) { } } - if dir == "" && oppDir == "" { - writeJSONError(w, "no exit found between these rooms", http.StatusNotFound) - return - } - - if roomA.Exits != nil { + if roomA != nil && roomA.Exits != nil { delete(roomA.Exits, dir) } - if roomB.Exits != nil { + if roomB != nil && roomB.Exits != nil { delete(roomB.Exits, oppDir) } - pathA, okA2 := s.world.GetRoomPath(body.From) - pathB, okB2 := s.world.GetRoomPath(body.To) - if !okA2 || !okB2 { - writeJSON(w, map[string]any{"error": "room path not found"}) - return - } + var pushEntries []ChangeDesc - oldA, _ := snapshotFile(pathA) - oldB, _ := snapshotFile(pathB) - newA, err := writeYAMLFile(pathA, roomA) - if err != nil { - writeJSON(w, map[string]any{"error": "write A: " + err.Error()}) - return + if roomA != nil { + pathA, okA2 := s.world.GetRoomPath(body.From) + if !okA2 { + writeJSON(w, map[string]any{"error": "room A path not found"}) + return + } + oldA, _ := snapshotFile(pathA) + newA, err := writeYAMLFile(pathA, roomA) + if err != nil { + writeJSON(w, map[string]any{"error": "write A: " + err.Error()}) + return + } + pushEntries = append(pushEntries, ChangeDesc{ + Description: fmt.Sprintf("unlink %d %s %d", body.From, dir, body.To), + FilePath: pathA, + OldContent: oldA, + NewContent: newA, + }) + } + + if roomB != nil { + pathB, okB2 := s.world.GetRoomPath(body.To) + if !okB2 { + writeJSON(w, map[string]any{"error": "room B path not found"}) + return + } + oldB, _ := snapshotFile(pathB) + newB, err := writeYAMLFile(pathB, roomB) + if err != nil { + writeJSON(w, map[string]any{"error": "write B: " + err.Error()}) + return + } + pushEntries = append(pushEntries, ChangeDesc{ + Description: fmt.Sprintf("unlink %d %s %d (reverse)", body.To, oppDir, body.From), + FilePath: pathB, + OldContent: oldB, + NewContent: newB, + }) } - newB, err := writeYAMLFile(pathB, roomB) - if err != nil { - writeJSON(w, map[string]any{"error": "write B: " + err.Error()}) - return + + for _, entry := range pushEntries { + s.undoStack.Push(entry) } - s.undoStack.Push(ChangeDesc{ - Description: fmt.Sprintf("unlink %d %s %d", body.From, dir, body.To), - FilePath: pathA, - OldContent: oldA, - NewContent: newA, - }) - s.undoStack.Push(ChangeDesc{ - Description: fmt.Sprintf("unlink %d %s %d (reverse)", body.To, oppDir, body.From), - FilePath: pathB, - OldContent: oldB, - NewContent: newB, - }) writeJSON(w, map[string]any{"ok": true}) default: @@ -631,12 +672,19 @@ func (s *AdminServer) handleRoomRename(w http.ResponseWriter, r *http.Request) { writeJSON(w, map[string]any{"error": "room not found"}) return } + + if _, ok := s.world.GetRoomPath(body.NewID); ok { + writeJSON(w, map[string]any{"error": fmt.Sprintf("room %d already exists", body.NewID)}) + return + } + dir := filepath.Dir(oldPath) newPath := filepath.Join(dir, strconv.Itoa(body.NewID)+".yaml") if _, err := os.Stat(newPath); err == nil { writeJSON(w, map[string]any{"error": fmt.Sprintf("room %d already exists", body.NewID)}) return } + data, err := os.ReadFile(oldPath) if err != nil { writeJSON(w, map[string]any{"error": "read: " + err.Error()}) @@ -650,10 +698,41 @@ func (s *AdminServer) handleRoomRename(w http.ResponseWriter, r *http.Request) { writeJSON(w, map[string]any{"error": "remove old: " + err.Error()}) return } + s.world.RebuildRoomIndex(s.dataDir) s.world.ClearRoomState(body.ID) + + allIDs, _ := listRoomIDs(s.dataDir) + var exitUpdates int + for _, otherID := range allIDs { + if otherID == body.NewID { + continue + } + otherRoom, loadErr := s.world.LoadRoom(otherID) + if loadErr != nil { + continue + } + changed := false + for _, dir := range world.ExitOrder { + exit, exists := otherRoom.Exits[dir] + if !exists || exit.Room != body.ID { + continue + } + exit.Room = body.NewID + otherRoom.Exits[dir] = exit + changed = true + } + if changed { + otherPath, pathOk := s.world.GetRoomPath(otherID) + if pathOk { + writeYAMLFile(otherPath, otherRoom) + exitUpdates++ + } + } + } + s.undoStack.Push(ChangeDesc{ - Description: fmt.Sprintf("rename room %d to %d", body.ID, body.NewID), + Description: fmt.Sprintf("rename room %d to %d (updated %d exits)", body.ID, body.NewID, exitUpdates), FilePath: oldPath, NewFilePath: newPath, OldContent: data, |
