diff options
Diffstat (limited to 'internal/admin/api_map.go')
| -rw-r--r-- | internal/admin/api_map.go | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/internal/admin/api_map.go b/internal/admin/api_map.go new file mode 100644 index 0000000..1520279 --- /dev/null +++ b/internal/admin/api_map.go @@ -0,0 +1,241 @@ +package admin + +import ( + "net/http" + "os" + "path/filepath" + "strconv" + + "thehouseoficarus/internal/world" +) + +func (s *AdminServer) handleMap(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed) + return + } + + zStr := r.URL.Query().Get("z") + z, err := strconv.Atoi(zStr) + if err != nil { + z = 0 + } + + dir := r.URL.Query().Get("dir") + seed := s.cfg.StartingRoom + if dir != "" { + base := filepath.Join(s.dataDir, "rooms", dir) + if low, ok := findLowestRoom(base); ok { + seed = low + } + } + + g := world.BuildGrid(seed, func(id int) (*world.Room, bool) { + room, err := s.world.LoadRoom(id) + if err != nil { + return nil, false + } + return room, true + }, nil, nil) + + type RoomEntry struct { + ID int `json:"id"` + X int `json:"x"` + Y int `json:"y"` + Name string `json:"name"` + Color string `json:"color"` + Symbol string `json:"symbol"` + } + + type LinkEntry struct { + From int `json:"from"` + To int `json:"to"` + Dir string `json:"dir"` + Bidirectional bool `json:"bidirectional"` + } + + type UDLink struct { + From int `json:"from"` + To int `json:"to"` + } + + roomData := make(map[int]*world.Room) + var rooms []RoomEntry + + minX, maxX := 0, 0 + minY, maxY := 0, 0 + first := true + + for rid, coord := range g.Coord { + if coord[2] != z { + continue + } + + r, err := s.world.LoadRoom(rid) + if err != nil { + continue + } + roomData[rid] = r + + rooms = append(rooms, RoomEntry{ + ID: rid, + X: coord[0], + Y: coord[1], + Name: r.Name, + Color: r.Color, + }) + + if first { + minX, maxX = coord[0], coord[0] + minY, maxY = coord[1], coord[1] + first = false + } else { + if coord[0] < minX { + minX = coord[0] + } + if coord[0] > maxX { + maxX = coord[0] + } + if coord[1] < minY { + minY = coord[1] + } + if coord[1] > maxY { + maxY = coord[1] + } + } + } + + var links []LinkEntry + var upLinks []UDLink + var downLinks []UDLink + + seenLinks := make(map[string]bool) + for rid, room := range roomData { + c := g.Coord[rid] + for dir, exit := range room.Exits { + target := exit.Room + if target <= 0 { + continue + } + targetCoord, ok := g.Coord[target] + if !ok { + continue + } + + if targetCoord[2] > c[2] { + upLinks = append(upLinks, UDLink{From: rid, To: target}) + continue + } + if targetCoord[2] < c[2] { + downLinks = append(downLinks, UDLink{From: rid, To: target}) + continue + } + + if dir == world.Up || dir == world.Down { + continue + } + + if _, onZ := roomData[target]; !onZ { + continue + } + + bidirectional := false + if targetRoom, ok := roomData[target]; ok { + if oppExit, ok := targetRoom.Exits[world.OppositeExit[dir]]; ok && oppExit.Room == rid { + bidirectional = true + } + } + + key := linkKey(rid, target) + if bidirectional && seenLinks[key] { + continue + } + seenLinks[key] = true + + links = append(links, LinkEntry{ + From: rid, + To: target, + Dir: string(dir), + Bidirectional: bidirectional, + }) + } + } + + writeJSON(w, map[string]any{ + "rooms": rooms, + "links": links, + "upLinks": upLinks, + "downLinks": downLinks, + "dir": getRoomDir(s, seed), + "bounds": map[string]int{ + "minX": minX, + "maxX": maxX, + "minY": minY, + "maxY": maxY, + }, + }) +} + +func getRoomDir(s *AdminServer, roomID int) string { + path, ok := s.world.GetRoomPath(roomID) + if !ok { + return "" + } + rel, err := filepath.Rel(filepath.Join(s.dataDir, "rooms"), filepath.Dir(path)) + if err != nil || rel == "." { + return "" + } + return rel +} + +func linkKey(a, b int) string { + if a < b { + return strconv.Itoa(a) + "-" + strconv.Itoa(b) + } + return strconv.Itoa(b) + "-" + strconv.Itoa(a) +} + +func findLowestRoom(dir string) (int, bool) { + entries, err := os.ReadDir(dir) + if err != nil { + return 0, false + } + lowest := 0 + found := false + for _, e := range entries { + if e.IsDir() { + continue + } + name := e.Name() + if filepath.Ext(name) != ".yaml" { + continue + } + id, err := strconv.Atoi(name[:len(name)-5]) + if err != nil || id <= 0 { + continue + } + if !found || id < lowest { + lowest = id + found = true + } + } + return lowest, found +} + +func (s *AdminServer) handleNextRoomID(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed) + return + } + fromStr := r.URL.Query().Get("from") + fromID := 0 + if fromStr != "" { + fromID, _ = strconv.Atoi(fromStr) + } + id, _, err := nextRoomIDInDir(s.dataDir, fromID) + if err != nil { + writeJSON(w, map[string]any{"error": err.Error()}) + return + } + writeJSON(w, map[string]any{"id": id}) +} |
