DarkflameServer/dGame/dBehaviors/ProjectileAttackBehavior.cpp
David Markowitz a2ca273370
Cleanup behavior bitstream reads (#888)
* Add failArmor server side

Address out of bounds reading in behavior

Address the basicAttackBehavior reading out of bounds memory and reading bits that didnt exist, which occasionally caused crashes and also caused the behavior to do undefined behavior due to the bad reads.

Tested that attacking a wall anywhere with a projectile now does not crash the game.  Tested with logs that the behavior correctly returned when there were no allocated bits or returned when other states were met.

Add back logs and add fail handle

Remove comment block

Revert "Add back logs and add fail handle"

This reverts commit db19be0906fc8bf35bf89037e2bfba39f5ef9c0c.

Split out checks

* Cleanup Behavior streams
2022-12-16 15:23:02 -06:00

161 lines
4.8 KiB
C++

#include "ProjectileAttackBehavior.h"
#include "BehaviorBranchContext.h"
#include "BehaviorContext.h"
#include "EntityManager.h"
#include "Game.h"
#include "dLogger.h"
#include "SkillComponent.h"
#include "../dWorldServer/ObjectIDManager.h"
void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
LWOOBJID target{};
if (!bitStream->Read(target)) {
Game::logger->Log("ProjectileAttackBehavior", "Unable to read target from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
auto* entity = EntityManager::Instance()->GetEntity(context->originator);
if (entity == nullptr) {
Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator);
return;
}
auto* skillComponent = entity->GetComponent<SkillComponent>();
if (skillComponent == nullptr) {
Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!", -context->originator);
return;
}
if (m_useMouseposit) {
NiPoint3 targetPosition = NiPoint3::ZERO;
if (!bitStream->Read(targetPosition)) {
Game::logger->Log("ProjectileAttackBehavior", "Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
}
auto* targetEntity = EntityManager::Instance()->GetEntity(target);
for (auto i = 0u; i < this->m_projectileCount; ++i) {
LWOOBJID projectileId{};
if (!bitStream->Read(projectileId)) {
Game::logger->Log("ProjectileAttackBehavior", "Unable to read projectileId from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
return;
};
branch.target = target;
branch.isProjectile = true;
branch.referencePosition = targetEntity == nullptr ? entity->GetPosition() : targetEntity->GetPosition();
skillComponent->RegisterPlayerProjectile(projectileId, context, branch, this->m_lot);
}
}
void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
bitStream->Write(branch.target);
auto* entity = EntityManager::Instance()->GetEntity(context->originator);
if (entity == nullptr) {
Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator);
return;
}
auto* skillComponent = entity->GetComponent<SkillComponent>();
if (skillComponent == nullptr) {
Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!", context->originator);
return;
}
auto* other = EntityManager::Instance()->GetEntity(branch.target);
if (other == nullptr) {
Game::logger->Log("ProjectileAttackBehavior", "Invalid projectile target (%llu)!", branch.target);
return;
}
const auto position = entity->GetPosition() + this->m_offset;
const auto distance = Vector3::Distance(position, other->GetPosition());
const auto time = distance / this->m_projectileSpeed;
const auto rotation = NiQuaternion::LookAtUnlocked(position, other->GetPosition());
const auto targetPosition = other->GetPosition();
//entity->SetRotation(rotation);
const auto angleDelta = this->m_spreadAngle;
const auto angleStep = angleDelta / this->m_projectileCount;
auto angle = -angleStep;
const auto maxTime = this->m_maxDistance / this->m_projectileSpeed;
for (auto i = 0u; i < this->m_projectileCount; ++i) {
auto id = static_cast<LWOOBJID>(ObjectIDManager::Instance()->GenerateObjectID());
id = GeneralUtils::SetBit(id, OBJECT_BIT_SPAWNED);
bitStream->Write(id);
auto eulerAngles = rotation.GetEulerAngles();
eulerAngles.y += angle * (3.14 / 180);
const auto angledRotation = NiQuaternion::FromEulerAngles(eulerAngles);
const auto direction = angledRotation.GetForwardVector();
const auto destination = position + direction * distance;
branch.isProjectile = true;
branch.referencePosition = destination;
skillComponent->RegisterCalculatedProjectile(id, context, branch, this->m_lot, maxTime, position, direction * this->m_projectileSpeed, this->m_trackTarget, this->m_trackRadius);
// No idea how to calculate this properly
if (this->m_projectileCount == 2) {
angle += angleDelta;
} else if (this->m_projectileCount == 3) {
angle += angleStep;
}
}
}
void ProjectileAttackBehavior::Load() {
this->m_lot = GetInt("LOT_ID");
this->m_projectileCount = GetInt("spread_count");
if (this->m_projectileCount == 0) {
this->m_projectileCount = 1;
}
this->m_maxDistance = GetFloat("max_distance");
this->m_projectileSpeed = GetFloat("projectile_speed");
this->m_spreadAngle = GetFloat("spread_angle");
this->m_offset = { GetFloat("offset_x"), GetFloat("offset_y"), GetFloat("offset_z") };
this->m_trackTarget = GetBoolean("track_target");
this->m_trackRadius = GetFloat("track_radius");
this->m_useMouseposit = GetBoolean("use_mouseposit");
}