some fixes

master
Denis Ranneft 1 month ago
parent bc510fb9c7
commit 3c9c811201

@ -1582,6 +1582,7 @@ func (e *Engine) processCombatTickLocked(now time.Time) {
if hm, ok := e.movements[heroID]; ok { if hm, ok := e.movements[heroID]; ok {
hm.Die() hm.Die()
} }
e.persistHeroDeathLocked(heroID, cs.Hero)
dctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) dctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
e.applyOfflineDigest(dctx, heroID, cs.Hero, now, storage.OfflineDigestDelta{Deaths: 1}) e.applyOfflineDigest(dctx, heroID, cs.Hero, now, storage.OfflineDigestDelta{Deaths: 1})
cancel() cancel()
@ -1614,6 +1615,21 @@ func (e *Engine) processAttackEvent(evt *model.AttackEvent, cs *model.CombatStat
} }
} }
// persistHeroDeathLocked writes the dead hero snapshot immediately so DB state
// never lags behind the live in-memory death state.
// Caller must hold e.mu.
func (e *Engine) persistHeroDeathLocked(heroID int64, hero *model.Hero) {
if e.heroStore == nil || hero == nil {
return
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
err := e.heroStore.Save(ctx, hero)
cancel()
if err != nil && e.logger != nil {
e.logger.Error("persist hero after death", "hero_id", heroID, "error", err)
}
}
// sendDebuffAppliedForString pushes debuff_applied when a debuff proc string is non-empty. // sendDebuffAppliedForString pushes debuff_applied when a debuff proc string is non-empty.
func (e *Engine) sendDebuffAppliedForString(heroID int64, debuffTypeStr string, now time.Time) { func (e *Engine) sendDebuffAppliedForString(heroID int64, debuffTypeStr string, now time.Time) {
if e.sender == nil || debuffTypeStr == "" { if e.sender == nil || debuffTypeStr == "" {
@ -1748,6 +1764,7 @@ func (e *Engine) processEnemyAttack(cs *model.CombatState, now time.Time) {
if hm, ok := e.movements[cs.HeroID]; ok { if hm, ok := e.movements[cs.HeroID]; ok {
hm.Die() hm.Die()
} }
e.persistHeroDeathLocked(cs.HeroID, cs.Hero)
dctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) dctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
e.applyOfflineDigest(dctx, cs.HeroID, cs.Hero, now, storage.OfflineDigestDelta{Deaths: 1}) e.applyOfflineDigest(dctx, cs.HeroID, cs.Hero, now, storage.OfflineDigestDelta{Deaths: 1})
cancel() cancel()

@ -1289,6 +1289,16 @@ func (h *AdminHandler) ReviveHero(w http.ResponseWriter, r *http.Request) {
return return
} }
// Admin UI displays live in-engine state when the hero is online.
// Use that same authoritative snapshot for revive validation to avoid
// false "hero is not dead" when DB lagged behind live movement/combat.
if h.engine != nil {
if hm := h.engine.GetMovements(heroID); hm != nil && hm.Hero != nil {
live := *hm.Hero
hero = &live
}
}
if !game.IsEffectivelyDead(hero) { if !game.IsEffectivelyDead(hero) {
writeJSON(w, http.StatusBadRequest, map[string]string{ writeJSON(w, http.StatusBadRequest, map[string]string{
"error": "hero is not dead", "error": "hero is not dead",

@ -659,8 +659,9 @@ func (s *HeroStore) ClearWsDisconnectedAt(ctx context.Context, heroID int64) err
func (s *HeroStore) ListHeroesForEngineBootstrap(ctx context.Context) ([]*model.Hero, error) { func (s *HeroStore) ListHeroesForEngineBootstrap(ctx context.Context) ([]*model.Hero, error) {
query := heroSelectQuery + ` query := heroSelectQuery + `
WHERE h.hp > 0 AND h.ws_disconnected_at IS NOT NULL WHERE h.ws_disconnected_at IS NOT NULL
ORDER BY h.updated_at ASC ORDER BY id ASC
LIMIT 100
` `
rows, err := s.pool.Query(ctx, query) rows, err := s.pool.Query(ctx, query)

Loading…
Cancel
Save