Commit Graph
24 Commits
Author SHA1 Message Date
adminandClaude 9dc8f21528 FurShell: scale-aware length/curvature + X-ray glow mirror
The fur is drawn from a CPU-baked unit-scale mesh whose instance matrix
carries the avatar's world scale, so the extrusion scaled fully 1:1 with
the player (hider 0.5 / hunter 1.5). That read as too-short fur on the
small hider and too-long on the big hunter, and the curvature droop was
sized off the raw unity_ObjectToWorld which doesn't carry the per-instance
scale in the RenderMeshInstanced path.

- FurShellRenderer pushes the avatar's lossyScale (_FurObjScale) plus a new
  Fur Scale Influence (0..1, default 0.5) that blends the fur SIZE between
  fully proportional (1) and a constant world length (0). The shader
  pre-divides the object-space displacement so the net world length follows
  effScale; curl droop and wind use the same effScale, keeping the curl
  SHAPE invariant across avatar sizes and influence settings.
- The body's see-through X-ray reveal (forward half) is mirrored onto the
  visible fur so strands glow WITH the reveal instead of hiding it under
  opaque fur. FurShellRenderer pulls the live colour/pulse/flash from the
  sibling MeshPainter (new getters), in phase with the body. A new X-Ray
  Fur Strength (default 0.2) tames the per-shell accumulation, since the
  body writes the glow once (opaque) but the fur stacks N transparent
  shells that each composite it.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-06 16:33:21 +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 cad5015d42 Radar: fade in/out statt hartem Enable-Toggle
Gemeinsamer 0..1-Fade-Faktor treibt Disc-Alpha (baseAlpha * fade via MPB),
Blip-Alpha (RadarTarget, im Gleichschritt) und Radar-Scale (0.8 -> 1.0).
Fade-in/-out-Speed separat einstellbar; Kamera bleibt an solange fade > 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 12:23:42 +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 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 f5de233e0c Add radar blip system: Radar spawner + directional RadarTarget
Radar.Spawn(transform, lifetime) clones the "Target Template", names it
"Target" and attaches a RadarTarget that self-destructs after lifetime.

RadarTarget aims each frame toward camera->target (full 3D LookRotation),
drives the point renderer's _BaseColor from a forward-bearing gradient
(ahead/side/behind depth cue lost in the flat disc projection) via a
MaterialPropertyBlock, and scales the point renderer transform by
camera->target distance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 20:46:58 +02:00
adminandClaude Opus 4.8 e571375cab feat(ui): move HSV swatch onto the SV handle
HsvColorPicker: read the color swatch from the SV handle's child
("Handle/Swatch") instead of a standalone root child; drop the dead
leftover-alpha bar and root-swatch fallback handling.
PaintHudPanel.prefab: restructure the picker so the swatch lives under
the SV handle and wire _swatch accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 17:26:57 +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 1b783a39be Fur: Albedo-gekoppelte Länge, Toggle-Gate, Soft-Edge, World-Gravity, Pipette & FP-Hide
- Fur-Map trägt nur noch R = Länge (linearer Datenkanal); Farbe kommt per-texel
  aus der Live-Albedo-RT (an _BaseMap des Shell-Shaders gebunden)
- Toggle_Fur als echtes Gate (IsChannelActive = fur), Default aus, furLength 0.5
- Weicher Alpha-Übergang (radial/tip/length coverage) statt Hard-Clip; Transparent-
  Pass mit Depth-Bias (Offset -1,-1) gegen Body-Durchflimmern
- Root dunkler / Tip heller aus gemalter Farbe abgeleitet (kein Fix-Tint)
- Gravity/Curl in World-Space nach Transform (unabhängig von Mesh-Rotation)
- Pipette aktiviert Fur-Toggle immer; liest R-Kanal als Länge
- First-Person blendet FurShellRenderer mit aus
- Netzwerk (FlagFur), Undo, Persistence (fur.png R=Länge) mitgezogen

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 23:40:58 +02:00
adminandClaude Opus 4.8 7536e8ec8b Fur als 4. Paint-Map + Ziel-Opacity-Blend
Fur wird die vierte kanonische Paint-Map (RGB=Farbe, A=Länge). Integration
über Seed (kahl), GPU/CPU-Paint, Undo, Netzwerk-Sync, Persistence (fur.png,
v6) und Live-RT-Hook im FurShellRenderer. HUD-Binding (Toggle/Picker/Alpha)
aktiviert. Fur-Alpha lerpt jetzt zu einer Ziel-Opacity (Slider_FurOpacity)
statt additiv Richtung 1 zu akkumulieren (zwei Brush-Passes: Fade + Deposit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 21:35:53 +02:00
adminandClaude Opus 4.8 43791abc79 Add fur-map support, skinned driver, and world-down curvature to fur shell
FurShell now reads an RGBA fur map (RGB = per-texel strand colour,
A = fur length) so the standalone look can be driven per-texel. Alpha 0
clips the whole shell stack (root included) so a painted body shows
through; _SolidRoot keeps the opaque base shell only for the full-coverage
prototype. White map default keeps the standalone prototype unchanged.

FurShellRenderer drops the MeshFilter requirement and resolves its mesh
per frame: on a SkinnedMeshRenderer it borrows the SkinnedColliderBaker's
per-frame baked pose so the fur follows the animation with no extra bake.

Curvature/gravity now bends strands toward WORLD down (converted into
object space via unity_WorldToObject) instead of object-local down, so a
rotated player mesh droops downward correctly. Identity rotation is
unchanged, so the test sphere is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 20:47:15 +02:00
adminandClaude Opus 4.8 bf4297a3b1 Add generic shell-texturing fur shader and renderer
FurShell.shader renders N normal-extruded shells with per-strand
alpha-cutout for hair/fur/grass on any mesh (needs only normals/UVs).
Parameters cover length, density, thickness, taper, tip fill, curvature,
per-strand direction randomness, wind sway and silhouette strand stretch.

FurShellRenderer drives every parameter via MaterialPropertyBlock and
draws the mesh shellCount times with RenderMeshInstanced from
beginCameraRendering (works in edit, game and screenshot cameras).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 17:34:58 +02:00
adminandClaude Opus 4.8 50efc7e8b3 Fix: wheel over UI scrolls the list instead of zooming the camera
The orbit rig read the wheel unfiltered for zoom, so scrolling a paint-mode
scroll list also zoomed the camera. Gate the zoom behind a shared
InputUtil.PointerOverUi() helper (EventSystem raycast); MeshPainter's private
IsPointerOverUi() now delegates to the same helper (DRY).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 16:04:51 +02:00
adminandClaude Opus 4.8 ba7f3c2e89 Move settings to Settings.json and add master volume
Replace the former per-value PlayerPrefs storage with a shared human-readable
Settings.json store (GameSettings). MouseSensitivity keeps its public .Multiplier
API and only swaps its backing to the JSON store, so the camera controllers stay
untouched. Add a MasterVolume facade that drives the AudioMixer's exposed
"MasterVolume" parameter (loaded from Resources, linear<->dB mapping), applied at
startup and on change, plus a MasterVolumeSlider binder. The default is the level
currently authored on the mixer instead of an arbitrary constant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 15:30:44 +02:00
adminandClaude Opus 4.8 f586ef7a15 Simplify HUD layout save path to a fixed PaintHud.json
Drop the scene-derived hudSaveId/key mechanism and save the HUD layout to a
single PaintHud.json under persistentDataPath.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:52:22 +02:00
adminandClaude Opus 4.8 6ef4f56394 Store paintings as per-painting folder of PNGs + JSON
Replace the flat binary .paint format with a folder per painting under
Paintings/<key>/: albedo/emission as sRGB PNGs, the packed MSO map split
into human-readable metallic/occlusion/smoothness grayscale PNGs, and the
non-baked scalars (name, size, emission intensity, camo/height knobs) in
painting.json. MSO.B is always 0 (pack shader), so the split round-trips
losslessly with no alpha ambiguity. Public API (SavePaintAs/LoadPaintByName/
ListSavedPaintings/PaintExists/DeletePaint) and the network snapshot path
(WriteCanonicalMaps/ReadCanonicalMaps) are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:52:16 +02:00
adminandClaude Opus 4.8 cadc8f8b17 Bind PaintHud to the scene-authored canvas
Drop the code-gen canvas/EventSystem bootstrap and the layoutPrefab
instantiation; the canvas and its panel now live in the scene, so PaintHud
binds to its first child at startup instead of building the UI at runtime.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 10:32:42 +02:00
adminandClaude Opus 4.8 fbbb4f7419 Fix low-opacity paint never reaching the target colour
Paint RTs were ARGB32 (8 bpp). Repeated source-over at low alpha rounds
back to the previous value once the per-stroke decrement dst*alpha drops
below half an LSB, so it freezes at a grey floor (~0.5/alpha in 255ths) -
e.g. black at low opacity never reaches 0. Switch the accumulation buffers
to ARGBHalf (16-bit linear). The sRGB round-trip stays at the byte boundary
(seed decodes on upload, ReadRtPixels re-encodes on readback), so canonical
bytes and CPU/GPU parity are unchanged - only the accumulation gained bits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 10:32:29 +02:00
adminandClaude Opus 4.8 0c0a250015 Fix players colliding with the idle FreeCamera capsule
The FreeCamera's CharacterController stayed enabled permanently, so its
invisible capsule sat in the play area at (0,1,0) and blocked players even
when the freecam was not in use: the controller script disables only itself
in Awake, not the independent CharacterController collider.

Keep the capsule out of the physics world unless the freecam is actually
flying: disable it in Awake and toggle it with SetActive (enabled before the
teleport in SyncToCurrentView, which preserves the current enabled state).
Also ignore collision against all live players instead of just the first on
each activation, since Physics.IgnoreCollision is reset when the capsule is
toggled off and back on.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:06:53 +02:00
adminandClaude Opus 4.8 d867452dcb Fix: allow wheel zoom while sprinting (Shift)
The orbit camera suppressed wheel zoom whenever Shift/Ctrl was held, to
reserve Shift/Ctrl+wheel for the paint brush resize. But Shift is also
the sprint key, so sprinting blocked zoom outside paint mode.

Gate the reservation on PanEnabled (set only by PaintMode.Enter/Exit), so
the wheel is only claimed for brush resize while actually in paint mode;
otherwise it zooms normally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 18:26:35 +02:00
adminandClaude Opus 4.8 0d14980a76 Fix maps never binding due to partial-class static init order
MapPropIds (in MeshPainter.Backend.cs) referenced the *Id fields from the
MeshPainter.cs partial in its field initializer. Static field-initializer
order across partial-class files is unspecified in C#; after the script
reorg the composite array initialized before the *Id fields and captured 0
for every property id. HasProperty(0) is always false, so AssignMapTexture
bound no maps at all -> the shader fell back to its white default textures,
making every fresh avatar fully glossy (smoothness 1) and emissive.

Build MapPropIds lazily on first access (runtime, after all static
initializers) so the file order no longer matters. The per-stroke allocation
savings are preserved; only a single null-check per call is added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 16:23:37 +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