remove move state

master
Denis Ranneft 1 month ago
parent a138b6583d
commit 0c7468cc55

@ -1138,7 +1138,6 @@
const live = h.adminLiveMovement;
const tp = h.townPause;
const rows = [];
rows.push(`<div class="kv"><kbd>moveState</kbd><div>${e(h.moveState)}</div></div>`);
if (h.currentTownId != null) rows.push(`<div class="kv"><kbd>currentTownId</kbd><div>${e(h.currentTownId)}</div></div>`);
if (h.destinationTownId != null) rows.push(`<div class="kv"><kbd>destinationTownId</kbd><div>${e(h.destinationTownId)}</div></div>`);
if (h.restKind) rows.push(`<div class="kv"><kbd>restKind</kbd><div>${e(h.restKind)}</div></div>`);

@ -187,7 +187,7 @@ func main() {
WithRewardStores(gearStore, achievementStore, taskStore).
WithDigestStore(digestStore)
bootCtx, bootCancel := context.WithTimeout(ctx, 3*time.Minute)
game.BootstrapResidentHeroes(bootCtx, engine, heroStore, bootstrapSim, 500, logger)
game.BootstrapResidentHeroes(bootCtx, engine, heroStore, bootstrapSim, logger)
bootCancel()
// Start game engine (after resident heroes are registered).

@ -1974,7 +1974,6 @@ func (e *Engine) mergeTownSessionFromRedis(hero *model.Hero) {
return
}
hero.State = model.StateInTown
hero.MoveState = string(model.StateInTown)
hero.TownPause = snap.TownPause
hero.PositionX = snap.PositionX
hero.PositionY = snap.PositionY

@ -16,11 +16,11 @@ import (
// BootstrapResidentHeroes loads heroes whose WebSocket session had ended before this process started,
// catches up wall time using the same batch path as server-downtime recovery, then registers them
// in the engine so movement and combat continue without a live subscriber.
func BootstrapResidentHeroes(ctx context.Context, e *Engine, heroStore *storage.HeroStore, sim *OfflineSimulator, limit int, logger *slog.Logger) {
func BootstrapResidentHeroes(ctx context.Context, e *Engine, heroStore *storage.HeroStore, sim *OfflineSimulator, logger *slog.Logger) {
if e == nil || heroStore == nil || sim == nil {
return
}
heroes, err := heroStore.ListHeroesForEngineBootstrap(ctx, limit)
heroes, err := heroStore.ListHeroesForEngineBootstrap(ctx)
if err != nil {
if logger != nil {
logger.Error("engine bootstrap: list heroes", "error", err)

@ -1320,7 +1320,6 @@ func (hm *HeroMovement) SyncToHero() {
} else {
hm.Hero.DestinationTownID = nil
}
hm.Hero.MoveState = string(hm.State)
hm.Hero.RestKind = model.RestKindNone
if hm.State == model.StateResting {
if hm.ActiveRestKind != model.RestKindNone {

@ -88,7 +88,6 @@ type adminTownTourLiveJSON struct {
// adminLiveMovementJSON exposes in-memory movement timers for the admin UI (online heroes only).
type adminLiveMovementJSON struct {
Online bool `json:"online"`
MoveState string `json:"moveState,omitempty"`
RestUntil *time.Time `json:"restUntil,omitempty"`
TownLeaveAt *time.Time `json:"townLeaveAt,omitempty"`
NextTownNPCRollAt *time.Time `json:"nextTownNPCRollAt,omitempty"`
@ -164,7 +163,6 @@ func buildAdminLiveMovementSnap(hm *game.HeroMovement) *adminLiveMovementJSON {
}
s := &adminLiveMovementJSON{
Online: true,
MoveState: string(hm.State),
}
if !hm.RestUntil.IsZero() {
t := hm.RestUntil
@ -3126,7 +3124,6 @@ func applyNewPlayerHeroDefaults(hero *model.Hero) {
hero.ExcursionPhase = model.ExcursionNone
hero.RestKind = model.RestKindNone
hero.TownPause = nil
hero.MoveState = string(model.StateWalking)
}
// resetHeroToLevel1 restores a hero to fresh level 1 defaults,

@ -63,7 +63,6 @@ type Hero struct {
// Movement state (persisted to DB for reconnect recovery).
CurrentTownID *int64 `json:"currentTownId,omitempty"`
DestinationTownID *int64 `json:"destinationTownId,omitempty"`
MoveState string `json:"moveState"`
RestKind RestKind `json:"restKind,omitempty"`
// ExcursionPhase is set when a mini-adventure session is active (out/wild/return); empty otherwise.
ExcursionPhase ExcursionPhase `json:"excursionPhase,omitempty"`

@ -30,7 +30,7 @@ const heroSelectQuery = `
h.buff_free_charges_remaining, h.buff_quota_period_end, h.buff_charges,
h.position_x, h.position_y, h.potions,
h.total_kills, h.elite_kills, h.total_deaths, h.kills_since_death, h.legendary_drops,
h.current_town_id, h.destination_town_id, h.move_state, h.town_pause,
h.current_town_id, h.destination_town_id, h.town_pause,
h.last_online_at, h.changelog_ack_version,
h.ws_disconnected_at,
h.created_at, h.updated_at
@ -266,10 +266,6 @@ func (s *HeroStore) insertNewHeroRow(ctx context.Context, hero *model.Hero) erro
hero.CreatedAt = now
hero.UpdatedAt = now
if hero.MoveState == "" {
hero.MoveState = string(model.StateWalking)
}
buffChargesJSON := marshalBuffCharges(hero.BuffCharges)
query := `
@ -285,7 +281,7 @@ func (s *HeroStore) insertNewHeroRow(ctx context.Context, hero *model.Hero) erro
total_kills, elite_kills, total_deaths, kills_since_death, legendary_drops,
last_online_at,
created_at, updated_at,
current_town_id, destination_town_id, move_state
current_town_id, destination_town_id
) VALUES (
$1, $2,
$3, $4, $5, $6, $7,
@ -298,7 +294,7 @@ func (s *HeroStore) insertNewHeroRow(ctx context.Context, hero *model.Hero) erro
$25, $26, $27, $28, $29,
$30,
$31, $32,
$33, $34, $35
$33, $34
) RETURNING id
`
@ -314,7 +310,7 @@ func (s *HeroStore) insertNewHeroRow(ctx context.Context, hero *model.Hero) erro
hero.TotalKills, hero.EliteKills, hero.TotalDeaths, hero.KillsSinceDeath, hero.LegendaryDrops,
hero.LastOnlineAt,
hero.CreatedAt, hero.UpdatedAt,
hero.CurrentTownID, hero.DestinationTownID, hero.MoveState,
hero.CurrentTownID, hero.DestinationTownID,
).Scan(&hero.ID)
if err != nil {
return fmt.Errorf("insert hero: %w", err)
@ -425,7 +421,6 @@ func (s *HeroStore) CreateHeroWithSpawn(ctx context.Context, telegramID int64, n
PositionY: by,
CurrentTownID: &birth,
DestinationTownID: &dest,
MoveState: string(model.StateWalking),
BuffFreeChargesRemaining: model.FreeBuffActivationsPerPeriodRuntime(),
}
@ -572,9 +567,8 @@ func (s *HeroStore) Save(ctx context.Context, hero *model.Hero) error {
updated_at = $29,
destination_town_id = $30,
current_town_id = $31,
move_state = $32,
town_pause = $33
WHERE id = $34
town_pause = $32
WHERE id = $33
`
townPauseJSON := marshalTownPause(hero.TownPause)
@ -593,7 +587,6 @@ func (s *HeroStore) Save(ctx context.Context, hero *model.Hero) error {
hero.UpdatedAt,
hero.DestinationTownID,
hero.CurrentTownID,
hero.MoveState,
townPauseJSON,
hero.ID,
)
@ -661,80 +654,17 @@ func (s *HeroStore) ClearWsDisconnectedAt(ctx context.Context, heroID int64) err
return nil
}
// ListOfflineHeroes returns heroes that need catch-up: walking heroes stale on the map,
// or heroes resting / in town whose DB row has not been updated recently (offline town timers).
// Heroes with an active WebSocket session are filtered out by the offline simulator (skipIfLive).
func (s *HeroStore) ListOfflineHeroes(ctx context.Context, offlineThreshold time.Duration, limit int) ([]*model.Hero, error) {
if limit <= 0 {
limit = 100
}
if limit > 500 {
limit = 500
}
cutoff := time.Now().Add(-offlineThreshold)
query := heroSelectQuery + `
WHERE h.hp > 0 AND h.updated_at < $1
AND (
(h.state = 'walking'
AND (h.move_state IS NULL OR h.move_state NOT IN ('in_town', 'resting')))
OR h.state IN ('resting', 'in_town')
)
ORDER BY h.updated_at ASC
LIMIT $2
`
rows, err := s.pool.Query(ctx, query, cutoff, limit)
if err != nil {
return nil, fmt.Errorf("list offline heroes: %w", err)
}
defer rows.Close()
var heroes []*model.Hero
for rows.Next() {
h, err := scanHeroFromRows(rows)
if err != nil {
return nil, fmt.Errorf("list offline heroes scan: %w", err)
}
heroes = append(heroes, h)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("list offline heroes rows: %w", err)
}
for _, h := range heroes {
if err := s.loadHeroGear(ctx, h); err != nil {
return nil, fmt.Errorf("list offline heroes load gear: %w", err)
}
if err := s.loadHeroInventory(ctx, h); err != nil {
return nil, fmt.Errorf("list offline heroes load inventory: %w", err)
}
}
return heroes, nil
}
// ListHeroesForEngineBootstrap returns heroes that should be loaded into the game engine after a cold start:
// session ended (ws_disconnected_at set) and simulatable world state. Limit caps memory use.
func (s *HeroStore) ListHeroesForEngineBootstrap(ctx context.Context, limit int) ([]*model.Hero, error) {
if limit <= 0 {
limit = 500
}
if limit > 2000 {
limit = 2000
}
func (s *HeroStore) ListHeroesForEngineBootstrap(ctx context.Context) ([]*model.Hero, error) {
query := heroSelectQuery + `
WHERE h.hp > 0 AND h.ws_disconnected_at IS NOT NULL
AND (
(h.state = 'walking'
AND (h.move_state IS NULL OR h.move_state NOT IN ('in_town', 'resting')))
OR h.state IN ('resting', 'in_town', 'fighting')
)
ORDER BY h.updated_at ASC
LIMIT $1
`
rows, err := s.pool.Query(ctx, query, limit)
rows, err := s.pool.Query(ctx, query)
if err != nil {
return nil, fmt.Errorf("list heroes for engine bootstrap: %w", err)
}
@ -780,7 +710,7 @@ func scanHeroFromRows(rows pgx.Rows) (*model.Hero, error) {
&h.BuffFreeChargesRemaining, &h.BuffQuotaPeriodEnd, &buffChargesRaw,
&h.PositionX, &h.PositionY, &h.Potions,
&h.TotalKills, &h.EliteKills, &h.TotalDeaths, &h.KillsSinceDeath, &h.LegendaryDrops,
&h.CurrentTownID, &h.DestinationTownID, &h.MoveState, &townPauseRaw,
&h.CurrentTownID, &h.DestinationTownID, &townPauseRaw,
&h.LastOnlineAt, &h.ChangelogAckVersion,
&h.WsDisconnectedAt,
&h.CreatedAt, &h.UpdatedAt,
@ -815,7 +745,7 @@ func scanHeroRow(row pgx.Row) (*model.Hero, error) {
&h.BuffFreeChargesRemaining, &h.BuffQuotaPeriodEnd, &buffChargesRaw,
&h.PositionX, &h.PositionY, &h.Potions,
&h.TotalKills, &h.EliteKills, &h.TotalDeaths, &h.KillsSinceDeath, &h.LegendaryDrops,
&h.CurrentTownID, &h.DestinationTownID, &h.MoveState, &townPauseRaw,
&h.CurrentTownID, &h.DestinationTownID, &townPauseRaw,
&h.LastOnlineAt, &h.ChangelogAckVersion,
&h.WsDisconnectedAt,
&h.CreatedAt, &h.UpdatedAt,

@ -0,0 +1,2 @@
ALTER TABLE public.heroes
DROP COLUMN IF EXISTS move_state;
Loading…
Cancel
Save