PC3 Phase 1.4-1.6: avatars wired into the game end to end
- api_client.gd: get_avatar_loadout() / save_avatar_loadout() - main_menu.gd: on successful auth (fresh or session-restore), load the catalog + fetch the saved loadout into AvatarSystem so the in-world player renders as the player's avatar. Best-effort: a slow/failed prime never gates getting in (UI goes authenticated first, prime runs after). New "Customize Avatar" button (enabled only when signed in). - avatar_system.gd: local-player convenience API -- ensure_catalog(), set_loadout_from_dict() (from the backend's GET shape), has_loadout(), build_current_avatar(). - player.gd: swaps the placeholder capsule for the assembled avatar (feet-aligned to the capsule bottom) when a loadout is primed; silent fallback to the capsule otherwise. Camera stays first-person for now (third-person is a noted follow-up). - avatar_visualizer.gd: rewrote it -- the old version referenced AvatarLoader.SlotResult / load_slot() which never existed, so it didn't compile and took avatar_customization_ui.gd down with it. Now a thin wrapper over AvatarLoader for the preview. - avatar_customization_ui.gd: seeds from the live loadout, saves through to AvatarSystem + PUT /api/avatar/loadout (local file kept as fallback), fixed a Camera3D.look_at() before-in-tree crash. - scenes/avatar_customization.tscn rebuilt (old one used the Godot-3 `ViewportContainer` node type) + avatar_customization_screen.gd wrapper that returns to the menu on close. - smoke_test_avatar_in_world.gd: primed loadout -> game.tscn -> player shows the assembled avatar, capsule hidden, rig + bone mounts present. Verified: cold-cache smokes green (player 15/15, avatar_system 14/14, avatar_in_world 10/10, main_menu_ui 13/13); against a live backend main_menu_full_flow 12/12, main_menu_back 20/20, world_list 4/4, enter_world 9/9, e2e 4/4; plus a manual register->default-loadout-> customize->save->re-fetch-persisted round trip. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jtxAiu5dAW4WxCNdGkrkJ
This commit is contained in:
@@ -32,7 +32,14 @@ const PITCH_LIMIT: float = deg_to_rad(89.0)
|
||||
var _input_direction := Vector2.ZERO
|
||||
var _camera_pitch: float = 0.0
|
||||
|
||||
## Vertical offset applied to the assembled avatar so its feet (origin y=0)
|
||||
## line up with the bottom of the player's collision capsule.
|
||||
const AVATAR_FEET_OFFSET: float = -0.8
|
||||
|
||||
@onready var _camera: Camera3D = $Camera3D
|
||||
@onready var _capsule_mesh: MeshInstance3D = $CapsuleMesh
|
||||
|
||||
var _avatar_view: Node3D = null
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -67,6 +74,28 @@ func _ready() -> void:
|
||||
if DisplayServer.get_name() != "headless":
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
|
||||
_apply_avatar()
|
||||
|
||||
|
||||
## Replace the placeholder capsule with the player's assembled avatar, if the
|
||||
## AvatarSystem has a loadout primed (set at login by main_menu.gd). Falls back
|
||||
## to the capsule silently when there's no avatar to show -- e.g. running this
|
||||
## scene directly in a test, or an offline/failed catalog load.
|
||||
## TODO(PC3): a third-person camera so the local player actually sees this;
|
||||
## for now it's mainly for other players (Phase 2) and looking down.
|
||||
func _apply_avatar() -> void:
|
||||
var avatars := get_node_or_null("/root/AvatarSystem")
|
||||
if avatars == null or not avatars.has_method("build_current_avatar"):
|
||||
return
|
||||
var avatar: Node3D = avatars.build_current_avatar()
|
||||
if avatar == null:
|
||||
return
|
||||
avatar.position = Vector3(0.0, AVATAR_FEET_OFFSET, 0.0)
|
||||
add_child(avatar)
|
||||
_avatar_view = avatar
|
||||
if _capsule_mesh:
|
||||
_capsule_mesh.visible = false
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _unhandled_input — capture keyboard / mouse for movement
|
||||
|
||||
Reference in New Issue
Block a user