From 40747ae5a31a3b76ae3b50a8594c372a4dc0785d Mon Sep 17 00:00:00 2001 From: Noudess Date: Mon, 18 Nov 2019 14:58:45 -0500 Subject: [PATCH 1/3] Repair client updates when client is on (does not have to have control) a boat --- zone/client_packet.cpp | 58 +++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 0bb319a20..c99ffe3b8 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -4404,7 +4404,36 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { } return; } + + // At this point, all that's left is a client update. + // Pure boat updates, and client contolled mob updates are complete. + // This can still be tricky. If ppu->vehicle_id is set, then the client + // position is actually an offset from the boat he is inside. + + bool on_boat = (ppu->vehicle_id != 0); + + // From this point forward, we need to use a new set of variables for client + // position. If the client is in a boat, we need to add the boat pos and + // the client offset together. + float cx = ppu->x_pos; + float cy = ppu->y_pos; + float cz = ppu->z_pos; + float new_heading = EQ12toFloat(ppu->heading); + + if (on_boat) { + Mob *boat = entity_list.GetMob(ppu->vehicle_id); + if (boat == 0) { + LogError("Can't find boat for client position offset."); + } + else { + cx += boat->GetX(); + cy += boat->GetY(); + cz += boat->GetZ(); + new_heading += boat->GetHeading(); + } + } + if (IsDraggingCorpse()) DragCorpses(); @@ -4412,9 +4441,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { float rewind_x_diff = 0; float rewind_y_diff = 0; - rewind_x_diff = ppu->x_pos - m_RewindLocation.x; + rewind_x_diff = cx - m_RewindLocation.x; rewind_x_diff *= rewind_x_diff; - rewind_y_diff = ppu->y_pos - m_RewindLocation.y; + rewind_y_diff = cy - m_RewindLocation.y; rewind_y_diff *= rewind_y_diff; /* @@ -4432,26 +4461,26 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { */ if ((rewind_x_diff > 5000) || (rewind_y_diff > 5000)) - m_RewindLocation = glm::vec3(ppu->x_pos, ppu->y_pos, ppu->z_pos); + m_RewindLocation = glm::vec3(cx, cy, cz); if (proximity_timer.Check()) { - entity_list.ProcessMove(this, glm::vec3(ppu->x_pos, ppu->y_pos, ppu->z_pos)); + entity_list.ProcessMove(this, glm::vec3(cx, cy, cz)); if (RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem, EnableTaskProximity)) - ProcessTaskProximities(ppu->x_pos, ppu->y_pos, ppu->z_pos); + ProcessTaskProximities(cx, cy, cz); - m_Proximity = glm::vec3(ppu->x_pos, ppu->y_pos, ppu->z_pos); + m_Proximity = glm::vec3(cx, cy, cz); } /* Update internal state */ m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); - if (IsTracking() && ((m_Position.x != ppu->x_pos) || (m_Position.y != ppu->y_pos))) { + if (IsTracking() && ((m_Position.x != cx) || (m_Position.y != cy))) { if (zone->random.Real(0, 100) < 70)//should be good CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, -20); } /* Break Hide if moving without sneaking and set rewind timer if moved */ - if (ppu->y_pos != m_Position.y || ppu->x_pos != m_Position.x) { + if (cy != m_Position.y || cx != m_Position.x) { if ((hidden || improved_hidden) && !sneaking) { hidden = false; improved_hidden = false; @@ -4470,7 +4499,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { } /* Handle client aggro scanning timers NPCs */ - is_client_moving = (ppu->y_pos == m_Position.y && ppu->x_pos == m_Position.x) ? false : true; + is_client_moving = (cy == m_Position.y && cx == m_Position.x) ? false : true; if (is_client_moving) { LogDebug("ClientUpdate: Client is moving - scan timer is: [{}]", client_scan_npc_aggro_timer.GetDuration()); @@ -4531,17 +4560,16 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { SetLastPositionBeforeBulkUpdate(GetPosition()); } - float new_heading = EQ12toFloat(ppu->heading); int32 new_animation = ppu->animation; /* Update internal server position from what the client has sent */ - m_Position.x = ppu->x_pos; - m_Position.y = ppu->y_pos; - m_Position.z = ppu->z_pos; + m_Position.x = cx; + m_Position.y = cy; + m_Position.z = cz; /* Visual Debugging */ if (RuleB(Character, OPClientUpdateVisualDebug)) { - LogDebug("ClientUpdate: ppu x: [{}] y: [{}] z: [{}] h: [{}]", ppu->x_pos, ppu->y_pos, ppu->z_pos, ppu->heading); + LogDebug("ClientUpdate: ppu x: [{}] y: [{}] z: [{}] h: [{}]", cx, cy, cz, new_heading); this->SendAppearanceEffect(78, 0, 0, 0, 0); this->SendAppearanceEffect(41, 0, 0, 0, 0); } @@ -4550,7 +4578,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { if (is_client_moving || new_heading != m_Position.w || new_animation != animation) { animation = ppu->animation; - m_Position.w = EQ12toFloat(ppu->heading); + m_Position.w = new_heading; /* Broadcast update to other clients */ auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); From 7e724568a6844251f88ff1dd60b50db54178e2a2 Mon Sep 17 00:00:00 2001 From: Uleat Date: Thu, 5 Dec 2019 18:24:29 -0500 Subject: [PATCH 2/3] Update to boat-related opcode handlers --- zone/client_packet.cpp | 36 ++++++++++++++++++++++++------------ zone/mob.cpp | 19 ++++++++++++++++++- zone/mob.h | 1 + 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index c99ffe3b8..8b21c2f70 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -3838,8 +3838,9 @@ void Client::Handle_OP_BoardBoat(const EQApplicationPacket *app) boatname[63] = '\0'; Mob* boat = entity_list.GetMob(boatname); - if (!boat || (boat->GetRace() != CONTROLLED_BOAT && boat->GetRace() != 502)) + if (!boat || !boat->IsControllableBoat()) { return; + } controlling_boat_id = boat->GetID(); // set the client's BoatID to show that it's on this boat Message(0, "Board boat: %s", boatname); @@ -4941,12 +4942,16 @@ void Client::Handle_OP_ControlBoat(const EQApplicationPacket *app) LogError("Wrong size: OP_ControlBoat, size=[{}], expected [{}]", app->size, sizeof(ControlBoat_Struct)); return; } + ControlBoat_Struct* cbs = (ControlBoat_Struct*)app->pBuffer; Mob* boat = entity_list.GetMob(cbs->boatId); - if (boat == 0) - return; // do nothing if the boat isn't valid + if (!boat) { - if (!boat->IsNPC() || (boat->GetRace() != CONTROLLED_BOAT && boat->GetRace() != 502)) + LogError("Player tried to take control of non-existent boat (char_id: %u, boat_eid: %u)", CharacterID(), cbs->boatId); + return; // do nothing if the boat isn't valid + } + + if (!boat->IsNPC() || !boat->IsControllableBoat()) { char *hacked_string = nullptr; MakeAnyLenString(&hacked_string, "OP_Control Boat was sent against %s which is of race %u", boat->GetName(), boat->GetRace()); @@ -4957,20 +4962,24 @@ void Client::Handle_OP_ControlBoat(const EQApplicationPacket *app) if (cbs->TakeControl) { // this uses the boat's target to indicate who has control of it. It has to check hate to make sure the boat isn't actually attacking anyone. - if ((boat->GetTarget() == 0) || (boat->GetTarget() == this && boat->GetHateAmount(this) == 0)) { + if (!boat->GetTarget() || (boat->GetTarget() == this && boat->GetHateAmount(this) == 0)) { boat->SetTarget(this); } else { + this->MessageString(Chat::Red, IN_USE); return; } } - else - boat->SetTarget(0); + else { + if (boat->GetTarget() == this) { + boat->SetTarget(nullptr); + } + } + + // client responds better to a packet echo than an empty op + QueuePacket(app); - auto outapp = new EQApplicationPacket(OP_ControlBoat, 0); - FastQueuePacket(&outapp); - safe_delete(outapp); // have the boat signal itself, so quests can be triggered by boat use boat->CastToNPC()->SignalNPC(0); } @@ -8940,10 +8949,13 @@ void Client::Handle_OP_LeaveBoat(const EQApplicationPacket *app) { Mob* boat = entity_list.GetMob(this->controlling_boat_id); // find the mob corresponding to the boat id if (boat) { - if ((boat->GetTarget() == this) && boat->GetHateAmount(this) == 0) // if the client somehow left while still controlling the boat (and the boat isn't attacking them) - boat->SetTarget(0); // fix it to stop later problems + if ((boat->GetTarget() == this) && boat->GetHateAmount(this) == 0) { // if the client somehow left while still controlling the boat (and the boat isn't attacking them) + boat->SetTarget(nullptr); // fix it to stop later problems + } } + this->controlling_boat_id = 0; + return; } diff --git a/zone/mob.cpp b/zone/mob.cpp index 37d59c78c..5cbd4d70f 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4829,7 +4829,24 @@ void Mob::RemoveNimbusEffect(int effectid) } bool Mob::IsBoat() const { - return (race == 72 || race == 73 || race == 114 || race == 404 || race == 550 || race == 551 || race == 552); + + return ( + race == RACE_SHIP_72 || + race == RACE_LAUNCH_73 || + race == RACE_GHOST_SHIP_114 || + race == RACE_SHIP_404 || + race == RACE_MERCHANT_SHIP_550 || + race == RACE_PIRATE_SHIP_551 || + race == RACE_GHOST_SHIP_552 + ); +} + +bool Mob::IsControllableBoat() const { + + return ( + race == RACE_BOAT_141 || + race == RACE_ROWBOAT_502 + ); } void Mob::SetBodyType(bodyType new_body, bool overwrite_orig) { diff --git a/zone/mob.h b/zone/mob.h index bcf3adcca..25e62f29e 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -566,6 +566,7 @@ public: inline const float GetBaseSize() const { return base_size; } inline const GravityBehavior GetFlyMode() const { return flymode; } bool IsBoat() const; + bool IsControllableBoat() const; //Group virtual bool HasRaid() = 0; From 326e1be09f223554eac082922ee1d561e5d79c10 Mon Sep 17 00:00:00 2001 From: Uleat Date: Thu, 5 Dec 2019 18:53:07 -0500 Subject: [PATCH 3/3] Added Mob::m_RelativePosition in preparation for more boat work --- zone/mob.cpp | 1 + zone/mob.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/zone/mob.cpp b/zone/mob.cpp index 5cbd4d70f..b12df39c1 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -128,6 +128,7 @@ Mob::Mob( SetMoving(false); moved = false; m_RewindLocation = glm::vec3(); + m_RelativePosition = glm::vec4(); name[0] = 0; orig_name[0] = 0; diff --git a/zone/mob.h b/zone/mob.h index 25e62f29e..2578db0c8 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -562,6 +562,12 @@ public: inline const float GetY() const { return m_Position.y; } inline const float GetZ() const { return m_Position.z; } inline const float GetHeading() const { return m_Position.w; } + inline const glm::vec4& GetRelativePosition() const { return m_RelativePosition; } + inline void SetRelativePosition(const float x, const float y, const float z) { m_RelativePosition.x = x; m_RelativePosition.y = y; m_RelativePosition.z = z; } + inline const float GetRelativeX() const { return m_RelativePosition.x; } + inline const float GetRelativeY() const { return m_RelativePosition.y; } + inline const float GetRelativeZ() const { return m_RelativePosition.z; } + inline const float GetRelativeHeading() const { return m_RelativePosition.w; } inline const float GetSize() const { return size; } inline const float GetBaseSize() const { return base_size; } inline const GravityBehavior GetFlyMode() const { return flymode; } @@ -1299,6 +1305,7 @@ protected: uint32 npctype_id; glm::vec4 m_Position; + glm::vec4 m_RelativePosition; int animation; // this is really what MQ2 calls SpeedRun just packed like (int)(SpeedRun * 40.0f) float base_size; float size;