aboutsummaryrefslogtreecommitdiff
path: root/internal/world/inbound.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/world/inbound.go')
-rw-r--r--internal/world/inbound.go66
1 files changed, 66 insertions, 0 deletions
diff --git a/internal/world/inbound.go b/internal/world/inbound.go
new file mode 100644
index 0000000..0fbef04
--- /dev/null
+++ b/internal/world/inbound.go
@@ -0,0 +1,66 @@
+package world
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "gopkg.in/yaml.v3"
+)
+
+// CountExtraInbound returns the number of exits in rooms OTHER than A and C
+// that point into B, plus any A/C exits to B other than the expected
+// (A→dir→B, C→oppositeDir→B). A nonzero result means B has been modified
+// since it was inserted and a remove would silently orphan edges. It walks
+// data/rooms and matches \b<id>\b against raw file contents to skip rooms
+// that don't mention bID at all, then unmarshals only the matching files.
+//
+// Shared by the in-game room-remove command and the admin API so the two
+// removal paths cannot drift.
+func CountExtraInbound(dataDir string, bID, aID, cID int, dir, oppositeDir ExitDir) int {
+ roomsDir := filepath.Join(dataDir, "rooms")
+ re := regexp.MustCompile(fmt.Sprintf(`\b%d\b`, bID))
+ var extra int
+ _ = filepath.WalkDir(roomsDir, func(path string, d os.DirEntry, err error) error {
+ if err != nil || d.IsDir() || filepath.Ext(path) != ".yaml" {
+ return nil
+ }
+ data, rerr := os.ReadFile(path)
+ if rerr != nil {
+ return nil
+ }
+ if !re.MatchString(string(data)) {
+ return nil
+ }
+ idStr := strings.TrimSuffix(filepath.Base(path), ".yaml")
+ rid, serr := strconv.Atoi(idStr)
+ if serr != nil || rid == bID {
+ return nil
+ }
+ var room Room
+ if yerr := yaml.Unmarshal(data, &room); yerr != nil {
+ return nil
+ }
+ if room.Exits == nil {
+ return nil
+ }
+ for ed, exitDef := range room.Exits {
+ if exitDef.Room != bID {
+ continue
+ }
+ // Allowed: A→dir→B and C→oppositeDir→B.
+ if rid == aID && ed == dir {
+ continue
+ }
+ if rid == cID && ed == oppositeDir {
+ continue
+ }
+ extra++
+ }
+ return nil
+ })
+ return extra
+}