From e9144cad4a8c55dcee4a694149f06588edd8595a Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Mon, 6 Jul 2026 21:56:32 -0400 Subject: fix: change one-way modifier on admin map from shift to ctrl for firefox support --- internal/admin/api_map.go | 119 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 21 deletions(-) (limited to 'internal/admin/api_map.go') diff --git a/internal/admin/api_map.go b/internal/admin/api_map.go index bb81e59..5168165 100644 --- a/internal/admin/api_map.go +++ b/internal/admin/api_map.go @@ -84,7 +84,6 @@ func (s *AdminServer) handleMap(w http.ResponseWriter, r *http.Request) { if err != nil { continue } - // Try adjacent to a connected neighbour already on grid. for _, exit := range room.Exits { if exit.Room <= 0 { continue @@ -93,32 +92,69 @@ func (s *AdminServer) handleMap(w http.ResponseWriter, r *http.Request) { if !ok { continue } - for dx := -1; dx <= 1; dx++ { - for dy := -1; dy <= 1; dy++ { - if dx == 0 && dy == 0 { - continue - } - want := [3]int{nc[0] + dx, nc[1] + dy, nc[2]} - if _, used := g.RoomAt[want]; !used { - g.Coord[id] = want - g.RoomAt[want] = id - goto placed - } + if tryPlaceAdjacent(&g, id, nc) { + goto placed + } + } + tryPlaceRoom(&g, id, [3]int{}, false, [3]int{0, 0, z}) + placed: + } + + // Place rooms that have a one-way exit into the already-placed set. + // These rooms are not reachable from the seed via outgoing exits but + // their one-way link points into the connected component, so they + // should appear on the map as connected (not disconnected). + { + roomIndex := s.world.RoomIndex() + sortedIDs := make([]int, 0, len(roomIndex)) + for id := range roomIndex { + sortedIDs = append(sortedIDs, id) + } + sort.Ints(sortedIDs) + + type revEdge struct { + src int + dir world.ExitDir + } + rev := make(map[int][]revEdge) + for _, id := range sortedIDs { + room, err := s.world.LoadRoom(id) + if err != nil { + continue + } + for _, dir := range world.ExitOrder { + exit, ok := room.Exits[dir] + if !ok || exit.Room <= 0 || exit.Room == id { + continue } + rev[exit.Room] = append(rev[exit.Room], revEdge{src: id, dir: dir}) } } - // Fallback: scan a generous rectangle for a free cell. - for sx := -10; sx <= 10; sx++ { - for sy := -10; sy <= 10; sy++ { - want := [3]int{sx, sy, z} - if _, used := g.RoomAt[want]; !used { - g.Coord[id] = want - g.RoomAt[want] = id - goto placed + + queue := make([]int, 0, len(g.Coord)) + for rid := range g.Coord { + queue = append(queue, rid) + } + sort.Ints(queue) + + for len(queue) > 0 { + target := queue[0] + queue = queue[1:] + for _, e := range rev[target] { + if _, placed := g.Coord[e.src]; placed || e.src == target { + continue + } + tc := g.Coord[target] + delta := world.DirectionDeltas3D[world.OppositeExit[e.dir]] + want := [3]int{tc[0] + delta[0], tc[1] + delta[1], tc[2] + delta[2]} + if tryPlaceRoom(&g, e.src, want, true, tc) { + if d, ok := g.Dist[target]; ok { + g.Dist[e.src] = d + 1 + } + queue = append(queue, e.src) } } } - placed: } type RoomEntry struct { @@ -262,6 +298,47 @@ func (s *AdminServer) handleMap(w http.ResponseWriter, r *http.Request) { }) } +func tryPlaceAdjacent(g *world.RoomGrid, roomID int, center [3]int) bool { + for dx := -1; dx <= 1; dx++ { + for dy := -1; dy <= 1; dy++ { + if dx == 0 && dy == 0 { + continue + } + cell := [3]int{center[0] + dx, center[1] + dy, center[2]} + if _, used := g.RoomAt[cell]; !used { + g.Coord[roomID] = cell + g.RoomAt[cell] = roomID + return true + } + } + } + return false +} + +func tryPlaceRoom(g *world.RoomGrid, roomID int, want [3]int, allowWant bool, center [3]int) bool { + if allowWant { + if _, used := g.RoomAt[want]; !used { + g.Coord[roomID] = want + g.RoomAt[want] = roomID + return true + } + } + if tryPlaceAdjacent(g, roomID, center) { + return true + } + for sx := -10; sx <= 10; sx++ { + for sy := -10; sy <= 10; sy++ { + cell := [3]int{center[0] + sx, center[1] + sy, center[2]} + if _, used := g.RoomAt[cell]; !used { + g.Coord[roomID] = cell + g.RoomAt[cell] = roomID + return true + } + } + } + return false +} + func getRoomDir(s *AdminServer, roomID int) string { path, ok := s.world.GetRoomPath(roomID) if !ok { -- cgit v1.2.3