(Feat) Add Network Body

This commit is contained in:
2026-07-04 09:33:53 +02:00
parent 7bd2aa3120
commit 031ac42e5d
32 changed files with 1385 additions and 49 deletions
+29 -1
View File
@@ -25,7 +25,11 @@ Context for current work:
no "temporary" shortcuts; if something is worth doing, do it properly.
- **Multiplayer co-op is a hard constraint** — when touching any player, world or shared
system, assume two+ players exist (see §3).
- **No player arms / viewmodel** — feedback comes from camera, audio and UI only.
- **Player body is split by viewpoint** — the **local owner** sees a **first-person arms
viewmodel** (his own hands/tools); **remote players** are drawn as a **full third-person
body**. Each client renders its own arms *and* everyone else's full body. The owner's own
third-person body is hidden from his first-person camera (owner-only vs remote-only gating
lives in `PlayerNetworkController` — see §3). HUD/audio feedback still applies on top.
- Animations use **DOTween** (tweens, not Animator) wherever possible.
- Shaders are **hand-written HLSL/ShaderLab** — do not propose Shader Graph.
@@ -86,6 +90,30 @@ player — get it from `PlayerInventory.Instance` / `PlayerStats.Instance` (owne
singletons), **never** `FindObjectOfType<PlayerX>()`, which also matches disabled remote
puppets (their root GameObject stays active) and targets the wrong player.
### Visible body — first-person arms (owner) + third-person body (remotes)
Every player is drawn twice, split by viewpoint (see §1):
- **First-person arms** — the owner's own hands/tools, seen *only* by the owner. The arms mesh
goes in `PlayerNetworkController.ownerOnlyObjects` (hidden on remotes); it is **never**
networked because no one else renders it.
- **Third-person body** — the full character everyone else sees. It stays active on *all*
clients so its `Animator` keeps running. `PlayerBodyVisibility` (a `NetworkBehaviour` on the
player root) relayers the **owner's own** body onto a `LocalBody` layer that the owner's
first-person camera excludes from its culling mask — so the owner never sees his own body
clip the view, yet every remote still renders it. **Layers are local and never networked**,
so hiding your body from yourself does not hide it from anyone else.
**Animation is a bus consumer, replicated by `NetworkAnimator`.** `PlayerAnimatorDriver`
(`Player/Animation/`) drives an `Animator` purely from `PlayerEvents` (`VelocityChanged`,
`GroundedChanged`, `Jumped`, `AttackSwung`, `CrouchChanged`, …). The same component drives both
rigs from that one shared source, so arms and body stay in lockstep. Each instance is owner-only
local simulation → **add every `PlayerAnimatorDriver` to `ownerOnlyBehaviours`**. On the body,
a sibling FishNet **`NetworkAnimator`** replicates the owner's animation to remotes (whose driver
is disabled and whose body is animated by the replicated parameters instead). Need a new
animation cue? Add an event to `PlayerEvents` and have the driver subscribe — never poll another
system's internals.
### Networking a player system — the canonical pattern (mirror `PlayerInventory`/`PlayerStats`)
- Make it a `NetworkBehaviour`. **No destructive `Awake` singleton guard** (it would destroy