Fix #488
This commit is contained in:
parent
83ec8af494
commit
704122cce2
6 changed files with 78 additions and 82 deletions
EQ2/source/WorldServer
|
@ -30,6 +30,9 @@ Bot::Bot() : NPC() {
|
|||
info->set_wis_base(20);
|
||||
info->set_intel_base(20);
|
||||
info->set_agi_base(20);
|
||||
|
||||
camping = false;
|
||||
immediate_camp = false;
|
||||
}
|
||||
|
||||
Bot::~Bot() {
|
||||
|
@ -629,31 +632,8 @@ bool Bot::ShouldMelee() {
|
|||
|
||||
void Bot::Camp(bool immediate) {
|
||||
// Copy from COMMAND_GROUP_LEAVE
|
||||
GroupMemberInfo* gmi = GetGroupMemberInfo();
|
||||
if (gmi) {
|
||||
int32 group_id = gmi->group_id;
|
||||
world.GetGroupManager()->RemoveGroupMember(group_id, this);
|
||||
if (!world.GetGroupManager()->IsGroupIDValid(group_id)) {
|
||||
// leader->Message(CHANNEL_COLOR_GROUP, "%s has left the group.", client->GetPlayer()->GetName());
|
||||
}
|
||||
else {
|
||||
world.GetGroupManager()->GroupMessage(group_id, "%s has left the group.", GetName());
|
||||
}
|
||||
}
|
||||
|
||||
if(!immediate)
|
||||
{
|
||||
GetZone()->PlayAnimation(this, 538);
|
||||
SetVisualState(540);
|
||||
GetZone()->Despawn(this, 5000);
|
||||
}
|
||||
|
||||
if (!GetOwner())
|
||||
return;
|
||||
|
||||
Client* client = GetZone()->GetClientBySpawn(GetOwner());
|
||||
if (client)
|
||||
client->GetPlayer()->SpawnedBots.erase(BotIndex);
|
||||
camping = true;
|
||||
immediate_camp = immediate;
|
||||
}
|
||||
|
||||
void Bot::ChangeLevel(int16 old_level, int16 new_level) {
|
||||
|
@ -722,4 +702,35 @@ void Bot::ChangeLevel(int16 old_level, int16 new_level) {
|
|||
GetPlayer()->GetSkills()->SetSkillCapsByType(6, 5 * new_level);
|
||||
GetPlayer()->GetSkills()->SetSkillCapsByType(13, 5 * new_level);
|
||||
*/
|
||||
}
|
||||
|
||||
void Bot::Begin_Camp() {
|
||||
GroupMemberInfo* gmi = GetGroupMemberInfo();
|
||||
if (gmi) {
|
||||
int32 group_id = gmi->group_id;
|
||||
world.GetGroupManager()->RemoveGroupMember(group_id, this);
|
||||
if (!world.GetGroupManager()->IsGroupIDValid(group_id)) {
|
||||
// leader->Message(CHANNEL_COLOR_GROUP, "%s has left the group.", client->GetPlayer()->GetName());
|
||||
}
|
||||
else {
|
||||
world.GetGroupManager()->GroupMessage(group_id, "%s has left the group.", GetName());
|
||||
}
|
||||
}
|
||||
|
||||
if(!immediate_camp)
|
||||
{
|
||||
GetZone()->PlayAnimation(this, 538);
|
||||
SetVisualState(540);
|
||||
GetZone()->Despawn(this, 5000);
|
||||
}
|
||||
|
||||
if (!GetOwner())
|
||||
return;
|
||||
|
||||
Client* client = GetZone()->GetClientBySpawn(GetOwner());
|
||||
if (client)
|
||||
client->GetPlayer()->SpawnedBots.erase(BotIndex);
|
||||
|
||||
camping = false;
|
||||
immediate_camp = true;
|
||||
}
|
|
@ -47,6 +47,9 @@ public:
|
|||
void Camp(bool immediate=false);
|
||||
void ChangeLevel(int16 old_level, int16 new_level);
|
||||
|
||||
bool IsCamping() { return camping; }
|
||||
bool IsImmediateCamp() { return immediate_camp; }
|
||||
void Begin_Camp();
|
||||
private:
|
||||
bool CanEquipItem(Item* item);
|
||||
bool IsSpellReady(Spell* spell);
|
||||
|
@ -86,4 +89,7 @@ private:
|
|||
|
||||
// First int32 = spell id (change to timer id later), second int32 is time the spell is available to cast again
|
||||
map<int32, int32> recast_times;
|
||||
std::atomic<bool> camping;
|
||||
std::atomic<bool> immediate_camp;
|
||||
|
||||
};
|
||||
|
|
|
@ -197,7 +197,6 @@ void PlayerGroup::MakeLeader(Entity* new_leader) {
|
|||
PlayerGroupManager::PlayerGroupManager() {
|
||||
m_nextGroupID = 1;
|
||||
|
||||
MGroups.SetName("PlayerGroupManager::m_groups");
|
||||
MPendingInvites.SetName("PlayerGroupManager::m_pendingInvites");
|
||||
}
|
||||
|
||||
|
@ -206,26 +205,23 @@ PlayerGroupManager::~PlayerGroupManager() {
|
|||
m_pendingInvites.clear();
|
||||
MPendingInvites.releasewritelock(__FUNCTION__, __LINE__);
|
||||
|
||||
MGroups.writelock(__FUNCTION__, __LINE__);
|
||||
std::unique_lock lock(MGroups);
|
||||
map<int32, PlayerGroup*>::iterator itr;
|
||||
for (itr = m_groups.begin(); itr != m_groups.end(); itr++)
|
||||
safe_delete(itr->second);
|
||||
|
||||
m_groups.clear();
|
||||
MGroups.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
bool PlayerGroupManager::AddGroupMember(int32 group_id, Entity* member) {
|
||||
std::unique_lock lock(MGroups);
|
||||
bool ret = false;
|
||||
MGroups.writelock(__FUNCTION__, __LINE__);
|
||||
|
||||
if (m_groups.count(group_id) > 0) {
|
||||
PlayerGroup* group = m_groups[group_id];
|
||||
ret = group->AddMember(member);
|
||||
}
|
||||
|
||||
MGroups.releasewritelock(__FUNCTION__, __LINE__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -242,7 +238,8 @@ bool PlayerGroupManager::RemoveGroupMember(int32 group_id, Entity* member) {
|
|||
tmpPlayer->EnableResetMentorship();
|
||||
}
|
||||
}
|
||||
MGroups.writelock(__FUNCTION__, __LINE__);
|
||||
|
||||
GroupLock(__FUNCTION__, __LINE__);
|
||||
|
||||
if (m_groups.count(group_id) > 0) {
|
||||
PlayerGroup* group = m_groups[group_id];
|
||||
|
@ -256,8 +253,8 @@ bool PlayerGroupManager::RemoveGroupMember(int32 group_id, Entity* member) {
|
|||
if (group->Size() == 1)
|
||||
remove = true;
|
||||
}
|
||||
|
||||
MGroups.releasewritelock(__FUNCTION__, __LINE__);
|
||||
|
||||
ReleaseGroupLock(__FUNCTION__, __LINE__);
|
||||
|
||||
if (client)
|
||||
RemoveGroupBuffs(group_id, client);
|
||||
|
@ -270,7 +267,7 @@ bool PlayerGroupManager::RemoveGroupMember(int32 group_id, Entity* member) {
|
|||
}
|
||||
|
||||
void PlayerGroupManager::NewGroup(Entity* leader) {
|
||||
MGroups.writelock(__FUNCTION__, __LINE__);
|
||||
std::unique_lock lock(MGroups);
|
||||
|
||||
// Highly doubt this will ever be needed but putting it in any way, basically bump the id and ensure
|
||||
// no active group is currently using this id, if we hit the max for an int32 then reset the id to 1
|
||||
|
@ -292,12 +289,10 @@ void PlayerGroupManager::NewGroup(Entity* leader) {
|
|||
new_group->AddMember(leader);
|
||||
|
||||
leader->GetGroupMemberInfo()->leader = true;
|
||||
|
||||
MGroups.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
void PlayerGroupManager::RemoveGroup(int32 group_id) {
|
||||
MGroups.writelock(__FUNCTION__, __LINE__);
|
||||
std::unique_lock lock(MGroups);
|
||||
|
||||
// Check to see if the id is in the list
|
||||
if (m_groups.count(group_id) > 0) {
|
||||
|
@ -308,8 +303,6 @@ void PlayerGroupManager::RemoveGroup(int32 group_id) {
|
|||
// Delete the group
|
||||
safe_delete(group);
|
||||
}
|
||||
|
||||
MGroups.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
int8 PlayerGroupManager::Invite(Player* leader, Entity* member) {
|
||||
|
@ -318,7 +311,7 @@ int8 PlayerGroupManager::Invite(Player* leader, Entity* member) {
|
|||
// Lock the pending invite list so we can work with it
|
||||
MPendingInvites.writelock(__FUNCTION__, __LINE__);
|
||||
|
||||
if (!member)
|
||||
if (!member || (member->IsBot() && ((Bot*)member)->IsImmediateCamp()))
|
||||
ret = 6; // failure, not a valid target
|
||||
else if (member->IsNPC() && (!member->IsBot() /*|| !member->IsMec()*/))
|
||||
ret = 6;
|
||||
|
@ -332,9 +325,9 @@ int8 PlayerGroupManager::Invite(Player* leader, Entity* member) {
|
|||
// Check to see if the player that invited is already in a group
|
||||
else if (leader->GetGroupMemberInfo()) {
|
||||
// Read lock the group list so we can get the size of the inviters group
|
||||
MGroups.readlock(__FUNCTION__, __LINE__);
|
||||
GroupLock(__FUNCTION__, __LINE__);
|
||||
int32 group_size = m_groups[leader->GetGroupMemberInfo()->group_id]->Size();
|
||||
MGroups.releasereadlock(__FUNCTION__, __LINE__);
|
||||
ReleaseGroupLock(__FUNCTION__, __LINE__);
|
||||
|
||||
// Check to see if the group is full
|
||||
if (m_groups[leader->GetGroupMemberInfo()->group_id]->Size() >= 6)
|
||||
|
@ -415,21 +408,18 @@ void PlayerGroupManager::DeclineInvite(Entity* member) {
|
|||
}
|
||||
|
||||
bool PlayerGroupManager::IsGroupIDValid(int32 group_id) {
|
||||
std::shared_lock lock(MGroups);
|
||||
bool ret = false;
|
||||
MGroups.readlock(__FUNCTION__, __LINE__);
|
||||
ret = m_groups.count(group_id) > 0;
|
||||
MGroups.releasereadlock(__FUNCTION__, __LINE__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PlayerGroupManager::SendGroupUpdate(int32 group_id, Client* exclude) {
|
||||
MGroups.writelock(__FUNCTION__, __LINE__);
|
||||
std::unique_lock lock(MGroups);
|
||||
|
||||
if (m_groups.count(group_id) > 0) {
|
||||
m_groups[group_id]->SendGroupUpdate(exclude);
|
||||
}
|
||||
|
||||
MGroups.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
PlayerGroup* PlayerGroupManager::GetGroup(int32 group_id) {
|
||||
|
@ -458,7 +448,7 @@ void PlayerGroupManager::RemoveGroupBuffs(int32 group_id, Client* client) {
|
|||
Entity* charmed_pet = 0;
|
||||
PlayerGroup* group = 0;
|
||||
|
||||
MGroups.readlock(__FUNCTION__, __LINE__);
|
||||
MGroups.lock_shared();
|
||||
if (m_groups.count(group_id) > 0)
|
||||
group = m_groups[group_id];
|
||||
|
||||
|
@ -515,24 +505,22 @@ void PlayerGroupManager::RemoveGroupBuffs(int32 group_id, Client* client) {
|
|||
if (packet)
|
||||
client->QueuePacket(packet);
|
||||
}
|
||||
MGroups.releasereadlock(__FUNCTION__, __LINE__);
|
||||
MGroups.unlock_shared();
|
||||
}
|
||||
|
||||
int32 PlayerGroupManager::GetGroupSize(int32 group_id) {
|
||||
std::shared_lock lock(MGroups);
|
||||
int32 ret = 0;
|
||||
MGroups.readlock(__FUNCTION__, __LINE__);
|
||||
|
||||
if (m_groups.count(group_id) > 0)
|
||||
ret = m_groups[group_id]->Size();
|
||||
|
||||
MGroups.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PlayerGroupManager::SendGroupQuests(int32 group_id, Client* client) {
|
||||
std::shared_lock lock(MGroups);
|
||||
GroupMemberInfo* info = 0;
|
||||
MGroups.readlock(__FUNCTION__, __LINE__);
|
||||
if (m_groups.count(group_id) > 0) {
|
||||
m_groups[group_id]->MGroupMembers.readlock(__FUNCTION__, __LINE__);
|
||||
deque<GroupMemberInfo*>* members = m_groups[group_id]->GetMembers();
|
||||
|
@ -547,13 +535,12 @@ void PlayerGroupManager::SendGroupQuests(int32 group_id, Client* client) {
|
|||
}
|
||||
m_groups[group_id]->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
MGroups.releasereadlock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
bool PlayerGroupManager::HasGroupCompletedQuest(int32 group_id, int32 quest_id) {
|
||||
std::shared_lock lock(MGroups);
|
||||
bool questComplete = true;
|
||||
GroupMemberInfo* info = 0;
|
||||
MGroups.readlock(__FUNCTION__, __LINE__);
|
||||
if (m_groups.count(group_id) > 0) {
|
||||
m_groups[group_id]->MGroupMembers.readlock(__FUNCTION__, __LINE__);
|
||||
deque<GroupMemberInfo*>* members = m_groups[group_id]->GetMembers();
|
||||
|
@ -571,17 +558,14 @@ bool PlayerGroupManager::HasGroupCompletedQuest(int32 group_id, int32 quest_id)
|
|||
}
|
||||
m_groups[group_id]->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
MGroups.releasereadlock(__FUNCTION__, __LINE__);
|
||||
return questComplete;
|
||||
}
|
||||
|
||||
void PlayerGroupManager::SimpleGroupMessage(int32 group_id, const char* message) {
|
||||
MGroups.readlock(__FUNCTION__, __LINE__);
|
||||
std::shared_lock lock(MGroups);
|
||||
|
||||
if (m_groups.count(group_id) > 0)
|
||||
m_groups[group_id]->SimpleGroupMessage(message);
|
||||
|
||||
MGroups.releasereadlock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
void PlayerGroupManager::GroupMessage(int32 group_id, const char* message, ...) {
|
||||
|
@ -595,21 +579,17 @@ void PlayerGroupManager::GroupMessage(int32 group_id, const char* message, ...)
|
|||
}
|
||||
|
||||
void PlayerGroupManager::GroupChatMessage(int32 group_id, Spawn* from, int32 language, const char* message) {
|
||||
MGroups.readlock(__FUNCTION__, __LINE__);
|
||||
std::shared_lock lock(MGroups);
|
||||
|
||||
if (m_groups.count(group_id) > 0)
|
||||
m_groups[group_id]->GroupChatMessage(from, language, message);
|
||||
|
||||
MGroups.releasereadlock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
void PlayerGroupManager::MakeLeader(int32 group_id, Entity* new_leader) {
|
||||
MGroups.writelock(__FUNCTION__, __LINE__);
|
||||
std::unique_lock lock(MGroups);
|
||||
|
||||
if (m_groups.count(group_id) > 0)
|
||||
m_groups[group_id]->MakeLeader(new_leader);
|
||||
|
||||
MGroups.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
void PlayerGroupManager::UpdateGroupBuffs() {
|
||||
|
@ -811,10 +791,9 @@ void PlayerGroupManager::UpdateGroupBuffs() {
|
|||
}
|
||||
|
||||
bool PlayerGroupManager::IsInGroup(int32 group_id, Entity* member) {
|
||||
std::shared_lock lock(MGroups);
|
||||
bool ret = false;
|
||||
|
||||
MGroups.readlock(__FUNCTION__, __LINE__);
|
||||
|
||||
|
||||
if (m_groups.count(group_id) > 0) {
|
||||
m_groups[group_id]->MGroupMembers.readlock(__FUNCTION__, __LINE__);
|
||||
deque<GroupMemberInfo*>* members = m_groups[group_id]->GetMembers();
|
||||
|
@ -827,16 +806,14 @@ bool PlayerGroupManager::IsInGroup(int32 group_id, Entity* member) {
|
|||
m_groups[group_id]->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
MGroups.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Entity* PlayerGroupManager::IsPlayerInGroup(int32 group_id, int32 character_id) {
|
||||
std::shared_lock lock(MGroups);
|
||||
|
||||
Entity* ret = nullptr;
|
||||
|
||||
MGroups.readlock(__FUNCTION__, __LINE__);
|
||||
|
||||
if (m_groups.count(group_id) > 0) {
|
||||
m_groups[group_id]->MGroupMembers.readlock(__FUNCTION__, __LINE__);
|
||||
deque<GroupMemberInfo*>* members = m_groups[group_id]->GetMembers();
|
||||
|
@ -848,9 +825,7 @@ Entity* PlayerGroupManager::IsPlayerInGroup(int32 group_id, int32 character_id)
|
|||
}
|
||||
m_groups[group_id]->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
MGroups.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include "../common/types.h"
|
||||
#include "Entity.h"
|
||||
|
@ -152,12 +154,14 @@ public:
|
|||
/// <summary>Read locks the group list, no changes to the list should be made when using this</summary>
|
||||
/// <param name='function'>Name of the function called from, used for better debugging in the event of a deadlock</param>
|
||||
/// <param name='line'>Line number that this was called from, used for better debugging in the event of a deadlock</param>
|
||||
void GroupLock(const char* function = 0, int32 line = 0U) { MGroups.readlock(function, line); }
|
||||
void GroupHardLock(const char* function = 0, int32 line = 0U) { MGroups.lock(); }
|
||||
void GroupLock(const char* function = 0, int32 line = 0U) { MGroups.lock_shared(); }
|
||||
|
||||
/// <summary>Releases the readlock acquired from GroupLock()</summary>
|
||||
/// <param name='function'>Name of the function called from, used for better debugging in the event of a deadlock</param>
|
||||
/// <param name='line'>Line number that this was called from, used for better debugging in the event of a deadlock</param>
|
||||
void ReleaseGroupLock(const char* function = 0, int32 line = 0U) { MGroups.releasereadlock(function, line); }
|
||||
void ReleaseGroupHardLock(const char* function = 0, int32 line = 0U) { MGroups.unlock(); }
|
||||
void ReleaseGroupLock(const char* function = 0, int32 line = 0U) { MGroups.unlock_shared(); }
|
||||
|
||||
void ClearPendingInvite(Entity* member);
|
||||
|
||||
|
@ -186,7 +190,7 @@ private:
|
|||
map<int32, PlayerGroup*> m_groups; // int32 is the group id, PlayerGroup* is a pointer to the actual group
|
||||
map<string, string> m_pendingInvites; // First string is the person invited to the group, second string is the leader of the group
|
||||
|
||||
Mutex MGroups; // Mutex for the group map (m_groups)
|
||||
mutable std::shared_mutex MGroups; // Mutex for the group map (m_groups)
|
||||
Mutex MPendingInvites; // Mutex for the pending invites map (m_pendingInvites)
|
||||
};
|
||||
|
||||
|
|
|
@ -2795,6 +2795,9 @@ void Spawn::MoveToLocation(Spawn* spawn, float distance, bool immediate, bool ma
|
|||
void Spawn::ProcessMovement(bool isSpawnListLocked){
|
||||
CheckProximities();
|
||||
|
||||
if(IsBot() && ((Bot*)this)->IsCamping()) {
|
||||
((Bot*)this)->Begin_Camp();
|
||||
}
|
||||
if(IsPlayer()){
|
||||
//Check if player is riding a boat, if so update pos (boat's current location + XYZ offsets)
|
||||
Player* player = ((Player*)this);
|
||||
|
|
|
@ -4543,11 +4543,8 @@ void ZoneServer::Despawn(Spawn* spawn, int32 timer){
|
|||
if (spawn && movementMgr != nullptr) {
|
||||
movementMgr->RemoveMob((Entity*)spawn);
|
||||
}
|
||||
|
||||
if(!spawn || spawn->IsPlayer())
|
||||
return;
|
||||
|
||||
RemoveSpawnSupportFunctions(spawn, true);
|
||||
if(spawn->IsEntity())
|
||||
((Entity*)spawn)->InCombat(false);
|
||||
if(timer == 0)
|
||||
|
|
Loading…
Add table
Reference in a new issue