mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-25 06:26:24 +00:00
[Stability] Various crash fixes based on Regrad fixes and crashlogs. (#1928)
These contains various fixes, fixes that have history worked one in past more then once as person as group, aswell @Wishmaster117. But due various reasons we had to drop them due priority or simply timewise. These fixes have recollected again by @Regrad based on his crash logs. Most crash logs we have, i am talking 30+ of them, to many to post here. @Regrad running a larger server 100+ real players with bots, which means he will walk into issues that most of us wont or are extremely difficult to reproduce. @Regrad used LLM to solve them based on crash log and mentioned his server crashes almost disappeared, instead of redoing every single PR and pull them apart. I tried to keep his bunch of changes together as whole, reviewed them, some redone, verified again etc etc. This is not how would normally do this. But since i want @Regrad being able to confirm, we need this in a package as a whole. Pulling them apart in the current situation is simply to much, to complicated in the verification process. So this PR is open and in my opinion has priority above others, but @Regrad is only person who can give the green light for the mod-playerbot changes for now. I, we spend huge amount of time into these issues over last couple of months. I will put other PR's on hold for abit. --------- Signed-off-by: Engardium <regradius@gmail.com> Co-authored-by: Engardium <regradius@gmail.com>
This commit is contained in:
@@ -21,11 +21,37 @@ bool IsSameLocation(WorldLocation const& a, WorldLocation const& b)
|
||||
|
||||
bool Formation::IsNullLocation(WorldLocation const& loc) { return IsSameLocation(loc, Formation::NullLocation); }
|
||||
|
||||
bool ValidateTargetContext(Unit* a, Unit* b, Map*& outMap)
|
||||
{
|
||||
if (!a || !b || a == b)
|
||||
return false;
|
||||
|
||||
if (!a->IsInWorld() || !b->IsInWorld())
|
||||
return false;
|
||||
|
||||
if (a->IsDuringRemoveFromWorld() || b->IsDuringRemoveFromWorld())
|
||||
return false;
|
||||
|
||||
Map* map = a->GetMap();
|
||||
if (!map || map != b->GetMap())
|
||||
return false;
|
||||
|
||||
outMap = map;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateTargetContext(Unit* a, Unit* b)
|
||||
{
|
||||
Map* unused = nullptr;
|
||||
return ValidateTargetContext(a, b, unused);
|
||||
}
|
||||
|
||||
WorldLocation MoveAheadFormation::GetLocation()
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master || master == bot)
|
||||
return WorldLocation();
|
||||
if (!ValidateTargetContext(master, bot))
|
||||
return Formation::NullLocation;
|
||||
|
||||
WorldLocation loc = GetLocationInternal();
|
||||
if (Formation::IsNullLocation(loc))
|
||||
@@ -40,7 +66,7 @@ WorldLocation MoveAheadFormation::GetLocation()
|
||||
// float ori = master->GetOrientation();
|
||||
// float x1 = x + sPlayerbotAIConfig->tooCloseDistance * cos(ori);
|
||||
// float y1 = y + sPlayerbotAIConfig->tooCloseDistance * sin(ori);
|
||||
// float ground = master->GetMap()->GetHeight(x1, y1, z);
|
||||
// float ground = map->GetHeight(x1, y1, z);
|
||||
// if (ground > INVALID_HEIGHT)
|
||||
// {
|
||||
// x = x1;
|
||||
@@ -48,7 +74,7 @@ WorldLocation MoveAheadFormation::GetLocation()
|
||||
// }
|
||||
// }
|
||||
|
||||
// float ground = master->GetMap()->GetHeight(x, y, z);
|
||||
// float ground = map->GetHeight(x, y, z);
|
||||
// if (ground <= INVALID_HEIGHT)
|
||||
// return Formation::NullLocation;
|
||||
|
||||
@@ -81,16 +107,17 @@ public:
|
||||
WorldLocation GetLocationInternal() override
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return WorldLocation();
|
||||
Map* map = nullptr;
|
||||
if (!ValidateTargetContext(master, bot, map))
|
||||
return Formation::NullLocation;
|
||||
|
||||
float range = sPlayerbotAIConfig->followDistance;
|
||||
float angle = GetFollowAngle();
|
||||
float x = master->GetPositionX() + cos(angle) * range;
|
||||
float y = master->GetPositionY() + sin(angle) * range;
|
||||
float z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), x, y, z))
|
||||
if (!map->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = master->GetPositionX() + cos(angle) * range;
|
||||
y = master->GetPositionY() + sin(angle) * range;
|
||||
@@ -111,8 +138,9 @@ public:
|
||||
WorldLocation GetLocationInternal() override
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return WorldLocation();
|
||||
Map* map = nullptr;
|
||||
if (!ValidateTargetContext(master, bot, map))
|
||||
return Formation::NullLocation;
|
||||
|
||||
float range = sPlayerbotAIConfig->followDistance;
|
||||
float angle = GetFollowAngle();
|
||||
@@ -120,49 +148,28 @@ public:
|
||||
time_t now = time(nullptr);
|
||||
if (!lastChangeTime || now - lastChangeTime >= 3)
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return WorldLocation();
|
||||
lastChangeTime = now;
|
||||
|
||||
float range = sPlayerbotAIConfig->followDistance;
|
||||
float angle = GetFollowAngle();
|
||||
|
||||
time_t now = time(nullptr);
|
||||
if (!lastChangeTime || now - lastChangeTime >= 3)
|
||||
{
|
||||
lastChangeTime = now;
|
||||
dx = (urand(0, 10) / 10.0 - 0.5) * sPlayerbotAIConfig->tooCloseDistance;
|
||||
dy = (urand(0, 10) / 10.0 - 0.5) * sPlayerbotAIConfig->tooCloseDistance;
|
||||
dr = sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
float x = master->GetPositionX() + cos(angle) * range + dx;
|
||||
float y = master->GetPositionY() + sin(angle) * range + dy;
|
||||
float z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
if (!master->GetMap()->CheckCollisionAndGetValidCoords(
|
||||
master, master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = master->GetPositionX() + cos(angle) * range + dx;
|
||||
y = master->GetPositionY() + sin(angle) * range + dy;
|
||||
z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
master->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
// bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
// bot->GetPositionZ(), x, y, z);
|
||||
return WorldLocation(master->GetMapId(), x, y, z);
|
||||
dx = (urand(0, 10) / 10.0f - 0.5f) * sPlayerbotAIConfig->tooCloseDistance;
|
||||
dy = (urand(0, 10) / 10.0f - 0.5f) * sPlayerbotAIConfig->tooCloseDistance;
|
||||
dr = std::sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
float x = master->GetPositionX() + cos(angle) * range + dx;
|
||||
float y = master->GetPositionY() + sin(angle) * range + dy;
|
||||
float x = master->GetPositionX() + std::cos(angle) * range + dx;
|
||||
float y = master->GetPositionY() + std::sin(angle) * range + dy;
|
||||
float z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), x, y, z))
|
||||
|
||||
if (!map->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = master->GetPositionX() + cos(angle) * range + dx;
|
||||
y = master->GetPositionY() + sin(angle) * range + dy;
|
||||
// Recompute a clean fallback and clamp Z
|
||||
x = master->GetPositionX() + std::cos(angle) * range + dx;
|
||||
y = master->GetPositionY() + std::sin(angle) * range + dy;
|
||||
z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
|
||||
master->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
|
||||
return WorldLocation(master->GetMapId(), x, y, z);
|
||||
}
|
||||
|
||||
@@ -182,16 +189,18 @@ public:
|
||||
|
||||
WorldLocation GetLocation() override
|
||||
{
|
||||
float range = 2.0f;
|
||||
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
Player* master = GetMaster();
|
||||
if (!target && target != bot)
|
||||
|
||||
// Fix: if no target OR target is the bot, fall back to master
|
||||
if (!target || target == bot)
|
||||
target = master;
|
||||
|
||||
if (!target)
|
||||
Map* map = nullptr;
|
||||
if (!ValidateTargetContext(master, bot, map))
|
||||
return Formation::NullLocation;
|
||||
|
||||
float range = 2.0f;
|
||||
switch (bot->getClass())
|
||||
{
|
||||
case CLASS_HUNTER:
|
||||
@@ -214,14 +223,16 @@ public:
|
||||
float x = target->GetPositionX() + cos(angle) * range;
|
||||
float y = target->GetPositionY() + sin(angle) * range;
|
||||
float z = target->GetPositionZ();
|
||||
if (!target->GetMap()->CheckCollisionAndGetValidCoords(target, target->GetPositionX(), target->GetPositionY(),
|
||||
target->GetPositionZ(), x, y, z))
|
||||
|
||||
if (!map->CheckCollisionAndGetValidCoords(target, target->GetPositionX(), target->GetPositionY(),
|
||||
target->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = target->GetPositionX() + cos(angle) * range;
|
||||
y = target->GetPositionY() + sin(angle) * range;
|
||||
z = target->GetPositionZ();
|
||||
target->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
|
||||
return WorldLocation(bot->GetMapId(), x, y, z);
|
||||
}
|
||||
};
|
||||
@@ -249,18 +260,18 @@ public:
|
||||
float orientation = master->GetOrientation();
|
||||
|
||||
std::vector<Player*> players;
|
||||
GroupReference* gref = group->GetFirstMember();
|
||||
while (gref)
|
||||
players.reserve(group->GetMembersCount());
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* member = gref->GetSource();
|
||||
if (member != master)
|
||||
players.push_back(member);
|
||||
if (!member || member == master)
|
||||
continue;
|
||||
|
||||
gref = gref->next();
|
||||
players.push_back(member);
|
||||
}
|
||||
|
||||
players.insert(players.begin() + group->GetMembersCount() / 2, master);
|
||||
|
||||
players.insert(players.begin() + players.size() / 2, master);
|
||||
return MoveLine(players, 0.0f, x, y, z, orientation, range);
|
||||
}
|
||||
};
|
||||
@@ -289,19 +300,17 @@ public:
|
||||
|
||||
std::vector<Player*> tanks;
|
||||
std::vector<Player*> dps;
|
||||
GroupReference* gref = group->GetFirstMember();
|
||||
while (gref)
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* member = gref->GetSource();
|
||||
if (member != master)
|
||||
{
|
||||
if (botAI->IsTank(member))
|
||||
tanks.push_back(member);
|
||||
else
|
||||
dps.push_back(member);
|
||||
}
|
||||
if (!member || member == master)
|
||||
continue;
|
||||
|
||||
gref = gref->next();
|
||||
if (botAI->IsTank(member))
|
||||
tanks.push_back(member);
|
||||
else
|
||||
dps.push_back(member);
|
||||
}
|
||||
|
||||
if (botAI->IsTank(master))
|
||||
@@ -310,25 +319,21 @@ public:
|
||||
dps.insert(dps.begin() + (dps.size() + 1) / 2, master);
|
||||
|
||||
if (botAI->IsTank(bot) && botAI->IsTank(master))
|
||||
{
|
||||
return MoveLine(tanks, 0.0f, x, y, z, orientation, range);
|
||||
}
|
||||
|
||||
if (!botAI->IsTank(bot) && !botAI->IsTank(master))
|
||||
{
|
||||
return MoveLine(dps, 0.0f, x, y, z, orientation, range);
|
||||
}
|
||||
|
||||
if (botAI->IsTank(bot) && !botAI->IsTank(master))
|
||||
{
|
||||
float diff = tanks.size() % 2 == 0 ? -sPlayerbotAIConfig->tooCloseDistance / 2.0f : 0.0f;
|
||||
float diff = (tanks.size() % 2 == 0) ? -sPlayerbotAIConfig->tooCloseDistance / 2.0f : 0.0f;
|
||||
return MoveLine(tanks, diff, x + cos(orientation) * range, y + sin(orientation) * range, z, orientation,
|
||||
range);
|
||||
}
|
||||
|
||||
if (!botAI->IsTank(bot) && botAI->IsTank(master))
|
||||
{
|
||||
float diff = dps.size() % 2 == 0 ? -sPlayerbotAIConfig->tooCloseDistance / 2.0f : 0.0f;
|
||||
float diff = (dps.size() % 2 == 0) ? -sPlayerbotAIConfig->tooCloseDistance / 2.0f : 0.0f;
|
||||
return MoveLine(dps, diff, x - cos(orientation) * range, y - sin(orientation) * range, z, orientation,
|
||||
range);
|
||||
}
|
||||
@@ -344,65 +349,69 @@ public:
|
||||
|
||||
WorldLocation GetLocation() override
|
||||
{
|
||||
Player* master = GetMaster();
|
||||
Map* map = nullptr;
|
||||
if (!ValidateTargetContext(master, bot, map))
|
||||
return Formation::NullLocation;
|
||||
|
||||
float range = sPlayerbotAIConfig->farDistance;
|
||||
float followRange = sPlayerbotAIConfig->followDistance;
|
||||
|
||||
Player* master = GetMaster();
|
||||
if (!master)
|
||||
return Formation::NullLocation;
|
||||
|
||||
if (sServerFacade->GetDistance2d(bot, master) <= range)
|
||||
return Formation::NullLocation;
|
||||
|
||||
float angle = master->GetAngle(bot);
|
||||
float angleToBot = master->GetAngle(bot);
|
||||
float followAngle = GetFollowAngle();
|
||||
|
||||
float x = master->GetPositionX() + cos(angle) * range + cos(followAngle) * followRange;
|
||||
float y = master->GetPositionY() + sin(angle) * range + sin(followAngle) * followRange;
|
||||
float x = master->GetPositionX() + cos(angleToBot) * range + cos(followAngle) * followRange;
|
||||
float y = master->GetPositionY() + sin(angleToBot) * range + sin(followAngle) * followRange;
|
||||
float z = master->GetPositionZ();
|
||||
|
||||
float ground = master->GetMapHeight(x, y, z + 30.0f);
|
||||
if (ground <= INVALID_HEIGHT)
|
||||
{
|
||||
float minDist = 0, minX = 0, minY = 0;
|
||||
for (float angle = 0.0f; angle <= 2 * M_PI; angle += M_PI / 16.0f)
|
||||
float minDist = 0.f;
|
||||
float minX = 0.f, minY = 0.f;
|
||||
|
||||
for (float a = 0.0f; a <= 2 * M_PI; a += M_PI / 16.0f)
|
||||
{
|
||||
x = master->GetPositionX() + cos(angle) * range + cos(followAngle) * followRange;
|
||||
y = master->GetPositionY() + sin(angle) * range + sin(followAngle) * followRange;
|
||||
float dist = sServerFacade->GetDistance2d(bot, x, y);
|
||||
float ground = master->GetMapHeight(x, y, z + 30.0f);
|
||||
if (ground > INVALID_HEIGHT && (!minDist || minDist > dist))
|
||||
float tx = master->GetPositionX() + cos(a) * range + cos(followAngle) * followRange;
|
||||
float ty = master->GetPositionY() + sin(a) * range + sin(followAngle) * followRange;
|
||||
|
||||
float dist = sServerFacade->GetDistance2d(bot, tx, ty);
|
||||
float tg = master->GetMapHeight(tx, ty, z + 30.0f);
|
||||
|
||||
if (tg > INVALID_HEIGHT && (!minDist || dist < minDist))
|
||||
{
|
||||
minDist = dist;
|
||||
minX = x;
|
||||
minY = y;
|
||||
minX = tx;
|
||||
minY = ty;
|
||||
}
|
||||
}
|
||||
|
||||
if (minDist)
|
||||
if (!minDist)
|
||||
return Formation::NullLocation;
|
||||
|
||||
float lz = z;
|
||||
if (!map->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), minX, minY, lz))
|
||||
{
|
||||
if (!master->GetMap()->CheckCollisionAndGetValidCoords(
|
||||
master, master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = master->GetPositionX() + cos(angle) * range + cos(followAngle) * followRange;
|
||||
y = master->GetPositionY() + sin(angle) * range + sin(followAngle) * followRange;
|
||||
z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
master->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
return WorldLocation(bot->GetMapId(), minX, minY, z);
|
||||
lz = z + master->GetHoverHeight();
|
||||
master->UpdateAllowedPositionZ(minX, minY, lz);
|
||||
}
|
||||
|
||||
return Formation::NullLocation;
|
||||
return WorldLocation(bot->GetMapId(), minX, minY, lz);
|
||||
}
|
||||
|
||||
if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), x, y, z))
|
||||
if (!map->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = master->GetPositionX() + cos(angle) * range + cos(followAngle) * followRange;
|
||||
y = master->GetPositionY() + sin(angle) * range + sin(followAngle) * followRange;
|
||||
x = master->GetPositionX() + cos(angleToBot) * range + cos(followAngle) * followRange;
|
||||
y = master->GetPositionY() + sin(angleToBot) * range + sin(followAngle) * followRange;
|
||||
z = master->GetPositionZ() + master->GetHoverHeight();
|
||||
master->UpdateAllowedPositionZ(x, y, z);
|
||||
}
|
||||
|
||||
return WorldLocation(bot->GetMapId(), x, y, z);
|
||||
}
|
||||
};
|
||||
@@ -653,31 +662,36 @@ WorldLocation MoveFormation::MoveSingleLine(std::vector<Player*> line, float dif
|
||||
float orientation, float range)
|
||||
{
|
||||
float count = line.size();
|
||||
float angle = orientation - M_PI / 2.0f;
|
||||
float x = cx + cos(angle) * (range * floor(count / 2.0f) + diff);
|
||||
float y = cy + sin(angle) * (range * floor(count / 2.0f) + diff);
|
||||
float angleLeft = orientation - M_PI / 2.0f;
|
||||
float x0 = cx + std::cos(angleLeft) * (range * std::floor(count / 2.0f) + diff);
|
||||
float y0 = cy + std::sin(angleLeft) * (range * std::floor(count / 2.0f) + diff);
|
||||
|
||||
uint32 index = 0;
|
||||
for (Player* member : line)
|
||||
{
|
||||
if (member == bot)
|
||||
{
|
||||
float angle = orientation + M_PI / 2.0f;
|
||||
float angleRight = orientation + M_PI / 2.0f;
|
||||
float radius = range * index;
|
||||
|
||||
float lx = x + cos(angle) * radius;
|
||||
float ly = y + sin(angle) * radius;
|
||||
float lx = x0 + std::cos(angleRight) * radius;
|
||||
float ly = y0 + std::sin(angleRight) * radius;
|
||||
float lz = cz;
|
||||
|
||||
Player* master = botAI->GetMaster();
|
||||
if (!master || !master->GetMap()->CheckCollisionAndGetValidCoords(
|
||||
master, master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), lx, ly, lz))
|
||||
Map* map = master ? master->GetMap() : nullptr;
|
||||
|
||||
// if not fully in world ignore collision corrections.
|
||||
if (!master || !map || !bot || map != bot->GetMap() || !master->IsInWorld() ||
|
||||
master->IsDuringRemoveFromWorld() || !bot->IsInWorld() || bot->IsDuringRemoveFromWorld())
|
||||
{
|
||||
lx = x + cos(angle) * radius;
|
||||
ly = y + sin(angle) * radius;
|
||||
lz = cz;
|
||||
return WorldLocation(bot->GetMapId(), lx, ly, lz);
|
||||
}
|
||||
|
||||
// if fully loaded check collision and applies coordinate corrections if needed
|
||||
map->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
|
||||
master->GetPositionZ(), lx, ly, lz);
|
||||
|
||||
return WorldLocation(bot->GetMapId(), lx, ly, lz);
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ ItemUsage ItemUsageValue::Calculate()
|
||||
return ITEM_USAGE_USE;
|
||||
|
||||
if (proto->Class == ITEM_CLASS_CONSUMABLE &&
|
||||
(proto->MaxCount == 0 || AI_VALUE2(uint32, "item count", proto->Name1) < proto->MaxCount))
|
||||
(proto->MaxCount == 0 || bot->GetItemCount(itemId, false) < proto->MaxCount))
|
||||
{
|
||||
std::string const foodType = GetConsumableType(proto, bot->GetPower(POWER_MANA));
|
||||
|
||||
@@ -520,7 +520,7 @@ bool ItemUsageValue::IsItemUsefulForQuest(Player* player, ItemTemplate const* pr
|
||||
{
|
||||
if (quest->RequiredItemId[i] == proto->ItemId)
|
||||
{
|
||||
if (AI_VALUE2(uint32, "item count", proto->Name1) >= quest->RequiredItemCount[i])
|
||||
if (player->GetItemCount(proto->ItemId, false) >= quest->RequiredItemCount[i])
|
||||
continue;
|
||||
|
||||
return true; // Item is directly required for a quest
|
||||
@@ -549,7 +549,7 @@ bool ItemUsageValue::IsItemUsefulForQuest(Player* player, ItemTemplate const* pr
|
||||
{
|
||||
if (quest->RequiredItemId[j] == createdItemId)
|
||||
{
|
||||
if (AI_VALUE2(uint32, "item count", createdItemId) >= quest->RequiredItemCount[j])
|
||||
if (player->GetItemCount(createdItemId, false) >= quest->RequiredItemCount[j])
|
||||
continue;
|
||||
|
||||
return true; // Item is useful because it creates a required quest item
|
||||
|
||||
Reference in New Issue
Block a user