From bab5dd653039d026eb3d4e46da7aafef7137fe7c Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Sat, 19 Sep 2026 03:52:04 -0400 Subject: fix: journal in-game room insert/remove, rewrite non-room room refs on rename/swap, seed admin grid from edited room, type action switches --- internal/admin/api_rooms.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'internal/admin/api_rooms.go') diff --git a/internal/admin/api_rooms.go b/internal/admin/api_rooms.go index ca7ad06..efc466c 100644 --- a/internal/admin/api_rooms.go +++ b/internal/admin/api_rooms.go @@ -101,7 +101,7 @@ func (s *AdminServer) handleRooms(w http.ResponseWriter, r *http.Request) { opp, validDir := world.OppositeExit[dir] if validDir { conflicts := 0 - world.BuildGrid(s.cfg.StartingRoom, func(rid int) (*world.Room, bool) { + world.BuildGrid(*linkFrom, func(rid int) (*world.Room, bool) { if rid == id { ex := make(map[world.ExitDir]world.ExitDef) if !linkOneWay { @@ -571,7 +571,11 @@ func (s *AdminServer) handleRoomLink(w http.ResponseWriter, r *http.Request) { return } } else { - grid := world.BuildGrid(s.cfg.StartingRoom, func(id int) (*world.Room, bool) { + // Auto-detect the direction from the room being edited, not the + // configured starting room: a detached in-progress area is not + // reachable from the start room, and seeding there would report + // both rooms as unreachable even though they are adjacent. + grid := world.BuildGrid(body.From, func(id int) (*world.Room, bool) { room, err := s.world.LoadRoom(id) if err != nil { log.Printf("link: BuildGrid failed to load room %d: %v", id, err) @@ -583,7 +587,7 @@ func (s *AdminServer) handleRoomLink(w http.ResponseWriter, r *http.Request) { cA, okA := grid.Coord[body.From] cB, okB := grid.Coord[body.To] if !okA || !okB { - writeJSONError(w, "one or both rooms are not reachable from the seed room", http.StatusBadRequest) + writeJSONError(w, "rooms are not in the same connected component; specify a direction explicitly", http.StatusBadRequest) return } if cA[2] != cB[2] { @@ -636,7 +640,7 @@ func (s *AdminServer) handleRoomLink(w http.ResponseWriter, r *http.Request) { } } - conflicts := world.BuildGridConflicts(s.cfg.StartingRoom, func(id int) (*world.Room, bool) { + conflicts := world.BuildGridConflicts(body.From, func(id int) (*world.Room, bool) { room, err := s.world.LoadRoom(id) if err != nil { log.Printf("link: conflict test BuildGrid failed to load room %d: %v", id, err) @@ -1062,6 +1066,15 @@ func (s *AdminServer) handleRoomRename(w http.ResponseWriter, r *http.Request) { } refUpdates++ } + // Non-room content (courses, modules, triggers, items, objects, mobs) + // carries structural room references too. Update it in the same journaled + // commit, or a renamed room leaves a course obstacle or transport + // destination pointing at an ID that no longer exists. + contentExtras, err := rewriteContentRoomRefs(s.dataDir, idMap, txn) + if err != nil { + writeJSONError(w, "plan content write: "+err.Error(), http.StatusInternalServerError) + return + } if err := txn.Commit(); err != nil { writeJSONError(w, "commit rename: "+err.Error(), http.StatusInternalServerError) return @@ -1101,6 +1114,9 @@ func (s *AdminServer) handleRoomRename(w http.ResponseWriter, r *http.Request) { }) } } + // Content-file rewrites are part of the same change, so undo restores + // them alongside the room files. + change.ExtraFiles = append(change.ExtraFiles, contentExtras...) s.undoStack.Push(change) writeJSON(w, map[string]any{"ok": true, "refs": refUpdates}) } -- cgit v1.2.3