add hud to joiners...

sync alittle better, so double damage isn't done.
This commit is contained in:
2026-01-11 04:02:21 +01:00
parent 92ac3df666
commit a43a17ed10
5 changed files with 56 additions and 13 deletions

View File

@@ -423,6 +423,16 @@ func _die():
killer_player.character_stats.kills += 1
print(name, " kill credited to ", killer_player.name, " (total kills: ", killer_player.character_stats.kills, ")")
# Sync kill update to client if this player belongs to a client
# Only sync if we're on the server and the killer is a client's player
if multiplayer.has_multiplayer_peer() and is_multiplayer_authority():
var killer_peer_id = killer_player.get_multiplayer_authority()
# Only sync if killer is a client (not server's own player)
if killer_peer_id != 0 and killer_peer_id != multiplayer.get_unique_id() and killer_player.has_method("_sync_stats_update"):
# Server is updating a client's player stats - sync to the client
var coins = killer_player.character_stats.coin if "coin" in killer_player.character_stats else 0
killer_player._sync_stats_update.rpc_id(killer_peer_id, killer_player.character_stats.kills, coins)
# Spawn loot immediately (before death animation)
_spawn_loot()

View File

@@ -997,6 +997,9 @@ func _sync_dungeon(dungeon_data_sync: Dictionary, seed_value: int, level: int, h
# Note: Level number is shown via _sync_show_level_number RPC, not here
# This prevents duplicate displays and ensures consistent timing
# Load HUD on client (same as server does)
call_deferred("_load_hud")
# Sync existing dungeon to newly connected clients
if multiplayer.is_server():
# This shouldn't happen, but just in case
@@ -1441,7 +1444,17 @@ func _clear_level():
# Clear previous level data
print("GameWorld: Clearing previous level...")
# Clear tilemap layers
# Clear tilemap layers - ensure we get references from scene if they exist
var environment = get_node_or_null("Environment")
if environment:
var layer0 = environment.get_node_or_null("DungeonLayer0")
if layer0:
layer0.clear()
var layer_above = environment.get_node_or_null("TileMapLayerAbove")
if layer_above:
layer_above.clear()
# Also clear via stored references if they exist
if dungeon_tilemap_layer:
dungeon_tilemap_layer.clear()
if dungeon_tilemap_layer_above:
@@ -2414,7 +2427,7 @@ func _spawn_blocking_doors():
func _spawn_floor_switch(i_position: Vector2, required_weight: float, tile_x: int, tile_y: int, switch_type: String = "walk", switch_room: Dictionary = {}) -> Node:
# Spawn a floor switch using the scene file
# switch_type: "walk" for walk-on switch (weight 1), "pillar" for pillar switch (weight 5)
var switch_scene = preload("res://scenes/floor_switch.tscn")
var switch_scene = load("res://scenes/floor_switch.tscn")
if not switch_scene:
push_error("ERROR: Could not load floor_switch scene!")
return null

View File

@@ -71,8 +71,8 @@ func show_stats(enemies_defeated: int, times_downed: int, exp_collected: float,
# Format level time as MM:SS
if time_label:
var minutes = int(level_time) / 60
var seconds = int(level_time) % 60
var minutes = int(level_time / 60.0)
var seconds = int(fmod(level_time, 60.0))
time_label.text = "Finish time: %02d:%02d" % [minutes, seconds]
time_label.visible = true
else:

View File

@@ -1878,6 +1878,11 @@ func _sync_release(obj_path: NodePath):
obj.set_collision_mask_value(2, true)
if "is_frozen" in obj:
obj.is_frozen = false
# CRITICAL: Clear is_being_held so object can be grabbed again and switches can detect it
if "is_being_held" in obj:
obj.is_being_held = false
if "held_by_player" in obj:
obj.held_by_player = null
elif _is_player(obj):
obj.set_collision_layer_value(1, true)
obj.set_collision_mask_value(1, true)
@@ -2384,12 +2389,27 @@ func add_coins(amount: int):
if character_stats:
character_stats.add_coin(amount)
print(name, " picked up ", amount, " coin(s)! Total coins: ", character_stats.coin)
# Sync coins to client if this is server-side coin collection
# (e.g., when loot is collected on server, sync to client)
if multiplayer.has_multiplayer_peer() and multiplayer.is_server() and not is_multiplayer_authority() and can_send_rpcs and is_inside_tree():
# Server is adding coins to a client's player - sync to the client
var peer_id = get_multiplayer_authority()
if peer_id != 0:
_sync_stats_update.rpc_id(peer_id, character_stats.kills, character_stats.coin)
else:
coins += amount
print(name, " picked up ", amount, " coin(s)! Total coins: ", coins)
# Sync coins to other players if needed (for UI display)
# This can be expanded later if coins need to be synced across network
@rpc("authority", "reliable")
func _sync_stats_update(kills_count: int, coins_count: int):
# Client receives stats update from server (for kills and coins)
# Update local stats to match server
if character_stats:
character_stats.kills = kills_count
character_stats.coin = coins_count
print(name, " stats synced from server: kills=", kills_count, " coins=", coins_count)
func heal(amount: float):
if is_dead:

View File

@@ -70,12 +70,12 @@ func _on_body_entered(body):
if body in hit_targets:
return
# For players: only the projectile owner (authority) should register hits
# This prevents duplicate damage from multiple clients
# For enemies: clients can also send RPCs to server to deal damage
if body.is_in_group("player"):
# CRITICAL: Only the projectile owner (authority) should deal damage
# This prevents duplicate damage when the projectile exists on both server and clients
# Server creates the projectile first, then clients create it via _sync_attack
# Without this check, both server and client projectiles would deal damage
if player_owner and not player_owner.is_multiplayer_authority():
return # Only server players can damage other players
return # Only the authority (creator) of the projectile can deal damage
# Add to hit_targets IMMEDIATELY to prevent multiple hits (mark as hit before processing)
hit_targets[body] = true
@@ -100,7 +100,7 @@ func _on_body_entered(body):
body.rpc_take_damage.rpc(damage, attacker_pos)
print("Sword projectile hit player: ", body.name, " for ", damage, " damage!")
# Deal damage to enemies - clients can send RPC to server to deal damage
# Deal damage to enemies - only authority (creator) deals damage
elif body.is_in_group("enemy") and body.has_method("rpc_take_damage"):
$SfxImpact.play()
var attacker_pos = player_owner.global_position if player_owner else global_position