adventure: work the five review findings the last pass left open
The extract pre-check is gone. It read a snapshot up to two minutes behind and still got the last word, so somebody who set out over Matrix during a lagging roster push was told they weren't on an expedition for a run gogobee would happily have ended. Same call abandon and leave already made: let it through and let rejected_not_running be the answer. The siege_join check stays, because whether a boss is camped outside town is town-wide and runs on a day-or-longer clock, but it now reads one column through SiegeIsCamped instead of loading every defender row and the whole history to look at one flag. The war-room history insert is OR REPLACE. boss_id is the primary key and it was never settled whether gogobee means the siege instance or the boss type by it, so a duplicate pair used to fail the transaction carrying the live boss and the muster too and freeze the war room on the last good snapshot. A dropped history row is the smaller failure; the open question is noted in the schema. offersToUndo's guard didn't cover the case its comment claimed. A gogobee too old to push seats sends a valid blob with no party key, which decodes to the same empty slice as a solo run, and a party member got shown the button that throws away everyone's day. That needs a new field, so whoDetail gains party_known and the flag gates the empty-list branch alone; the branch that reads the viewer's own seat is self-evidencing and keeps working against any sender. gogobee's half is written up in adventure_party_known_flag.md. And an empty offer list no longer claims "you're already out there", which Pete can't actually know from a game box too old to push offers at all.
This commit is contained in:
@@ -114,8 +114,14 @@ func ReplaceSiege(s Siege, snapshotAt int64) error {
|
||||
}
|
||||
}
|
||||
|
||||
// OR REPLACE, because boss_id is the primary key and a duplicate in gogobee's
|
||||
// list would otherwise fail this whole transaction — the live boss and the
|
||||
// muster with it, freezing the war room on the previous snapshot indefinitely.
|
||||
// The table is deleted and rebuilt from the pushed list every time, so a
|
||||
// collision is a wire quirk rather than data loss, and keeping the last of a
|
||||
// colliding pair is a far smaller failure than a war room that stops moving.
|
||||
hstmt, err := tx.Prepare(`
|
||||
INSERT INTO adventure_siege_history
|
||||
INSERT OR REPLACE INTO adventure_siege_history
|
||||
(boss_id, boss_name, tier, outcome, hp_remaining, hp_max, defenders, mvp, mvp_fights, ended_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
||||
if err != nil {
|
||||
@@ -174,6 +180,25 @@ func SiegeBarForBoss(boss string, at int64) (current, max int, ok bool) {
|
||||
return hpCur, hpMax, true
|
||||
}
|
||||
|
||||
// SiegeIsCamped answers the one question the siege_join pre-check asks, without
|
||||
// LoadSiege's defender rows and whole history behind it — a one-column read on a
|
||||
// pool that is MaxOpenConns(1).
|
||||
//
|
||||
// known is false when gogobee has never pushed a war room at all, which is NOT
|
||||
// the same as a pushed snapshot saying no Siege is camped. The caller has to keep
|
||||
// the two apart: a fresh deploy that has not been pushed to yet must still queue
|
||||
// the order rather than show a dead button.
|
||||
func SiegeIsCamped() (active, known bool, err error) {
|
||||
err = Get().QueryRow(`SELECT active FROM adventure_siege WHERE id = 1`).Scan(&active)
|
||||
if err == sql.ErrNoRows {
|
||||
return false, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
return active, true, nil
|
||||
}
|
||||
|
||||
// LoadSiege returns the war room as last pushed. ok is false when gogobee has
|
||||
// never pushed one at all — distinct from a pushed snapshot that says no Siege
|
||||
// is camped, which is a real answer the page can render.
|
||||
|
||||
Reference in New Issue
Block a user