Repository navigation
Add a referral system to the activity menu - #97
Conversation
New players pick who invited them in /referral (or the new button in /activity). Both players then claim per-act milestone rewards as the new player's AFK-aware playtime grows. Links are permanent, refused across shared connections, loops and inviter caps, and only open in the season's first days or an account's first week. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A typo or a first season.start no longer wipes referrals.yml, joining or an unknown command no longer counts as activity, players online at a reload keep their connection history, a broken file is read again on reload, and staff can exempt an account with /referral allowip. Menu pages no longer drift, the way back needs activity.use, and menu switches run on the next tick. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/referral allowip now takes two players and covers only that pair, the last real season.start survives a blank one so the next date still starts over, the delayed menu switches check the player is online, and max-invitees defaults to 10 in code as in referral.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Referral and reward configuration src/main/java/net/tfminecraft/activitytf/config/ReferralConfiguration.java, src/main/java/net/tfminecraft/activitytf/config/ActivityConfiguration.java, src/main/java/net/tfminecraft/activitytf/models/RewardEntry.java, src/main/java/net/tfminecraft/activitytf/utils/ItemPath.java, src/main/java/net/tfminecraft/activitytf/managers/ActivityManager.java, src/main/resources/referral.yml, src/main/resources/config.yml, src/test/java/net/tfminecraft/activitytf/config/*, src/test/java/net/tfminecraft/activitytf/utils/ItemPathTest.java, src/test/java/net/tfminecraft/activitytf/managers/ActivityManagerRewardItemsTest.java |
Referral configuration defines season settings, eligibility rules, milestones, rare-track steps, and reward pools. Reward items can have configured names. Cooking paths are validated and resolved through the TLibs path. |
Referral data and persistence src/main/java/net/tfminecraft/activitytf/models/ReferralData.java, src/main/java/net/tfminecraft/activitytf/store/ReferralStore.java, src/test/java/net/tfminecraft/activitytf/models/ReferralDataTest.java, src/test/java/net/tfminecraft/activitytf/store/ReferralStoreTest.java |
Referral account state includes links, playtime, claims, connection hashes, and staff flags. ReferralStore loads and saves records by season, archives data on season changes, and serialises writes. |
Activity, eligibility, and reward claims src/main/java/net/tfminecraft/activitytf/managers/ReferralManager.java, src/main/java/net/tfminecraft/activitytf/managers/ActivityManager.java, src/main/java/net/tfminecraft/activitytf/listeners/ReferralListener.java, src/test/java/net/tfminecraft/activitytf/managers/*Referral*, src/test/java/net/tfminecraft/activitytf/listeners/ReferralListenerTest.java, src/test/java/net/tfminecraft/activitytf/hooks/TLibsItemsTest.java |
ReferralManager tracks activity and eligible playtime, enforces linking and rare-track rules, and processes claims and staff changes. Reward claim state is saved before dispatch and reverted if saving or dispatch fails. |
Player referral interface src/main/java/net/tfminecraft/activitytf/gui/ReferralGui.java, src/main/java/net/tfminecraft/activitytf/gui/ActivityGui.java, src/main/java/net/tfminecraft/activitytf/config/Messages.java, src/main/resources/messages.yml, src/test/java/net/tfminecraft/activitytf/gui/ReferralGuiTest.java, src/test/java/net/tfminecraft/activitytf/config/MessagesLinesTest.java, src/test/java/net/tfminecraft/activitytf/ActivityPluginTest.java |
ReferralGui displays linking, progress, milestones, invitees, and rare-track status. ActivityGui exposes referral access when enabled and permitted. |
Staff commands and plugin registration src/main/java/net/tfminecraft/activitytf/commands/ReferralCommand.java, src/main/java/net/tfminecraft/activitytf/ActivityPlugin.java, src/main/resources/plugin.yml, src/main/resources/messages.yml, README.md, src/test/java/net/tfminecraft/activitytf/commands/ReferralCommandTest.java |
The referral command provides player access and staff operations. Plugin metadata registers the command, alias, and permissions. The README adds a referral feature summary. |
Priority:
Estimated code review effort: 4 (Complex) | ~45 minutes
Change: Feature
Sequence Diagram(s)
sequenceDiagram
actor Player
participant ReferralGui
participant ReferralManager
participant ReferralStore
participant ActivityManager
Player->>ReferralGui: Select an eligible reward
ReferralGui->>ReferralManager: Request claim
ReferralManager->>ReferralStore: Save claim state
ReferralManager->>ActivityManager: Dispatch reward
ActivityManager-->>ReferralManager: Return dispatch result
ReferralManager-->>ReferralGui: Return claim result
Suggested reviewers: justinasla, ryanbarlow97
Merge Risk: 
Minimal · up to b4fc0
-
The referral feature adds menus, claims and staff commands, and no merge-blocking issue was found in this review. Cooking paths are intentionally accepted only as reward items, not as icons, so that behavior is by design.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
The Dev bot test showed a player pacing back to the same spot on each minute boundary never counted as moving. Movement is now sampled every second, while minutes are still counted once a minute. Audit lines also drop colour codes from pool reward names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The milestones are now one list for every act (1h, 4h, 12h, 24h by default, 24h rare), so each one is claimed once ever. An act only sets the pools those milestones draw from (acts.<act>.pools, then the shared pools, then the activity pools), so the loot follows the act. Up to four milestones sit one slot apart in the menu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hovering a milestone that draws from a single-entry pool (the starter kit) now shows every item in it, as fixed rewards already did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An act no longer applies while there are no milestones (an old-layout referral.yml crashed the menu), the old acts.<act>.milestones key is named in the log, missing-pool warnings come once per act and not when disabled, an empty act pool falls back to the shared one, and a claim uses one act for its rare count and its loot. The rules and referral.yml explain that milestones are claimed once by their hours. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Milestones are no longer capped at seven: the menu row shows seven at a time and scrolls. The rare flag and per-act rare-limit are gone; instead every invitee who reaches the last milestone moves their inviter along a rare track (rare-track: players/reward), each step claimed once per season. An invitee counts for one inviter only and not on a shared connection. Default steps 1/3/5 draw from act pools; 24h now pays Act materials (large). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A nether star glints by default, so the rare-track button always looked claimable on Dev. Stars, milestone and rare-step icons now set their glint either way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An invitee who reached the last milestone with their inviter (or that a rare step was claimed with) keeps counting for that inviter when a later milestone raises the goal. rare-reached-with is noted on reaching the goal and cleared by an unlink, so a staff fix of a wrong link still moves an unclaimed invitee; rare-counted-for (set by a claim) still blocks every other inviter. The rare-track title now says how many count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New players get steel tools and rations at 1h, then Ignitium and gold denars, and 2 tin + 2 fragments at 24h. Inviters get 10 gold denars at 1h and 12/20/32 Ignitium. The rare track moves to 2/4/6/8/10 invitees (1/2/3/4/6 tin and fragments, no denars), and invitees are unlimited. Reward items accept Cooking paths (c.<category>(type=...)) through TLibs. Staff get /referral help, link, settime, unclaim, markclaimed, rare unclaim/markclaimed/exclude/include and hold/release next to the existing commands. Every staff change saves at once and is undone and reported when it can't be saved; held accounts claim nothing and show as held in the menu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A reload that changes season.start saved the store and loaded the new season even when the save failed, dropping progress not yet on disk. Now the old season and its start stay in use and the next reload retries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The inviter's 4h/12h/24h pools pay 6/10/16 Ignitium (32 per invitee, was 64). Reward items can set 'name:' for what menus call them; the steel_axe item is a Steel Hatchet in game. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Steps at 2/4/6/8/10 invitees pay 1/1/2/2/2 tin and fragments (8 each in total, was 16), keeping 40:1 against the inviter's 320 Ignitium. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New player 8/16/24 (48, was 64), inviter 4/8/12 (24, was 32). Tin, fragments, the rare track, tools and denars are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New player 10/20/30/40 gold denars (100, was 50), inviter 5 at 1h and 20 at 24h (25 per invitee, was 10 at 1h). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@coderabbitai full review |
✅ Action performed
|
What
A referral system inside ActivityTF that reuses the plugin's reward pools, claim flow and menu style. This is still a draft. The reward values below are the ones agreed with fran for Act I.
/referral(or the head button at slot 22 of/activity), clicks Who invited you?, picks an online player or types a name (/referral invitedby <name>), and confirms. Each account gets one link, and the player can never change it. Staff can fix links with/referral linkand/referral unlink.link.max-invitees: 0). The rare track still ends at 10 players, so inviting more people after that adds nothing to it.max-links-per-day(3) still applies.milestones:inreferral.yml: any number of milestones, any hours, any reward per side). The new player claims each one once ever per season. The inviter claims each one once per invited player, from the same menu. The row shows seven at a time and scrolls past that.rare-track:). Every invited player who reaches the last milestone (24h) moves the inviter one step along it. Each step is claimed once per season.acts.<id>setsstartsand its ownpools, and the latest act that has started applies. A pool is looked up in the act's pools, then the sharedpools, then the activity's week-lockedrewards.pools.season.open-days(14) days afterseason.start, any account can link, and its playtime since the season start already counts. After that, only accounts in their firstlink.new-account-days(7) days can link. Changingseason.startmovesreferrals.ymlaside and starts a fresh season. If the store can't be saved first, the season doesn't change (it logs SEVERE), and the next reload tries again.Rewards (Act I)
The denars match the economy on Main (2026-10-24): 100d is one median week of earnings and the price of a first paid class change, and 25d is a quarter of a week. There are no denars on the rare track. Its total, 8 tin and 8 fragments, is 30:1 against the 240 Ignitium ten invitees pay their inviter (rule 4 of the Act System's Activity trickle is about 40:1).
ACT-SYSTEM.mdin the workspace logs referrals as a new one-off source of act materials, with these tables and their impact.Cooking reward items
Reward items can now be Cooking items:
c.<category>(type=<food>;...), such asc.dry_ration(type=dry_ration;quality=1)from the RPCharacters starting kit. They are handed over through TLibs likem.paths. Any reward item can also setname:, what the menu calls it (the shippedm.tools.steel_axeis named "Steel Hatchet", as in game). A malformed path is named at load time, and if Cooking isn't enabled, a warning says the path hands over nothing. They are only accepted as reward items, not as craft keys or icons.Menu (
/referral, 54 slots)Invited by: X), Who invited you?, or why linking is closed14h / 24hPlayers you invited (n)[CLAIM 20h]. A click claims everything due for that playerThe rare-track menu has a header listing who counts and one item per step (locked / glowing claimable / ✔ claimed, with the step's contents and how many more players it needs).
Anti-abuse
I checked several public referral plugins (RallyRefer, MysticalReferral, InviteRewards, RedeemMaster, ReferMe) and some fraud-prevention write-ups. Most of them pay on a single playtime threshold plus a same-IP check. This PR goes further:
playtime.afk-minutes, the player moved at leastmove-blocksblocks, chatted, ran a real command, or broke or placed a block, and Paper's idle timer is under the limit too. Turning the camera, swinging or autoclicking alone earns nothing. Movement is sampled every second.character_selection): no counting and no claiming there./referral allowip <a> <b>allows one real household pair.rare-counted-for). The goal is recorded when an invitee reaches it (rare-reached-goal), so raising the goal mid-season doesn't take credit away.REFERRAL-AUDITline.enabled: false.Commands and permissions
/referral(alias/referrals) and/referral invitedby <name>:activity.referral(default true).activity.referral.admin, op, and a child ofactivity.admin)./referral helplists these:info <player>: hours, inviter, claims on both sides, invitees and their claims, rare count and who counts, rare claims, ties and flags.link <player> <inviter>/unlink <player>: staff links skip the season, daily and connection checks and replace an existing link, but still refuse self links and loops.addtime <player> <minutes>/settime <player> <minutes>: lowering time below the goal a player reached removes their rare credit, unless a claimed step already ties them.unclaim <player> <hours|all> [new|inviter|both]/markclaimed ...: reopen or close milestones.rare unclaim|markclaimed <inviter> <players|all>:unclaim allalso frees the invitee ties, andmarkclaimedties the invitees it stands on.rare exclude|include <player>: keep an invitee off every rare track.hold <player>/release <player>: an account on hold can't claim anything, and its inviter can't claim for it.allowip <player> <player>: toggle the household pair./activity reloadalso reloadsreferral.yml.Deploy notes
season.startships empty, so set it before going live.plugins/activity/messages.yml(from 09-18) has noreferral:section, so every referral text comes from the jar's defaults and nothing needs editing at deploy. To change a referral text, copy that key from the jar'smessages.ymlinto the file and run/activity reload. Once a key is in the file, later jars won't update it.Tests
mvn verify: 1075 tests pass. The new code has 100% line coverage. Locally, 10 lines in the existingActivityCommand/PlayerStoreare uncovered because their POSIX-only tests are skipped on Windows. That is unchanged frommain, and Linux CI covers them.Dev test (TFMCDev01, now
activity-DEV-referral-20261024b.jar)~/referral-test/claims.jsran 40 checks with mineflayer bots that have real characters, and all 40 passed on…24b(the current values), and before that on…24aand…22d. Earlier versions of the run passed 38/38 on…22band…22c. TestChar2 was the new player and TestChar1 the inviter.holdrefused the claim and handed over nothing;releaselet it through.Steel Hatchet.markclaimedon an already-claimed milestone changed nothing.rare excludeshowsflags: rare-excludedin info, andincludeundoes it.Nothing was changed on Main or Tutorial. The old jars are backed up under
~/dev-jar-backup/.🤖 Generated with Claude Code