Skip to content

Kills per hour and cash per minute: leave out the time a match waits for its players - #54

Open
jbob06 wants to merge 2 commits into
warcon-app:mainfrom
jbob06:active-match-time
Open

jbob06 wants to merge 2 commits into
warcon-app:mainfrom
jbob06:active-match-time

Conversation

@jbob06

@jbob06 jbob06 commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

The problem

Kills per hour leaves out seed time, but seed time is only kept while a Seeding reward rule is on. A server that rewards seeding some other way (ours does it from a Discord bot) has no seed time at all, so every hour a player spends on the server waiting for the match to start counts as played.

On our server (MinimumRequiredPlayers=20) a match on 2026-10-17 sat at a score of 0 for about six hours with 1 to 7 players on before it went live. A player who seeded it and then played the match had 434 minutes on and 43 kills that day, and their K/h divided by all six hours of the wait. They asked for K/h to count only the time a match is actually being played.

The change

  • Idle time is tallied beside time on (tallyLook, match-players.ts): the gaps a player was on while no side had scored yet, the same test AFK protection uses for "the server is seeding". It is written with the line as match_players.idle_seconds.
  • Migration 0051 adds the column to match_players, player_totals and player_days, and restates the six functions that list the line columns: 0038's player_totals_recount and 0039's player_days_recount, player_lines_cleared, player_totals_match_ended, player_days_rebuild and player_totals_rebuild. Each has idle_seconds added and nothing else changed (checked line by line against the originals). Every existing line has 0, so nothing needs rebuilding.
  • Boards: rangeBase, seasonBase and totalsBase carry idle_minutes, and kills per hour is kills / (minutes - GREATEST(seed_minutes, idle_minutes)): in SQL for the sort, and in perHour for the table and the export. The larger of the two rather than their sum, because on a server with a Seeding reward both count mostly the same minutes.
  • Cash per minute leaves out the same wait, cash / (cash_minutes - GREATEST(seed_minutes, idle_minutes)), in SQL and in perMinute. Its time is whole sessions while idle time goes by when a match ended, so on a 7, 30 or 90-day board the two can differ a little at the range's first day; all time they agree. Seed time has the same kind of edge.

Things worth your view

  • "No side has scored" or the feed's match state. Season 2's feed reports MatchState.PreMatch.WaitingForPlayers, which says it exactly, but only where the feed reaches Warcon. Scores work on every server, so I used them. Preferring the state when there is one would be a small follow-up.
  • Idle time is kept from the deploy on; earlier matches have none, so their K/h reads as before.
  • A server whose match starts scoring with anyone on records next to no idle time, and its K/h is as before.
  • The first score period of a live match counts as idle (24 s on ours), which is negligible.

Tests

  • tallyLook tallies idle time only while no side has scored, and none when the scores are unknown; writeMatchPlayers stores it; perHour and perMinute leave out the larger of seed and idle time.
  • totals-oracle.ts carries idle_minutes, so the exactness tests compare it. The 120-step test writes lines with idle time (fixed values: a random draw would change the seeded history after it), and dayTable compares the column.
  • The tests that insert lines into a database migrated only to 0037, 0038 or 0046 now use insertEarlyLines (src/test/db.ts): a raw insert of just the columns given, because Drizzle's insert names every column in the schema, idle_seconds included, which those databases do not have yet. Any later column on match_players would have hit the same thing.

Checks

  • prettier --check .: clean.
  • bun run check: 0 errors, 0 warnings.
  • bun test with TEST_DATABASE_URL on Linux, against timescale/timescaledb:2.30.0-pg18: 1669 pass, 1 skip, 0 fail across 169 files.
  • Not run against a live server or in a browser.

🤖 Generated with Claude Code

https://claude.ai/code/session_011q1rvh2JotX9onGUYQH78V

jbob06 and others added 2 commits October 17, 2026 21:10
Seed time is only kept while a Seeding reward rule is on, so on a server
without one every hour spent seeding counted as played. The worker now
tallies idle time per match line (time on before any side has scored),
0051 rolls it into the totals and day rows, and kills per hour leaves out
the larger of seed and idle time.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011q1rvh2JotX9onGUYQH78V
The same rule as kills per hour: the larger of seed and idle time comes
off the time the cash was made in.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011q1rvh2JotX9onGUYQH78V
@jbob06 jbob06 changed the title Kills per hour: leave out the time a match waits for its players Kills per hour and cash per minute: leave out the time a match waits for its players Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant