mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-12-25 23:13:35 +00:00
455f9470a5
* Move EntityManager to Game namespace * move initialization to later Need to wait for dZoneManager to be initialized. * Fix bugs - Cannot delete from a RandomAccessIterator while in a range based for loop. Touchup zone manager initialize replace magic numbers with better named constants replace magic zonecontrol id with a more readable hex alternative condense stack variables move initializers closer to their use initialize entity manager with zone control change initialize timings If zone is not zero we expect to initialize the entity manager during zone manager initialization Add constexpr for zone control LOT * Add proper error handling * revert vanity changes * Update WorldServer.cpp * Update dZoneManager.cpp
368 lines
8.5 KiB
C++
368 lines
8.5 KiB
C++
#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"
|
|
|
|
BehaviorSyncEntry::BehaviorSyncEntry() {
|
|
}
|
|
|
|
BehaviorTimerEntry::BehaviorTimerEntry() {
|
|
}
|
|
|
|
BehaviorEndEntry::BehaviorEndEntry() {
|
|
}
|
|
|
|
uint32_t BehaviorContext::GetUniqueSkillId() const {
|
|
auto* entity = Game::entityManager->GetEntity(this->originator);
|
|
|
|
if (entity == nullptr) {
|
|
Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator);
|
|
|
|
return 0;
|
|
}
|
|
|
|
auto* component = entity->GetComponent<SkillComponent>();
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void BehaviorContext::ExecuteUpdates() {
|
|
for (const auto& id : this->scheduledUpdates) {
|
|
auto* entity = Game::entityManager->GetEntity(id);
|
|
|
|
if (entity == nullptr) continue;
|
|
|
|
Game::entityManager->SerializeEntity(entity);
|
|
}
|
|
|
|
this->scheduledUpdates.clear();
|
|
}
|
|
|
|
void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream* bitStream) {
|
|
BehaviorSyncEntry entry;
|
|
auto found = false;
|
|
|
|
/*
|
|
* There may be more than one of each handle
|
|
*/
|
|
for (auto i = 0u; i < this->syncEntries.size(); ++i) {
|
|
const auto syncEntry = this->syncEntries.at(i);
|
|
|
|
if (syncEntry.handle == syncId) {
|
|
found = true;
|
|
entry = syncEntry;
|
|
|
|
this->syncEntries.erase(this->syncEntries.begin() + i);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
if (behavior == nullptr) {
|
|
Game::logger->Log("BehaviorContext", "Invalid behavior for sync id (%i)!", syncId);
|
|
|
|
return;
|
|
}
|
|
|
|
behavior->Sync(this, bitStream, branch);
|
|
}
|
|
|
|
|
|
void BehaviorContext::Update(const float deltaTime) {
|
|
for (auto i = 0u; i < this->timerEntries.size(); ++i) {
|
|
auto entry = this->timerEntries.at(i);
|
|
|
|
if (entry.time > 0) {
|
|
entry.time -= deltaTime;
|
|
|
|
this->timerEntries[i] = entry;
|
|
}
|
|
|
|
if (entry.time > 0) {
|
|
continue;
|
|
}
|
|
|
|
entry.behavior->Timer(this, entry.branchContext, entry.second);
|
|
}
|
|
|
|
std::vector<BehaviorTimerEntry> valid;
|
|
|
|
for (const auto& entry : this->timerEntries) {
|
|
if (entry.time <= 0) {
|
|
continue;
|
|
}
|
|
|
|
valid.push_back(entry);
|
|
}
|
|
|
|
this->timerEntries = valid;
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
void BehaviorContext::InvokeEnd(const uint32_t id) {
|
|
std::vector<BehaviorEndEntry> entries;
|
|
|
|
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;
|
|
}
|
|
|
|
bool BehaviorContext::CalculateUpdate(const float deltaTime) {
|
|
auto any = false;
|
|
|
|
for (auto i = 0u; i < this->syncEntries.size(); ++i) {
|
|
auto entry = this->syncEntries.at(i);
|
|
|
|
if (entry.time > 0) {
|
|
entry.time -= deltaTime;
|
|
|
|
this->syncEntries[i] = entry;
|
|
}
|
|
|
|
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);
|
|
|
|
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;
|
|
|
|
for (const auto& entry : this->syncEntries) {
|
|
if (entry.time <= 0) {
|
|
continue;
|
|
}
|
|
|
|
valid.push_back(entry);
|
|
}
|
|
|
|
this->syncEntries = valid;
|
|
|
|
return any;
|
|
}
|
|
|
|
void BehaviorContext::Interrupt() {
|
|
std::vector<BehaviorSyncEntry> keptSync{};
|
|
|
|
for (const auto& entry : this->syncEntries) {
|
|
if (!entry.ignoreInterrupts) continue;
|
|
|
|
keptSync.push_back(entry);
|
|
}
|
|
|
|
this->syncEntries = keptSync;
|
|
}
|
|
|
|
void BehaviorContext::Reset() {
|
|
for (const auto& entry : this->timerEntries) {
|
|
entry.behavior->Timer(this, entry.branchContext, entry.second);
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, int32_t includeFaction, bool targetSelf, bool targetEnemy, bool targetFriend) const {
|
|
auto* entity = Game::entityManager->GetEntity(this->caster);
|
|
|
|
std::vector<LWOOBJID> targets;
|
|
|
|
if (entity == nullptr) {
|
|
Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator);
|
|
|
|
return targets;
|
|
}
|
|
|
|
if (!ignoreFaction && !includeFaction) {
|
|
for (auto entry : entity->GetTargetsInPhantom()) {
|
|
auto* instance = Game::entityManager->GetEntity(entry);
|
|
|
|
if (instance == nullptr) {
|
|
continue;
|
|
}
|
|
|
|
targets.push_back(entry);
|
|
}
|
|
}
|
|
|
|
if (ignoreFaction || includeFaction || (!entity->HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) && targets.empty())) {
|
|
DestroyableComponent* destroyableComponent;
|
|
if (!entity->TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) {
|
|
return targets;
|
|
}
|
|
|
|
auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS);
|
|
for (auto* candidate : entities) {
|
|
const auto id = candidate->GetObjectID();
|
|
|
|
if ((id != entity->GetObjectID() || targetSelf) && destroyableComponent->CheckValidity(id, ignoreFaction || includeFaction, targetEnemy, targetFriend)) {
|
|
targets.push_back(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
return targets;
|
|
}
|
|
|
|
|
|
BehaviorContext::BehaviorContext(const LWOOBJID originator, const bool calculation) {
|
|
this->originator = originator;
|
|
this->syncEntries = {};
|
|
this->timerEntries = {};
|
|
|
|
if (calculation) {
|
|
this->skillUId = GetUniqueSkillId();
|
|
} else {
|
|
this->skillUId = 0;
|
|
}
|
|
}
|
|
|
|
BehaviorContext::~BehaviorContext() {
|
|
Reset();
|
|
}
|