feat: Sketchfab-to-game character pipeline, FP/TP animated views, client-auth netcode, audio system

Character pipeline (tools/):
- sketchfab_import.py: search/download via Sketchfab Download API with
  license/attribution tracking (SKETCHFAB_API_TOKEN)
- autorig.py: headless Blender auto-rig — fits a Mixamo-named skeleton
  to unrigged humanoids, binds automatic weights
- merge_animations.py: merges the shared Mixamo-skeleton animation
  library onto any rigged character, strips root motion, canonical names
- pipeline.py: one command chains download -> rig -> animate -> register

In-game skin system:
- SkinManager autoload reads skins.json (auto-written by the pipeline)
- SkinnedPlayerModel rewritten: canonical clips with fallback chains,
  blend times, speed-scaled locomotion, weapon bone attachment
- First-person: full animated body for the owner, head hidden via
  SkeletonModifier3D; third-person: full model for other players
- Skin selector in main menu; skin id synced in multiplayer
- Fixed GLBLoader crash (GLTFDocument.get_animation_count doesn't exist)

Multiplayer sync overhaul:
- Movement is now client-authoritative: the owning peer simulates
  locally (no input round-trip), server keeps health/kills/death
- Remote players interpolate synced_position/velocity with
  extrapolation and snap-on-teleport
- Knockback/impulses routed to the simulating peer

Audio:
- AudioManager autoload: SFX/Weapons/Footsteps/UI/Music buses, pooled
  3D players, variation + pitch randomization, auto-registration from
  assets/sounds

Docs: 3D_ASSET_PIPELINE.md rewritten end-to-end, new ASSET_SOURCES.md
(non-procedural animation/map/sound sources) and SOUND_DESIGN.md.
Verified with debug/spawn_smoke_test.gd (headless: 24/24 checks pass).

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Nicholas Butzke
2026-07-06 02:28:58 -04:00
co-authored by Claude Fable 5
parent 552338112e
commit d05477c135
52 changed files with 1933 additions and 466 deletions
+117 -44
View File
@@ -1,52 +1,125 @@
# 3D Asset Pipeline for Papaya-Shooter
# Character Pipeline: Sketchfab → Rigged → Animated → In-Game
## Blender Setup
- Blender 5.0.1 installed system-wide
- Blender MCP addon at ~/.config/blender/5.0/scripts/addons/blender_mcp/
- Bridge: ~/blender-mcp/blender_bridge.py (socket port 9876)
- Start: xvfb-run -a blender --python ~/blender-mcp/blender_server.py &
One command turns a Sketchfab model into a playable character skin:
## Export Workflow
1. Write Blender Python script (generate model, rig, animate)
2. Run: blender --background --python script.py
3. Export as .glb to assets/ subdirectory
4. Godot auto-imports on editor open
```bash
python tools/pipeline.py --uid <sketchfab-uid> --name space_marine
```
## Directory Structure
- assets/characters/skins/ — player skin models
- assets/characters/animations/ — animation clips
- assets/weapons/models/ — weapon meshes
- assets/weapons/skins/ — weapon skin textures
- assets/props/ — level props
That downloads the model, auto-rigs it in Blender, merges the shared
animation library onto it, writes `assets/characters/skins/space_marine.glb`,
and registers it in `skins.json`. Restart the game — the skin is in the main
menu dropdown, fully animated in first AND third person, synced in multiplayer.
## Character System
- HumanoidModel: characters/humanoid_model.gd
- Procedural rig: torso, head, 4 arms, 4 legs with pivot nodes
- States: idle, run, crouch, slide, air, wall_run, wall_cling, grapple, dash, death
- Color: @export var color (StandardMaterial3D)
- shadows_only for local player (don't see own model)
- Weapon attach: set_weapon(script_path) → root_pivot child
## Prerequisites (one-time setup)
## Loadout System
- LoadoutManager: globals/loadout_manager.gd (autoload)
- 5 slots, each: primary_1, primary_2, special, melee
- Save: user://loadouts.json
1. **Sketchfab API token** — from <https://sketchfab.com/settings/password>.
Put it in the env var `SKETCHFAB_API_TOKEN`, or in a file named
`.sketchfab_token` in the project root (gitignored).
2. **Blender 3.6+** — on PATH, or set `BLENDER_PATH` to `blender.exe`.
3. **Animation library** — fill `assets/characters/animations/` with one clip
per file on the Mixamo skeleton. This is done ONCE and reused for every
character forever. See "Building the animation library" below.
## Weapon System
- WeaponManager: weapons/weapon_manager.gd
- 1st person: SubViewport + vm_camera (layer 20)
- 3rd person: HumanoidModel.set_weapon()
## The pipeline, step by step
## Skin System (NEW)
- Store skin metadata in loadout or player settings
- Each skin: display_name, model_path, texture_path, color_tint
- Apply by replacing HumanoidModel mesh nodes or swapping material
- For full model replacement: load GLB scene, reparent to player
Each step is also runnable on its own:
## Godot 4.2.1 Compatibility
- absf() → abs()
- fog_sky_affinity → remove
- is not Type → not (x is Type)
- lerpf → lerp
- := from untyped arrays → explicit type
- preload() on parse-error scripts → load()
| Step | Tool | What it does |
|---|---|---|
| 1. Find | `python tools/sketchfab_import.py search "anime robot" --rigged` | Search downloadable models (license shown per result) |
| 2. Download | `python tools/sketchfab_import.py download <uid>` | GLB + license/attribution JSON into `assets/characters/incoming/` |
| 3. Auto-rig | `blender --background --python tools/autorig.py -- in.glb out.glb` | Fits a Mixamo-named skeleton, binds automatic weights |
| 4. Animate | `blender --background --python tools/merge_animations.py -- rigged.glb assets/characters/animations out.glb` | Merges the shared clip library, strips root motion, canonical names |
| 5. Register | (automatic in pipeline.py) | Copies to `skins/`, adds entry to `skins.json` |
`tools/pipeline.py` chains all of it. Useful flags:
- `--input file.glb` instead of `--uid` for local files (GLB/FBX/OBJ).
- `--rigged` — skip auto-rig for models that already have a skeleton
(Mixamo/AccuRig/Tripo output). Bones get renamed to Mixamo convention
automatically when recognizable.
- `--height 1.6` — target character height in meters.
## Auto-rigging: what to use when
Mixamo has **no public API** (and Adobe has said one isn't coming), so full
automation needs an alternative. In order of preference:
1. **Built-in autorig (`tools/autorig.py`)** — heuristic skeleton fit +
Blender automatic weights, fully automated, zero cost. Works well for
normal-proportioned upright humanoids. Weakest on flowing
dresses/capes/extreme proportions.
2. **Mixamo web (manual, ~2 min/model)** — upload FBX/OBJ at
<https://www.mixamo.com>, place 7 markers, download rigged FBX "without
animations", then `pipeline.py --input rigged.fbx --rigged --name x`.
Best weight quality for the effort.
3. **Reallusion AccuRig** (free desktop app) — better auto-weights than
Mixamo for tricky meshes; export FBX and feed with `--rigged`.
4. **UniRig / Tripo AI / Meshy / Anything World** — ML auto-riggers. UniRig is
open source (VAST/Tripo); Tripo, Meshy, and Anything World offer paid HTTP
APIs if you ever want a fully hosted rigging step with no Blender at all.
All roads lead to the same place: a GLB with Mixamo bone names, which is what
`merge_animations.py` and the game expect.
## Building the animation library (once)
The library lives in `assets/characters/animations/` — one clip per file,
filename = clip name (`idle.fbx``Idle`, `crouch_walk.fbx``CrouchWalk`).
**Recommended: Mixamo clips.** Go to mixamo.com, pick the X Bot character,
download each clip as *FBX Binary, Without Skin, 30 fps* (use "In Place"
variants where offered):
| File | Mixamo search |
|---|---|
| `idle.fbx` | Rifle Idle (or Idle) |
| `walk.fbx` | Walking (In Place) |
| `run.fbx` | Rifle Run / Fast Run (In Place) |
| `sprint.fbx` | Sprint (In Place) |
| `jump.fbx` | Jump |
| `fall.fbx` | Falling Idle |
| `crouch_idle.fbx` | Crouch Idle |
| `crouch_walk.fbx` | Crouch Walk (In Place) |
| `slide.fbx` | Running Slide |
| `wall_run.fbx` | (see note) Run variant works fine |
| `dash.fbx` | Sprint or Dive |
| `death.fbx` | Dying |
CC0 alternative: **Quaternius Universal Animation Library** (quaternius.com,
500+ clips, Mixamo-compatible skeleton) or **Kenney character assets**
both free for commercial use, no attribution required.
Missing clips are fine: the game falls back along sensible chains
(`Slide → CrouchIdle → Idle`, `WallRun → Run`, etc. — see
`CLIP_FALLBACKS` in `characters/skinned_player_model.gd`). A model with just
Idle/Walk/Run still animates in every movement state.
## How it works in-game
- **`SkinManager` (autoload)** reads `assets/characters/skins/skins.json` at
boot. Selected skin persists per-user and is synced to other players via
`synced_skin_id`.
- **`SkinnedPlayerModel`** loads the GLB at runtime, maps canonical clip
names, sets loop modes, blends between clips (0.15 s), and scales
locomotion playback speed to actual movement speed.
- **First person (owner):** full body visible and animated; the head bone is
shrunk via a `SkeletonModifier3D` so you never see your own face — you DO
see your legs, arms and shadow.
- **Third person (everyone else):** the full model, driven by the synced
movement state, with the current weapon attached to the right-hand bone.
- **Licensing:** every Sketchfab download writes `<name>.license.json`.
CC-BY models require crediting the author — keep these files and surface
them in your credits screen before shipping.
## Troubleshooting
- *Model T-poses in game* — the GLB has no animations; re-run
`merge_animations.py` and check it printed `Merged N clips`.
- *Mesh deforms badly at shoulders/hips* — heuristic rig didn't fit; rig via
Mixamo web or AccuRig and re-run with `--rigged`.
- *Character slides while walking* — clips exported with root motion; re-run
without `--keep-root-motion` (stripping is the default).
- *Skin missing in exported build* — raw `.glb` files must be included in the
export: Project → Export → Resources → include filter `*.glb, *.json`.