fix alot of shit for webrtc to work
This commit is contained in:
@@ -142,10 +142,9 @@ func _physics_process(delta):
|
||||
var game_world = get_tree().get_first_node_in_group("game_world")
|
||||
if game_world and game_world.has_method("_sync_enemy_position"):
|
||||
# Send via game_world using enemy name/index and position for identification
|
||||
game_world._sync_enemy_position.rpc(enemy_name, enemy_index, position, velocity, position_z, current_direction, anim_frame, "", 0, state_val)
|
||||
else:
|
||||
# Fallback: try direct rpc (may fail if node path doesn't match)
|
||||
rpc("_sync_position", position, velocity, position_z, current_direction, anim_frame, "", 0, state_val)
|
||||
game_world._rpc_to_ready_peers("_sync_enemy_position", [enemy_name, enemy_index, position, velocity, position_z, current_direction, anim_frame, "", 0, state_val])
|
||||
# Removed fallback rpc() call - it causes node path resolution errors
|
||||
# If game_world is not available, skip sync (will sync next frame)
|
||||
|
||||
func _ai_behavior(_delta):
|
||||
# Override in subclasses
|
||||
@@ -235,7 +234,7 @@ func _attack_player(player):
|
||||
# Fallback: broadcast if we can't get peer_id
|
||||
player.rpc_take_damage.rpc(damage, global_position)
|
||||
attack_timer = attack_cooldown
|
||||
print(name, " attacked ", player.name, " (peer: ", player_peer_id, ", server: ", multiplayer.get_unique_id(), ")")
|
||||
LogManager.log(str(name) + " attacked " + str(player.name) + " (peer: " + str(player_peer_id) + ", server: " + str(multiplayer.get_unique_id()) + ")", LogManager.CATEGORY_ENEMY)
|
||||
|
||||
func _find_nearest_player() -> Node:
|
||||
var players = get_tree().get_nodes_in_group("player")
|
||||
@@ -306,7 +305,8 @@ func take_damage(amount: float, from_position: Vector2, is_critical: bool = fals
|
||||
var dodge_chance = character_stats.dodge_chance
|
||||
if dodge_roll < dodge_chance:
|
||||
_was_dodged = true
|
||||
print(name, " DODGED the attack! (DEX: ", character_stats.baseStats.dex + character_stats.get_pass("dex"), ", dodge chance: ", dodge_chance * 100.0, "%)")
|
||||
var dex_total = character_stats.baseStats.dex + character_stats.get_pass("dex")
|
||||
LogManager.log(str(name) + " DODGED the attack! (DEX: " + str(dex_total) + ", dodge chance: " + str(dodge_chance * 100.0) + "%)", LogManager.CATEGORY_ENEMY)
|
||||
# Show "DODGED" text
|
||||
_show_damage_number(0.0, from_position, false, false, true) # is_dodged = true
|
||||
# Sync dodge visual to clients (pass damage_amount=0.0 and is_dodged=true to indicate dodge)
|
||||
@@ -315,7 +315,7 @@ func take_damage(amount: float, from_position: Vector2, is_critical: bool = fals
|
||||
var enemy_index = get_meta("enemy_index") if has_meta("enemy_index") else -1
|
||||
var game_world = get_tree().get_first_node_in_group("game_world")
|
||||
if game_world and game_world.has_method("_sync_enemy_damage_visual"):
|
||||
game_world._sync_enemy_damage_visual.rpc(enemy_name, enemy_index, 0.0, from_position, false, true)
|
||||
game_world._rpc_to_ready_peers("_sync_enemy_damage_visual", [enemy_name, enemy_index, 0.0, from_position, false, true])
|
||||
return # No damage taken, exit early
|
||||
|
||||
# If not dodged, apply damage with DEF reduction
|
||||
@@ -328,12 +328,12 @@ func take_damage(amount: float, from_position: Vector2, is_critical: bool = fals
|
||||
if character_stats.hp <= 0:
|
||||
character_stats.no_health.emit()
|
||||
var effective_def = character_stats.defense * (0.2 if is_critical else 1.0)
|
||||
print(name, " took ", actual_damage, " damage (", amount, " base - ", effective_def, " DEF = ", actual_damage, ")! Health: ", current_health, "/", character_stats.maxhp)
|
||||
LogManager.log(str(name) + " took " + str(actual_damage) + " damage (" + str(amount) + " base - " + str(effective_def) + " DEF = " + str(actual_damage) + ")! Health: " + str(current_health) + "/" + str(character_stats.maxhp), LogManager.CATEGORY_ENEMY)
|
||||
else:
|
||||
# Fallback for legacy (shouldn't happen if _initialize_character_stats is called)
|
||||
current_health -= amount
|
||||
actual_damage = amount
|
||||
print(name, " took ", amount, " damage! Health: ", current_health, " (critical: ", is_critical, ")")
|
||||
LogManager.log(str(name) + " took " + str(amount) + " damage! Health: " + str(current_health) + " (critical: " + str(is_critical) + ")", LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# Calculate knockback direction (away from attacker)
|
||||
var knockback_direction = (global_position - from_position).normalized()
|
||||
@@ -357,7 +357,7 @@ func take_damage(amount: float, from_position: Vector2, is_critical: bool = fals
|
||||
var enemy_index = get_meta("enemy_index") if has_meta("enemy_index") else -1
|
||||
var game_world = get_tree().get_first_node_in_group("game_world")
|
||||
if game_world and game_world.has_method("_sync_enemy_damage_visual"):
|
||||
game_world._sync_enemy_damage_visual.rpc(enemy_name, enemy_index, actual_damage, from_position, is_critical)
|
||||
game_world._rpc_to_ready_peers("_sync_enemy_damage_visual", [enemy_name, enemy_index, actual_damage, from_position, is_critical])
|
||||
else:
|
||||
# Fallback: try direct RPC (may fail if node path doesn't match)
|
||||
_sync_damage_visual.rpc(actual_damage, from_position, is_critical)
|
||||
@@ -467,7 +467,7 @@ func _notify_doors_enemy_died():
|
||||
if door.requires_enemies:
|
||||
# Trigger puzzle state check immediately (doors will verify if all enemies are dead)
|
||||
door.call_deferred("_check_puzzle_state")
|
||||
print("Enemy: Notified door ", door.name, " to check puzzle state after enemy death")
|
||||
LogManager.log("Enemy: Notified door " + str(door.name) + " to check puzzle state after enemy death", LogManager.CATEGORY_ENEMY)
|
||||
|
||||
func _set_animation(_anim_name: String):
|
||||
# Virtual function - override in subclasses that use animation state system
|
||||
@@ -479,17 +479,26 @@ func _die():
|
||||
return
|
||||
|
||||
is_dead = true
|
||||
print(name, " died!")
|
||||
LogManager.log(str(name) + " died!", LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# Track defeated enemy for syncing to new clients
|
||||
if multiplayer.has_multiplayer_peer() and multiplayer.is_server():
|
||||
var game_world = get_tree().get_first_node_in_group("game_world")
|
||||
if game_world:
|
||||
var enemy_index = get_meta("enemy_index") if has_meta("enemy_index") else -1
|
||||
if enemy_index >= 0:
|
||||
game_world.defeated_enemies[enemy_index] = true
|
||||
LogManager.log("Enemy: Tracked defeated enemy with index " + str(enemy_index), LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# Credit kill and grant EXP to the player who dealt the fatal damage
|
||||
if killer_player and is_instance_valid(killer_player) and killer_player.character_stats:
|
||||
killer_player.character_stats.kills += 1
|
||||
print(name, " kill credited to ", killer_player.name, " (total kills: ", killer_player.character_stats.kills, ")")
|
||||
LogManager.log(str(name) + " kill credited to " + str(killer_player.name) + " (total kills: " + str(killer_player.character_stats.kills) + ")", LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# Grant EXP to the killer
|
||||
if exp_reward > 0:
|
||||
killer_player.character_stats.add_xp(exp_reward)
|
||||
print(name, " granted ", exp_reward, " EXP to ", killer_player.name)
|
||||
LogManager.log(str(name) + " granted " + str(exp_reward) + " EXP to " + str(killer_player.name), LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# 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
|
||||
@@ -499,7 +508,7 @@ func _die():
|
||||
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
|
||||
print(name, " syncing kill stats to client peer_id=", killer_peer_id, " kills=", killer_player.character_stats.kills, " coins=", coins)
|
||||
LogManager.log(str(name) + " syncing kill stats to client peer_id=" + str(killer_peer_id) + " kills=" + str(killer_player.character_stats.kills) + " coins=" + str(coins), LogManager.CATEGORY_ENEMY)
|
||||
killer_player._sync_stats_update.rpc_id(killer_peer_id, killer_player.character_stats.kills, coins)
|
||||
|
||||
# Spawn loot immediately (before death animation)
|
||||
@@ -512,7 +521,7 @@ func _die():
|
||||
var enemy_index = get_meta("enemy_index") if has_meta("enemy_index") else -1
|
||||
var game_world = get_tree().get_first_node_in_group("game_world")
|
||||
if game_world and game_world.has_method("_sync_enemy_death"):
|
||||
game_world._sync_enemy_death.rpc(enemy_name, enemy_index)
|
||||
game_world._rpc_to_ready_peers("_sync_enemy_death", [enemy_name, enemy_index])
|
||||
else:
|
||||
# Fallback: try direct RPC (may fail if node path doesn't match)
|
||||
_sync_death.rpc()
|
||||
@@ -528,20 +537,20 @@ func _play_death_animation():
|
||||
func _spawn_loot():
|
||||
# Only spawn loot on server/authority
|
||||
if not is_multiplayer_authority():
|
||||
print(name, " _spawn_loot() called but not authority, skipping")
|
||||
LogManager.log(str(name) + " _spawn_loot() called but not authority, skipping", LogManager.CATEGORY_ENEMY)
|
||||
return
|
||||
|
||||
print(name, " _spawn_loot() called on authority")
|
||||
LogManager.log(str(name) + " _spawn_loot() called on authority", LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# Spawn random loot at enemy position
|
||||
var loot_scene = preload("res://scenes/loot.tscn")
|
||||
if not loot_scene:
|
||||
print(name, " ERROR: loot_scene is null!")
|
||||
LogManager.log_error(str(name) + " ERROR: loot_scene is null!", LogManager.CATEGORY_ENEMY)
|
||||
return
|
||||
|
||||
# Random chance to drop loot (70% chance)
|
||||
var loot_chance = randf()
|
||||
print(name, " loot chance roll: ", loot_chance, " (need > 0.3)")
|
||||
LogManager.log(str(name) + " loot chance roll: " + str(loot_chance) + " (need > 0.3)", LogManager.CATEGORY_ENEMY)
|
||||
if loot_chance > 0.3:
|
||||
# Decide what to drop: 30% coin, 30% food, 40% item
|
||||
var drop_roll = randf()
|
||||
@@ -575,7 +584,7 @@ func _spawn_loot():
|
||||
|
||||
var entities_node = get_parent()
|
||||
if not entities_node:
|
||||
print(name, " ERROR: entities_node is null! Cannot spawn loot!")
|
||||
LogManager.log_error(str(name) + " ERROR: entities_node is null! Cannot spawn loot!", LogManager.CATEGORY_ENEMY)
|
||||
return
|
||||
|
||||
if drop_item:
|
||||
@@ -583,7 +592,7 @@ func _spawn_loot():
|
||||
var item = ItemDatabase.get_random_enemy_drop()
|
||||
if item:
|
||||
ItemLootHelper.spawn_item_loot(item, global_position, entities_node, game_world)
|
||||
print(name, " ✓ dropped item: ", item.item_name, " at ", safe_spawn_pos)
|
||||
LogManager.log(str(name) + " ✓ dropped item: " + str(item.item_name) + " at " + str(safe_spawn_pos), LogManager.CATEGORY_ENEMY)
|
||||
else:
|
||||
# Spawn regular loot (coin or food)
|
||||
var loot = loot_scene.instantiate()
|
||||
@@ -595,7 +604,7 @@ func _spawn_loot():
|
||||
loot.velocity_z = random_velocity_z
|
||||
loot.velocity_set_by_spawner = true
|
||||
loot.is_airborne = true
|
||||
print(name, " ✓ dropped loot: ", loot_type, " at ", safe_spawn_pos, " (original enemy pos: ", global_position, ")")
|
||||
LogManager.log(str(name) + " ✓ dropped loot: " + str(loot_type) + " at " + str(safe_spawn_pos) + " (original enemy pos: " + str(global_position) + ")", LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# Sync loot spawn to all clients (use safe position)
|
||||
if multiplayer.has_multiplayer_peer():
|
||||
@@ -608,12 +617,12 @@ func _spawn_loot():
|
||||
# Store loot ID on server loot instance
|
||||
loot.set_meta("loot_id", loot_id)
|
||||
# Sync to clients with ID
|
||||
game_world._sync_loot_spawn.rpc(safe_spawn_pos, loot_type, initial_velocity, random_velocity_z, loot_id)
|
||||
print(name, " ✓ synced loot spawn to clients")
|
||||
game_world._rpc_to_ready_peers("_sync_loot_spawn", [safe_spawn_pos, loot_type, initial_velocity, random_velocity_z, loot_id])
|
||||
LogManager.log(str(name) + " ✓ synced loot spawn to clients", LogManager.CATEGORY_ENEMY)
|
||||
else:
|
||||
print(name, " ERROR: game_world not found for loot sync!")
|
||||
LogManager.log_error(str(name) + " ERROR: game_world not found for loot sync!", LogManager.CATEGORY_ENEMY)
|
||||
else:
|
||||
print(name, " loot chance failed (", loot_chance, " <= 0.3), no loot dropped")
|
||||
LogManager.log(str(name) + " loot chance failed (" + str(loot_chance) + " <= 0.3), no loot dropped", LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# This function can be called directly (not just via RPC) when game_world routes the update
|
||||
func _sync_position(pos: Vector2, vel: Vector2, z_pos: float = 0.0, dir: int = 0, frame: int = 0, anim: String = "", frame_num: int = 0, state_value: int = -1):
|
||||
@@ -625,12 +634,12 @@ func _sync_position(pos: Vector2, vel: Vector2, z_pos: float = 0.0, dir: int = 0
|
||||
# Debug: Log when client receives position update (first few times)
|
||||
if not has_meta("position_sync_count"):
|
||||
set_meta("position_sync_count", 0)
|
||||
print("Enemy ", name, " (client) RECEIVED first position sync! pos=", pos, " authority: ", get_multiplayer_authority(), " is_authority: ", is_multiplayer_authority(), " in_tree: ", is_inside_tree())
|
||||
LogManager.log("Enemy " + str(name) + " (client) RECEIVED first position sync! pos=" + str(pos) + " authority: " + str(get_multiplayer_authority()) + " is_authority: " + str(is_multiplayer_authority()) + " in_tree: " + str(is_inside_tree()), LogManager.CATEGORY_ENEMY)
|
||||
|
||||
var sync_count = get_meta("position_sync_count") + 1
|
||||
set_meta("position_sync_count", sync_count)
|
||||
if sync_count <= 3: # Log first 3 syncs
|
||||
print("Enemy ", name, " (client) received position sync #", sync_count, ": pos=", pos)
|
||||
LogManager.log("Enemy " + str(name) + " (client) received position sync #" + str(sync_count) + ": pos=" + str(pos), LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# Update position and state
|
||||
position = pos
|
||||
@@ -661,6 +670,10 @@ func _sync_damage_visual(damage_amount: float = 0.0, attacker_position: Vector2
|
||||
if is_multiplayer_authority():
|
||||
return # Server ignores its own updates
|
||||
|
||||
# Trigger damage animation and state change on client
|
||||
# This ensures clients play the damage animation (e.g., slime DAMAGE animation)
|
||||
_on_take_damage()
|
||||
|
||||
_flash_damage()
|
||||
|
||||
# Show damage number on client (even if damage_amount is 0 for dodges/misses)
|
||||
@@ -676,7 +689,7 @@ func _sync_death():
|
||||
|
||||
if not is_dead:
|
||||
is_dead = true
|
||||
print(name, " received death sync, dying on client")
|
||||
LogManager.log(str(name) + " received death sync, dying on client", LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# Remove collision layer so they don't collide with players, but still collide with walls
|
||||
# This matches what happens on the server when rats/slimes die
|
||||
@@ -687,7 +700,7 @@ func _sync_death():
|
||||
_play_death_animation()
|
||||
else:
|
||||
# Already dead, but make sure collision is removed and it's removed from scene
|
||||
print(name, " received death sync but already dead, ensuring removal")
|
||||
LogManager.log(str(name) + " received death sync but already dead, ensuring removal", LogManager.CATEGORY_ENEMY)
|
||||
|
||||
# Remove collision layer if not already removed
|
||||
if get_collision_layer_value(2):
|
||||
|
||||
Reference in New Issue
Block a user