Fix auto-attack stalling after SMSG_ATTACKSTOP and remove stale comments

Re-send CMSG_ATTACKSWING every second while auto-attacking so combat
resumes automatically when the server pauses the attack loop (out of
range, etc). Previously the client kept autoAttacking=true but never
re-engaged, requiring the player to manually right-click again.

Also remove leftover single-player/offline references from comments.
This commit is contained in:
Kelsi 2026-02-17 15:37:02 -08:00
parent 22648870f3
commit bd70ca17ca
5 changed files with 14 additions and 4 deletions

View file

@ -1279,6 +1279,7 @@ private:
bool autoAttacking = false; bool autoAttacking = false;
uint64_t autoAttackTarget = 0; uint64_t autoAttackTarget = 0;
bool autoAttackOutOfRange_ = false; bool autoAttackOutOfRange_ = false;
float autoAttackResendTimer_ = 0.0f; // Re-send CMSG_ATTACKSWING every ~1s while attacking
std::unordered_set<uint64_t> hostileAttackers_; std::unordered_set<uint64_t> hostileAttackers_;
std::vector<CombatTextEntry> combatText; std::vector<CombatTextEntry> combatText;

View file

@ -43,7 +43,7 @@ struct ActiveTransport {
glm::mat4 transform; // Cached world transform glm::mat4 transform; // Cached world transform
glm::mat4 invTransform; // Cached inverse for collision glm::mat4 invTransform; // Cached inverse for collision
// Player attachment (single-player for now) // Player attachment state
bool playerOnBoard; bool playerOnBoard;
glm::vec3 playerLocalOffset; glm::vec3 playerLocalOffset;

View file

@ -771,7 +771,7 @@ void AmbientSoundManager::updateBellTolls(float deltaTime) {
return; return;
} }
// Get current system time (server time for single-player) // Get current system time
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
std::time_t currentTime = std::chrono::system_clock::to_time_t(now); std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::tm* localTime = std::localtime(&currentTime); std::tm* localTime = std::localtime(&currentTime);

View file

@ -418,7 +418,6 @@ void Application::setState(AppState newState) {
gameHandler->sendMovement(static_cast<game::Opcode>(opcode)); gameHandler->sendMovement(static_cast<game::Opcode>(opcode));
} }
}); });
// Keep player locomotion WoW-like in both single-player and online modes.
cc->setUseWoWSpeed(true); cc->setUseWoWSpeed(true);
} }
if (gameHandler) { if (gameHandler) {
@ -884,7 +883,7 @@ void Application::render() {
renderer->beginFrame(); renderer->beginFrame();
// Only render 3D world when in-game (after server connect or single-player) // Only render 3D world when in-game
if (state == AppState::IN_GAME) { if (state == AppState::IN_GAME) {
if (world) { if (world) {
renderer->renderWorld(world.get(), gameHandler.get()); renderer->renderWorld(world.get(), gameHandler.get());

View file

@ -522,6 +522,7 @@ void GameHandler::update(float deltaTime) {
auto distanceStart = std::chrono::high_resolution_clock::now(); auto distanceStart = std::chrono::high_resolution_clock::now();
// Leave combat if auto-attack target is too far away (leash range) // Leave combat if auto-attack target is too far away (leash range)
// Also re-send CMSG_ATTACKSWING every second to resume after server SMSG_ATTACKSTOP
if (autoAttacking && autoAttackTarget != 0) { if (autoAttacking && autoAttackTarget != 0) {
auto targetEntity = entityManager.getEntity(autoAttackTarget); auto targetEntity = entityManager.getEntity(autoAttackTarget);
if (targetEntity) { if (targetEntity) {
@ -531,6 +532,13 @@ void GameHandler::update(float deltaTime) {
if (dist > 40.0f) { if (dist > 40.0f) {
stopAutoAttack(); stopAutoAttack();
LOG_INFO("Left combat: target too far (", dist, " yards)"); LOG_INFO("Left combat: target too far (", dist, " yards)");
} else if (state == WorldState::IN_WORLD && socket) {
autoAttackResendTimer_ += deltaTime;
if (autoAttackResendTimer_ >= 1.0f) {
autoAttackResendTimer_ = 0.0f;
auto pkt = AttackSwingPacket::build(autoAttackTarget);
socket->send(pkt);
}
} }
} }
} }
@ -6382,6 +6390,7 @@ void GameHandler::startAutoAttack(uint64_t targetGuid) {
autoAttacking = true; autoAttacking = true;
autoAttackTarget = targetGuid; autoAttackTarget = targetGuid;
autoAttackOutOfRange_ = false; autoAttackOutOfRange_ = false;
autoAttackResendTimer_ = 0.0f;
if (state == WorldState::IN_WORLD && socket) { if (state == WorldState::IN_WORLD && socket) {
auto packet = AttackSwingPacket::build(targetGuid); auto packet = AttackSwingPacket::build(targetGuid);
socket->send(packet); socket->send(packet);
@ -6394,6 +6403,7 @@ void GameHandler::stopAutoAttack() {
autoAttacking = false; autoAttacking = false;
autoAttackTarget = 0; autoAttackTarget = 0;
autoAttackOutOfRange_ = false; autoAttackOutOfRange_ = false;
autoAttackResendTimer_ = 0.0f;
if (state == WorldState::IN_WORLD && socket) { if (state == WorldState::IN_WORLD && socket) {
auto packet = AttackStopPacket::build(); auto packet = AttackStopPacket::build();
socket->send(packet); socket->send(packet);