OneLiteFeatherNET / OneLiteFeatherNET/Voyager
feat(scoring): pool-based map point distribution for cosmetic currency
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 0
- Forks
- 0
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 12
Description
Description
The game designer has specified a new scoring model to replace (or augment) the time-bracket system introduced in Epic #168. Rather than awarding fixed bracket points per tier, a per-map point pool is distributed among all players who completed the map in that session, proportional to each player's finish time relative to a reference time.
This model decouples competitive performance feedback (medal tiers) from cosmetic currency reward, and makes the currency feel dynamic — the pool is finite and shared.
Mechanic Specification
Reference Time
- Primary source: all-time fastest completion of the map, stored in
map_recordstable (requires V4 migration). - Fallback (no record exists): fastest finisher of the current session becomes the reference for that session's pool distribution only. The record is then written to
map_recordsso future sessions have a persistent reference.
Point Pool
- Each map carries a fixed point pool (exact size and configurability TBD — see open questions).
- At map-end, the pool is split among all players who completed the map in that session.
- Distribution is proportional to performance vs the reference time: finishing at or faster than the reference time yields a larger share; finishing slower yields a smaller share.
- The total distributed across all players must not exceed the pool (no inflation).
Currency
- Points awarded by this system are a cosmetic currency used to purchase cosmetic items.
- The currency name is TBD (see open questions).
- This is distinct from any competitive leaderboard metric.
No-Completion Case
- Players who did not complete the map receive no pool share.
- DNF handling follows #170.
Open Questions (must be resolved before implementation)
- Pool size: Fixed value (e.g. 1000 per map)? Configurable per map in
MapDefinition? Or formula-based (e.g.base * number_of_rings)? - Split formula: Weighted proportional (each player's weight =
referenceTime / playerTime)? Threshold-based buckets? Something else? - Slow-finisher floor: Do players finishing slower than the reference time always receive a reduced but non-zero share, or can the share reach 0 for extreme outliers?
- Currency name: What is the cosmetic currency called in-game?
- Medal tier coexistence: Does this pool system replace the DIAMOND/GOLD/SILVER/BRONZE bracket tiers (Epic #168) entirely, or do medal tiers continue as a separate performance feedback layer while the pool drives currency rewards?
- Record write-back: Is the session-fastest written to
map_recordsonly when it beats the existing record, or always (first-time insert)? - Multi-map cups: Is the pool distributed per map or aggregated across the full cup?
Acceptance Criteria
-
MapDefinitionhas a configurable point pool value (exact type and default TBD per open questions above) -
map_recordstable stores the all-time fastest completion per map; referenced at distribution time -
PoolScoringStrategy(or equivalent) implementsScoringStrategyfrom the ADR-0007 sealed hierarchy introduced in PR #178 - Pool distribution formula is unit-tested for: all players equal time, one player significantly faster, one player at exactly reference time, fallback (no pre-existing record)
- Session-fastest is written to
map_recordswhen no prior record exists (and optionally when beaten) - Cosmetic currency amount is recorded on
GameResultEntityand persisted - All open questions above are answered and reflected in updated
MapDefinition+ ADR - Existing bracket medal tiers (DIAMOND/GOLD/SILVER/BRONZE) either remain for feedback-only purposes or are explicitly removed — decision documented in ADR
- ArchUnit tests still pass (no cross-module boundary violations)
- Flyway migration adds
map_recordstable (V4) and any new currency column(s) ongame_results
Technical Details
- The
ScoringStrategysealed interface (introduced in PR #178) is the correct extension point. Add aPoolScoringStrategypermit. - Distribution math runs in
applyMapResults()after all finish times for a session are known. - The reference-time lookup must be async-safe (DB read at map-start or cached at session-start).
- Component:
ScoreComponentmay need acosmeticCurrencyEarnedfield (Java record, compact constructor validation). - Follow the ManisGame enum DSL pattern if a distribution-tier enum is introduced.
Dependencies
- #168 — Zeit-Bracket scoring epic (active, PR #178 in review);
ScoringStrategysealed hierarchy andScoreComponentfields originate here map_recordstable — V4 Flyway migration (does not yet exist; blocks reference-time lookup)- #177 — Flyway migration infrastructure (merged before V4 migration can land)
- #170 — DNF handling (determines which players are eligible for pool share)
Estimate
L
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with ADR-0007, the sealed ScoringStrategy hierarchy from PR #178, and the ScoreComponent and MapDefinition types. Trace applyMapResults(), the existing game-results persistence, and Flyway migration infrastructure before resolving the listed scoring and currency questions. Done means a documented decision in the ADR, V4 schema changes, persisted currency, unit tests for the specified cases, and passing ArchUnit tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, sql
- Domain
- backend, database, testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100