PC3 Phase 1.1: game boots clean from a bare clone
Root cause: a stale .godot/global_script_class_cache.cfg was force-committed to the repo (last regenerated before the avatar system merged), and Godot does not rebuild the global class registry on a plain headless scene run -- only an editor scan / `--import` does. So every cross-file `class_name` reference in the avatar module failed to resolve from a fresh clone, and the AvatarSystem autoload failed to instantiate entirely. - Untrack .godot/ and sandbox_probe/.godot/ (already in .gitignore; were force-added during old WIP checkpoints) - Reference sibling avatar scripts via preload() constants instead of their global class_name, so the module parses independent of scan order. Keeps the class_name declarations for editor/tooling use. - avatar_loadout.gd's static from_json() factory self-references via a preload const too (a script can't resolve its own class_name mid-compile on a cold cache). - smoke_test_avatar_system.gd: same preload treatment so it runs from a bare `--script` invocation. Verified from a wiped .godot/: main_menu.tscn and game.tscn boot with zero script errors; smoke_test_avatar_system 10/10, smoke_test_player 15/15, smoke_test_main_menu_ui 13/13, smoke_test_test_level PASS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jtxAiu5dAW4WxCNdGkrkJ
This commit is contained in:
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
63f7b34db8d8cdea90c76aacccf841ec
|
||||
::res://::1787275036
|
||||
export_presets.cfg::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
README.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
::res://addons/::1787272930
|
||||
::res://assets/::1787272930
|
||||
::res://backend/::1787272930
|
||||
alembic.ini::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
docker-compose.yml::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
pytest.ini::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
requirements.txt::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
::res://backend/alembic/::1787272930
|
||||
::res://backend/alembic/versions/::1787272930
|
||||
::res://backend/app/::1787272930
|
||||
::res://backend/app/models/::1787272930
|
||||
::res://backend/app/routers/::1787272930
|
||||
::res://backend/app/services/::1787272930
|
||||
::res://backend/tests/::1787272930
|
||||
::res://docs/::1787272930
|
||||
::res://docs/architecture/::1787272930
|
||||
avatar.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
content_moderation.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
editor.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
networking.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
pc2_test_level.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
scripting_sandbox.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
world.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
::res://docs/checkpoints/::1787272930
|
||||
PC1.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
::res://docs/planning/::1787272930
|
||||
client-server-wiring.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
economy.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
social.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
::res://docs/testing/::1787275036
|
||||
README.md::TextFile::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
test_inventory.md::TextFile::-1::1787275036::0::1::::<><><>0<>0<><>::
|
||||
::res://scenes/::1787275036
|
||||
game.tscn::PackedScene::-1::1787272930::0::1::::<><><>0<>0<><>::res://scenes/worlds/test_level.tscn<>res://scenes/player.tscn
|
||||
main.tscn::PackedScene::-1::1787272930::0::1::::<><><>0<>0<><>::res://scripts/chunk_stream_manager.gd
|
||||
main_menu.tscn::PackedScene::-1::1787272930::0::1::::<><><>0<>0<><>::res://scripts/main_menu.gd
|
||||
player.tscn::PackedScene::-1::1787272930::0::1::::<><><>0<>0<><>::res://scripts/player.gd
|
||||
server.tscn::PackedScene::-1::1787275036::0::1::::<><><>0<>0<><>::res://scripts/server.gd
|
||||
server_player.tscn::PackedScene::-1::1787275036::0::1::::<><><>0<>0<><>::res://scripts/player_spawner.gd
|
||||
world_list.tscn::PackedScene::-1::1787272930::0::1::::<><><>0<>0<><>::res://scripts/world_list.gd
|
||||
::res://scenes/worlds/::1787272930
|
||||
test_level.tscn::PackedScene::-1::1787272930::0::1::::<><><>0<>0<><>::
|
||||
::res://scripts/::1787275098
|
||||
api_client.gd::GDScript::5412288119287126975::1787272930::0::1::::<>Node<><>0<>0<><>::
|
||||
chunk.gd::GDScript::7364239597441807588::1787272930::0::1::::Chunk<>Node3D<><>0<>0<><>::
|
||||
chunk_data_decoder.gd::GDScript::3922068956043581888::1787272930::0::1::::ChunkDataDecoder<>RefCounted<><>0<>0<><>::
|
||||
chunk_scene.gd::GDScript::9207602004456600331::1787272930::0::1::::ChunkScene<>Node3D<><>0<>0<><>::
|
||||
chunk_stream_manager.gd::GDScript::2366645676568508746::1787272930::0::1::::ChunkStreamManager<>Node<><>0<>0<><>::
|
||||
dynamic_object_node.gd::GDScript::8863349716576659118::1787272930::0::1::::DynamicObjectNode<>Node3D<><>0<>0<><>::
|
||||
main_menu.gd::GDScript::2834562513277893052::1787272930::0::1::::<>Control<><>0<>0<><>::
|
||||
network_client.gd::GDScript::5408296350353838185::1787275098::0::1::::NetworkClient<>Node<><>0<>0<><>::
|
||||
network_player_proxy.gd::GDScript::4787436336771232797::1787275036::0::1::::<>Node<><>0<>0<><>::
|
||||
network_receiver_proxy.gd::GDScript::6742760436861380520::1787275036::0::1::::<>Node<><>0<>0<><>::
|
||||
player.gd::GDScript::4510795778937304264::1787275036::0::1::::Player<>CharacterBody3D<><>0<>0<><>::
|
||||
player_spawner.gd::GDScript::3637338339553764865::1787275036::0::1::::PlayerNode<>CharacterBody3D<><>0<>0<><>::
|
||||
server.gd::GDScript::6336910781803684784::1787275036::0::1::::<>Node<><>0<>0<><>::
|
||||
smoke_test_api.gd::GDScript::1760923834350699002::1787272930::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
smoke_test_auth.gd::GDScript::3027816090663230577::1787272930::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
smoke_test_e2e.gd::GDScript::9086409960595132737::1787272930::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
smoke_test_enter_world.gd::GDScript::4171815758762850910::1787275036::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
smoke_test_main_menu_back.gd::GDScript::4436937414562273157::1787272930::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
smoke_test_main_menu_full_flow.gd::GDScript::1948803640558784862::1787272930::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
smoke_test_main_menu_ui.gd::GDScript::396938597300585484::1787272930::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
smoke_test_network_client.gd::GDScript::3109386529184855644::1787275067::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
smoke_test_player.gd::GDScript::3497042634752676337::1787272930::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
smoke_test_test_level.gd::GDScript::2607555612829866949::1787272930::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
smoke_test_world_list.gd::GDScript::4300757286283894147::1787272930::0::1::::<>SceneTree<><>0<>0<><>::
|
||||
static_object_node.gd::GDScript::5276389741929225897::1787272930::0::1::::StaticObjectNode<>Node3D<><>0<>0<><>::
|
||||
tile_def.gd::GDScript::2430528079284085109::1787272930::0::1::::TileDef<>RefCounted<><>0<>0<><>::
|
||||
tile_layer.gd::GDScript::4797906255131447844::1787272930::0::1::::TileLayer<>RefCounted<><>0<>0<><>::
|
||||
tile_layer_node.gd::GDScript::9033225196818247616::1787272930::0::1::::TileLayerNode<>Node3D<><>0<>0<><>::
|
||||
world_list.gd::GDScript::6119591848847211153::1787275036::0::1::::<>Control<><>0<>0<><>::
|
||||
world_object.gd::GDScript::6429674491464200335::1787272930::0::1::::WorldObject<>RefCounted<><>0<>0<><>::
|
||||
@@ -1,5 +0,0 @@
|
||||
[folding]
|
||||
|
||||
node_unfolds=[NodePath("."), PackedStringArray("Layout"), NodePath("CenterContainer"), PackedStringArray("Layout"), NodePath("CenterContainer/VBoxContainer"), PackedStringArray("Layout", "Theme Overrides"), NodePath("CenterContainer/VBoxContainer/TitleLabel"), PackedStringArray("Layout", "Theme Overrides"), NodePath("CenterContainer/VBoxContainer/CustomizeButton"), PackedStringArray("Layout"), NodePath("CenterContainer/VBoxContainer/PlayButton"), PackedStringArray("Layout"), NodePath("CenterContainer/VBoxContainer/QuitButton"), PackedStringArray("Layout")]
|
||||
resource_unfolds=[]
|
||||
nodes_folded=[]
|
||||
@@ -1,11 +0,0 @@
|
||||
[game_view]
|
||||
|
||||
select_mode=0
|
||||
|
||||
[editor_metadata]
|
||||
|
||||
executable_path="/home/daddy/godot/godot"
|
||||
|
||||
[recent_files]
|
||||
|
||||
scenes=["res://scenes/main_menu.tscn", "res://scenes/server.tscn"]
|
||||
@@ -1,5 +0,0 @@
|
||||
[folding]
|
||||
|
||||
node_unfolds=[]
|
||||
resource_unfolds=[]
|
||||
nodes_folded=[]
|
||||
@@ -1,105 +0,0 @@
|
||||
list=[{
|
||||
"base": &"Node3D",
|
||||
"class": &"Chunk",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/chunk.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"ChunkDataDecoder",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/chunk_data_decoder.gd"
|
||||
}, {
|
||||
"base": &"Node3D",
|
||||
"class": &"ChunkScene",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/chunk_scene.gd"
|
||||
}, {
|
||||
"base": &"Node",
|
||||
"class": &"ChunkStreamManager",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/chunk_stream_manager.gd"
|
||||
}, {
|
||||
"base": &"Node3D",
|
||||
"class": &"DynamicObjectNode",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/dynamic_object_node.gd"
|
||||
}, {
|
||||
"base": &"Node",
|
||||
"class": &"NetworkClient",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/network_client.gd"
|
||||
}, {
|
||||
"base": &"CharacterBody3D",
|
||||
"class": &"Player",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/player.gd"
|
||||
}, {
|
||||
"base": &"CharacterBody3D",
|
||||
"class": &"PlayerNode",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/player_spawner.gd"
|
||||
}, {
|
||||
"base": &"Node3D",
|
||||
"class": &"StaticObjectNode",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/static_object_node.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"TileDef",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/tile_def.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"TileLayer",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/tile_layer.gd"
|
||||
}, {
|
||||
"base": &"Node3D",
|
||||
"class": &"TileLayerNode",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/tile_layer_node.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"WorldObject",
|
||||
"icon": "",
|
||||
"is_abstract": false,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://scripts/world_object.gd"
|
||||
}]
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
class_name AvatarCatalog
|
||||
extends RefCounted
|
||||
|
||||
# Preloaded rather than referenced by global class_name -- see avatar_loadout.gd.
|
||||
const AvatarLoadout := preload("res://scripts/avatar/avatar_loadout.gd")
|
||||
|
||||
|
||||
## Emitted when the catalog is loaded successfully.
|
||||
signal catalog_loaded
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
class_name AvatarCustomizationUI
|
||||
extends Control
|
||||
|
||||
# Preloaded rather than referenced by global class_name -- see avatar_loadout.gd.
|
||||
const AvatarLoadout := preload("res://scripts/avatar/avatar_loadout.gd")
|
||||
const AvatarCatalog := preload("res://scripts/avatar/avatar_catalog.gd")
|
||||
const AvatarLoader := preload("res://scripts/avatar/avatar_loader.gd")
|
||||
const AvatarVisualizer := preload("res://scripts/avatar/avatar_visualizer.gd")
|
||||
const AvatarSlotRegistry := preload("res://scripts/avatar/avatar_slot_registry.gd")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Signals
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
class_name AvatarLoader
|
||||
extends Node
|
||||
|
||||
# Preloaded rather than referenced by global class_name -- see avatar_loadout.gd.
|
||||
const AvatarCatalog := preload("res://scripts/avatar/avatar_catalog.gd")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Constants
|
||||
|
||||
@@ -8,6 +8,15 @@
|
||||
class_name AvatarLoadout
|
||||
extends RefCounted
|
||||
|
||||
# Sibling avatar scripts are referenced via preload rather than by their
|
||||
# global class_name so this module parses correctly from a bare clone (a
|
||||
# headless `godot <scene>` run does not rebuild the global class registry;
|
||||
# only an editor scan / `--import` does). See docs/architecture/avatar.md.
|
||||
const AvatarSlotRegistry := preload("res://scripts/avatar/avatar_slot_registry.gd")
|
||||
# Self-reference for the static factory below -- referring to our own
|
||||
# class_name doesn't resolve during a cold-cache compile (see note above).
|
||||
const _Self := preload("res://scripts/avatar/avatar_loadout.gd")
|
||||
|
||||
|
||||
## Maximum number of accessories allowed in the accessory slot.
|
||||
const MAX_ACCESSORIES: int = 8
|
||||
@@ -58,7 +67,7 @@ func _init() -> void:
|
||||
|
||||
## Create a loadout from a JSON string.
|
||||
static func from_json(json_string: String) -> AvatarLoadout:
|
||||
var loadout := AvatarLoadout.new()
|
||||
var loadout := _Self.new()
|
||||
var data: Variant = JSON.parse_string(json_string)
|
||||
if not (data is Dictionary):
|
||||
loadout.validation_errors.append("Loadout JSON root is not an object")
|
||||
|
||||
@@ -10,6 +10,16 @@
|
||||
|
||||
extends Node
|
||||
|
||||
# Sibling avatar scripts are referenced via preload rather than by their global
|
||||
# class_name so this autoload parses correctly from a bare clone -- a headless
|
||||
# `godot <scene>` run does not rebuild the global class registry (only an editor
|
||||
# scan / `--import` does), and this script is parsed at startup before any such
|
||||
# scan could have happened. See docs/architecture/avatar.md.
|
||||
const AvatarCatalog := preload("res://scripts/avatar/avatar_catalog.gd")
|
||||
const AvatarLoader := preload("res://scripts/avatar/avatar_loader.gd")
|
||||
const AvatarLoadout := preload("res://scripts/avatar/avatar_loadout.gd")
|
||||
const AvatarSlotRegistry := preload("res://scripts/avatar/avatar_slot_registry.gd")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Signals
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
class_name AvatarVisualizer
|
||||
extends Object
|
||||
|
||||
# Preloaded rather than referenced by global class_name -- see avatar_loadout.gd.
|
||||
const AvatarLoadout := preload("res://scripts/avatar/avatar_loadout.gd")
|
||||
const AvatarLoader := preload("res://scripts/avatar/avatar_loader.gd")
|
||||
const AvatarSlotRegistry := preload("res://scripts/avatar/avatar_slot_registry.gd")
|
||||
|
||||
|
||||
## Emitted when the visualizer has finished building the render tree.
|
||||
signal build_complete
|
||||
|
||||
@@ -13,6 +13,10 @@ extends SceneTree
|
||||
## Run with:
|
||||
## godot --headless --path . --script res://scripts/smoke_test_avatar_system.gd
|
||||
|
||||
# Preloaded rather than referenced by global class_name so this test also
|
||||
# runs from a cold cache (a bare `--script` run with no prior --import).
|
||||
const AvatarLoadout := preload("res://scripts/avatar/avatar_loadout.gd")
|
||||
|
||||
var passed := 0
|
||||
var failed := 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user