Extract byte-identical duplicated code into shared helpers (behaviour-neutral):
- New InputUtil.cs: single source for mouse-delta/scroll/cursor-lock, modifier
and mouse-button reads, previously copied verbatim across camera controllers,
MeshPainter, FirstPersonMode and PlayerCharacterController.
- GetMatFloat/SetMatFloat replace the 12x material-instance + HasProperty guard
pattern for the camo/height float properties.
- Route two inline button hooks through the existing Hook() helper.
Bespoke variants deliberately kept local (FreeCam SprintHeld = LeftShift only,
MeshPainter.TryGetMouse with out-params).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MouseSensitivity is a static, PlayerPrefs-backed multiplier (default 1,
clamped 0.1-4.0) that scales the mouse-look delta in the FreeCam,
FirstPerson and ThirdPerson controllers. Writes flush immediately so the
value survives a hard build exit. MouseSensitivitySlider binds the
Settings-panel slider to it (range read from the inspector) and mirrors
the value into its label, syncing on panel open via OnEnable.
Main.unity now contains the session-manager canvas directly (the
Online Session Manager prefab was unpacked) and wires the slider binder.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Point the first-person camera at the dedicated FirstPersonTarget anchor
(eye height) instead of the shared CameraTarget, in both the runtime
SetPlayer rebind and the editor ResolveReferences fallback.
Rebind the paint HUD to the locally spawned avatar's MeshPainter via a
new GameModeManager.PainterChanged event. Since the spawn-on-connect
refactor, no player exists at PaintHud.Start(), so the HUD bound to a
null painter (no brush masks shown, color/settings were no-ops).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Install Netcode for GameObjects 2.13.0 + Unity Transport 2.6.0 and wire up
the first networking milestone: syncing player position/rotation across clients.
- NetworkBootstrap: Host/Client/Server controls (OnGUI + H/C hotkeys) for
local clone testing over loopback 127.0.0.1:7777.
- NetworkPlayerSetup: per-avatar owner gating. The local owner binds the
GameModeManager and cameras to itself; remote avatars disable their
controller/CharacterController and receive transform via NetworkTransform.
- GameModeManager.BindLocalPlayer: central runtime rebind to the locally
spawned player.
- FirstPersonController.SetPlayer: explicit runtime rebind hook.
- Player prefab: NetworkObject + NetworkTransform (owner-authoritative,
position + rotation) + NetworkPlayerSetup; registered as PlayerPrefab.
- Scene: NetworkManager + UnityTransport added; the fixed scene player
instance removed in favor of spawn-on-connect.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a FirstPersonController / FirstPersonMode pair (mirroring the
free-cam mode) wired into the GameModeManager Tab cycle. In first person the
mesh is hidden, the eye sits on CameraTarget plus a per-pose
firstPersonCameraTargetYOffset, and the character body yaw is driven to match
the camera via a new single-writer FaceYaw hook on PlayerCharacterController.
Also includes user content edits (poses, prefabs, scene) carried along.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>