feat(stealth): mask identities and notify admins on login
This commit is contained in:
@@ -29,7 +29,11 @@ As an **unlocked player**, I want to disconnect while invisibility from a potion
|
||||
- [x] When the sleep-count policy is `include`, concealed players count normally; ordinary players are never modified by either policy.
|
||||
- [x] A player's previous sleeping-ignore state is restored when concealment ends, the player disconnects or is reset, the policy changes to `include`, or the plugin disables.
|
||||
- [x] Policy changes apply immediately to currently concealed players.
|
||||
- [x] Throughout the concealed session, no overhead name tag identifies the player to any other player, including administrators.
|
||||
- [x] Throughout the concealed session, the overhead name is rendered as scrambled magic text, including for administrators, while the physical character stays visible.
|
||||
- [x] Concealed usernames are excluded from outgoing command suggestions, including `/msg`, `/tell`, and `/w`; manually addressing a known username remains possible.
|
||||
- [x] Default chat display names and vanilla private-message and advancement name components are scrambled without changing message content or signed chat bodies.
|
||||
- [x] Masked message name components do not expose the original identity through hover or click actions.
|
||||
- [x] Previous display names and ordinary suggestions return when concealment ends; ordinary players remain unaffected.
|
||||
- [x] The concealed player's physical character remains visible in the world and retains ordinary movement, interaction, combat, and permission behavior.
|
||||
- [x] The concealed player receives a private message explaining that stealth is active for the session.
|
||||
- [x] Concealment lasts until the player disconnects and is handled predictably across death and plugin reload or disable events.
|
||||
@@ -41,6 +45,16 @@ As an **unlocked player**, I want to disconnect while invisibility from a potion
|
||||
|
||||
Automated tests verify unlocked and locked disconnect transitions, ordinary-disconnect clearing, one-login consumption, concealed join and quit announcement suppression, preservation of ordinary announcements, private activation messaging, ordinary-login presentation, tab removal for existing and new observers, overhead-name suppression, active concealed-session tracking, ProtocolLib-independent native player-sample filtering, guarded public server-list count adjustment, nonnegative counts, unchanged maximum capacity, default sleep-count exclusion, immediate policy changes, restoration of prior sleeping-ignore state, and the absence of entity-hiding calls. ProtocolLib is declared as a required dependency, prepared state round trips through YAML, and `./gradlew clean check jar` passes.
|
||||
|
||||
Identity masking verification (2026-09-06): `./gradlew --offline clean check jar` passed all 65 tests and OKF validation. Tests cover semantic name slots, preserved message content, stripped identifying actions, reflected suggestion entries and chat-bound records, safe packet failure handling, immutable name snapshots, overhead formatting, and display-name restoration after repeated concealment. Presentation tests first failed to compile against the missing snapshot API, then passed after implementation. These are automated unit checks, not a live-client smoke test.
|
||||
|
||||
## Identity masking scope
|
||||
|
||||
Masking applies to active concealed sessions, not every potion effect. Outgoing username suggestions are filtered across commands; entering a known username manually still works. Default Bukkit chat uses a temporary scrambled `Anonymous` display name. Vanilla translated announcements and chat-type bound names are masked at the packet boundary without editing signed message bodies. The overhead tag uses scoreboard magic formatting on the profile name, not a profile rename; this is visual concealment, not anonymity against modified clients.
|
||||
|
||||
Custom chat formats that ignore Bukkit display names, nicknames, custom scoreboards, and third-party messaging plugins may need dedicated integration. Unsupported packet layouts retain the original packet and emit one warning per packet type rather than interrupting chat delivery. Live-server/client compatibility still requires a smoke test, particularly after Minecraft or ProtocolLib upgrades.
|
||||
|
||||
Implementation: [identity presentation](../../src/main/java/games/dmg/spigotstealth/BukkitIdentityPresentation.java), [packet listener](../../src/main/java/games/dmg/spigotstealth/ProtocolLibIdentityMaskingListener.java), and [semantic name masking](../../src/main/java/games/dmg/spigotstealth/StealthChatMasker.java).
|
||||
|
||||
## Related
|
||||
|
||||
- [Accumulate invisibility time and unlock stealth](us-001-accumulate-invisibility-and-unlock.md)
|
||||
|
||||
Reference in New Issue
Block a user