aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-07-11 18:30:58 -0400
committerhistoria <[not public]>2026-07-11 18:30:58 -0400
commit2bacbb08d1ac67c4f63ee535728cd4e8760e3211 (patch)
treed8ee366b3d32b486eb05c5e10bc65cf194ae4c23
parent131cbbe586463a7232f332650af5f0b2c13dc7e9 (diff)
downloadthehouseoficarus-2bacbb08d1ac67c4f63ee535728cd4e8760e3211.tar.gz
feat(admin): unify context menu, add context menu to files tab
-rw-r--r--data/.admin_history.json1
-rw-r--r--data/.admin_history.yaml1
-rw-r--r--data/drops/christmas_cracker_hat.yaml3
-rw-r--r--data/objects/000_test_object.yaml29
-rw-r--r--internal/admin/api_files.go65
-rw-r--r--internal/admin/server.go1
-rw-r--r--internal/admin/static/ctxmenu.js47
-rw-r--r--internal/admin/static/editor.js106
-rw-r--r--internal/admin/templates/files.html130
-rw-r--r--internal/admin/templates/layout.html1
10 files changed, 253 insertions, 131 deletions
diff --git a/data/.admin_history.json b/data/.admin_history.json
new file mode 100644
index 0000000..fde8314
--- /dev/null
+++ b/data/.admin_history.json
@@ -0,0 +1 @@
+{"history":[{"time":"2026-07-11T18:30:19-04:00","description":"Deleted file courses/test_copy.yaml","file_path":"data/courses/test_copy.yaml","old_content":"completion_xp: 0\nname: test\nobstacles:\n - exit_dir: southwest\n fail_damage:\n - 0\n - 0\n phases: []\n room_id: 1009\n verb: climb\n xp: 0\nrequired_level: 1\nstart_room: 1007\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-07-11T18:30:26-04:00","description":"Deleted file .admin_history.json","file_path":"data/.admin_history.json","old_content":"{\"history\":[{\"time\":\"2026-07-11T18:30:19-04:00\",\"description\":\"Deleted file courses/test_copy.yaml\",\"file_path\":\"data/courses/test_copy.yaml\",\"old_content\":\"completion_xp: 0\\nname: test\\nobstacles:\\n - exit_dir: southwest\\n fail_damage:\\n - 0\\n - 0\\n phases: []\\n room_id: 1009\\n verb: climb\\n xp: 0\\nrequired_level: 1\\nstart_room: 1007\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false}],\"redo\":null}","new_content":"","is_delete":true,"is_create":false},{"time":"2026-07-11T18:30:29-04:00","description":"Deleted file .admin_history.yaml","file_path":"data/.admin_history.yaml","old_content":"{\"history\":[{\"time\":\"2026-06-30T03:16:23-04:00\",\"description\":\"update room 1009\",\"file_path\":\"data/rooms/intro/1009.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"26\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs:\\n - id: man\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:16:24-04:00\",\"description\":\"update room 1009\",\"file_path\":\"data/rooms/intro/1009.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs:\\n - id: man\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"27\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs:\\n - id: man\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:16:25-04:00\",\"description\":\"update room 1009\",\"file_path\":\"data/rooms/intro/1009.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"27\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs:\\n - id: man\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"27\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs:\\n - id: man\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:20:00-04:00\",\"description\":\"update room 1009\",\"file_path\":\"data/rooms/intro/1009.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"27\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs:\\n - id: man\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"27\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:20:04-04:00\",\"description\":\"update room 1009\",\"file_path\":\"data/rooms/intro/1009.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"27\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"27\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs:\\n - id: man\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:20:07-04:00\",\"description\":\"update room 1009\",\"file_path\":\"data/rooms/intro/1009.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"27\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs:\\n - id: man\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"27\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1016\\n northwest:\\n room: 8\\n southwest:\\n room: 1006\\n west:\\n room: 1005\\nhazard: \\\"\\\"\\nid: 1009\\nitem_spawns: []\\nmobs:\\n - id: man\\n - id: man\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:28:54-04:00\",\"description\":\"rename room 1014 to 1015\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"new_file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1007\\n up:\\n room: 1015\\nhazard: \\\"\\\"\\nid: 1014\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1007\\n up:\\n room: 1015\\nhazard: \\\"\\\"\\nid: 1014\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:29:30-04:00\",\"description\":\"rename room 1007 to 10070\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"new_file_path\":\"data/rooms/intro/10070.yaml\",\"old_content\":\"id: 1007\\nname: New Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 12\\n northwest:\\n room: 1005\\n south:\\n room: 1014\\n up:\\n room: 11\\n west:\\n room: 1006\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: New Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 12\\n northwest:\\n room: 1005\\n south:\\n room: 1014\\n up:\\n room: 11\\n west:\\n room: 1006\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:30:46-04:00\",\"description\":\"update room 10070\",\"file_path\":\"data/rooms/intro/10070.yaml\",\"old_content\":\"id: 1007\\nname: New Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 12\\n northwest:\\n room: 1005\\n south:\\n room: 1014\\n up:\\n room: 11\\n west:\\n room: 1006\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 12\\n northwest:\\n room: 1005\\n south:\\n room: 1014\\n up:\\n room: 11\\n west:\\n room: 1006\\nhazard: \\\"\\\"\\nid: 10070\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:39:51-04:00\",\"description\":\"update room 2002 (add exit north to 1007)\",\"file_path\":\"data/rooms/intro/2002.yaml\",\"old_content\":\"id: 2002\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n east:\\n room: 2003\\n north:\\n room: 1013\\n southeast:\\n room: 2004\\n west:\\n room: 2001\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 2002\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n east:\\n room: 2003\\n north:\\n room: 1007\\n southeast:\\n room: 2004\\n west:\\n room: 2001\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:39:51-04:00\",\"description\":\"create room 1007\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n south: 2002\\nid: 1007\\nname: 'Room #1007'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:39:56-04:00\",\"description\":\"delete room 1007\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"exits:\\n south: 2002\\nid: 1007\\nname: 'Room #1007'\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:40:02-04:00\",\"description\":\"delete room 10070\",\"file_path\":\"data/rooms/intro/10070.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 12\\n northwest:\\n room: 1005\\n south:\\n room: 1014\\n up:\\n room: 11\\n west:\\n room: 1006\\nhazard: \\\"\\\"\\nid: 10070\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:40:04-04:00\",\"description\":\"delete room 1015\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1007\\n up:\\n room: 1015\\nhazard: \\\"\\\"\\nid: 1014\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:41:10-04:00\",\"description\":\"update room 1006\",\"file_path\":\"data/rooms/intro/1006.yaml\",\"old_content\":\"id: 1006\\nname: New Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 1005\\n northeast:\\n room: 1009\\n northwest:\\n room: 1008\\n up:\\n room: 1010\\n west:\\n room: 2003\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 1005\\n northeast:\\n room: 1009\\n northwest:\\n room: 1008\\n up:\\n room: 1010\\n west:\\n room: 2003\\nhazard: \\\"\\\"\\nid: 1006\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:41:11-04:00\",\"description\":\"update room 1006\",\"file_path\":\"data/rooms/intro/1006.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 1005\\n northeast:\\n room: 1009\\n northwest:\\n room: 1008\\n up:\\n room: 1010\\n west:\\n room: 2003\\nhazard: \\\"\\\"\\nid: 1006\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: E2\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 1005\\n northeast:\\n room: 1009\\n northwest:\\n room: 1008\\n up:\\n room: 1010\\n west:\\n room: 2003\\nhazard: \\\"\\\"\\nid: 1006\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:41:12-04:00\",\"description\":\"update room 1006\",\"file_path\":\"data/rooms/intro/1006.yaml\",\"old_content\":\"block_transport: false\\ncolor: E2\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 1005\\n northeast:\\n room: 1009\\n northwest:\\n room: 1008\\n up:\\n room: 1010\\n west:\\n room: 2003\\nhazard: \\\"\\\"\\nid: 1006\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: E2\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 1005\\n northeast:\\n room: 1009\\n northwest:\\n room: 1008\\n up:\\n room: 1010\\n west:\\n room: 2003\\nhazard: \\\"\\\"\\nid: 1006\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:41:16-04:00\",\"description\":\"update room 1016 (add exit east to 1007)\",\"file_path\":\"data/rooms/intro/1016.yaml\",\"old_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n south:\\n room: 1009\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n east:\\n room: 1007\\n south:\\n room: 1009\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:41:25-04:00\",\"description\":\"update room 1016 (add exit southeast to 1007)\",\"file_path\":\"data/rooms/intro/1016.yaml\",\"old_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n east:\\n room: 1007\\n south:\\n room: 1009\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n east:\\n room: 1007\\n south:\\n room: 1009\\n southeast:\\n room: 1007\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:41:37-04:00\",\"description\":\"update room 1016 (add exit southeast to 1007)\",\"file_path\":\"data/rooms/intro/1016.yaml\",\"old_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n east:\\n room: 1007\\n south:\\n room: 1009\\n southeast:\\n room: 1007\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n east:\\n room: 1007\\n south:\\n room: 1009\\n southeast:\\n room: 1007\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:41:44-04:00\",\"description\":\"update room 1016 (add exit southeast to 1007)\",\"file_path\":\"data/rooms/intro/1016.yaml\",\"old_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n east:\\n room: 1007\\n south:\\n room: 1009\\n southeast:\\n room: 1007\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n east:\\n room: 1007\\n south:\\n room: 1009\\n southeast:\\n room: 1007\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:41:57-04:00\",\"description\":\"update room 1006 (add exit east to 1007)\",\"file_path\":\"data/rooms/intro/1006.yaml\",\"old_content\":\"block_transport: false\\ncolor: E2\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 1005\\n northeast:\\n room: 1009\\n northwest:\\n room: 1008\\n up:\\n room: 1010\\n west:\\n room: 2003\\nhazard: \\\"\\\"\\nid: 1006\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"id: 1006\\nname: New Room\\ncolor: E2\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 1005\\n northeast:\\n room: 1009\\n northwest:\\n room: 1008\\n up:\\n room: 1010\\n west:\\n room: 2003\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:01-04:00\",\"description\":\"update room 2004 (add exit south to 1007)\",\"file_path\":\"data/rooms/intro/2004.yaml\",\"old_content\":\"id: 2004\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n north:\\n room: 2003\\n northwest:\\n room: 2002\\n west:\\n room: 2005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 2004\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n north:\\n room: 2003\\n northwest:\\n room: 2002\\n south:\\n room: 1007\\n west:\\n room: 2005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:01-04:00\",\"description\":\"create room 1007\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n north: 2004\\nid: 1007\\nname: 'Room #1007'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:42:20-04:00\",\"description\":\"unlink 1016 east 1007\",\"file_path\":\"data/rooms/intro/1016.yaml\",\"old_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n east:\\n room: 1007\\n south:\\n room: 1009\\n southeast:\\n room: 1007\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n south:\\n room: 1009\\n southeast:\\n room: 1007\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:20-04:00\",\"description\":\"unlink 1007 west 1016 (reverse)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"exits:\\n north: 2004\\nid: 1007\\nname: 'Room #1007'\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:23-04:00\",\"description\":\"unlink 1016 southeast 1007\",\"file_path\":\"data/rooms/intro/1016.yaml\",\"old_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n south:\\n room: 1009\\n southeast:\\n room: 1007\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n south:\\n room: 1009\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:23-04:00\",\"description\":\"unlink 1007 northwest 1016 (reverse)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:28-04:00\",\"description\":\"unlink 1006 east 1007\",\"file_path\":\"data/rooms/intro/1006.yaml\",\"old_content\":\"id: 1006\\nname: New Room\\ncolor: E2\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 1005\\n northeast:\\n room: 1009\\n northwest:\\n room: 1008\\n up:\\n room: 1010\\n west:\\n room: 2003\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1006\\nname: New Room\\ncolor: E2\\ndescription:\\n - text: A featureless room.\\nexits:\\n north:\\n room: 1005\\n northeast:\\n room: 1009\\n northwest:\\n room: 1008\\n up:\\n room: 1010\\n west:\\n room: 2003\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:28-04:00\",\"description\":\"unlink 1007 west 1006 (reverse)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:33-04:00\",\"description\":\"unlink 2002 north 1007\",\"file_path\":\"data/rooms/intro/2002.yaml\",\"old_content\":\"id: 2002\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n east:\\n room: 2003\\n north:\\n room: 1007\\n southeast:\\n room: 2004\\n west:\\n room: 2001\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 2002\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n east:\\n room: 2003\\n southeast:\\n room: 2004\\n west:\\n room: 2001\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:33-04:00\",\"description\":\"unlink 1007 south 2002 (reverse)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:38-04:00\",\"description\":\"unlink 1005 southeast 1007\",\"file_path\":\"data/rooms/intro/1005.yaml\",\"old_content\":\"block_transport: false\\ncolor: CC\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1009\\n northeast:\\n room: 1016\\n south:\\n room: 1006\\n southeast:\\n room: 1007\\n southwest:\\n room: 2003\\n west:\\n room: 1008\\nhazard: \\\"\\\"\\nid: 1005\\nitem_spawns: []\\nmobs: []\\nname: New Room\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"id: 1005\\nname: New Room\\ncolor: CC\\ndescription:\\n - text: A featureless room.\\nexits:\\n east:\\n room: 1009\\n northeast:\\n room: 1016\\n south:\\n room: 1006\\n southwest:\\n room: 2003\\n west:\\n room: 1008\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:38-04:00\",\"description\":\"unlink 1007 northwest 1005 (reverse)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:44-04:00\",\"description\":\"update room 1007 (add exit south to 1013)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\n south:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:44-04:00\",\"description\":\"create room 1013\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n north: 1007\\nid: 1013\\nname: 'Room #1013'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:42:44-04:00\",\"description\":\"update room 1013 (add exit east to 1014)\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"exits:\\n north: 1007\\nid: 1013\\nname: 'Room #1013'\\n\",\"new_content\":\"id: 1013\\nname: 'Room #1013'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1014\\n north:\\n room: 1007\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:44-04:00\",\"description\":\"create room 1014\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n west: 1013\\nid: 1014\\nname: 'Room #1014'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:42:45-04:00\",\"description\":\"update room 1014 (add exit east to 1015)\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"exits:\\n west: 1013\\nid: 1014\\nname: 'Room #1014'\\n\",\"new_content\":\"id: 1014\\nname: 'Room #1014'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1015\\n west:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:45-04:00\",\"description\":\"create room 1015\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n west: 1014\\nid: 1015\\nname: 'Room #1015'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:42:48-04:00\",\"description\":\"delete room 1015\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"exits:\\n west: 1014\\nid: 1015\\nname: 'Room #1015'\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:42:49-04:00\",\"description\":\"delete room 1014\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"id: 1014\\nname: 'Room #1014'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1015\\n west:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:42:51-04:00\",\"description\":\"delete room 1013\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"id: 1013\\nname: 'Room #1013'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1014\\n north:\\n room: 1007\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:42:53-04:00\",\"description\":\"update room 1007 (add exit east to 1013)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\n south:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1013\\n north:\\n room: 2004\\n south:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:42:53-04:00\",\"description\":\"create room 1013\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n west: 1007\\nid: 1013\\nname: 'Room #1013'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:43:23-04:00\",\"description\":\"delete room 1013\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"exits:\\n west: 1007\\nid: 1013\\nname: 'Room #1013'\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:43:24-04:00\",\"description\":\"update room 1007 (add exit south to 1013)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1013\\n north:\\n room: 2004\\n south:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1013\\n north:\\n room: 2004\\n south:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:24-04:00\",\"description\":\"create room 1013\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n north: 1007\\nid: 1013\\nname: 'Room #1013'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:43:35-04:00\",\"description\":\"unlink 1007 south 1013\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1013\\n north:\\n room: 2004\\n south:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1013\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:35-04:00\",\"description\":\"unlink 1013 north 1007 (reverse)\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"exits:\\n north: 1007\\nid: 1013\\nname: 'Room #1013'\\n\",\"new_content\":\"id: 1013\\nname: 'Room #1013'\\ncolor: \\\"\\\"\\ndescription: []\\nexits: {}\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:39-04:00\",\"description\":\"unlink 1007 east 1013\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1013\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:39-04:00\",\"description\":\"unlink 1013 west 1007 (reverse)\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"id: 1013\\nname: 'Room #1013'\\ncolor: \\\"\\\"\\ndescription: []\\nexits: {}\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1013\\nname: 'Room #1013'\\ncolor: \\\"\\\"\\ndescription: []\\nexits: {}\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:42-04:00\",\"description\":\"delete room 1013\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"id: 1013\\nname: 'Room #1013'\\ncolor: \\\"\\\"\\ndescription: []\\nexits: {}\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:43:43-04:00\",\"description\":\"update room 1007 (add exit south to 1013)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\n south:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:43-04:00\",\"description\":\"create room 1013\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n north: 1007\\nid: 1013\\nname: 'Room #1013'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:43:44-04:00\",\"description\":\"update room 1013 (add exit east to 1014)\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"exits:\\n north: 1007\\nid: 1013\\nname: 'Room #1013'\\n\",\"new_content\":\"id: 1013\\nname: 'Room #1013'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1014\\n north:\\n room: 1007\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:44-04:00\",\"description\":\"create room 1014\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n west: 1013\\nid: 1014\\nname: 'Room #1014'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:43:45-04:00\",\"description\":\"update room 1014 (add exit north to 1015)\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"exits:\\n west: 1013\\nid: 1014\\nname: 'Room #1014'\\n\",\"new_content\":\"id: 1014\\nname: 'Room #1014'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 1015\\n west:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:45-04:00\",\"description\":\"create room 1015\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n south: 1014\\nid: 1015\\nname: 'Room #1015'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:43:46-04:00\",\"description\":\"update room 1015 (add exit east to 1018)\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"exits:\\n south: 1014\\nid: 1015\\nname: 'Room #1015'\\n\",\"new_content\":\"id: 1015\\nname: 'Room #1015'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1018\\n south:\\n room: 1014\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:46-04:00\",\"description\":\"create room 1018\",\"file_path\":\"data/rooms/intro/1018.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n west: 1015\\nid: 1018\\nname: 'Room #1018'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:43:46-04:00\",\"description\":\"update room 1018 (add exit south to 1019)\",\"file_path\":\"data/rooms/intro/1018.yaml\",\"old_content\":\"exits:\\n west: 1015\\nid: 1018\\nname: 'Room #1018'\\n\",\"new_content\":\"id: 1018\\nname: 'Room #1018'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n south:\\n room: 1019\\n west:\\n room: 1015\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:46-04:00\",\"description\":\"create room 1019\",\"file_path\":\"data/rooms/intro/1019.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n north: 1018\\nid: 1019\\nname: 'Room #1019'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:43:47-04:00\",\"description\":\"link 1019 west 1014\",\"file_path\":\"data/rooms/intro/1019.yaml\",\"old_content\":\"exits:\\n north: 1018\\nid: 1019\\nname: 'Room #1019'\\n\",\"new_content\":\"id: 1019\\nname: 'Room #1019'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 1018\\n west:\\n room: 1014\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:47-04:00\",\"description\":\"link 1014 east 1019 (reverse)\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"id: 1014\\nname: 'Room #1014'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 1015\\n west:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1014\\nname: 'Room #1014'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1019\\n north:\\n room: 1015\\n west:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:43:50-04:00\",\"description\":\"delete room 1019\",\"file_path\":\"data/rooms/intro/1019.yaml\",\"old_content\":\"id: 1019\\nname: 'Room #1019'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 1018\\n west:\\n room: 1014\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:46:51-04:00\",\"description\":\"delete room 1018 (cleaned 1 exits)\",\"file_path\":\"data/rooms/intro/1018.yaml\",\"old_content\":\"id: 1018\\nname: 'Room #1018'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n south:\\n room: 1019\\n west:\\n room: 1015\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:46:53-04:00\",\"description\":\"delete room 1015 (cleaned 1 exits)\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"id: 1015\\nname: 'Room #1015'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n south:\\n room: 1014\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:46:56-04:00\",\"description\":\"delete room 1014 (cleaned 1 exits)\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"id: 1014\\nname: 'Room #1014'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1019\\n west:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:47:00-04:00\",\"description\":\"delete room 1013 (cleaned 1 exits)\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"id: 1013\\nname: 'Room #1013'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 1007\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:47:04-04:00\",\"description\":\"delete room 1007 (cleaned 1 exits)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"\",\"is_delete\":true,\"is_create\":false},{\"time\":\"2026-06-30T03:47:05-04:00\",\"description\":\"update room 2004 (add exit east to 1007)\",\"file_path\":\"data/rooms/intro/2004.yaml\",\"old_content\":\"id: 2004\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n north:\\n room: 2003\\n northwest:\\n room: 2002\\n west:\\n room: 2005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 2004\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 2003\\n northwest:\\n room: 2002\\n west:\\n room: 2005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:05-04:00\",\"description\":\"create room 1007\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n west: 2004\\nid: 1007\\nname: 'Room #1007'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:47:06-04:00\",\"description\":\"update room 1007 (add exit east to 1013)\",\"file_path\":\"data/rooms/intro/1007.yaml\",\"old_content\":\"exits:\\n west: 2004\\nid: 1007\\nname: 'Room #1007'\\n\",\"new_content\":\"id: 1007\\nname: 'Room #1007'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n east:\\n room: 1013\\n west:\\n room: 2004\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:06-04:00\",\"description\":\"create room 1013\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n west: 1007\\nid: 1013\\nname: 'Room #1013'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:47:07-04:00\",\"description\":\"update room 1013 (add exit northeast to 1014)\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"exits:\\n west: 1007\\nid: 1013\\nname: 'Room #1013'\\n\",\"new_content\":\"id: 1013\\nname: 'Room #1013'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n northeast:\\n room: 1014\\n west:\\n room: 1007\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:07-04:00\",\"description\":\"create room 1014\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n southwest: 1013\\nid: 1014\\nname: 'Room #1014'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:47:08-04:00\",\"description\":\"update room 1014 (add exit northeast to 1015)\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"exits:\\n southwest: 1013\\nid: 1014\\nname: 'Room #1014'\\n\",\"new_content\":\"id: 1014\\nname: 'Room #1014'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n northeast:\\n room: 1015\\n southwest:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:08-04:00\",\"description\":\"create room 1015\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n southwest: 1014\\nid: 1015\\nname: 'Room #1015'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:47:09-04:00\",\"description\":\"update room 1015 (add exit northwest to 1018)\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"exits:\\n southwest: 1014\\nid: 1015\\nname: 'Room #1015'\\n\",\"new_content\":\"id: 1015\\nname: 'Room #1015'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n northwest:\\n room: 1018\\n southwest:\\n room: 1014\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:09-04:00\",\"description\":\"create room 1018\",\"file_path\":\"data/rooms/intro/1018.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n southeast: 1015\\nid: 1018\\nname: 'Room #1018'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:47:09-04:00\",\"description\":\"link 1018 west 1016\",\"file_path\":\"data/rooms/intro/1018.yaml\",\"old_content\":\"exits:\\n southeast: 1015\\nid: 1018\\nname: 'Room #1018'\\n\",\"new_content\":\"id: 1018\\nname: 'Room #1018'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n southeast:\\n room: 1015\\n west:\\n room: 1016\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:09-04:00\",\"description\":\"link 1016 east 1018 (reverse)\",\"file_path\":\"data/rooms/intro/1016.yaml\",\"old_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n south:\\n room: 1009\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1016\\nname: New Room\\ncolor: \\\"97\\\"\\ndescription:\\n - text: A featureless room.\\nexits:\\n down:\\n room: 1017\\n east:\\n room: 1018\\n south:\\n room: 1009\\n southwest:\\n room: 1005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:17-04:00\",\"description\":\"update room 1018\",\"file_path\":\"data/rooms/intro/1018.yaml\",\"old_content\":\"id: 1018\\nname: 'Room #1018'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n southeast:\\n room: 1015\\n west:\\n room: 1016\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n southeast:\\n room: 1015\\n west:\\n room: 1016\\nhazard: \\\"\\\"\\nid: 1018\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1018'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:21-04:00\",\"description\":\"update room 1018\",\"file_path\":\"data/rooms/intro/1018.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n southeast:\\n room: 1015\\n west:\\n room: 1016\\nhazard: \\\"\\\"\\nid: 1018\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1018'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n southeast:\\n room: 1015\\n west:\\n room: 1016\\nhazard: \\\"\\\"\\nid: 1018\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1018'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:25-04:00\",\"description\":\"update room 1018\",\"file_path\":\"data/rooms/intro/1018.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n southeast:\\n room: 1015\\n west:\\n room: 1016\\nhazard: \\\"\\\"\\nid: 1018\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1018'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n southeast:\\n room: 1015\\n west:\\n room: 1016\\nhazard: \\\"\\\"\\nid: 1018\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1018'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:26-04:00\",\"description\":\"update room 1018\",\"file_path\":\"data/rooms/intro/1018.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n southeast:\\n room: 1015\\n west:\\n room: 1016\\nhazard: \\\"\\\"\\nid: 1018\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1018'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: D0\\ndescription: []\\nexits:\\n southeast:\\n room: 1015\\n west:\\n room: 1016\\nhazard: \\\"\\\"\\nid: 1018\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1018'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:33-04:00\",\"description\":\"update room 1015\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"id: 1015\\nname: 'Room #1015'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n northwest:\\n room: 1018\\n southwest:\\n room: 1014\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n northwest:\\n room: 1018\\n southwest:\\n room: 1014\\nhazard: \\\"\\\"\\nid: 1015\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1015'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:34-04:00\",\"description\":\"update room 1015\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n northwest:\\n room: 1018\\n southwest:\\n room: 1014\\nhazard: \\\"\\\"\\nid: 1015\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1015'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: 0C\\ndescription: []\\nexits:\\n northwest:\\n room: 1018\\n southwest:\\n room: 1014\\nhazard: \\\"\\\"\\nid: 1015\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1015'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:36-04:00\",\"description\":\"update room 1015\",\"file_path\":\"data/rooms/intro/1015.yaml\",\"old_content\":\"block_transport: false\\ncolor: 0C\\ndescription: []\\nexits:\\n northwest:\\n room: 1018\\n southwest:\\n room: 1014\\nhazard: \\\"\\\"\\nid: 1015\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1015'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: 0C\\ndescription: []\\nexits:\\n northwest:\\n room: 1018\\n southwest:\\n room: 1014\\nhazard: \\\"\\\"\\nid: 1015\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1015'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:40-04:00\",\"description\":\"update room 1014\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"id: 1014\\nname: 'Room #1014'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n northeast:\\n room: 1015\\n southwest:\\n room: 1013\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n northeast:\\n room: 1015\\n southwest:\\n room: 1013\\nhazard: \\\"\\\"\\nid: 1014\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1014'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:41-04:00\",\"description\":\"update room 1014\",\"file_path\":\"data/rooms/intro/1014.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n northeast:\\n room: 1015\\n southwest:\\n room: 1013\\nhazard: \\\"\\\"\\nid: 1014\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1014'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: D5\\ndescription: []\\nexits:\\n northeast:\\n room: 1015\\n southwest:\\n room: 1013\\nhazard: \\\"\\\"\\nid: 1014\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1014'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:45-04:00\",\"description\":\"update room 1013\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"id: 1013\\nname: 'Room #1013'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n northeast:\\n room: 1014\\n west:\\n room: 1007\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n northeast:\\n room: 1014\\n west:\\n room: 1007\\nhazard: \\\"\\\"\\nid: 1013\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1013'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:46-04:00\",\"description\":\"update room 1013\",\"file_path\":\"data/rooms/intro/1013.yaml\",\"old_content\":\"block_transport: false\\ncolor: \\\"00\\\"\\ndescription: []\\nexits:\\n northeast:\\n room: 1014\\n west:\\n room: 1007\\nhazard: \\\"\\\"\\nid: 1013\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1013'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"new_content\":\"block_transport: false\\ncolor: \\\"72\\\"\\ndescription: []\\nexits:\\n northeast:\\n room: 1014\\n west:\\n room: 1007\\nhazard: \\\"\\\"\\nid: 1013\\nitem_spawns: []\\nmobs: []\\nname: 'Room #1013'\\nobjects: []\\non_enter: []\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:57-04:00\",\"description\":\"update room 2004 (add exit south to 1019)\",\"file_path\":\"data/rooms/intro/2004.yaml\",\"old_content\":\"id: 2004\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 2003\\n northwest:\\n room: 2002\\n west:\\n room: 2005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 2004\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 2003\\n northwest:\\n room: 2002\\n south:\\n room: 1019\\n west:\\n room: 2005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:57-04:00\",\"description\":\"create room 1019\",\"file_path\":\"data/rooms/intro/1019.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n north: 2004\\nid: 1019\\nname: 'Room #1019'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:47:58-04:00\",\"description\":\"update room 1019 (add exit south to 1020)\",\"file_path\":\"data/rooms/intro/1019.yaml\",\"old_content\":\"exits:\\n north: 2004\\nid: 1019\\nname: 'Room #1019'\\n\",\"new_content\":\"id: 1019\\nname: 'Room #1019'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\n south:\\n room: 1020\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:47:58-04:00\",\"description\":\"create room 1020\",\"file_path\":\"data/rooms/intro/1020.yaml\",\"old_content\":\"\",\"new_content\":\"exits:\\n north: 1019\\nid: 1020\\nname: 'Room #1020'\\n\",\"is_delete\":false,\"is_create\":true},{\"time\":\"2026-06-30T03:48:00-04:00\",\"description\":\"unlink 2004 south 1019\",\"file_path\":\"data/rooms/intro/2004.yaml\",\"old_content\":\"id: 2004\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 2003\\n northwest:\\n room: 2002\\n south:\\n room: 1019\\n west:\\n room: 2005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 2004\\nname: Test Room\\ncolor: \\\"\\\"\\ndescription:\\n - text: It's a test room\\nexits:\\n east:\\n room: 1007\\n north:\\n room: 2003\\n northwest:\\n room: 2002\\n west:\\n room: 2005\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false},{\"time\":\"2026-06-30T03:48:00-04:00\",\"description\":\"unlink 1019 north 2004 (reverse)\",\"file_path\":\"data/rooms/intro/1019.yaml\",\"old_content\":\"id: 1019\\nname: 'Room #1019'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n north:\\n room: 2004\\n south:\\n room: 1020\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"new_content\":\"id: 1019\\nname: 'Room #1019'\\ncolor: \\\"\\\"\\ndescription: []\\nexits:\\n south:\\n room: 1020\\nobjects: []\\nitem_spawns: []\\nmobs: []\\non_enter: []\\nhazard: \\\"\\\"\\nblock_transport: false\\ntriggers: []\\n\",\"is_delete\":false,\"is_create\":false}],\"redo\":null}","new_content":"","is_delete":true,"is_create":false}],"redo":null} \ No newline at end of file
diff --git a/data/.admin_history.yaml b/data/.admin_history.yaml
deleted file mode 100644
index 97f11d9..0000000
--- a/data/.admin_history.yaml
+++ /dev/null
@@ -1 +0,0 @@
-{"history":[{"time":"2026-06-30T03:16:23-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"26\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:16:24-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:16:25-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:20:00-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:20:04-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:20:07-04:00","description":"update room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1016\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs:\n - id: man\n - id: man\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:28:54-04:00","description":"rename room 1014 to 1015","file_path":"data/rooms/intro/1014.yaml","new_file_path":"data/rooms/intro/1015.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1007\n up:\n room: 1015\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1007\n up:\n room: 1015\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:29:30-04:00","description":"rename room 1007 to 10070","file_path":"data/rooms/intro/1007.yaml","new_file_path":"data/rooms/intro/10070.yaml","old_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:30:46-04:00","description":"update room 10070","file_path":"data/rooms/intro/10070.yaml","old_content":"id: 1007\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nhazard: \"\"\nid: 10070\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:39:51-04:00","description":"update room 2002 (add exit north to 1007)","file_path":"data/rooms/intro/2002.yaml","old_content":"id: 2002\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n north:\n room: 1013\n southeast:\n room: 2004\n west:\n room: 2001\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2002\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n north:\n room: 1007\n southeast:\n room: 2004\n west:\n room: 2001\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:39:51-04:00","description":"create room 1007","file_path":"data/rooms/intro/1007.yaml","old_content":"","new_content":"exits:\n south: 2002\nid: 1007\nname: 'Room #1007'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:39:56-04:00","description":"delete room 1007","file_path":"data/rooms/intro/1007.yaml","old_content":"exits:\n south: 2002\nid: 1007\nname: 'Room #1007'\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:40:02-04:00","description":"delete room 10070","file_path":"data/rooms/intro/10070.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 12\n northwest:\n room: 1005\n south:\n room: 1014\n up:\n room: 11\n west:\n room: 1006\nhazard: \"\"\nid: 10070\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:40:04-04:00","description":"delete room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1007\n up:\n room: 1015\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:41:10-04:00","description":"update room 1006","file_path":"data/rooms/intro/1006.yaml","old_content":"id: 1006\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:11-04:00","description":"update room 1006","file_path":"data/rooms/intro/1006.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:12-04:00","description":"update room 1006","file_path":"data/rooms/intro/1006.yaml","old_content":"block_transport: false\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:16-04:00","description":"update room 1016 (add exit east to 1007)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:25-04:00","description":"update room 1016 (add exit southeast to 1007)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:37-04:00","description":"update room 1016 (add exit southeast to 1007)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:44-04:00","description":"update room 1016 (add exit southeast to 1007)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:41:57-04:00","description":"update room 1006 (add exit east to 1007)","file_path":"data/rooms/intro/1006.yaml","old_content":"block_transport: false\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nhazard: \"\"\nid: 1006\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"id: 1006\nname: New Room\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:01-04:00","description":"update room 2004 (add exit south to 1007)","file_path":"data/rooms/intro/2004.yaml","old_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 2003\n northwest:\n room: 2002\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 2003\n northwest:\n room: 2002\n south:\n room: 1007\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:01-04:00","description":"create room 1007","file_path":"data/rooms/intro/1007.yaml","old_content":"","new_content":"exits:\n north: 2004\nid: 1007\nname: 'Room #1007'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:42:20-04:00","description":"unlink 1016 east 1007","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1007\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:20-04:00","description":"unlink 1007 west 1016 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"exits:\n north: 2004\nid: 1007\nname: 'Room #1007'\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:23-04:00","description":"unlink 1016 southeast 1007","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southeast:\n room: 1007\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:23-04:00","description":"unlink 1007 northwest 1016 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:28-04:00","description":"unlink 1006 east 1007","file_path":"data/rooms/intro/1006.yaml","old_content":"id: 1006\nname: New Room\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1007\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1006\nname: New Room\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1005\n northeast:\n room: 1009\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:28-04:00","description":"unlink 1007 west 1006 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:33-04:00","description":"unlink 2002 north 1007","file_path":"data/rooms/intro/2002.yaml","old_content":"id: 2002\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n north:\n room: 1007\n southeast:\n room: 2004\n west:\n room: 2001\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2002\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2003\n southeast:\n room: 2004\n west:\n room: 2001\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:33-04:00","description":"unlink 1007 south 2002 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:38-04:00","description":"unlink 1005 southeast 1007","file_path":"data/rooms/intro/1005.yaml","old_content":"block_transport: false\ncolor: CC\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n northeast:\n room: 1016\n south:\n room: 1006\n southeast:\n room: 1007\n southwest:\n room: 2003\n west:\n room: 1008\nhazard: \"\"\nid: 1005\nitem_spawns: []\nmobs: []\nname: New Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"id: 1005\nname: New Room\ncolor: CC\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1009\n northeast:\n room: 1016\n south:\n room: 1006\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:38-04:00","description":"unlink 1007 northwest 1005 (reverse)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:44-04:00","description":"update room 1007 (add exit south to 1013)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:44-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:42:44-04:00","description":"update room 1013 (add exit east to 1014)","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","new_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1014\n north:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:44-04:00","description":"create room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"","new_content":"exits:\n west: 1013\nid: 1014\nname: 'Room #1014'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:42:45-04:00","description":"update room 1014 (add exit east to 1015)","file_path":"data/rooms/intro/1014.yaml","old_content":"exits:\n west: 1013\nid: 1014\nname: 'Room #1014'\n","new_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1015\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:45-04:00","description":"create room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"","new_content":"exits:\n west: 1014\nid: 1015\nname: 'Room #1015'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:42:48-04:00","description":"delete room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"exits:\n west: 1014\nid: 1015\nname: 'Room #1015'\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:42:49-04:00","description":"delete room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1015\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:42:51-04:00","description":"delete room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1014\n north:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:42:53-04:00","description":"update room 1007 (add exit east to 1013)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:42:53-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n west: 1007\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:23-04:00","description":"delete room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n west: 1007\nid: 1013\nname: 'Room #1013'\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:43:24-04:00","description":"update room 1007 (add exit south to 1013)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:24-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:35-04:00","description":"unlink 1007 south 1013","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:35-04:00","description":"unlink 1013 north 1007 (reverse)","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","new_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:39-04:00","description":"unlink 1007 east 1013","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:39-04:00","description":"unlink 1013 west 1007 (reverse)","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:42-04:00","description":"delete room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:43:43-04:00","description":"update room 1007 (add exit south to 1013)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:43-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:44-04:00","description":"update room 1013 (add exit east to 1014)","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n north: 1007\nid: 1013\nname: 'Room #1013'\n","new_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1014\n north:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:44-04:00","description":"create room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"","new_content":"exits:\n west: 1013\nid: 1014\nname: 'Room #1014'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:45-04:00","description":"update room 1014 (add exit north to 1015)","file_path":"data/rooms/intro/1014.yaml","old_content":"exits:\n west: 1013\nid: 1014\nname: 'Room #1014'\n","new_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1015\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:45-04:00","description":"create room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"","new_content":"exits:\n south: 1014\nid: 1015\nname: 'Room #1015'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:46-04:00","description":"update room 1015 (add exit east to 1018)","file_path":"data/rooms/intro/1015.yaml","old_content":"exits:\n south: 1014\nid: 1015\nname: 'Room #1015'\n","new_content":"id: 1015\nname: 'Room #1015'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1018\n south:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:46-04:00","description":"create room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"","new_content":"exits:\n west: 1015\nid: 1018\nname: 'Room #1018'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:46-04:00","description":"update room 1018 (add exit south to 1019)","file_path":"data/rooms/intro/1018.yaml","old_content":"exits:\n west: 1015\nid: 1018\nname: 'Room #1018'\n","new_content":"id: 1018\nname: 'Room #1018'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1019\n west:\n room: 1015\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:46-04:00","description":"create room 1019","file_path":"data/rooms/intro/1019.yaml","old_content":"","new_content":"exits:\n north: 1018\nid: 1019\nname: 'Room #1019'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:43:47-04:00","description":"link 1019 west 1014","file_path":"data/rooms/intro/1019.yaml","old_content":"exits:\n north: 1018\nid: 1019\nname: 'Room #1019'\n","new_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1018\n west:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:47-04:00","description":"link 1014 east 1019 (reverse)","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1015\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1019\n north:\n room: 1015\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:43:50-04:00","description":"delete room 1019","file_path":"data/rooms/intro/1019.yaml","old_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1018\n west:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:46:51-04:00","description":"delete room 1018 (cleaned 1 exits)","file_path":"data/rooms/intro/1018.yaml","old_content":"id: 1018\nname: 'Room #1018'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1019\n west:\n room: 1015\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:46:53-04:00","description":"delete room 1015 (cleaned 1 exits)","file_path":"data/rooms/intro/1015.yaml","old_content":"id: 1015\nname: 'Room #1015'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:46:56-04:00","description":"delete room 1014 (cleaned 1 exits)","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1019\n west:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:47:00-04:00","description":"delete room 1013 (cleaned 1 exits)","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:47:04-04:00","description":"delete room 1007 (cleaned 1 exits)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T03:47:05-04:00","description":"update room 2004 (add exit east to 1007)","file_path":"data/rooms/intro/2004.yaml","old_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 2003\n northwest:\n room: 2002\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 1007\n north:\n room: 2003\n northwest:\n room: 2002\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:05-04:00","description":"create room 1007","file_path":"data/rooms/intro/1007.yaml","old_content":"","new_content":"exits:\n west: 2004\nid: 1007\nname: 'Room #1007'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:06-04:00","description":"update room 1007 (add exit east to 1013)","file_path":"data/rooms/intro/1007.yaml","old_content":"exits:\n west: 2004\nid: 1007\nname: 'Room #1007'\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1013\n west:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:06-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n west: 1007\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:07-04:00","description":"update room 1013 (add exit northeast to 1014)","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n west: 1007\nid: 1013\nname: 'Room #1013'\n","new_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n northeast:\n room: 1014\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:07-04:00","description":"create room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"","new_content":"exits:\n southwest: 1013\nid: 1014\nname: 'Room #1014'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:08-04:00","description":"update room 1014 (add exit northeast to 1015)","file_path":"data/rooms/intro/1014.yaml","old_content":"exits:\n southwest: 1013\nid: 1014\nname: 'Room #1014'\n","new_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n northeast:\n room: 1015\n southwest:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:08-04:00","description":"create room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"","new_content":"exits:\n southwest: 1014\nid: 1015\nname: 'Room #1015'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:09-04:00","description":"update room 1015 (add exit northwest to 1018)","file_path":"data/rooms/intro/1015.yaml","old_content":"exits:\n southwest: 1014\nid: 1015\nname: 'Room #1015'\n","new_content":"id: 1015\nname: 'Room #1015'\ncolor: \"\"\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:09-04:00","description":"create room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"","new_content":"exits:\n southeast: 1015\nid: 1018\nname: 'Room #1018'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:09-04:00","description":"link 1018 west 1016","file_path":"data/rooms/intro/1018.yaml","old_content":"exits:\n southeast: 1015\nid: 1018\nname: 'Room #1018'\n","new_content":"id: 1018\nname: 'Room #1018'\ncolor: \"\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:09-04:00","description":"link 1016 east 1018 (reverse)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n east:\n room: 1018\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:17-04:00","description":"update room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"id: 1018\nname: 'Room #1018'\ncolor: \"\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:21-04:00","description":"update room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:25-04:00","description":"update room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:26-04:00","description":"update room 1018","file_path":"data/rooms/intro/1018.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: D0\ndescription: []\nexits:\n southeast:\n room: 1015\n west:\n room: 1016\nhazard: \"\"\nid: 1018\nitem_spawns: []\nmobs: []\nname: 'Room #1018'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:33-04:00","description":"update room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"id: 1015\nname: 'Room #1015'\ncolor: \"\"\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nhazard: \"\"\nid: 1015\nitem_spawns: []\nmobs: []\nname: 'Room #1015'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:34-04:00","description":"update room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nhazard: \"\"\nid: 1015\nitem_spawns: []\nmobs: []\nname: 'Room #1015'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: 0C\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nhazard: \"\"\nid: 1015\nitem_spawns: []\nmobs: []\nname: 'Room #1015'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:36-04:00","description":"update room 1015","file_path":"data/rooms/intro/1015.yaml","old_content":"block_transport: false\ncolor: 0C\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nhazard: \"\"\nid: 1015\nitem_spawns: []\nmobs: []\nname: 'Room #1015'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: 0C\ndescription: []\nexits:\n northwest:\n room: 1018\n southwest:\n room: 1014\nhazard: \"\"\nid: 1015\nitem_spawns: []\nmobs: []\nname: 'Room #1015'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:40-04:00","description":"update room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: 'Room #1014'\ncolor: \"\"\ndescription: []\nexits:\n northeast:\n room: 1015\n southwest:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northeast:\n room: 1015\n southwest:\n room: 1013\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: 'Room #1014'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:41-04:00","description":"update room 1014","file_path":"data/rooms/intro/1014.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northeast:\n room: 1015\n southwest:\n room: 1013\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: 'Room #1014'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: D5\ndescription: []\nexits:\n northeast:\n room: 1015\n southwest:\n room: 1013\nhazard: \"\"\nid: 1014\nitem_spawns: []\nmobs: []\nname: 'Room #1014'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:45-04:00","description":"update room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"\"\ndescription: []\nexits:\n northeast:\n room: 1014\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northeast:\n room: 1014\n west:\n room: 1007\nhazard: \"\"\nid: 1013\nitem_spawns: []\nmobs: []\nname: 'Room #1013'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:46-04:00","description":"update room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"block_transport: false\ncolor: \"00\"\ndescription: []\nexits:\n northeast:\n room: 1014\n west:\n room: 1007\nhazard: \"\"\nid: 1013\nitem_spawns: []\nmobs: []\nname: 'Room #1013'\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"72\"\ndescription: []\nexits:\n northeast:\n room: 1014\n west:\n room: 1007\nhazard: \"\"\nid: 1013\nitem_spawns: []\nmobs: []\nname: 'Room #1013'\nobjects: []\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:57-04:00","description":"update room 2004 (add exit south to 1019)","file_path":"data/rooms/intro/2004.yaml","old_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 1007\n north:\n room: 2003\n northwest:\n room: 2002\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 1007\n north:\n room: 2003\n northwest:\n room: 2002\n south:\n room: 1019\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:57-04:00","description":"create room 1019","file_path":"data/rooms/intro/1019.yaml","old_content":"","new_content":"exits:\n north: 2004\nid: 1019\nname: 'Room #1019'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:47:58-04:00","description":"update room 1019 (add exit south to 1020)","file_path":"data/rooms/intro/1019.yaml","old_content":"exits:\n north: 2004\nid: 1019\nname: 'Room #1019'\n","new_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\n south:\n room: 1020\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:47:58-04:00","description":"create room 1020","file_path":"data/rooms/intro/1020.yaml","old_content":"","new_content":"exits:\n north: 1019\nid: 1020\nname: 'Room #1020'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T03:48:00-04:00","description":"unlink 2004 south 1019","file_path":"data/rooms/intro/2004.yaml","old_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 1007\n north:\n room: 2003\n northwest:\n room: 2002\n south:\n room: 1019\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2004\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 1007\n north:\n room: 2003\n northwest:\n room: 2002\n west:\n room: 2005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T03:48:00-04:00","description":"unlink 1019 north 2004 (reverse)","file_path":"data/rooms/intro/1019.yaml","old_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 2004\n south:\n room: 1020\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1020\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false}],"redo":null} \ No newline at end of file
diff --git a/data/drops/christmas_cracker_hat.yaml b/data/drops/christmas_cracker_hat.yaml
index 23f7231..2a20878 100644
--- a/data/drops/christmas_cracker_hat.yaml
+++ b/data/drops/christmas_cracker_hat.yaml
@@ -17,5 +17,4 @@ drops:
weight: 1
- item_id: bronze_pickaxe
weight: 1
- - item_id: ""
- weight: 3
+id: christmas_cracker_hat
diff --git a/data/objects/000_test_object.yaml b/data/objects/000_test_object.yaml
deleted file mode 100644
index 7bd79b7..0000000
--- a/data/objects/000_test_object.yaml
+++ /dev/null
@@ -1,29 +0,0 @@
-color: C4
-description: A sinister altar of red biological interfaces. Place scrap here with a bio identifier to produce biojunk. Type 'id' to begin.
-gather:
- skill: mining
- success:
- base: 0
- cap: 1
- per_level: 0
- tools:
- - axe
-hidden: false
-id: 000_test_object
-name: 000 test object
-on_use:
- - condition:
- all_of:
- - global_flag: one
- - player_flag: two
- - all_of:
- - player_flag: three
- - global_flag: four
-safespot:
- decay_chance: 0
- decay_ticks: 0
- max_occupants: 1
- respawn_on_hide: false
- respawn_ticks: 0
- tier: 1
- unsafe_chance: 0
diff --git a/internal/admin/api_files.go b/internal/admin/api_files.go
index 2a87dd3..496b08d 100644
--- a/internal/admin/api_files.go
+++ b/internal/admin/api_files.go
@@ -8,6 +8,71 @@ import (
"strings"
)
+func (s *AdminServer) handleFileRename(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+ var body struct {
+ Path string `json:"path"`
+ NewName string `json:"new_name"`
+ }
+ if err := readJSON(r, &body); err != nil || body.Path == "" || body.NewName == "" {
+ writeJSON(w, map[string]any{"error": "missing path or new_name"})
+ return
+ }
+
+ newName := strings.TrimSpace(body.NewName)
+ if newName == "" || newName == "." || newName == ".." || strings.ContainsAny(newName, "/\\") {
+ writeJSON(w, map[string]any{"error": "invalid file name"})
+ return
+ }
+ for _, c := range newName {
+ if c < 32 || c == 127 {
+ writeJSON(w, map[string]any{"error": "file name contains invalid characters"})
+ return
+ }
+ }
+
+ relPath := strings.TrimPrefix(body.Path, "/")
+ relPath = strings.TrimPrefix(relPath, "data/")
+ oldAbs := filepath.Join(s.dataDir, relPath)
+
+ oldContent, err := snapshotFile(oldAbs)
+ if err != nil {
+ writeJSON(w, map[string]any{"error": "file not found: " + relPath})
+ return
+ }
+
+ newAbs := filepath.Join(filepath.Dir(oldAbs), newName)
+ if _, err := os.Stat(newAbs); err == nil {
+ writeJSON(w, map[string]any{"error": "a file named " + newName + " already exists"})
+ return
+ }
+
+ if err := os.WriteFile(newAbs, oldContent, 0644); err != nil {
+ writeJSON(w, map[string]any{"error": "write error: " + err.Error()})
+ return
+ }
+ if err := os.Remove(oldAbs); err != nil {
+ writeJSON(w, map[string]any{"error": "remove error: " + err.Error()})
+ return
+ }
+
+ newRelPath := filepath.Join(filepath.Dir(relPath), newName)
+ if filepath.Dir(relPath) == "." {
+ newRelPath = newName
+ }
+ s.undoStack.Push(ChangeDesc{
+ Description: "Renamed file " + relPath + " to " + newRelPath,
+ FilePath: oldAbs,
+ NewFilePath: newAbs,
+ OldContent: oldContent,
+ NewContent: oldContent,
+ })
+ writeJSON(w, map[string]any{"ok": true, "path": newRelPath})
+}
+
func (s *AdminServer) handleFiles(w http.ResponseWriter, r *http.Request) {
relPath := r.URL.Query().Get("path")
relPath = strings.TrimPrefix(relPath, "/")
diff --git a/internal/admin/server.go b/internal/admin/server.go
index f07bdd4..11efb5c 100644
--- a/internal/admin/server.go
+++ b/internal/admin/server.go
@@ -177,6 +177,7 @@ func NewServer(cfg *config.Config, useTLS bool, accountStore *player.AccountStor
apiMux.HandleFunc("/api/undo/redo", s.doRedo)
apiMux.HandleFunc("/api/next-room-id", s.handleNextRoomID)
apiMux.HandleFunc("/api/files", s.handleFiles)
+ apiMux.HandleFunc("/api/files/rename", s.handleFileRename)
apiMux.HandleFunc("/api/duplicate-rooms", s.handleDuplicateRooms)
apiMux.HandleFunc("/api/rooms/resolve-duplicate", s.handleResolveDuplicate)
apiMux.HandleFunc("/api/triggers", s.handleTriggers)
diff --git a/internal/admin/static/ctxmenu.js b/internal/admin/static/ctxmenu.js
new file mode 100644
index 0000000..96e92a9
--- /dev/null
+++ b/internal/admin/static/ctxmenu.js
@@ -0,0 +1,47 @@
+function openContextMenu(e, items) {
+ e.preventDefault();
+ e.stopPropagation();
+ closeContextMenu();
+
+ var overlay = document.createElement('div');
+ overlay.className = 'cm-overlay';
+ overlay.id = '_ctxMenuOverlay';
+ overlay.onclick = function() { closeContextMenu(); };
+ overlay.addEventListener('contextmenu', function(ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ var cx = ev.clientX, cy = ev.clientY;
+ closeContextMenu();
+ var el = document.elementFromPoint(cx, cy);
+ if (el) el.dispatchEvent(new MouseEvent('contextmenu', {bubbles:true, cancelable:true, clientX:cx, clientY:cy, button:2}));
+ });
+
+ var menu = document.createElement('div');
+ menu.className = 'cm-menu';
+ menu.id = '_ctxMenu';
+ menu.style.left = e.clientX + 'px';
+ menu.style.top = e.clientY + 'px';
+ menu.oncontextmenu = function(ev) { ev.preventDefault(); };
+
+ function addBtn(label, cls, handler) {
+ var btn = document.createElement('button');
+ btn.textContent = label;
+ if (cls) btn.className = cls;
+ btn.onclick = function() { closeContextMenu(); handler(); };
+ menu.appendChild(btn);
+ }
+
+ for (var i = 0; i < items.length; i++) {
+ addBtn(items[i].label, items[i].cls || '', items[i].handler);
+ }
+
+ document.body.appendChild(overlay);
+ document.body.appendChild(menu);
+}
+
+function closeContextMenu() {
+ var o = document.getElementById('_ctxMenuOverlay');
+ var m = document.getElementById('_ctxMenu');
+ if (o) o.remove();
+ if (m) m.remove();
+}
diff --git a/internal/admin/static/editor.js b/internal/admin/static/editor.js
index d5fb5c7..fe0ef10 100644
--- a/internal/admin/static/editor.js
+++ b/internal/admin/static/editor.js
@@ -271,48 +271,17 @@ function createNewDir() {
}
function showDirContextMenu(e, dir) {
- e.preventDefault();
- closeContextMenu();
if (dir === 'Root') return;
- var overlay = document.createElement('div');
- overlay.className = 'cm-overlay';
- overlay.id = '_ctxMenuOverlay';
- overlay.onclick = function() { closeContextMenu(); };
- overlay.addEventListener('contextmenu', function(ev) {
- ev.preventDefault();
- ev.stopPropagation();
- var cx = ev.clientX, cy = ev.clientY;
- closeContextMenu();
- var el = document.elementFromPoint(cx, cy);
- if (el) el.dispatchEvent(new MouseEvent('contextmenu', {bubbles:true, cancelable:true, clientX:cx, clientY:cy, button:2}));
- });
-
- var menu = document.createElement('div');
- menu.className = 'cm-menu';
- menu.id = '_ctxMenu';
- menu.style.left = e.clientX + 'px';
- menu.style.top = e.clientY + 'px';
- menu.oncontextmenu = function(ev) { ev.preventDefault(); };
-
- function addBtn(label, cls, handler) {
- var btn = document.createElement('button');
- btn.textContent = label;
- if (cls) btn.className = cls;
- btn.onclick = function() { closeContextMenu(); handler(); };
- menu.appendChild(btn);
- }
-
- addBtn('Rename Directory', '', function() { renameDirInline(dir); });
- addBtn('Delete Directory', 'danger', function() {
- API.post('/api/' + editorType + '/dirs', {action: 'delete', dir: dir}).then(function(r) {
- notify('Deleted directory ' + dir + (r.moved ? ' (' + r.moved + ' files moved to root)' : ''), 'success');
- updateUndoBar();
- loadList();
- }).catch(function(e) { notify('Delete failed: ' + e.message, 'error'); });
- });
-
- document.body.appendChild(overlay);
- document.body.appendChild(menu);
+ openContextMenu(e, [
+ {label: 'Rename Directory', handler: function() { renameDirInline(dir); }},
+ {label: 'Delete Directory', cls: 'danger', handler: function() {
+ API.post('/api/' + editorType + '/dirs', {action: 'delete', dir: dir}).then(function(r) {
+ notify('Deleted directory ' + dir + (r.moved ? ' (' + r.moved + ' files moved to root)' : ''), 'success');
+ updateUndoBar();
+ loadList();
+ }).catch(function(e) { notify('Delete failed: ' + e.message, 'error'); });
+ }},
+ ]);
}
function renameDirInline(dir) {
@@ -325,44 +294,12 @@ function renameDirInline(dir) {
}
function showItemContextMenu(e, id) {
- e.preventDefault();
- e.stopPropagation();
- closeContextMenu();
-
- var overlay = document.createElement('div');
- overlay.className = 'cm-overlay';
- overlay.id = '_ctxMenuOverlay';
- overlay.onclick = function() { closeContextMenu(); };
- overlay.addEventListener('contextmenu', function(ev) {
- ev.preventDefault();
- ev.stopPropagation();
- var cx = ev.clientX, cy = ev.clientY;
- closeContextMenu();
- var el = document.elementFromPoint(cx, cy);
- if (el) el.dispatchEvent(new MouseEvent('contextmenu', {bubbles:true, cancelable:true, clientX:cx, clientY:cy, button:2}));
- });
-
- var menu = document.createElement('div');
- menu.className = 'cm-menu';
- menu.id = '_ctxMenu';
- menu.style.left = e.clientX + 'px';
- menu.style.top = e.clientY + 'px';
- menu.oncontextmenu = function(ev) { ev.preventDefault(); };
-
- function addBtn(label, cls, handler) {
- var btn = document.createElement('button');
- btn.textContent = label;
- if (cls) btn.className = cls;
- btn.onclick = function() { closeContextMenu(); handler(); };
- menu.appendChild(btn);
- }
-
- addBtn('Rename', '', function() { startInlineItemRename(id); });
- addBtn('Duplicate', '', function() { duplicateFromMenu(id); });
- addBtn('Remove', 'danger', function() { deleteItem(id); });
-
- document.body.appendChild(overlay);
- document.body.appendChild(menu);
+ var row = e.currentTarget;
+ openContextMenu(e, [
+ {label: 'Rename', handler: function() { startInlineItemRename(id, row); }},
+ {label: 'Duplicate', handler: function() { duplicateFromMenu(id); }},
+ {label: 'Remove', cls: 'danger', handler: function() { deleteItem(id); }},
+ ]);
}
function duplicateFromMenu(id) {
@@ -409,15 +346,8 @@ function duplicateFromMenu(id) {
}).catch(function(e) { notify('Duplicate failed: ' + e.message, 'error'); });
}
-function closeContextMenu() {
- var o = document.getElementById('_ctxMenuOverlay');
- var m = document.getElementById('_ctxMenu');
- if (o) o.remove();
- if (m) m.remove();
-}
-
-function startInlineItemRename(id) {
- var el = document.querySelector('.item.active');
+function startInlineItemRename(id, row) {
+ var el = row;
if (!el) return;
var origHTML = el.innerHTML;
el.innerHTML = '<input class="item-rename-input" value="' + escAttr(id) + '" maxlength="128">';
diff --git a/internal/admin/templates/files.html b/internal/admin/templates/files.html
index b89a142..5a5106f 100644
--- a/internal/admin/templates/files.html
+++ b/internal/admin/templates/files.html
@@ -9,12 +9,14 @@
</div>
</div>
<script>
-var currentPath = '';
+var currentDir = '';
+var currentFile = null;
window._allFiles = [];
function loadFiles(path) {
- currentPath = path || '';
- API.get('/api/files' + (path ? '?path=' + encodeURIComponent(path) : '')).then(function(r){
+ currentDir = path || '';
+ currentFile = null;
+ return API.get('/api/files' + (path ? '?path=' + encodeURIComponent(path) : '')).then(function(r){
var files = r.files || r || [];
window._allFiles = files;
renderFileList('');
@@ -26,17 +28,17 @@ function renderFileList(filter){
var f = filter.toLowerCase();
var items = window._allFiles.filter(function(x){ return !f || x.name.toLowerCase().indexOf(f) >= 0; });
var html = '<div class="item" onclick="loadFiles(\'\')" style="color:#6cf">[root]</div>';
- if (currentPath) {
- var parent = currentPath.split('/').slice(0,-1).join('/');
+ if (currentDir) {
+ var parent = currentDir.split('/').slice(0,-1).join('/');
html += '<div class="item" onclick="loadFiles(\''+escJs(parent)+'\')" style="color:#6cf">[..]</div>';
}
items.forEach(function(x){
if (x.dir) {
- var sub = currentPath ? currentPath + '/' + x.name : x.name;
+ var sub = currentDir ? currentDir + '/' + x.name : x.name;
html += '<div class="item" onclick="loadFiles(\''+escJs(sub)+'\')" style="color:#fc6">'+escHtml(x.name)+'/</div>';
} else {
- var fp = currentPath ? currentPath + '/' + x.name : x.name;
- html += '<div class="item" onclick="loadFileContent(\''+escJs(fp)+'\',\''+escJs(x.name)+'\')">'+escHtml(x.name)+'</div>';
+ var fp = currentDir ? currentDir + '/' + x.name : x.name;
+ html += '<div class="item" data-path="'+escHtml(fp)+'" onclick="loadFileContent(\''+escJs(fp)+'\',\''+escJs(x.name)+'\')" oncontextmenu="showFileContextMenu(event,\''+escJs(fp)+'\',\''+escJs(x.name)+'\')">'+escHtml(x.name)+'</div>';
}
});
el.innerHTML = html;
@@ -45,7 +47,7 @@ function renderFileList(filter){
function filterFiles(val) { renderFileList(val); }
function loadFileContent(path, name) {
- currentPath = path;
+ currentFile = path;
API.get('/api/files?path=' + encodeURIComponent(path)).then(function(r){
var content = r.content || r.raw || JSON.stringify(r,null,2);
var html = '<h2>'+escHtml(name)+'</h2>';
@@ -66,13 +68,119 @@ function saveFile(path) {
}).then(function(r) {
if (!r.ok) throw new Error('Save failed');
return r.json();
- }).then(function() {
+ }).then(function(data) {
+ if (data && data.error) throw new Error(data.error);
notify('File saved', 'success');
updateUndoBar();
}).catch(function(e) { notify('Save failed: '+e.message, 'error'); });
}
-window.refreshPage = function() { loadFiles(currentPath); };
+function showFileContextMenu(e, path, name) {
+ openContextMenu(e, [
+ {label: 'Rename', handler: function() { startInlineFileRename(path, name); }},
+ {label: 'Duplicate', handler: function() { duplicateFile(path, name); }},
+ {label: 'Delete', cls: 'danger', handler: function() { deleteFile(path); }},
+ ]);
+}
+
+function deleteFile(path) {
+ API.del('/api/files?path=' + encodeURIComponent(path)).then(function(r) {
+ notify('File deleted', 'success');
+ updateUndoBar();
+ if (currentFile === path) {
+ $('#editorMain').innerHTML = '<p style="color:#888;text-align:center;margin-top:60px">Select a file to edit</p>';
+ currentFile = null;
+ }
+ loadFiles(currentDir);
+ }).catch(function(e) { notify('Delete failed: ' + e.message, 'error'); });
+}
+
+function duplicateFile(path, name) {
+ API.get('/api/files?path=' + encodeURIComponent(path)).then(function(r) {
+ var content = r.content || '';
+ var dot = name.lastIndexOf('.');
+ var base, ext;
+ if (dot > 0) { base = name.substring(0, dot); ext = name.substring(dot); }
+ else { base = name; ext = ''; }
+
+ var baseName = base + '_copy';
+ var newName = baseName + ext;
+ var counter = 2;
+ while (true) {
+ var exists = false;
+ for (var i = 0; i < window._allFiles.length; i++) {
+ if (window._allFiles[i].name === newName) { exists = true; break; }
+ }
+ if (!exists) break;
+ newName = baseName + '_' + counter + ext;
+ counter++;
+ }
+
+ var newPath = currentDir ? currentDir + '/' + newName : newName;
+ fetch('/api/files?path=' + encodeURIComponent(newPath), {
+ method: 'PUT',
+ headers: {'Content-Type': 'text/plain'},
+ body: content,
+ credentials: 'same-origin'
+ }).then(function(r) {
+ if (!r.ok) throw new Error('Duplicate failed');
+ return r.json();
+ }).then(function(data) {
+ if (data && data.error) throw new Error(data.error);
+ notify('Duplicated as ' + newName, 'success');
+ updateUndoBar();
+ loadFiles(currentDir).then(function() { loadFileContent(newPath, newName); });
+ }).catch(function(e) { notify('Duplicate failed: ' + e.message, 'error'); });
+ }).catch(function(e) { notify('Duplicate failed: ' + e.message, 'error'); });
+}
+
+function startInlineFileRename(path, name) {
+ var el = document.querySelector('#listEntries .item[data-path="' + escHtml(path) + '"]');
+ if (!el) return;
+ var origHTML = el.innerHTML;
+ el.innerHTML = '<input class="item-rename-input" value="' + escHtml(name) + '" maxlength="255">';
+ var input = el.querySelector('.item-rename-input');
+ input.focus();
+ input.select();
+
+ function finish(val) {
+ val = (val || '').trim();
+ if (!val || val === name) { el.innerHTML = origHTML; return; }
+ if (val.indexOf('/') >= 0 || val.indexOf('\\') >= 0 || val === '.' || val === '..') {
+ notify('Invalid file name', 'error');
+ el.innerHTML = origHTML;
+ return;
+ }
+ for (var i = 0; i < val.length; i++) {
+ var c = val.charCodeAt(i);
+ if (c < 32 || c === 127) { notify('Invalid file name', 'error'); el.innerHTML = origHTML; return; }
+ }
+ for (var j = 0; j < window._allFiles.length; j++) {
+ if (window._allFiles[j].name === val) {
+ notify('A file named "' + val + '" already exists.', 'error');
+ el.innerHTML = origHTML;
+ return;
+ }
+ }
+ API.post('/api/files/rename', {path: path, new_name: val}).then(function(r) {
+ var newPath = r.path || (currentDir ? currentDir + '/' + val : val);
+ notify('Renamed to ' + val, 'success');
+ updateUndoBar();
+ loadFiles(currentDir).then(function() { loadFileContent(newPath, val); });
+ }).catch(function(e) {
+ notify('Rename failed: ' + e.message, 'error');
+ el.innerHTML = origHTML;
+ });
+ }
+
+ input.onkeydown = function(e) {
+ if (e.key === 'Enter') { input.blur(); }
+ else if (e.key === 'Escape') { el.innerHTML = origHTML; }
+ };
+ input.onblur = function() { finish(input.value); };
+}
+
+window.refreshPage = function() { loadFiles(currentDir); };
function escHtml(s) { return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;'); }
function escJs(s) { return String(s||'').replace(/\\/g,'\\\\').replace(/'/g,"\\'").replace(/"/g,'\\"'); }
diff --git a/internal/admin/templates/layout.html b/internal/admin/templates/layout.html
index fe4e0f9..f6bd405 100644
--- a/internal/admin/templates/layout.html
+++ b/internal/admin/templates/layout.html
@@ -6,6 +6,7 @@
<title>THOI Admin{{if .Page}} — {{.Page}}{{end}}</title>
<link rel="stylesheet" href="/static/admin.css">
<script src="/static/admin.js"></script>
+<script src="/static/ctxmenu.js"></script>
<script src="/static/colorpicker.js"></script>
</head>
<body>