Commit Graph
26 Commits
Author SHA1 Message Date
adminandClaude Fable 5 0ab92933de Support styled multi-text nameplate label containers
PlayerNameplates clones a GameObject container instead of a single
TMP_Text and drives all TMP_Text children (text + distance font size),
so the label template can be authored with layered texts (e.g. outline
or shadow copies) in the editor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 20:40:56 +02:00
adminandClaude Fable 5 4c6a452f9d Fix late joiners never seeing earlier peers behind the paint reveal gate
Applying a snapshot now also raises the replica's sequence horizon: a
snapshot covers all events up to its captured cutoff. Previously the
horizon only advanced with the live stamp stream, so the server replica
of a player who never painted served snapshots with cutoff 0 - late
joiners then waited forever for the published baseline cutoff and the
reveal gate never opened (third client could not see the second).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 20:40:48 +02:00
adminandClaude Fable 5 b71cd61533 Add match result evaluation with live scoreboard in the Esc menu
MatchManager tracks per-participant outcomes from match start (hunter /
hiding / found / converted / left), freezes hit rows with seek time and
finder name, and decides the winner at seek end (any untouched hider ->
hiders win). Results replicate via a Match_Result named message,
broadcast live on hide start, every hit and mid-match leave (no-op once
the winner is frozen), with late joiners served the current state.

MatchResultScreen renders the scoreboard as a section of the session
panel: winner banner ("Match in progress" while live), summary counts
and pooled rows (name, outcome, time, found by); the section hides when
no result data exists. OnlineSessionBrowserUI auto-opens the Esc
overlay when the Resolution sub-phase begins.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 20:40:36 +02:00
adminandClaude Fable 5 262a20326a Hide hider nameplates from hunters during seek phase
Generalize the body-renderer gate to all avatars so nameplates inherit
the existing visibility matrix (hide phase, found hiders, paint reveal,
conversion settle), and add the one case the body gate cannot cover:
hunters see camouflaged hider bodies during seek, so suppress hider
names for a local hunter viewer while LocalSubPhase == Seek.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 15:05:48 +02:00
adminandClaude Fable 5 0e7ce0c410 Add player names: settings persistence, replication, screen-space nameplates
- GameSettings: playerName field persisted in Settings.json
- NetworkPlayerSetup: owner-written DisplayName NetworkVariable
  (seeded from settings on spawn, sanitized/truncated, live rename push)
- PlayerNameField: binds the session panel name input to settings
- PlayerNameplates: screen-space overlay labels above players with
  distance-based font scaling (clamped min/max), pooling, FP self-hide

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 14:58:15 +02:00
adminandClaude Fable 5 6c03e5d3f6 Refactor Assets/Scripts: trim restating comments, minor structure cleanups
Sweep over 48 files (Editor/ excluded): remove comments that restate the
code, condense class summaries, fix three stale doc statements
(HsvColorPicker alpha bar, PaintHud layoutPrefab, MasterVolume
FallbackDefault). Inline two single-use wrappers (IsPointerOverUi,
BuildModes), drop an unused using, replace a magic literal with the
existing ParallaxBase constant, and convert ~10 UnityEngine.Object null
checks to the implicit-bool convention. No serialized fields, signatures,
RPC/NetworkVariable names, defaults, or #if blocks touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 08:29:18 +02:00
adminandClaude Opus 4.8 50781e32d2 Camo: generalize brightness + add persistent saturation
Move brightness out of the half-lambert diffuse term to a final exposure
multiply on the whole shaded body color (diffuse + GI + specular), and add
a saturation grade (0 = neutral, -1 = grayscale, >0 = boosted) on the same
final stage. Saturation rides as a 4th component on CamoKnobs (Vector3 ->
Vector4) so it inherits all three persistence paths: HUD JSON, network
replication (_camo NetworkVariable), and painting-slot metadata. Wires the
renamed Slider_Brightness and new Slider_Saturation. Bumps HudFileVersion
and PaintMetaVersion with load-time remaps so existing paintings keep their
look (old 1=neutral saturation remaps to 0=neutral).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 07:23:40 +02:00
adminandClaude Opus 4.8 1fbd66095c Radar ping: anchor sweeps to seek start so they stay in sync with the HUD
RunSeekPhase fired the interval ping from an accumulating countdown that discarded each cycle's frame overshoot and drifted seconds late over a match, while the HUD ping countdown is anchored absolutely to _seekStartTime. Fire on absolute interval boundaries (n*interval from _seekStartTime) instead, sharing the HUD's anchor so the on-screen timer hits 0:00 the same moment the sweep fires. A missed boundary is skipped, never bursted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 22:36:59 +02:00
adminandClaude Opus 4.8 bfcd84afe4 Add manual radar ping, blip refresh/fade, and resolution statue barrier
- Manual hider ping on "E": server-authoritative RequestManualPing gated to
  Seek + living hider; shared EmitRadarPings path so interval and manual pings
  produce identical blips. Ping key read client-side in GameModeManager, role-
  gated and excluded in FreeCam (E is fly-up there).
- Radar refreshes an existing blip for the same transform target instead of
  duplicating it (lifetime resets to the configured value) via RadarTarget.Refresh.
- Blips fade in/out independently of the disc fade: per-blip MoveTowards factor
  multiplied on top of the radar fade, refresh-safe, with separate in/out speeds.
- Resolution countdown waits for conversion statues to load: generalized the
  match-start loading barrier (RunReadinessBarrier over _barrierTargets, hold
  phase carried in MsgBeginLoad) and run it a second time over statue IDs before
  starting the real resolveDuration. Only holds for Conversion with real statues.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 13:59:28 +02:00
adminandClaude Opus 4.8 043fafa796 MatchManager: Debug-ContextMenu-Label umbenannt
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 12:23:49 +02:00
adminandClaude Opus 4.8 414beaa403 Add player-collision toggle and make conversion statues follow it
Add a per-machine "Players Collide" switch on GameModeManager: a
self-healing reconciler routes the local capsule through other avatars'
body colliders via Physics.IgnoreCollision when disabled, re-asserting
every frame while off to survive the late-created runtime MeshCollider,
conversion respawns and teleport resets. Expose Active/ActiveVersion/
BodyCollider on NetworkPlayerSetup for the reconciler.

Give MatchStatue the same Active registry + BodyCollider pattern so the
frozen conversion statues obey the same toggle (they carry their own
paint MeshCollider but are deliberately not NetworkPlayerSetup avatars).
Also drive the statue's steady X-ray reveal in Resolution, matching an
un-found hider.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:17:19 +02:00
adminandClaude Opus 4.8 0f108fce47 Add conversion statues shown in resolution phase
In Conversion mode, capture a snapshot (pose index + paint) of each hider
at conversion time and materialize a frozen, painted statue at the found
spot for the resolution phase, independent of the now-hunter avatar.

- MatchStatue.cs (new): server-init pose/paint, network-driven pose then
  freeze, reveal-gate (hidden until paint applied), kills inherited sim.
- PlayerPaintSync: _isStatue (sibling auto-detect) suppresses the three
  auto-behaviours so MatchStatue drives the paint flow deterministically.
- MatchManager: statuePrefab; capture in ConvertToHunter; spawn on
  resolution enter; despawn + record clear on EndMatch/teardown/start.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 09:33:15 +02:00
adminandClaude Opus 4.8 0a1e286a34 Add debug skip-to-next-subphase for MatchManager
Server-authoritative skip flag consumed by each phase wait loop
(loading barrier, hide/resolution wait, seek phase), routed via
authority like RequestEndMatch. Exposed as a [ContextMenu] and
public method; single transition per trigger, cleared on teardown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 08:12:00 +02:00
adminandClaude Opus 4.8 a2c8a2c75d Freeze players during map load: kill gravity and hide own mesh
- PlayerCharacterController: GravityEnabled toggle. When off, hold
  vertical velocity at zero and skip steep-slope sliding so a frozen
  avatar neither falls nor drifts; true is byte-for-byte the old path.
- GameModeManager: during Loading, additionally disable gravity and
  hide the local body (SkinnedMesh + fur shell), re-asserted each frame
  to catch the mid-load lobby->match respawn. Restored (body shown,
  gravity on) before ActiveMode.Enter() on release to Hide.
- MatchManager: enter Loading *before* SwapScenes so still-bound lobby
  avatars are frozen before their floor unloads. Fixes the player
  falling into the void during the lobby->map scene swap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 07:55:40 +02:00
adminandClaude Opus 4.8 fba4780c0e Add match-start readiness barrier (Loading phase)
Gate the Lobby-to-world transition on a new MatchSubPhase.Loading before
Hide: movement stays frozen and the Hide countdown does not start until
every connected client has spawned all match avatars and applied their
paintings.

- MatchManager: Loading phase; matchLoadTimeout tunable; Match_BeginLoad
  broadcasts the respawned avatar NetworkObjectIds (+ generation tag),
  Match_Ready collects per-client ACKs (host self-checks locally); barrier
  coroutine in RunMatchPhases before Hide; disconnect/teardown cleanup.
- GameModeManager: freeze local player (movement/paint/tab) during Loading,
  restored via ActiveMode.Enter() on transition to Hide (no camera jump).
- NetworkPlayerSetup: treat Loading like Hide in ComputeVisible so a
  fast-loading client cannot reveal a hider early.
- MatchHud: "Loading" phase label.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 22:07:59 +02:00
adminandClaude Opus 4.8 de82ce25de Radar-Sichtbarkeitsgates, Hider-Pings im Seek + Ping-Countdown
Radar: nur sichtbar bei >=1 Target, in First-Person und in der Seek-Phase
(Overlay-Kamera getoggelt, Blip-Skripte laufen weiter). Singleton fuer
Server-Zugriff. GameModeManager: Kamera + Tab-Moduswechsel erst ab
gebundenem Lobby-Player (Inert-Zustand ohne Player, Orbit-Input geparkt).

MatchManager: Server tickt im Seek alle radarPingInterval (30s) und
broadcastet noch nicht gefundene Hider (NetworkObjectId + radarPingLifetime
3s) nur an Hunter-Clients; jeder Hunter loest lokal auf und spawnt Blips.
Ping-Loop in die Seek-Coroutine gefaltet (EndMatch stoppt ihn mit).

MatchHud: Ping-Countdown lokal aus Seek-Start + Kadenz berechnet, Format
m:ss (0:30..0:01), ausserhalb Seek / bei deaktivierten Pings 0:00.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 21:45:10 +02:00
adminandClaude Opus 4.8 48975c0f20 perf(paint): stronger X-ray hit flash + kill spawn/respawn freeze
X-ray hit flash: drive a dedicated flash mode instead of the normal
reveal - pulse off (steady), intensity boost (xrayFlashBoost, default 3x),
snap-on, then restore authored color/pulse exactly. Fixes the weak/dark
flicker where the 0.35s hit window often caught only the pulse's near-off
plateau.

Spawn/respawn freeze: pool GPU RenderTextures across despawn->respawn
(TeardownGpu recycles, CreateRT pops) so a hider->hunter conversion no
longer churns ~70MB of RT alloc/free on every observer; reuse staging
textures to cut per-map GC. Defer the blank base-seed on reveal-gated
remote replicas (DeferInitialSeed) - the real pixels arrive with the
snapshot apply anyway; gate the FurShellRenderer alongside the body so a
deferred replica never shows the pooled RT's stale fur; EnsureBackendSeeded
+ TryCaptureSnapshot guard against capture-before-reseed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 15:14:20 +02:00
adminandClaude Opus 4.8 9290ef650b Hunter shot: replicated laser beam + X-ray hit flash; snapshot apply in-place reseed
- Laser.shader + HunterLaserBeam: additive HDR beam, fade in/out over opacity
  and thickness, code-driven LineRenderer, tunable emission multiplier.
- FirstPersonMode: TryShoot computes world endpoint, fires beam with lateral
  muzzle offset (right) so it isn't dead-center from hunter view.
- NetworkPlayerSetup: shot relay RPCs (owner->server->all) + hit-flash RPC
  (server->all), flash OR-branch in ComputeXRay.
- MatchManager: hit reveal broadcasts X-ray flash first, delays hider removal
  by hitRevealDelay so the glow is visible before the body vanishes.
- MeshPainter reseed: in-place fast path avoids full GPU backend teardown on
  snapshot apply (no ~70MB RT churn), fixes spawn/paint-load hitch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:18:55 +02:00
adminandClaude Opus 4.8 ed09d6a1b0 Netcode: receiver-side paint reveal gate + fur pipette gating
Hide remote avatars until this client has actually applied a snapshot
reaching the owner-published baseline cutoff, preventing the default
grey/white material from flashing before a player's painting has loaded.

- PlayerPaintSync: owner-authoritative _publishedCutoff NetworkVariable,
  receiver tracks _appliedCutoff; explicit blank publish for never-painted
  avatars so they still reveal.
- NetworkPlayerSetup: cache _paintSync, hide body renderers on spawn, gate
  UpdateVisibility on PaintRevealReady.
- MeshPainter.Pick: fur toggle now follows pickedHeight (own paint-mesh
  only), matching the Occlusion/Height pipette behaviour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 12:08:46 +02:00
adminandClaude Opus 4.8 6434e1c4fc Show live hunter/hider counts in match HUD
Count spawned role variants from a client-side avatar registry in
NetworkPlayerSetup (network objects exist on every machine), so the
counts work without server-only match state. MatchHud binds the two
count texts and rewrites them only on change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 13:34:41 +02:00
adminandClaude Opus 4.8 8ee329eee0 MatchHud: hunter/hider count widgets + English phase labels
Authored HUD count widgets (Hunter/Hider label + count) wired to new
_hunterCount/_hiderCount serialized fields; phase labels switched to English.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 12:57:14 +02:00
adminandClaude Opus 4.8 8f9b6cf1bc Turn MatchHud into a uGUI canvas binder
Replace the runtime IMGUI (OnGUI) HUD with a binder that drives the authored
MatchHudCanvas widgets via [SerializeField] references (Canvas / Phase /
Time / Crosshair). Visibility toggles Canvas.enabled instead of the
GameObject, so Update keeps polling while hidden; an Awake guard disables
the component on unwired references. Drop the AddComponent<MatchHud>()
bootstrap in MatchManager - the component now lives on the scene canvas.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 10:32:34 +02:00
adminandClaude Opus 4.8 3e6191ead9 Add timeout to relay session operations
Relay host/join/refresh/sign-in could hang forever: none of the UGS
Sessions 2.2.4 calls accept a CancellationToken, so a stuck op left _busy
true and locked the whole browser UI with no recovery.

Wrap every hangable call in a Timed() helper (Task.WhenAny + Task.Delay,
the only option the API allows) driven by a new connectTimeoutSeconds
inspector field (default 25s, 0 = wait forever). On timeout the status is
reported, _busy is cleared and the event-driven UI recovers immediately.

Guard the two ways a late/partial op can corrupt shared state:
- LeaveIfDisplaced: an aborted CreateSessionAsync keeps running and may
  materialise a ghost host seconds later; leave it, but only when the user
  has no tracked session (_session == null), else it would tear down the
  shared NetworkManager and kill a fresh host.
- Partial-start shutdown: only for connection-owning ops (host/join), so a
  refresh timeout during hosting can't shut down the user's own host.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:09:28 +02:00
adminandClaude Opus 4.8 a59a5e53ab Add persistent per-install player identity
Introduce PersistentPlayerId: a stable id that survives an app restart and is
unique per install (built on the UGS install-path-namespaced anonymous
PlayerId, with a local PlayerPrefs GUID fallback for loopback). Clones on the
same machine stay distinct.

Each client reports its id to the server on connect via a new Match_Identity
named message (mirroring Match_ReportHit, so no ConnectionApproval timing
risk); the host records its own directly. The server keeps an ephemeral
clientId -> persistent id map, exposed via PersistentIdOf(clientId) as the
foundation for later reconnect recognition. Map entries are cleared on
disconnect and net stop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:09:19 +02:00
adminandClaude Opus 4.8 17bb37cb92 Fix stuck conversion render-gate on mid-settle disable/disconnect
The freshly converted hunter's body was hidden for the settle window via a
WaitForSeconds coroutine. If the object was disabled or the converting owner
disconnected mid-settle, the coroutine was stranded and _renderGate stayed
true forever, leaving the avatar invisible on every remote.

Replace it with a frame-driven Time.time deadline (_renderGateUntil) lifted
in UpdateVisibility, which runs every frame the component is active and can
never get stuck. Remove the coroutine and the now-unused System.Collections
using. Visible behaviour in the normal case is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:09:11 +02:00
adminandClaude Opus 4.8 e23fae0c50 Reorganize scripts into subfolders by responsibility
Move scripts under Assets/Scripts/ into Components, GameMode, Helper,
Network, Enum, Struct and ScriptableObject folders. Pure file moves
(plus folder .meta files); no code changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 15:02:15 +02:00