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>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-07-04 14:18:55 +02:00
1 parent 5b95cb7f56
commit 9290ef650b
10 files changed
+403 -23

No files matched your search

@@ -115,6 +115,8 @@ public class NetworkPlayerSetup : NetworkBehaviour
private bool _lastXRay;
private bool _frozenApplied;
private bool _lastFrozen;
private float _xrayFlashUntil; // Time.time deadline for the just-shot X-ray flash (local per client)
private HunterLaserBeam _laser; // shot beam visual, lazily attached on the hunter avatar
public override void OnNetworkSpawn()
{
@@ -361,6 +363,10 @@ public class NetworkPlayerSetup : NetworkBehaviour
// The X-ray reveal predicate for this avatar on the local machine.
private bool ComputeXRay()
{
// Just-shot flash: a hunter's hit lights this hider up for a brief window (server-broadcast), on top
// of the normal reveal triggers, so the moment of the hit reads before the hider leaves play.
if (Time.time < _xrayFlashUntil) return true;
// Buried-hider reveal: already gated to hider + running match on the owner before it is published.
if (_embeddedReveal.Value) return true;
@@ -369,6 +375,52 @@ public class NetworkPlayerSetup : NetworkBehaviour
return ComputeResolutionFreeze();
}
// --- Hunter shot beam ------------------------------------------------------------------------------
// Cosmetic and client-trusted (a co-op hide & seek, matching the ReportHit trust model). The local
// shooter draws its own beam instantly for responsiveness and relays the world-space segment to the
// server, which echoes it to every other client. The RPCs live on the hunter avatar (this
// NetworkObject), so they only run on this shooter's instances - other avatars never draw a beam.
/// <summary>Owner-only. Draws the shot beam locally now and replicates the world-space segment so every
/// other client sees the same shot.</summary>
public void FireShot(Vector3 start, Vector3 end)
{
if (!IsOwner) return;
EnsureLaser().Fire(start, end);
FireShotServerRpc(start, end);
}
[ServerRpc]
private void FireShotServerRpc(Vector3 start, Vector3 end) => FireShotClientRpc(start, end);
[ClientRpc]
private void FireShotClientRpc(Vector3 start, Vector3 end)
{
if (IsOwner) return; // the shooter already drew it locally
EnsureLaser().Fire(start, end);
}
private HunterLaserBeam EnsureLaser()
{
if (!_laser) _laser = GetComponentInChildren<HunterLaserBeam>(true);
if (!_laser) _laser = gameObject.AddComponent<HunterLaserBeam>();
return _laser;
}
// --- Hunter hit flash ------------------------------------------------------------------------------
/// <summary>Server-only. Flashes THIS hider's through-walls X-ray glow on every client for
/// <paramref name="seconds"/> (the just-shot feedback), overriding the normal reveal predicate for that
/// window. MatchManager delays the actual removal by the same span so the glow is seen before it leaves play.</summary>
public void FlashHitReveal(float seconds)
{
if (!IsServer) return;
FlashHitRevealClientRpc(Mathf.Max(0f, seconds));
}
[ClientRpc]
private void FlashHitRevealClientRpc(float seconds) => _xrayFlashUntil = Time.time + seconds;
// True if THIS machine's local player is a Hunter role variant (so it must not see hiders during hide).
// Shared with MatchHud. Called per frame per avatar during hide/seek, so the GetComponent result is
// cached per local PlayerObject; a respawn/conversion swaps the object and refreshes the cache.