diff --git a/scenes/main.gd b/scenes/main.gd index 36e7a30..cdec56f 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -58,6 +58,14 @@ func _ready(): if multiplayer.is_server(): randomize_game_grid() +@rpc("any_peer", "call_local", "reliable") +func sync_portal_configs(configs: Array): + if portal_mode_manager: + # Temporarily store the configs and trigger spawn + # Note: We use a custom property in manager to pass this + portal_mode_manager.set_meta("door_configs", configs) + portal_mode_manager._spawn_portal_doors() + # Force gridmap cell size to match player logic (1, 0.05, 1) - >0.001 to avoid errors var em = $EnhancedGridMap if em: diff --git a/scenes/portal_door.tscn b/scenes/portal_door.tscn index 6223aa6..6206158 100644 --- a/scenes/portal_door.tscn +++ b/scenes/portal_door.tscn @@ -21,7 +21,7 @@ emission = Color(0.0, 0.4, 1.0, 1) emission_energy_multiplier = 2.0 [sub_resource type="BoxShape3D" id="BoxShape3D_trigger"] -size = Vector3(1.4, 2.1, 0.5) +size = Vector3(1.4, 2.1, 0.8) [sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_portal"] properties/0/path = NodePath(":target_room_id") diff --git a/scripts/managers/portal_mode_manager.gd b/scripts/managers/portal_mode_manager.gd index 165f2df..535bbc1 100644 --- a/scripts/managers/portal_mode_manager.gd +++ b/scripts/managers/portal_mode_manager.gd @@ -210,36 +210,53 @@ func _setup_room_partitions(): var _pending_sync_data = null func _spawn_portal_doors(): - # Check if doors already exist to avoid duplicates - if not doors.is_empty(): - print("[PortalModeManager] Doors already exist, skipping spawn. Count: ", doors.size()) - return + # 1. Use synced configs if they exist (passed via main.rpc("sync_portal_configs")) + var door_configs = get_meta("door_configs") if has_meta("door_configs") else [] + + # 2. If no synced configs (e.g. Server start), generate base + extras + if door_configs.is_empty(): + if not multiplayer.is_server(): + print("[PortalModeManager] Client waiting for portal configs sync...") + return + + door_configs = [ + # BASE DOORS (2 per room) + {"room": 0, "pos": Vector2i(6, 2), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East + {"room": 0, "pos": Vector2i(2, 6), "rot": 0, "offset": Vector2i(0, -1)}, # South + {"room": 1, "pos": Vector2i(7, 2), "rot": PI / 2, "offset": Vector2i(1, 0)}, # West + {"room": 1, "pos": Vector2i(11, 6), "rot": 0, "offset": Vector2i(0, -1)}, # South + {"room": 2, "pos": Vector2i(2, 7), "rot": 0, "offset": Vector2i(0, 1)}, # North + {"room": 2, "pos": Vector2i(6, 11), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East + {"room": 3, "pos": Vector2i(11, 7), "rot": 0, "offset": Vector2i(0, 1)}, # North + {"room": 3, "pos": Vector2i(7, 11), "rot": PI / 2, "offset": Vector2i(1, 0)} # West + ] + + # Server adds extras + var extra_options = [ + {"room": 0, "pos": Vector2i(6, 5), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East (Gap from 6,2) + {"room": 1, "pos": Vector2i(7, 5), "rot": PI / 2, "offset": Vector2i(1, 0)}, # West (Gap from 7,2) + {"room": 2, "pos": Vector2i(6, 8), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East (Gap from 6,11) + {"room": 3, "pos": Vector2i(7, 8), "rot": PI / 2, "offset": Vector2i(1, 0)} # West (Gap from 7,11) + ] + extra_options.shuffle() + door_configs.append(extra_options[0]) + door_configs.append(extra_options[1]) + + # Broadcast to clients + main.rpc("sync_portal_configs", door_configs) + + # 3. Spawn the doors + if not doors.is_empty(): return # Guard against double spawn + + print("[PortalModeManager] Spawning %d doors. Peer: %d" % [door_configs.size(), multiplayer.get_unique_id()]) - print("[PortalModeManager] Spawning portal doors. Peer ID: ", multiplayer.get_unique_id()) var portal_scene = load("res://scenes/portal_door.tscn") var stands_container = main.get_node_or_null("Stands") - if not stands_container: - print("[PortalModeManager] Warning: 'Stands' container not found, creating one...") stands_container = Node3D.new() stands_container.name = "Stands" main.add_child(stands_container) - - var door_configs = [ - # Room 0 - {"room": 0, "pos": Vector2i(6, 2), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East - {"room": 0, "pos": Vector2i(2, 6), "rot": 0, "offset": Vector2i(0, -1)}, # South - # Room 1 - {"room": 1, "pos": Vector2i(7, 2), "rot": PI / 2, "offset": Vector2i(1, 0)}, # West - {"room": 1, "pos": Vector2i(11, 6), "rot": 0, "offset": Vector2i(0, -1)}, # South - # Room 2 - {"room": 2, "pos": Vector2i(2, 7), "rot": 0, "offset": Vector2i(0, 1)}, # North - {"room": 2, "pos": Vector2i(6, 11), "rot": PI / 2, "offset": Vector2i(-1, 0)}, # East - # Room 3 - {"room": 3, "pos": Vector2i(11, 7), "rot": 0, "offset": Vector2i(0, 1)}, # North - {"room": 3, "pos": Vector2i(7, 11), "rot": PI / 2, "offset": Vector2i(1, 0)} # West - ] - + for i in range(door_configs.size()): var cfg = door_configs[i] if not portal_scene: @@ -278,7 +295,8 @@ const PORTAL_COLORS = [ Color(0, 1, 1), # Cyan Color(1, 0, 1), # Magenta Color(1, 1, 0), # Yellow - Color(0, 1, 0) # Green + Color(0, 1, 0), # Green + Color(1, 0.5, 0) # Orange ] func _randomize_connections(): @@ -490,7 +508,8 @@ func handle_portal_interaction(player, door): var current_time = Time.get_ticks_msec() if player_portal_cooldowns.has(player.name): - if current_time - player_portal_cooldowns[player.name] < 1000: + # Reduce cooldown to 200ms (more responsive than 1s, but enough to avoid jitter) + if current_time - player_portal_cooldowns[player.name] < 200: return player_portal_cooldowns[player.name] = current_time diff --git a/scripts/portal_door.gd b/scripts/portal_door.gd index e7146f7..7da8d5b 100644 --- a/scripts/portal_door.gd +++ b/scripts/portal_door.gd @@ -35,7 +35,8 @@ func _on_body_entered(body: Node3D): if body.is_in_group("Players") or body.get("is_bot"): var current_time = Time.get_ticks_msec() if body.has_meta("last_portal_time"): - if current_time - body.get_meta("last_portal_time") < 1000: + # Reduce cooldown to 200ms to match manager logic and allow fast re-entry + if current_time - body.get_meta("last_portal_time") < 200: return body.set_meta("last_portal_time", current_time)