From e88da9a169b94b6a5b50697ce3a7fa641c9a0017 Mon Sep 17 00:00:00 2001 From: Elrinth Date: Tue, 20 Jan 2026 00:38:42 +0100 Subject: [PATCH] fix webrtc FINALLY! --- src/scripts/game_world.gd | 150 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 5 deletions(-) diff --git a/src/scripts/game_world.gd b/src/scripts/game_world.gd index f45b696..5ea663e 100644 --- a/src/scripts/game_world.gd +++ b/src/scripts/game_world.gd @@ -2483,7 +2483,13 @@ func _send_dungeon_blob_sync(client_peer_id: int): # Send metadata first var metadata = dungeon_blob_metadata print("GameWorld: HOST - [CHUNK 0] Sending metadata...") - _sync_dungeon_blob_metadata.rpc_id(client_peer_id, metadata.seed, metadata.level, metadata.map_size, metadata.host_room, total_chunks) + # Include all state data in metadata so client knows what's already changed + var defeated_list = metadata.get("defeated_enemies", []) + var broken_list = metadata.get("broken_objects", []) + var door_states_list = metadata.get("door_states", []) + var opened_chests_list = metadata.get("opened_chests", []) + var loot_list = metadata.get("existing_loot", []) + _sync_dungeon_blob_metadata.rpc_id(client_peer_id, metadata.seed, metadata.level, metadata.map_size, metadata.host_room, total_chunks, defeated_list, broken_list, door_states_list, opened_chests_list, loot_list) # Initialize acknowledgment tracking var chunk_acks = {} @@ -2729,11 +2735,73 @@ func _pack_dungeon_blob(): LogManager.log("GameWorld: Packing dungeon blob - enemies: " + str(enemy_count) + ", torches: " + str(torch_count) + ", objects: " + str(object_count), LogManager.CATEGORY_DUNGEON) # Store metadata separately (small, sent first) + # Include defeated enemies so clients know which enemies not to spawn + var defeated_indices = [] + for enemy_index in defeated_enemies.keys(): + defeated_indices.append(enemy_index) + + # Collect broken object indices + var broken_indices = [] + for obj_index in broken_objects.keys(): + broken_indices.append(obj_index) + + # Collect door states + var door_states_list = [] + var entities_node = get_node_or_null("Entities") + if entities_node: + for child in entities_node.get_children(): + if child.is_in_group("blocking_door") or child.has_method("_sync_door_open"): + var door_state = { + "door_name": child.name, + "is_closed": child.is_closed if "is_closed" in child else true, + "puzzle_solved": child.puzzle_solved if "puzzle_solved" in child else false, + "key_used": child.key_used if "key_used" in child else false, + "position": child.position if "position" in child else Vector2.ZERO, + "closed_position": child.closed_position if "closed_position" in child else Vector2.ZERO, + "open_offset": child.open_offset if "open_offset" in child else Vector2.ZERO + } + door_states_list.append(door_state) + + # Collect opened chest names + var opened_chest_names = [] + if entities_node: + for child in entities_node.get_children(): + if child.is_in_group("interactable_object"): + if "object_type" in child and child.object_type == "Chest": + if "is_chest_opened" in child and child.is_chest_opened: + opened_chest_names.append(child.name) + + # Collect existing loot + var loot_list = [] + if entities_node: + for child in entities_node.get_children(): + if child.is_in_group("loot"): + var current_velocity = child.velocity if "velocity" in child else Vector2.ZERO + var current_velocity_z = child.velocity_z if "velocity_z" in child else 0.0 + var loot_data = { + "position": child.global_position, + "loot_type": child.loot_type if "loot_type" in child else 0, + "loot_id": child.get_meta("loot_id") if child.has_meta("loot_id") else -1, + "velocity": current_velocity, + "velocity_z": current_velocity_z + } + # For item loot, include item data + if child.loot_type == child.LootType.ITEM and "item" in child and child.item: + var item = child.item + if item.has_method("save"): + loot_data["item_data"] = item.save() + loot_list.append(loot_data) + dungeon_blob_metadata = { "seed": dungeon_seed, "level": current_level, "map_size": full_dungeon_data.map_size, - "host_room": _get_host_room() + "host_room": _get_host_room(), + "defeated_enemies": defeated_indices, + "broken_objects": broken_indices, + "door_states": door_states_list, + "opened_chests": opened_chest_names, + "existing_loot": loot_list } # Serialize to bytes @@ -2906,11 +2974,56 @@ func _sync_dungeon(dungeon_data_sync: Dictionary, seed_value: int, level: int, h call_deferred("_fix_player_appearance_after_dungeon_sync") @rpc("authority", "reliable", "call_local") -func _sync_dungeon_blob_metadata(seed_value: int, level: int, map_size_sync: Vector2i, host_room: Dictionary, total_chunks: int): +func _sync_dungeon_blob_metadata(seed_value: int, level: int, map_size_sync: Vector2i, host_room: Dictionary, total_chunks: int, defeated_enemies_list: Array = [], broken_objects_list: Array = [], door_states_list: Array = [], opened_chests_list: Array = [], existing_loot_list: Array = []): # Client receives metadata for blob sync print("=== _sync_dungeon_blob_metadata RPC RECEIVED on client ===") - print("=== [CHUNK 0] Client received blob metadata - Level: ", level, ", Map size: ", map_size_sync, ", Total chunks: ", total_chunks, " ===") + print("=== [CHUNK 0] Client received blob metadata - Level: ", level, ", Map size: ", map_size_sync, ", Total chunks: ", total_chunks) + print("=== Defeated enemies: ", defeated_enemies_list.size(), ", Broken objects: ", broken_objects_list.size(), ", Door states: ", door_states_list.size(), ", Opened chests: ", opened_chests_list.size(), ", Existing loot: ", existing_loot_list.size(), " ===") if not multiplayer.is_server(): + # Store defeated enemies BEFORE dungeon is unpacked and enemies are spawned + defeated_enemies.clear() + for enemy_index in defeated_enemies_list: + defeated_enemies[enemy_index] = true + if defeated_enemies_list.size() > 0: + print("GameWorld: Client - Received ", defeated_enemies_list.size(), " defeated enemy indices before dungeon spawn") + LogManager.log("GameWorld: Client received " + str(defeated_enemies_list.size()) + " defeated enemy indices", LogManager.CATEGORY_NETWORK) + + # Store broken objects BEFORE objects are spawned + broken_objects.clear() + for obj_index in broken_objects_list: + broken_objects[obj_index] = true + if broken_objects_list.size() > 0: + print("GameWorld: Client - Received ", broken_objects_list.size(), " broken object indices before dungeon spawn") + LogManager.log("GameWorld: Client received " + str(broken_objects_list.size()) + " broken object indices", LogManager.CATEGORY_NETWORK) + + # Store door states (will be applied after doors spawn) + pending_door_states.clear() + for door_state in door_states_list: + var door_name = door_state.get("door_name", "") + if door_name != "": + pending_door_states[door_name] = door_state + if door_states_list.size() > 0: + print("GameWorld: Client - Received ", door_states_list.size(), " door states before dungeon spawn") + LogManager.log("GameWorld: Client received " + str(door_states_list.size()) + " door states", LogManager.CATEGORY_NETWORK) + + # Store opened chest states (will be applied after chests spawn) + pending_chest_opens.clear() + for chest_name in opened_chests_list: + pending_chest_opens[chest_name] = { + "loot_type": "coin", # Default, actual loot type should be stored if available + "player_peer_id": 0, + "item_data": {} + } + if opened_chests_list.size() > 0: + print("GameWorld: Client - Received ", opened_chests_list.size(), " opened chest names before dungeon spawn") + LogManager.log("GameWorld: Client received " + str(opened_chests_list.size()) + " opened chest names", LogManager.CATEGORY_NETWORK) + + # Store existing loot (will be spawned after dungeon is loaded) + # We'll need to store this temporarily and spawn it after dungeon is ready + # For now, we'll spawn it immediately after dungeon blob is reassembled + if existing_loot_list.size() > 0: + print("GameWorld: Client - Received ", existing_loot_list.size(), " existing loot items before dungeon spawn") + LogManager.log("GameWorld: Client received " + str(existing_loot_list.size()) + " existing loot items", LogManager.CATEGORY_NETWORK) # Check if this is a new level (different from current) var is_new_level = (current_level != level) if is_new_level: @@ -2921,11 +3034,13 @@ func _sync_dungeon_blob_metadata(seed_value: int, level: int, map_size_sync: Vec dungeon_sync_in_progress.clear() # Reset blob sync state + # Store metadata including state data for later use dungeon_sync_metadata = { "map_size": map_size_sync, "seed": seed_value, "level": level, - "host_room": host_room + "host_room": host_room, + "existing_loot": existing_loot_list # Store for spawning after dungeon is ready } dungeon_sync_chunks.clear() dungeon_sync_received_chunks = 0 @@ -3168,6 +3283,31 @@ func _reassemble_dungeon_blob(): _spawn_room_triggers() print("GameWorld: Client - Room triggers spawned") + # Apply door states (from metadata) - after doors are spawned + if pending_door_states.size() > 0: + print("GameWorld: Client - Applying ", pending_door_states.size(), " pending door states...") + var entities_node = get_node_or_null("Entities") + if entities_node: + for child in entities_node.get_children(): + if child.is_in_group("blocking_door") or child.has_method("_sync_door_open"): + if pending_door_states.has(child.name): + _apply_pending_door_state(child) + print("GameWorld: Client - Door states applied") + + # Spawn existing loot (from metadata) - call the RPC handler directly since we're the client + if dungeon_sync_metadata.has("existing_loot"): + var loot_list = dungeon_sync_metadata.existing_loot + if loot_list.size() > 0: + print("GameWorld: Client - Spawning ", loot_list.size(), " existing loot items from metadata...") + for loot_data in loot_list: + if loot_data.has("item_data"): + # Call the RPC handler directly (it's marked as call_local) + _sync_item_loot_spawn(loot_data.position, loot_data.item_data, loot_data.get("velocity", Vector2.ZERO), loot_data.get("velocity_z", 0.0), loot_data.get("loot_id", -1)) + else: + # Call the RPC handler directly (it's marked as call_local) + _sync_loot_spawn(loot_data.position, loot_data.get("loot_type", 0), loot_data.get("velocity", Vector2.ZERO), loot_data.get("velocity_z", 0.0), loot_data.get("loot_id", -1)) + print("GameWorld: Client - Existing loot spawned") + # Update spawn points print("GameWorld: Client - Updating spawn points...") var host_room = dungeon_sync_metadata.host_room