fix: Tracer direction now matches bot facing

Root cause: startFiring() sent ChangeFireStateMessage_Start before
updating orientation. Client caches orientation at fire-start for
tracer rendering, so tracers went in spawn direction.

Fix: In startFiring(), calculate target yaw, update orientation,
broadcast PlayerState with correct facing, THEN send fire state.

Also fixed facingYawUpper to be 0 (relative to body) instead of
absolute yaw value.
This commit is contained in:
Claude 2025-11-23 08:34:18 +00:00
parent d3eb0f4d9e
commit dab40e2262
No known key found for this signature in database

View file

@ -362,16 +362,16 @@ class BotManager(zone: Zone) extends Actor {
player.GUID,
player.Position,
player.Velocity,
player.Orientation.z,
0f,
player.Orientation.z,
player.Orientation.z, // facingYaw - body direction
0f, // facingPitch
0f, // facingYawUpper - relative to body, 0 = looking straight ahead
timestamp,
is_crouching = false,
is_jumping = false,
jump_thrust = false,
is_cloaked = false,
spectator = false,
weaponInHand = true // Weapon is always drawn (set at spawn)
weaponInHand = true // Weapon is always drawn (set at spawn)
)
)
}
@ -538,7 +538,7 @@ class BotManager(zone: Zone) extends Actor {
if (ticksSinceAcquired >= recognitionTime) {
// Start firing if not already
if (!combat.isFiring) {
startFiring(botState, targetPlayer.Name)
startFiring(botState, targetPlayer) // Pass target for orientation calculation
combat = combat.copy(isFiring = true, burstStartTick = tickCount, shotsFired = 0)
}
@ -578,11 +578,47 @@ class BotManager(zone: Zone) extends Actor {
combat
}
/** Broadcast that bot started firing - uses LocalEvents like turrets for proper client rendering */
private def startFiring(botState: BotState, targetName: String): Unit = {
getWeapon(botState.player).foreach { weapon =>
log.info(s"${botState.name} is attacking $targetName")
// Use LocalEvents like turrets do for proper tracer rendering
/**
* Broadcast that bot started firing.
* CRITICAL: Must update orientation and broadcast PlayerState BEFORE sending fire state,
* otherwise client will use stale orientation for tracer direction.
*/
private def startFiring(botState: BotState, target: Player): Unit = {
val player = botState.player
// Calculate yaw to face target
val dx = target.Position.x - player.Position.x
val dy = target.Position.y - player.Position.y
val targetYaw = math.toDegrees(math.atan2(dx, dy)).toFloat
// Update bot's orientation to face target
player.Orientation = Vector3(0, 0, targetYaw)
// Broadcast PlayerState with correct orientation BEFORE fire state
// This ensures client has correct facing when fire state arrives
val timestamp = (System.currentTimeMillis() % 65536).toInt
zone.AvatarEvents ! AvatarServiceMessage(
zone.id,
AvatarAction.PlayerState(
player.GUID,
player.Position,
player.Velocity,
targetYaw, // facingYaw - body direction
0f, // facingPitch
0f, // facingYawUpper - relative to body, 0 = looking straight
timestamp,
is_crouching = false,
is_jumping = false,
jump_thrust = false,
is_cloaked = false,
spectator = false,
weaponInHand = true
)
)
// NOW send fire state - client should have correct orientation
getWeapon(player).foreach { weapon =>
log.info(s"${botState.name} is attacking ${target.Name}")
zone.LocalEvents ! LocalServiceMessage(
zone.id,
LocalAction.SendResponse(ChangeFireStateMessage_Start(weapon.GUID))