Files
DungeonsOfKharadum/src/src/main.gd
2025-12-30 16:22:06 +01:00

252 lines
8.1 KiB
GDScript

extends Node2D
@export var DEBUG_MULTIPLAYER: bool = true
var player_scene = preload("res://scripts/entities/player/player.tscn")
var pot_scene = preload("res://scripts/entities/world/pot.tscn")
var has_started = false
var round_started = false
var start_round = false
var round_finished = false
func _ready() -> void:
MultiplayerManager.addPlayerSignal.connect(_addPlayer)
MultiplayerManager.delPlayerSignal.connect(_delPlayer)
MultiplayerManager.finished_hosting.connect(_finishedHosting)
MultiplayerManager.countdownFinished.connect(_finishedCountdown)
#if id == 1:
#var pot:CharacterBody2D = pot_scene.instantiate()
#pot.position = Vector2(90,80)
#$SpawnRoot.add_child(pot)
if DEBUG_MULTIPLAYER:
# Add a random delay to ensure instances start at different times
var random_delay = randf_range(0.1, 0.5)
await get_tree().create_timer(random_delay).timeout
call_deferred("_setup_debug_multiplayer")
pass
func _finishedCountdown():
round_started = true
# reset all players hp, kills and deaths
$TimerRound.start($TimerRound.wait_time)
# sync to other players!
if multiplayer.is_server():
_syncTimerToPlayer.rpc($TimerRound.time_left)
pass
func time_to_minutes_secs(time: float):
var mins = int(floor(int(time) / 60.0))
time -= mins * 60
var secs = int(time)
#var mili = int((time - int(time)) * 100)
var extraSecZero = "0" if secs < 10 else ""
var extraMinZero = "0" if mins < 10 else ""
return extraMinZero + str(mins) + ":" + extraSecZero + str(secs)
func _process(_delta: float) -> void:
if round_finished == false and round_started == false and start_round == false and multiplayer != null and multiplayer.is_server():
# make sure atleast 2 players are connected
var _players = 0
for pl: CharacterBody2D in $SpawnRoot.get_children():
if "is_player" in pl:
_players += 1
#if _players == 2:
#start_round_func.rpc()
if round_started:
$HUD/MarginContainerUpperRight/HBoxContainer/VBoxContainer/LabelTimeValue.text = time_to_minutes_secs($TimerRound.time_left)
pass
@rpc("call_local", "reliable")
func start_round_func():
if start_round == true:
return
start_round = true
MultiplayerManager.start_round()
pass
func _finishedHosting():
has_started = true
pass
func _addPlayer(id: int):
print("add player:", id)
#if id == 1:
#var pot:CharacterBody2D = pot_scene.instantiate()
#pot.position = Vector2(90,80)
#$SpawnRoot.add_child(pot, true)
var player: CharacterBody2D = player_scene.instantiate()
player.name = str(id)
#find empty 16x16 tile to spawn player
'
if get_parent().get_parent() != null and get_parent().get_parent().has_node("TileMapLayerLower"):
var tile_map = get_parent().get_parent().get_node("TileMapLayerLower")
if tile_map != null:
var player_cell = tile_map.local_to_map(self.global_position)
var cell_tile_data = tile_map.get_cell_tile_data(player_cell)
if cell_tile_data != null:
var terrainData = cell_tile_data.get_custom_data("terrain")
if terrainData != null and terrainData == 8: # 8 = stairs
terrainMultiplier = 0.5
pass
pass'
# Only server calculates spawn positions - clients receive position via sync
if multiplayer.is_server():
var best_spawn = Vector2(0, 0)
var best_distance = -1
for spawnP: Node2D in $PlayerSpawnPoints.get_children():
var pos = spawnP.position
var min_distance = INF
# find spawn position which is furthest from all players...
for pl: CharacterBody2D in $SpawnRoot.get_children():
if "is_player" in pl:
var dist = pl.position.distance_to(pos)
min_distance = min(min_distance, dist) # Keep the smallest distance
pass
# Choose the spawn with the largest minimum distance
if min_distance > best_distance:
best_distance = min_distance
best_spawn = pos
player.position = best_spawn
print("Server: Spawning player ", id, " at position: ", best_spawn)
# else: clients will receive position via MultiplayerSynchronizer after add_child
$SpawnRoot.add_child(player)
if id == multiplayer.get_unique_id():
player.initStats(MultiplayerManager.character_data) # iniitate with own stats, cuz this is us...
if multiplayer.is_server():
if !$TimerRound.is_stopped():
_syncTimerToPlayer.rpc_id(id, $TimerRound.time_left)
pass
@rpc("reliable")
func _syncTimerToPlayer(iTimeLeft: float):
round_started = true
$TimerRound.start(iTimeLeft)
pass
func _delPlayer(id: int):
if !$SpawnRoot.has_node(str(id)):
return
$SpawnRoot.get_node(str(id)).queue_free()
pass
func _on_timer_timeout() -> void:
if has_started:
var countPots = 0
for child in $SpawnRoot.get_children():
if "object_name" in child:
countPots += 1
pass
if countPots < 8:
var pot = pot_scene.instantiate()
pot.is_spawning = true
pot.positionZ = 90
pot.position = Vector2(64 + 16 * randi_range(0, 5), 64 + 16 * randi_range(0, 5))
# Set server as authority for pot synchronization
pot.set_multiplayer_authority(1)
Console.print("Pot spawned with authority: ", pot.get_multiplayer_authority())
$SpawnRoot.add_child(pot, true)
$TimerSpawnPots.wait_time = randf_range(0.2, 1.4)
$TimerSpawnPots.start() # restart timer...
pass # Replace with function body.
func _on_timer_round_timeout() -> void:
round_started = false
$TimerUntilNextRound.start($TimerUntilNextRound.wait_time)
if multiplayer.is_server():
MultiplayerManager.round_finished.rpc()
pass # Replace with function body.
func _on_timer_until_next_round_timeout() -> void:
if multiplayer.is_server():
for pl2: CharacterBody2D in $SpawnRoot.get_children():
if "is_player" in pl2:
var best_spawn = Vector2(0, 0)
var best_distance = -1
for spawnP: Node2D in $PlayerSpawnPoints.get_children():
var pos = spawnP.position
var min_distance = INF
# find spawn position which is furthest from all players...
for pl: CharacterBody2D in $SpawnRoot.get_children():
if "is_player" in pl and pl != pl2:
var dist = pl.position.distance_to(pos)
min_distance = min(min_distance, dist) # Keep the smallest distance
pass
# Choose the spawn with the largest minimum distance
if min_distance > best_distance:
best_distance = min_distance
best_spawn = pos
pl2.position = best_spawn # reset player positions...
start_round = false
MultiplayerManager.new_round_started()
if multiplayer.is_server():
start_round_func.rpc()
pass # Replace with function body.
func _setup_debug_multiplayer():
# Get the character select scene to access the selected character
var character_select = get_tree().get_first_node_in_group("character_select")
if not character_select:
# Try to find it in the scene tree
character_select = get_tree().current_scene.get_node_or_null("CanvasLayer/CharacterSelect")
if character_select and character_select.has_method("get_current_character_stats"):
# Set the character data from the character select
MultiplayerManager.character_data = character_select.get_current_character_stats()
else:
# Fallback: create a default character
MultiplayerManager.character_data = CharacterStats.new()
MultiplayerManager.character_data.character_name = "DebugPlayer"
$MainMenu._showHostButton()
# Determine if this instance should host or join
# Check for command line arguments first
var should_host = false
var args = OS.get_cmdline_args()
# Check if --host or --join argument was passed
if "--host" in args:
should_host = true
print("DEBUG: Host mode specified via command line argument")
elif "--join" in args:
should_host = false
print("DEBUG: Join mode specified via command line argument")
else:
# Fallback: use process ID for deterministic behavior
var process_id = OS.get_process_id()
should_host = process_id % 2 == 1
print("DEBUG: No command line args, using process ID: ", process_id, " Should host: ", should_host)
if should_host:
print("DEBUG: Starting as HOST")
$MainMenu._on_button_host_pressed()
else:
print("DEBUG: Starting as CLIENT")
$MainMenu._on_button_join_pressed()
func _exit_tree():
# Clean up the debug lock file when exiting
if DEBUG_MULTIPLAYER:
var lock_file_path = "user://debug_host.lock"
if FileAccess.file_exists(lock_file_path):
DirAccess.remove_absolute(lock_file_path)
print("DEBUG: Cleaned up host lock file")