aboutsummaryrefslogtreecommitdiff
path: root/internal/game/sys_triggers.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/sys_triggers.go')
-rw-r--r--internal/game/sys_triggers.go28
1 files changed, 23 insertions, 5 deletions
diff --git a/internal/game/sys_triggers.go b/internal/game/sys_triggers.go
index 790eb12..6ae5e21 100644
--- a/internal/game/sys_triggers.go
+++ b/internal/game/sys_triggers.go
@@ -33,6 +33,7 @@ type sequence struct {
key string // dedup key
locked bool // atomic + resumable on disconnect
roomLocked bool // skip steps whose player has left roomID
+ dirty bool // a step advanced since the last persisted snapshot
}
// verbSeqKey builds a dedup key for a verb-triggered sequence so two of the
@@ -144,6 +145,7 @@ func (g *Game) advanceSequence(seq *sequence) {
seq.wait--
if seq.wait <= 0 && len(seq.steps) > 0 {
seq.steps = seq.steps[1:]
+ seq.dirty = true
if len(seq.steps) > 0 {
seq.wait = seq.steps[0].Wait
}
@@ -160,6 +162,7 @@ func (g *Game) advanceSequence(seq *sequence) {
for seq.wait <= 0 && len(seq.steps) > 0 {
step := seq.steps[0]
seq.steps = seq.steps[1:]
+ seq.dirty = true
jobs = append(jobs, step)
if len(seq.steps) > 0 {
seq.wait = seq.steps[0].Wait
@@ -233,6 +236,10 @@ func (g *Game) syncPendingSequence(seq *sequence, p *player.Player) {
if len(seq.steps) == 0 {
return
}
+ if !seq.dirty {
+ return
+ }
+ seq.dirty = false
p.PendingSequence.Steps = append([]behavior.Step(nil), seq.steps...)
p.PendingSequence.Wait = seq.wait
g.saveCharacter(p)
@@ -301,6 +308,15 @@ func (g *Game) cancelSequences(name string) {
delete(g.sequences, k)
}
g.seqMu.Unlock()
+ // Clearing the live sequences is not enough: the persisted marker would
+ // otherwise re-arm the cancelled steps on the next login.
+ g.charsMu.Lock()
+ sess := g.loggedInChars[name]
+ g.charsMu.Unlock()
+ if sess != nil && sess.Player != nil && sess.Player.PendingSequence != nil {
+ sess.Player.PendingSequence = nil
+ g.saveCharacter(sess.Player)
+ }
}
// abortAllSequences drops every in-flight sequence (player and global) and
@@ -360,7 +376,8 @@ func (g *Game) resumePendingSequence(sess *net.Session, p *player.Player) {
return
}
ps := p.PendingSequence
- p.PendingSequence = nil
+ // Keep the marker: completePlayerSequence clears it when the matching key
+ // finishes, so a crash mid-resume still has a durable snapshot to replay.
seq := &sequence{
sess: sess,
player: p,
@@ -400,11 +417,12 @@ func (g *Game) TransientMobTick() {
g.charsMu.Lock()
ownerSess := g.loggedInChars[inst.Owner]
g.charsMu.Unlock()
- if ownerSess == nil || ownerSess.Player == nil {
- continue
+ // An offline owner counts as out of the allowed rooms so the despawn
+ // grace still runs; otherwise the mob persists forever after logout.
+ ownerRoom := -1
+ if ownerSess != nil && ownerSess.Player != nil {
+ ownerRoom = ownerSess.Player.RoomID
}
-
- ownerRoom := ownerSess.Player.RoomID
allowed := inst.DespawnRooms
if len(allowed) == 0 {
allowed = []int{inst.HomeRoomID}