DarkflameServer/dGame/dBehaviors/BehaviorContext.cpp

368 lines
8.6 KiB
C++
Raw Permalink Normal View History

2022-08-06 03:01:59 +00:00
#include "BehaviorContext.h"
#include "Behavior.h"
#include "BehaviorBranchContext.h"
#include "EntityManager.h"
#include "SkillComponent.h"
#include "Game.h"
#include "dLogger.h"
#include "dServer.h"
#include "PacketUtils.h"
#include <sstream>
#include "DestroyableComponent.h"
#include "EchoSyncSkill.h"
#include "PhantomPhysicsComponent.h"
#include "RebuildComponent.h"
#include "eReplicaComponentType.h"
#include "eConnectionType.h"
2022-07-28 13:39:57 +00:00
BehaviorSyncEntry::BehaviorSyncEntry() {
}
2022-07-28 13:39:57 +00:00
BehaviorTimerEntry::BehaviorTimerEntry() {
}
2022-07-28 13:39:57 +00:00
BehaviorEndEntry::BehaviorEndEntry() {
}
2022-07-28 13:39:57 +00:00
uint32_t BehaviorContext::GetUniqueSkillId() const {
auto* entity = EntityManager::Instance()->GetEntity(this->originator);
2022-07-28 13:39:57 +00:00
if (entity == nullptr) {
Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator);
return 0;
}
auto* component = entity->GetComponent<SkillComponent>();
2022-07-28 13:39:57 +00:00
if (component == nullptr) {
Game::logger->Log("BehaviorContext", "No skill component attached to (%llu)!", this->originator);;
return 0;
}
return component->GetUniqueSkillId();
}
void BehaviorContext::RegisterSyncBehavior(const uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext, const float duration, bool ignoreInterrupts) {
auto entry = BehaviorSyncEntry();
entry.handle = syncId;
entry.behavior = behavior;
entry.branchContext = branchContext;
entry.branchContext.isSync = true;
entry.ignoreInterrupts = ignoreInterrupts;
// Add 10 seconds + duration time to account for lag and give clients time to send their syncs to the server.
constexpr float lagTime = 10.0f;
entry.time = lagTime + duration;
this->syncEntries.push_back(entry);
}
2022-07-28 13:39:57 +00:00
void BehaviorContext::RegisterTimerBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, const LWOOBJID second) {
BehaviorTimerEntry entry;
entry.time = branchContext.duration;
entry.behavior = behavior;
entry.branchContext = branchContext;
entry.second = second;
this->timerEntries.push_back(entry);
}
2022-07-28 13:39:57 +00:00
void BehaviorContext::RegisterEndBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, const LWOOBJID second) {
BehaviorEndEntry entry;
entry.behavior = behavior;
entry.branchContext = branchContext;
entry.second = second;
entry.start = branchContext.start;
this->endEntries.push_back(entry);
}
2022-07-28 13:39:57 +00:00
void BehaviorContext::ScheduleUpdate(const LWOOBJID id) {
if (std::find(this->scheduledUpdates.begin(), this->scheduledUpdates.end(), id) != this->scheduledUpdates.end()) {
return;
}
this->scheduledUpdates.push_back(id);
}
2022-07-28 13:39:57 +00:00
void BehaviorContext::ExecuteUpdates() {
for (const auto& id : this->scheduledUpdates) {
auto* entity = EntityManager::Instance()->GetEntity(id);
if (entity == nullptr) continue;
EntityManager::Instance()->SerializeEntity(entity);
}
this->scheduledUpdates.clear();
}
2022-07-28 13:39:57 +00:00
void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream* bitStream) {
BehaviorSyncEntry entry;
auto found = false;
/*
* There may be more than one of each handle
*/
2022-07-28 13:39:57 +00:00
for (auto i = 0u; i < this->syncEntries.size(); ++i) {
const auto syncEntry = this->syncEntries.at(i);
2022-07-28 13:39:57 +00:00
if (syncEntry.handle == syncId) {
found = true;
entry = syncEntry;
this->syncEntries.erase(this->syncEntries.begin() + i);
break;
}
}
2022-07-28 13:39:57 +00:00
if (!found) {
Game::logger->Log("BehaviorContext", "Failed to find behavior sync entry with sync id (%i)!", syncId);
return;
}
auto* behavior = entry.behavior;
const auto branch = entry.branchContext;
2022-07-28 13:39:57 +00:00
if (behavior == nullptr) {
Game::logger->Log("BehaviorContext", "Invalid behavior for sync id (%i)!", syncId);
return;
}
behavior->Sync(this, bitStream, branch);
}
2022-07-28 13:39:57 +00:00
void BehaviorContext::Update(const float deltaTime) {
for (auto i = 0u; i < this->timerEntries.size(); ++i) {
auto entry = this->timerEntries.at(i);
2022-07-28 13:39:57 +00:00
if (entry.time > 0) {
entry.time -= deltaTime;
this->timerEntries[i] = entry;
}
2022-07-28 13:39:57 +00:00
if (entry.time > 0) {
continue;
}
entry.behavior->Timer(this, entry.branchContext, entry.second);
}
std::vector<BehaviorTimerEntry> valid;
2022-07-28 13:39:57 +00:00
for (const auto& entry : this->timerEntries) {
if (entry.time <= 0) {
continue;
}
valid.push_back(entry);
}
this->timerEntries = valid;
}
2022-07-28 13:39:57 +00:00
void BehaviorContext::SyncCalculation(const uint32_t syncId, const float time, Behavior* behavior, const BehaviorBranchContext& branch, const bool ignoreInterrupts) {
BehaviorSyncEntry entry;
entry.behavior = behavior;
entry.time = time;
entry.branchContext = branch;
entry.handle = syncId;
entry.ignoreInterrupts = ignoreInterrupts;
this->syncEntries.push_back(entry);
}
void BehaviorContext::UpdatePlayerSyncs(float deltaTime) {
uint32_t i = 0;
while (i < this->syncEntries.size()) {
auto& entry = this->syncEntries.at(i);
entry.time -= deltaTime;
if (entry.time >= 0.0f) {
i++;
continue;
}
this->syncEntries.erase(this->syncEntries.begin() + i);
}
}
2022-07-28 13:39:57 +00:00
void BehaviorContext::InvokeEnd(const uint32_t id) {
std::vector<BehaviorEndEntry> entries;
2022-07-28 13:39:57 +00:00
for (const auto& entry : this->endEntries) {
if (entry.start == id) {
entry.behavior->End(this, entry.branchContext, entry.second);
continue;
}
entries.push_back(entry);
}
this->endEntries = entries;
}
2022-07-28 13:39:57 +00:00
bool BehaviorContext::CalculateUpdate(const float deltaTime) {
auto any = false;
2022-07-28 13:39:57 +00:00
for (auto i = 0u; i < this->syncEntries.size(); ++i) {
auto entry = this->syncEntries.at(i);
2022-07-28 13:39:57 +00:00
if (entry.time > 0) {
entry.time -= deltaTime;
this->syncEntries[i] = entry;
}
2022-07-28 13:39:57 +00:00
if (entry.time > 0) {
any = true;
continue;
}
// Echo sync
EchoSyncSkill echo;
echo.bDone = true;
echo.uiBehaviorHandle = entry.handle;
echo.uiSkillHandle = this->skillUId;
auto* bitStream = new RakNet::BitStream();
// Calculate sync
entry.behavior->SyncCalculation(this, bitStream, entry.branchContext);
2022-07-28 13:39:57 +00:00
if (!clientInitalized) {
echo.sBitStream.assign((char*)bitStream->GetData(), bitStream->GetNumberOfBytesUsed());
// Write message
RakNet::BitStream message;
PacketUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
message.Write(this->originator);
echo.Serialize(&message);
Game::server->Send(&message, UNASSIGNED_SYSTEM_ADDRESS, true);
}
ExecuteUpdates();
delete bitStream;
}
std::vector<BehaviorSyncEntry> valid;
2022-07-28 13:39:57 +00:00
for (const auto& entry : this->syncEntries) {
if (entry.time <= 0) {
continue;
}
valid.push_back(entry);
}
this->syncEntries = valid;
return any;
}
2022-07-28 13:39:57 +00:00
void BehaviorContext::Interrupt() {
std::vector<BehaviorSyncEntry> keptSync{};
2022-07-28 13:39:57 +00:00
for (const auto& entry : this->syncEntries) {
if (!entry.ignoreInterrupts) continue;
keptSync.push_back(entry);
}
this->syncEntries = keptSync;
}
2022-07-28 13:39:57 +00:00
void BehaviorContext::Reset() {
for (const auto& entry : this->timerEntries) {
entry.behavior->Timer(this, entry.branchContext, entry.second);
}
2022-07-28 13:39:57 +00:00
for (const auto& entry : this->endEntries) {
entry.behavior->End(this, entry.branchContext, entry.second);
}
this->endEntries.clear();
this->timerEntries.clear();
this->syncEntries.clear();
this->scheduledUpdates.clear();
}
2022-07-28 13:39:57 +00:00
std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, int32_t includeFaction, bool targetSelf, bool targetEnemy, bool targetFriend) const {
auto* entity = EntityManager::Instance()->GetEntity(this->caster);
std::vector<LWOOBJID> targets;
2022-07-28 13:39:57 +00:00
if (entity == nullptr) {
Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator);
return targets;
}
2022-07-28 13:39:57 +00:00
if (!ignoreFaction && !includeFaction) {
for (auto entry : entity->GetTargetsInPhantom()) {
auto* instance = EntityManager::Instance()->GetEntity(entry);
2022-07-28 13:39:57 +00:00
if (instance == nullptr) {
continue;
}
targets.push_back(entry);
}
}
if (ignoreFaction || includeFaction || (!entity->HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) && targets.empty())) {
2022-07-28 13:39:57 +00:00
DestroyableComponent* destroyableComponent;
if (!entity->TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) {
return targets;
}
auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS);
2022-07-28 13:39:57 +00:00
for (auto* candidate : entities) {
const auto id = candidate->GetObjectID();
2022-07-28 13:39:57 +00:00
if ((id != entity->GetObjectID() || targetSelf) && destroyableComponent->CheckValidity(id, ignoreFaction || includeFaction, targetEnemy, targetFriend)) {
targets.push_back(id);
}
}
}
return targets;
}
2022-07-28 13:39:57 +00:00
BehaviorContext::BehaviorContext(const LWOOBJID originator, const bool calculation) {
this->originator = originator;
this->syncEntries = {};
this->timerEntries = {};
2022-07-28 13:39:57 +00:00
if (calculation) {
this->skillUId = GetUniqueSkillId();
2022-07-28 13:39:57 +00:00
} else {
this->skillUId = 0;
}
}
2022-07-28 13:39:57 +00:00
BehaviorContext::~BehaviorContext() {
Reset();
}