XTargets will move auto entries up on removal like live

This also makes use of the bulk packet so not a crap ton of packets
generated.
This commit is contained in:
Michael Cook (mackal) 2015-09-03 02:56:51 -04:00
parent b7ee4634be
commit 4ae02e5efe
3 changed files with 80 additions and 22 deletions

View File

@ -7041,7 +7041,7 @@ void Client::UpdateClientXTarget(Client *c)
} }
} }
void Client::AddAutoXTarget(Mob *m) void Client::AddAutoXTarget(Mob *m, bool send)
{ {
if(!XTargettingAvailable() || !XTargetAutoAddHaters) if(!XTargettingAvailable() || !XTargetAutoAddHaters)
return; return;
@ -7054,7 +7054,10 @@ void Client::AddAutoXTarget(Mob *m)
if((XTargets[i].Type == Auto) && (XTargets[i].ID == 0)) if((XTargets[i].Type == Auto) && (XTargets[i].ID == 0))
{ {
XTargets[i].ID = m->GetID(); XTargets[i].ID = m->GetID();
SendXTargetPacket(i, m); if (send) // if we don't send we're bulk sending updates later on
SendXTargetPacket(i, m);
else
XTargets[i].dirty = true;
break; break;
} }
} }
@ -7062,42 +7065,59 @@ void Client::AddAutoXTarget(Mob *m)
void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots) void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots)
{ {
if(!XTargettingAvailable()) if (!XTargettingAvailable())
return; return;
bool HadFreeAutoSlotsBefore = false; bool HadFreeAutoSlotsBefore = false;
int FreedAutoSlots = 0; int FreedAutoSlots = 0;
if(m->GetID() == 0) if (m->GetID() == 0)
return; return;
for(int i = 0; i < GetMaxXTargets(); ++i) for (int i = 0; i < GetMaxXTargets(); ++i) {
{ if (OnlyAutoSlots && XTargets[i].Type != Auto)
if(OnlyAutoSlots && (XTargets[i].Type !=Auto))
continue; continue;
if(XTargets[i].ID == m->GetID()) if (XTargets[i].ID == m->GetID()) {
{ if (XTargets[i].Type == CurrentTargetNPC)
if(XTargets[i].Type == CurrentTargetNPC)
XTargets[i].Type = Auto; XTargets[i].Type = Auto;
if(XTargets[i].Type == Auto) if (XTargets[i].Type == Auto)
++FreedAutoSlots; ++FreedAutoSlots;
XTargets[i].ID = 0; XTargets[i].ID = 0;
XTargets[i].dirty = true;
SendXTargetPacket(i, nullptr); } else {
} if (XTargets[i].Type == Auto && XTargets[i].ID == 0)
else
{
if((XTargets[i].Type == Auto) && (XTargets[i].ID == 0))
HadFreeAutoSlotsBefore = true; HadFreeAutoSlotsBefore = true;
} }
} }
// If there are more mobs aggro on us than we had auto-hate slots, add one of those haters into the slot(s) we just freed up.
if(!HadFreeAutoSlotsBefore && FreedAutoSlots) // move shit up!
std::queue<int> empty_slots;
for (int i = 0; i < GetMaxXTargets(); ++i) {
if (XTargets[i].Type != Auto)
continue;
if (XTargets[i].ID == 0) {
empty_slots.push(i);
continue;
}
if (XTargets[i].ID != 0 && !empty_slots.empty()) {
int temp = empty_slots.front();
std::swap(XTargets[i], XTargets[temp]);
XTargets[i].dirty = XTargets[temp].dirty = true;
empty_slots.pop();
empty_slots.push(i);
}
}
// If there are more mobs aggro on us than we had auto-hate slots, add one of those haters into the slot(s) we
// just freed up.
if (!HadFreeAutoSlotsBefore && FreedAutoSlots)
entity_list.RefreshAutoXTargets(this); entity_list.RefreshAutoXTargets(this);
SendXTargetUpdates();
} }
void Client::UpdateXTargetType(XTargetType Type, Mob *m, const char *Name) void Client::UpdateXTargetType(XTargetType Type, Mob *m, const char *Name)
@ -7166,6 +7186,42 @@ void Client::SendXTargetPacket(uint32 Slot, Mob *m)
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
} }
// This is a bulk packet, we use it when we remove something since we need to reorder the xtargets and maybe
// add new mobs! Currently doesn't check if there is a dirty flag set, so it should only be called when there is
void Client::SendXTargetUpdates()
{
if (!XTargettingAvailable())
return;
int count = 0;
// header is 4 bytes max xtargets, 4 bytes count
// entry is 4 bytes slot, 1 byte unknown, 4 bytes ID, 65 char name
auto outapp = new EQApplicationPacket(OP_XTargetResponse, 8 + 74 * GetMaxXTargets()); // fuck it max size
outapp->WriteUInt32(GetMaxXTargets());
outapp->WriteUInt32(1); // we will correct this later
for (int i = 0; i < GetMaxXTargets(); ++i) {
if (XTargets[i].dirty) {
outapp->WriteUInt32(i);
outapp->WriteUInt8(0); // no idea what this is
outapp->WriteUInt32(XTargets[i].ID);
outapp->WriteString(XTargets[i].Name);
count++;
XTargets[i].dirty = false;
}
}
assert(count > 0); // we don't have any logic to prevent this, assert for now
auto newbuff = new uchar[outapp->GetWritePosition()];
memcpy(newbuff, outapp->pBuffer, outapp->GetWritePosition());
safe_delete_array(outapp->pBuffer);
outapp->pBuffer = newbuff;
outapp->size = outapp->GetWritePosition();
outapp->SetWritePosition(4);
outapp->WriteUInt32(count);
FastQueuePacket(&outapp);
}
void Client::RemoveGroupXTargets() void Client::RemoveGroupXTargets()
{ {
if(!XTargettingAvailable()) if(!XTargettingAvailable())
@ -8670,4 +8726,4 @@ uint32 Client::GetMoney(uint8 type, uint8 subtype) {
int Client::GetAccountAge() { int Client::GetAccountAge() {
return (time(nullptr) - GetAccountCreation()); return (time(nullptr) - GetAccountCreation());
} }

View File

@ -175,6 +175,7 @@ typedef enum
struct XTarget_Struct struct XTarget_Struct
{ {
XTargetType Type; XTargetType Type;
bool dirty;
uint16 ID; uint16 ID;
char Name[65]; char Name[65];
}; };
@ -1144,9 +1145,10 @@ public:
bool IsClientXTarget(const Client *c) const; bool IsClientXTarget(const Client *c) const;
void UpdateClientXTarget(Client *c); void UpdateClientXTarget(Client *c);
void UpdateXTargetType(XTargetType Type, Mob *m, const char *Name = nullptr); void UpdateXTargetType(XTargetType Type, Mob *m, const char *Name = nullptr);
void AddAutoXTarget(Mob *m); void AddAutoXTarget(Mob *m, bool send = true);
void RemoveXTarget(Mob *m, bool OnlyAutoSlots); void RemoveXTarget(Mob *m, bool OnlyAutoSlots);
void SendXTargetPacket(uint32 Slot, Mob *m); void SendXTargetPacket(uint32 Slot, Mob *m);
void SendXTargetUpdates();
void RemoveGroupXTargets(); void RemoveGroupXTargets();
void RemoveAutoXTargets(); void RemoveAutoXTargets();
void ShowXTargets(Client *c); void ShowXTargets(Client *c);

View File

@ -1373,7 +1373,7 @@ void EntityList::RefreshAutoXTargets(Client *c)
continue; continue;
if (m->CheckAggro(c) && !c->IsXTarget(m)) { if (m->CheckAggro(c) && !c->IsXTarget(m)) {
c->AddAutoXTarget(m); c->AddAutoXTarget(m, false); // we only call this before a bulk, so lets not send right away
break; break;
} }