aboutsummaryrefslogtreecommitdiff
path: root/internal/game/cmd_room_insert.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/cmd_room_insert.go')
-rw-r--r--internal/game/cmd_room_insert.go47
1 files changed, 30 insertions, 17 deletions
diff --git a/internal/game/cmd_room_insert.go b/internal/game/cmd_room_insert.go
index 2d7ff58..09b2e74 100644
--- a/internal/game/cmd_room_insert.go
+++ b/internal/game/cmd_room_insert.go
@@ -127,12 +127,6 @@ func (g *Game) roomInsert(sess *net.Session, args []string) {
sess.WriteLine("Error creating directory.")
return
}
- if err := writeRoomFile(newPath, data); err != nil {
- sess.WriteLine("Error writing room file.")
- return
- }
-
- g.World.AddRoomPath(newID, newPath)
curRoom.Exits[dir] = world.RewirePreserving(exitDef, newID)
curData, err := yaml.Marshal(curRoom)
@@ -140,23 +134,42 @@ func (g *Game) roomInsert(sess *net.Session, args []string) {
sess.WriteLine("Error updating current room YAML.")
return
}
- if err := writeRoomFile(curPath, curData); err != nil {
- sess.WriteLine("Error writing current room file.")
+
+ // Stage all three files (the new room, the current room, and the far
+ // room's reciprocal exit when it points back) into ONE journal
+ // transaction. The previous sequential writes could stop after the new
+ // room existed but before the current room's exit was rewritten, leaving
+ // a dangling exit with no recovery record; the transaction rolls the
+ // whole insert back on any failure or crash.
+ txn := g.newTxn()
+ if err := txn.Replace(newPath, data, 0644); err != nil {
+ sess.WriteLine(fmt.Sprintf("Error writing room file: %v", err))
+ return
+ }
+ if err := txn.Replace(curPath, curData, 0644); err != nil {
+ sess.WriteLine(fmt.Sprintf("Error writing current room file: %v", err))
return
}
-
if targetExit, tok := targetRoom.Exits[oppositeDir]; tok && targetExit.Room == p.RoomID {
- targetRoom.Exits[oppositeDir] = world.RewirePreserving(targetExit, newID)
- }
- targetPath, tok2 := g.World.GetRoomPath(targetID)
- if tok2 {
- targetData, terr := yaml.Marshal(targetRoom)
- if terr == nil {
- if werr := writeRoomFile(targetPath, targetData); werr != nil {
- sess.WriteLine(fmt.Sprintf("Warning: could not link the opposite exit in room %d: %v", targetID, werr))
+ if targetPath, tok2 := g.World.GetRoomPath(targetID); tok2 {
+ targetRoom.Exits[oppositeDir] = world.RewirePreserving(targetExit, newID)
+ targetData, terr := yaml.Marshal(targetRoom)
+ if terr != nil {
+ sess.WriteLine(fmt.Sprintf("Error updating room %d YAML: %v", targetID, terr))
+ return
+ }
+ if err := txn.Replace(targetPath, targetData, 0644); err != nil {
+ sess.WriteLine(fmt.Sprintf("Error linking the opposite exit in room %d: %v", targetID, err))
+ return
}
}
}
+ if err := txn.Commit(); err != nil {
+ sess.WriteLine(fmt.Sprintf("Error committing room insert: %v", err))
+ return
+ }
+
+ g.World.AddRoomPath(newID, newPath)
oldRoom := p.RoomID
p.ClearMoveState()