Skip to content

feat: per-member island activity counters (foundation for #30) - #35

Merged
tastybento merged 1 commit into
developfrom
feature/activity-counters
Aug 15, 2026
Merged

feat: per-member island activity counters (foundation for #30)#35
tastybento merged 1 commit into
developfrom
feature/activity-counters

Conversation

@tastybento

Copy link
Copy Markdown
Member

Closes #30.

The counting substrate that the contribution ledger (#7), leagues (#10) and cooperative relay (#9) each need, built once. Nothing here is player-facing; it is done when something else can ask "how many chunks did this member claim for this island in the last 7 days" and get an answer — which the new member-activity request handler now answers.

Design points from the issue, as implemented

  • Keyed on (island, player). ActivityManager.record drops amounts attributed to a player who is not on the island's team, so recruiting a veteran cannot import old progress, and a member who leaves keeps their contribution credited to the island they made it on.
  • Time windows are buckets, not running totals. IslandActivity (table ChunkBlockActivity) stores a lifetime total plus per-day buckets as flat String -> Long maps with composite keys (member|COUNTER / member|COUNTER|epochDay) — a shape every database backend serializes without custom adapters. Daily, weekly and season readouts are all sums over the same buckets.
  • Retention is configurable. chunkblock.activity.daily-retention-days (default 100) prunes old buckets on write; lifetime totals are never pruned.
  • No double-counting on re-lock and re-claim. "Chunks claimed" means distinct chunks (ChunkBlock leagues / competitions #10's "first-unlocked" reading): a claimedEver set — which deliberately survives re-locks and clears only on island create/reset — distinguishes CHUNKS_CLAIMED from CHUNKS_RECLAIMED.
  • Offline members count. Everything is recorded against UUIDs, not online players.
  • Counters are data, not reward. No trophy logic here; the trophies foundation ([foundation] Island trophies and titles #31) reads these in a follow-up PR.

Counters

MAGIC_BLOCKS, LEVELS_EARNED (island scope — Level cannot attribute a level change to a member), CHUNKS_CLAIMED, CHUNKS_RECLAIMED, CHUNKS_RELOCKED, RINGS_COMPLETED.

Wiring

  • ActivityListener observes the addon's own events at MONITOR priority (MagicBlockEvent, ChunkUnlockEvent, ChunkRelockEvent, RingCompleteEvent — counted even when cancelled, since the completion is a fact) plus island create/reset/delete for lifecycle.
  • ChunkUnlockEvent now carries the claiming player's UUID (additive; the old constructor remains).
  • Level gains are recorded directly in LevelListener.applyLevel, where the delta is known.
  • Magic-block saves are throttled (every 20 records); rare counters save immediately; shutdown flushes synchronously like the block-count cache.

Tests

30 new tests: ActivityManagerTest (attribution, windows, retention, the distinct-claim rule, save throttling), ActivityListenerTest, MemberActivityHandlerTest. Full suite: 700 tests, 0 failures.

🤖 Generated with Claude Code

https://claude.ai/code/session_01W8GghDu6oXiUf6eCoimJqD

The counting substrate that a contribution ledger (#7), a season
leaderboard (#10) and a relay score (#9) all read from, built once
instead of three times.

Counters are keyed on (island, member): activity is only credited while
the player is actually on the island's team, so recruiting a veteran
cannot import old progress, and a member who leaves keeps their
contribution credited to the island they made it on. Activity no member
can be credited with (level changes, re-locks, minion breaks) is
recorded at island scope.

Each counter stores a lifetime total plus per-day buckets, so daily,
weekly and season windows are all sums over the same data. Buckets
older than a configurable retention (default 100 days) are pruned;
lifetime totals never are. "Chunks claimed" means distinct chunks: a
claimedEver set that survives re-locks tells a first claim from the
recovery of re-locked territory, so nothing is counted twice.

Writers observe the addon's own events at MONITOR priority;
ChunkUnlockEvent now carries the claiming player's UUID. A new
member-activity request handler lets other plugins ask e.g. how many
chunks a member claimed for their island in the last 7 days.

Foundation for #30.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W8GghDu6oXiUf6eCoimJqD
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit 312a841 into develop Aug 15, 2026
3 checks passed
@tastybento
tastybento deleted the feature/activity-counters branch August 15, 2026 02:50
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.

[foundation] Per-member island activity counters

1 participant