Merge branch 'DarkflameUniverse:main' into PetFixes

This commit is contained in:
jadebenn 2023-12-09 21:29:35 -06:00 committed by GitHub
commit 93592c775b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 319 additions and 194 deletions

View File

@ -23,6 +23,9 @@ We do not recommend hosting public servers. Darkflame Universe is intended for s
### Supply of resource files
Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed [here](#verifying-your-client-files) to see if a client will work.
## Step by step walkthrough for a single-player server
If you would like a setup for a single player server only on a Windows machine, use the [Native Windows Setup Guide by HailStorm](https://gist.github.com/HailStorm32/169df65a47a104199b5cc57d10fa57de) and skip this README.
## Steps to setup server
* [Clone this repository](#clone-the-repository)
* [Install dependencies](#install-dependencies)

View File

@ -34,7 +34,7 @@ enum class eReplicaComponentType : uint32_t {
PLATFORM_BOUNDARY,
MODULE,
ARCADE,
VEHICLE_PHYSICS, // Havok demo based
HAVOK_VEHICLE_PHYSICS,
MOVEMENT_AI,
EXHIBIT,
OVERHEAD_ICON,
@ -50,11 +50,11 @@ enum class eReplicaComponentType : uint32_t {
PROPERTY_ENTRANCE,
FX,
PROPERTY_MANAGEMENT,
VEHICLE_PHYSICS_NEW, // internal physics based on havok
VEHICLE_PHYSICS,
PHYSICS_SYSTEM,
QUICK_BUILD,
SWITCH,
ZONE_CONTROL, // Minigame
MINI_GAME_CONTROL,
CHANGLING,
CHOICE_BUILD,
PACKAGE,

View File

@ -62,7 +62,7 @@
#include "ModelComponent.h"
#include "ZCompression.h"
#include "PetComponent.h"
#include "VehiclePhysicsComponent.h"
#include "HavokVehiclePhysicsComponent.h"
#include "PossessableComponent.h"
#include "PossessorComponent.h"
#include "ModuleAssemblyComponent.h"
@ -76,7 +76,7 @@
#include "eGameMasterLevel.h"
#include "eReplicaComponentType.h"
#include "eReplicaPacketType.h"
#include "ZoneControlComponent.h"
#include "MiniGameControlComponent.h"
#include "RacingStatsComponent.h"
#include "CollectibleComponent.h"
#include "ItemComponent.h"
@ -217,8 +217,8 @@ void Entity::Initialize() {
AddComponent<PetComponent>(petComponentId);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ZONE_CONTROL) > 0) {
AddComponent<ZoneControlComponent>();
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MINI_GAME_CONTROL) > 0) {
AddComponent<MiniGameControlComponent>();
}
uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::POSSESSABLE);
@ -299,10 +299,10 @@ void Entity::Initialize() {
AddComponent<PhantomPhysicsComponent>()->SetPhysicsEffectActive(false);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VEHICLE_PHYSICS) > 0) {
auto* vehiclePhysicsComponent = AddComponent<VehiclePhysicsComponent>();
vehiclePhysicsComponent->SetPosition(m_DefaultPosition);
vehiclePhysicsComponent->SetRotation(m_DefaultRotation);
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::HAVOK_VEHICLE_PHYSICS) > 0) {
auto* havokVehiclePhysicsComponent = AddComponent<HavokVehiclePhysicsComponent>();
havokVehiclePhysicsComponent->SetPosition(m_DefaultPosition);
havokVehiclePhysicsComponent->SetRotation(m_DefaultRotation);
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) {
@ -554,6 +554,12 @@ void Entity::Initialize() {
Loot::CacheMatrix(activityID);
}
const auto timeBeforeSmash = GetVar<float>(u"tmeSmsh");
if (timeBeforeSmash > 0) {
rebuildComponent->SetTimeBeforeSmash(timeBeforeSmash);
}
const auto compTime = GetVar<float>(u"compTime");
if (compTime > 0) {
@ -738,7 +744,7 @@ void Entity::Initialize() {
!HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) &&
!HasComponent(eReplicaComponentType::PROPERTY) &&
!HasComponent(eReplicaComponentType::RACING_CONTROL) &&
!HasComponent(eReplicaComponentType::VEHICLE_PHYSICS)
!HasComponent(eReplicaComponentType::HAVOK_VEHICLE_PHYSICS)
)
//if (HasComponent(eReplicaComponentType::BASE_COMBAT_AI))
{
@ -1017,9 +1023,9 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
rigidbodyPhantomPhysics->Serialize(outBitStream, bIsInitialUpdate);
}
VehiclePhysicsComponent* vehiclePhysicsComponent;
if (TryGetComponent(eReplicaComponentType::VEHICLE_PHYSICS, vehiclePhysicsComponent)) {
vehiclePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
HavokVehiclePhysicsComponent* havokVehiclePhysicsComponent;
if (TryGetComponent(eReplicaComponentType::HAVOK_VEHICLE_PHYSICS, havokVehiclePhysicsComponent)) {
havokVehiclePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
}
PhantomPhysicsComponent* phantomPhysicsComponent;
@ -1191,9 +1197,9 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
}
}
ZoneControlComponent* zoneControlComponent;
if (TryGetComponent(eReplicaComponentType::ZONE_CONTROL, zoneControlComponent)) {
zoneControlComponent->Serialize(outBitStream, bIsInitialUpdate);
MiniGameControlComponent* miniGameControlComponent;
if (TryGetComponent(eReplicaComponentType::MINI_GAME_CONTROL, miniGameControlComponent)) {
miniGameControlComponent->Serialize(outBitStream, bIsInitialUpdate);
}
// BBB Component, unused currently
@ -1503,7 +1509,7 @@ void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u
destroyableComponent->Smash(source, killType, deathType);
}
void Entity::Kill(Entity* murderer) {
void Entity::Kill(Entity* murderer, const eKillType killType) {
if (!m_PlayerIsReadyForUpdates) return;
for (const auto& cb : m_DieCallbacks) {
@ -1527,7 +1533,7 @@ void Entity::Kill(Entity* murderer) {
bool waitForDeathAnimation = false;
if (destroyableComponent) {
waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0;
waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0 && killType != eKillType::SILENT;
}
// Live waited a hard coded 12 seconds for death animations of type 0 before networking destruction!
@ -1840,7 +1846,7 @@ const NiPoint3& Entity::GetPosition() const {
return simple->GetPosition();
}
auto* vehicel = GetComponent<VehiclePhysicsComponent>();
auto* vehicel = GetComponent<HavokVehiclePhysicsComponent>();
if (vehicel != nullptr) {
return vehicel->GetPosition();
@ -1868,7 +1874,7 @@ const NiQuaternion& Entity::GetRotation() const {
return simple->GetRotation();
}
auto* vehicel = GetComponent<VehiclePhysicsComponent>();
auto* vehicel = GetComponent<HavokVehiclePhysicsComponent>();
if (vehicel != nullptr) {
return vehicel->GetRotation();
@ -1896,7 +1902,7 @@ void Entity::SetPosition(NiPoint3 position) {
simple->SetPosition(position);
}
auto* vehicel = GetComponent<VehiclePhysicsComponent>();
auto* vehicel = GetComponent<HavokVehiclePhysicsComponent>();
if (vehicel != nullptr) {
vehicel->SetPosition(position);
@ -1924,7 +1930,7 @@ void Entity::SetRotation(NiQuaternion rotation) {
simple->SetRotation(rotation);
}
auto* vehicel = GetComponent<VehiclePhysicsComponent>();
auto* vehicel = GetComponent<HavokVehiclePhysicsComponent>();
if (vehicel != nullptr) {
vehicel->SetRotation(rotation);

View File

@ -210,7 +210,7 @@ public:
void RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled);
void Smash(const LWOOBJID source = LWOOBJID_EMPTY, const eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"");
void Kill(Entity* murderer = nullptr);
void Kill(Entity* murderer = nullptr, const eKillType killType = eKillType::SILENT);
void AddRebuildCompleteCallback(const std::function<void(Entity* user)>& callback) const;
void AddCollisionPhantomCallback(const std::function<void(Entity* target)>& callback);
void AddDieCallback(const std::function<void()>& callback);

View File

@ -405,7 +405,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
return;
}
if (Database::Get()->GetCharacterInfo(newName)) {
if (!Database::Get()->GetCharacterInfo(newName)) {
if (IsNamePreapproved(newName)) {
Database::Get()->SetCharacterName(charID, newName);
LOG("Character %s now known as %s", character->GetName().c_str(), newName.c_str());

View File

@ -15,7 +15,7 @@ void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
if (buffComponent == nullptr) return;
buffComponent->ApplyBuff(m_BuffId, m_Duration, context->originator, addImmunity, cancelOnDamaged, cancelOnDeath,
cancelOnLogout, cancelonRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone);
cancelOnLogout, cancelonRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone, m_ApplyOnTeammates);
}
void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
@ -45,4 +45,5 @@ void ApplyBuffBehavior::Load() {
cancelOnUi = GetBoolean("cancel_on_ui");
cancelOnUnequip = GetBoolean("cancel_on_unequip");
cancelOnZone = GetBoolean("cancel_on_zone");
m_ApplyOnTeammates = GetBoolean("apply_on_teammates");
}

View File

@ -31,4 +31,6 @@ public:
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
void Load() override;
private:
bool m_ApplyOnTeammates;
};

View File

@ -38,10 +38,12 @@ void JetPackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit
}
void JetPackBehavior::Load() {
this->m_WarningEffectID = GetInt("warning_effect_id");
this->m_Airspeed = GetFloat("airspeed");
this->m_MaxAirspeed = GetFloat("max_airspeed");
this->m_VerticalVelocity = GetFloat("vertical_velocity");
this->m_EnableHover = GetBoolean("enable_hover");
this->m_BypassChecks = GetBoolean("bypass_checks", true);
this->m_WarningEffectID = GetInt("warning_effect_id", -1);
this->m_Airspeed = GetFloat("airspeed", 10);
this->m_MaxAirspeed = GetFloat("max_airspeed", 15);
this->m_VerticalVelocity = GetFloat("vertical_velocity", 1);
this->m_EnableHover = GetBoolean("enable_hover", false);
// TODO: Implement proper jetpack checks, so we can set this default to false
this->m_BypassChecks = GetBoolean("bypass_checks", true);
}

View File

@ -104,7 +104,7 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
const auto casterPosition = self->GetPosition();
auto reference = self->GetPosition(); //+ m_offset;
auto reference = self->GetPosition() + m_offset;
targets.clear();
@ -114,46 +114,34 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
context->FilterTargets(validTargets, this->m_ignoreFactionList, this->m_includeFactionList, this->m_targetSelf, this->m_targetEnemy, this->m_targetFriend, this->m_targetTeam);
for (auto validTarget : validTargets) {
if (targets.size() >= this->m_maxTargets) {
break;
}
if (std::find(targets.begin(), targets.end(), validTarget) != targets.end()) {
continue;
}
if (targets.size() >= this->m_maxTargets) break;
if (std::find(targets.begin(), targets.end(), validTarget) != targets.end()) continue;
if (validTarget->GetIsDead()) continue;
const auto otherPosition = validTarget->GetPosition();
const auto targetPos = validTarget->GetPosition();
const auto heightDifference = std::abs(otherPosition.y - casterPosition.y);
/*if (otherPosition.y > reference.y && heightDifference > this->m_upperBound || otherPosition.y < reference.y && heightDifference > this->m_lowerBound)
{
// make sure we aren't too high or low in comparison to the targer
const auto heightDifference = std::abs(reference.y - targetPos.y);
if (targetPos.y > reference.y && heightDifference > this->m_upperBound || targetPos.y < reference.y && heightDifference > this->m_lowerBound)
continue;
}*/
const auto forward = self->GetRotation().GetForwardVector();
// forward is a normalized vector of where the caster is facing.
// otherPosition is the position of the target.
// targetPos is the position of the target.
// reference is the position of the caster.
// If we cast a ray forward from the caster, does it come within m_farWidth of the target?
const auto distance = Vector3::Distance(reference, otherPosition);
const auto distance = Vector3::Distance(reference, targetPos);
if (m_method == 2) {
NiPoint3 rayPoint = casterPosition + forward * distance;
if (m_farWidth > 0 && Vector3::DistanceSquared(rayPoint, otherPosition) > this->m_farWidth * this->m_farWidth) {
if (m_farWidth > 0 && Vector3::DistanceSquared(rayPoint, targetPos) > this->m_farWidth * this->m_farWidth)
continue;
}
}
auto normalized = (reference - otherPosition) / distance;
auto normalized = (reference - targetPos) / distance;
const float degreeAngle = std::abs(Vector3::Angle(forward, normalized) * (180 / 3.14) - 180);
if (distance >= this->m_minRange && this->m_maxRange >= distance && degreeAngle <= 2 * this->m_angle) {
targets.push_back(validTarget);
}
@ -167,33 +155,26 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
});
const auto hit = !targets.empty();
bitStream->Write(hit);
if (this->m_checkEnv) {
const auto blocked = false; // TODO
bitStream->Write(blocked);
}
if (hit) {
if (combatAi != nullptr) {
combatAi->LookAt(targets[0]->GetPosition());
}
if (combatAi) combatAi->LookAt(targets[0]->GetPosition());
context->foundTarget = true; // We want to continue with this behavior
const auto count = static_cast<uint32_t>(targets.size());
bitStream->Write(count);
for (auto* target : targets) {
bitStream->Write(target->GetObjectID());
}
for (auto* target : targets) {
branch.target = target->GetObjectID();
this->m_action->Calculate(context, bitStream, branch);
}
} else {
@ -214,8 +195,8 @@ void TacArcBehavior::Load() {
GetFloat("offset_z", 0.0f)
);
this->m_method = GetInt("method", 1);
this->m_upperBound = GetFloat("upper_bound", 4.4f);
this->m_lowerBound = GetFloat("lower_bound", 0.4f);
this->m_upperBound = std::abs(GetFloat("upper_bound", 4.4f));
this->m_lowerBound = std::abs(GetFloat("lower_bound", 0.4f));
this->m_usePickedTarget = GetBoolean("use_picked_target", false);
this->m_useTargetPostion = GetBoolean("use_target_position", false);
this->m_checkEnv = GetBoolean("check_env", false);

View File

@ -11,9 +11,21 @@
#include "EntityManager.h"
#include "CDClientManager.h"
#include "CDSkillBehaviorTable.h"
#include "TeamManager.h"
std::unordered_map<int32_t, std::vector<BuffParameter>> BuffComponent::m_Cache{};
namespace {
std::map<std::string, std::string> BuffFx = {
{ "overtime", "OTB_" },
{ "max_health", "HEALTH_" },
{ "max_imagination", "IMAGINATION_" },
{ "max_armor", "ARMOR_" },
{ "speed", "SPEED_" },
{ "loot", "LOOT_" }
};
}
BuffComponent::BuffComponent(Entity* parent) : Component(parent) {
}
@ -22,32 +34,38 @@ BuffComponent::~BuffComponent() {
void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
if (!bIsInitialUpdate) return;
if (m_Buffs.empty()) {
outBitStream->Write0();
} else {
outBitStream->Write1();
outBitStream->Write(!m_Buffs.empty());
if (!m_Buffs.empty()) {
outBitStream->Write<uint32_t>(m_Buffs.size());
for (const auto& buff : m_Buffs) {
outBitStream->Write<uint32_t>(buff.first);
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
for (const auto& [id, buff] : m_Buffs) {
outBitStream->Write<uint32_t>(id);
outBitStream->Write(buff.time != 0.0f);
if (buff.time != 0.0f) outBitStream->Write(static_cast<uint32_t>(buff.time * 1000.0f));
outBitStream->Write(buff.cancelOnDeath);
outBitStream->Write(buff.cancelOnZone);
outBitStream->Write(buff.cancelOnDamaged);
outBitStream->Write(buff.cancelOnRemoveBuff);
outBitStream->Write(buff.cancelOnUi);
outBitStream->Write(buff.cancelOnLogout);
outBitStream->Write(buff.cancelOnUnequip);
outBitStream->Write0(); // Cancel on Damage Absorb Ran Out. Generally false from what I can tell
outBitStream->Write0();
outBitStream->Write0();
auto* team = TeamManager::Instance()->GetTeam(buff.source);
bool addedByTeammate = false;
if (team) {
addedByTeammate = std::count(team->members.begin(), team->members.end(), m_Parent->GetObjectID()) > 0;
}
outBitStream->Write<uint32_t>(0);
outBitStream->Write(addedByTeammate); // Added by teammate. If source is in the same team as the target, this is true. Otherwise, false.
outBitStream->Write(buff.applyOnTeammates);
if (addedByTeammate) outBitStream->Write(buff.source);
outBitStream->Write<uint32_t>(buff.refCount);
}
}
outBitStream->Write0();
outBitStream->Write0(); // something to do with immunity buffs?
}
void BuffComponent::Update(float deltaTime) {
@ -83,17 +101,55 @@ void BuffComponent::Update(float deltaTime) {
}
}
const std::string& GetFxName(const std::string& buffname) {
const auto& toReturn = BuffFx[buffname];
if (toReturn.empty()) {
LOG_DEBUG("No fx name for %s", buffname.c_str());
}
return toReturn;
}
void BuffComponent::ApplyBuffFx(uint32_t buffId, const BuffParameter& buff) {
std::string fxToPlay;
const auto& buffName = GetFxName(buff.name);
if (buffName.empty()) return;
fxToPlay += std::to_string(buffId);
LOG_DEBUG("Playing %s %i", fxToPlay.c_str(), buff.effectId);
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), buff.effectId, u"cast", fxToPlay, LWOOBJID_EMPTY, 1.07f, 1.0f, false);
}
void BuffComponent::RemoveBuffFx(uint32_t buffId, const BuffParameter& buff) {
std::string fxToPlay;
const auto& buffName = GetFxName(buff.name);
if (buffName.empty()) return;
fxToPlay += std::to_string(buffId);
LOG_DEBUG("Stopping %s", fxToPlay.c_str());
GameMessages::SendStopFXEffect(m_Parent, false, fxToPlay);
}
void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOOBJID source, bool addImmunity,
bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, bool cancelOnRemoveBuff,
bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone) {
bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone, bool applyOnTeammates) {
// Prevent buffs from stacking.
if (HasBuff(id)) {
m_Buffs[id].refCount++;
m_Buffs[id].time = duration;
return;
}
auto* team = TeamManager::Instance()->GetTeam(source);
bool addedByTeammate = false;
if (team) {
addedByTeammate = std::count(team->members.begin(), team->members.end(), m_Parent->GetObjectID()) > 0;
}
GameMessages::SendAddBuff(const_cast<LWOOBJID&>(m_Parent->GetObjectID()), source, (uint32_t)id,
(uint32_t)duration * 1000, addImmunity, cancelOnDamaged, cancelOnDeath,
cancelOnLogout, cancelOnRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone);
cancelOnLogout, cancelOnRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone, addedByTeammate, applyOnTeammates);
float tick = 0;
float stacks = 0;
@ -121,17 +177,43 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
buff.stacks = stacks;
buff.source = source;
buff.behaviorID = behaviorID;
buff.cancelOnDamaged = cancelOnDamaged;
buff.cancelOnDeath = cancelOnDeath;
buff.cancelOnLogout = cancelOnLogout;
buff.cancelOnRemoveBuff = cancelOnRemoveBuff;
buff.cancelOnUi = cancelOnUi;
buff.cancelOnUnequip = cancelOnUnequip;
buff.cancelOnZone = cancelOnZone;
buff.refCount = 1;
m_Buffs.emplace(id, buff);
auto* parent = GetParent();
if (!cancelOnDeath) return;
m_Parent->AddDieCallback([parent, id]() {
LOG_DEBUG("Removing buff %i because parent died", id);
if (!parent) return;
auto* buffComponent = parent->GetComponent<BuffComponent>();
if (buffComponent) buffComponent->RemoveBuff(id, false, false, true);
});
}
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity) {
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity, bool ignoreRefCount) {
const auto& iter = m_Buffs.find(id);
if (iter == m_Buffs.end()) {
return;
}
if (!ignoreRefCount && !iter->second.cancelOnRemoveBuff) {
iter->second.refCount--;
LOG_DEBUG("refCount for buff %i is now %i", id, iter->second.refCount);
if (iter->second.refCount > 0) {
return;
}
}
GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id);
m_Buffs.erase(iter);
@ -146,6 +228,7 @@ bool BuffComponent::HasBuff(int32_t id) {
void BuffComponent::ApplyBuffEffect(int32_t id) {
const auto& parameters = GetBuffParameters(id);
for (const auto& parameter : parameters) {
ApplyBuffFx(id, parameter);
if (parameter.name == "max_health") {
const auto maxHealth = parameter.value;
@ -182,6 +265,7 @@ void BuffComponent::ApplyBuffEffect(int32_t id) {
void BuffComponent::RemoveBuffEffect(int32_t id) {
const auto& parameters = GetBuffParameters(id);
for (const auto& parameter : parameters) {
RemoveBuffFx(id, parameter);
if (parameter.name == "max_health") {
const auto maxHealth = parameter.value;
@ -251,13 +335,25 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
auto* buffEntry = buffElement->FirstChildElement("b");
while (buffEntry != nullptr) {
while (buffEntry) {
int32_t id = buffEntry->IntAttribute("id");
float t = buffEntry->FloatAttribute("t");
float tk = buffEntry->FloatAttribute("tk");
float tt = buffEntry->FloatAttribute("tt");
int32_t s = buffEntry->FloatAttribute("s");
LWOOBJID sr = buffEntry->Int64Attribute("sr");
int32_t b = buffEntry->IntAttribute("b");
int32_t refCount = buffEntry->IntAttribute("refCount");
bool cancelOnDamaged = buffEntry->BoolAttribute("cancelOnDamaged");
bool cancelOnDeath = buffEntry->BoolAttribute("cancelOnDeath");
bool cancelOnLogout = buffEntry->BoolAttribute("cancelOnLogout");
bool cancelOnRemoveBuff = buffEntry->BoolAttribute("cancelOnRemoveBuff");
bool cancelOnUi = buffEntry->BoolAttribute("cancelOnUi");
bool cancelOnUnequip = buffEntry->BoolAttribute("cancelOnUnequip");
bool cancelOnZone = buffEntry->BoolAttribute("cancelOnZone");
bool applyOnTeammates = buffEntry->BoolAttribute("applyOnTeammates");
Buff buff;
buff.id = id;
@ -266,6 +362,18 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
buff.stacks = s;
buff.source = sr;
buff.behaviorID = b;
buff.refCount = refCount;
buff.tickTime = tt;
buff.cancelOnDamaged = cancelOnDamaged;
buff.cancelOnDeath = cancelOnDeath;
buff.cancelOnLogout = cancelOnLogout;
buff.cancelOnRemoveBuff = cancelOnRemoveBuff;
buff.cancelOnUi = cancelOnUi;
buff.cancelOnUnequip = cancelOnUnequip;
buff.cancelOnZone = cancelOnZone;
buff.applyOnTeammates = applyOnTeammates;
m_Buffs.emplace(id, buff);
@ -288,15 +396,27 @@ void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
buffElement->DeleteChildren();
}
for (const auto& buff : m_Buffs) {
for (const auto& [id, buff] : m_Buffs) {
auto* buffEntry = doc->NewElement("b");
if (buff.cancelOnZone || buff.cancelOnLogout) continue;
buffEntry->SetAttribute("id", buff.first);
buffEntry->SetAttribute("t", buff.second.time);
buffEntry->SetAttribute("tk", buff.second.tick);
buffEntry->SetAttribute("s", buff.second.stacks);
buffEntry->SetAttribute("sr", buff.second.source);
buffEntry->SetAttribute("b", buff.second.behaviorID);
buffEntry->SetAttribute("id", id);
buffEntry->SetAttribute("t", buff.time);
buffEntry->SetAttribute("tk", buff.tick);
buffEntry->SetAttribute("tt", buff.tickTime);
buffEntry->SetAttribute("s", buff.stacks);
buffEntry->SetAttribute("sr", buff.source);
buffEntry->SetAttribute("b", buff.behaviorID);
buffEntry->SetAttribute("refCount", buff.refCount);
buffEntry->SetAttribute("cancelOnDamaged", buff.cancelOnDamaged);
buffEntry->SetAttribute("cancelOnDeath", buff.cancelOnDeath);
buffEntry->SetAttribute("cancelOnLogout", buff.cancelOnLogout);
buffEntry->SetAttribute("cancelOnRemoveBuff", buff.cancelOnRemoveBuff);
buffEntry->SetAttribute("cancelOnUi", buff.cancelOnUi);
buffEntry->SetAttribute("cancelOnUnequip", buff.cancelOnUnequip);
buffEntry->SetAttribute("cancelOnZone", buff.cancelOnZone);
buffEntry->SetAttribute("applyOnTeammates", buff.applyOnTeammates);
buffElement->LinkEndChild(buffEntry);
}
@ -309,8 +429,7 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
return pair->second;
}
auto query = CDClientDatabase::CreatePreppedStmt(
"SELECT * FROM BuffParameters WHERE BuffID = ?;");
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM BuffParameters WHERE BuffID = ?;");
query.bind(1, (int)buffId);
auto result = query.execQuery();
@ -321,11 +440,12 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
BuffParameter param;
param.buffId = buffId;
param.name = result.getStringField(1);
param.value = result.getFloatField(2);
param.name = result.getStringField("ParameterName");
param.value = result.getFloatField("NumberValue");
param.effectId = result.getIntField("EffectID");
if (!result.fieldIsNull(3)) {
std::istringstream stream(result.getStringField(3));
std::istringstream stream(result.getStringField("StringValue"));
std::string token;
while (std::getline(stream, token, ',')) {

View File

@ -14,8 +14,7 @@ class Entity;
/**
* Extra information on effects to apply after applying a buff, for example whether to buff armor, imag or health and by how much
*/
struct BuffParameter
{
struct BuffParameter {
int32_t buffId;
std::string name;
float value;
@ -26,8 +25,7 @@ struct BuffParameter
/**
* Meta information about a buff that can be applied, e.g. how long it's applied, who applied it, etc.
*/
struct Buff
{
struct Buff {
int32_t id = 0;
float time = 0;
float tick = 0;
@ -35,6 +33,15 @@ struct Buff
int32_t stacks = 0;
LWOOBJID source = 0;
int32_t behaviorID = 0;
bool cancelOnDamaged = false;
bool cancelOnDeath = false;
bool cancelOnLogout = false;
bool cancelOnRemoveBuff = false;
bool cancelOnUi = false;
bool cancelOnUnequip = false;
bool cancelOnZone = false;
bool applyOnTeammates = false;
uint32_t refCount = 0;
};
/**
@ -74,14 +81,17 @@ public:
*/
void ApplyBuff(int32_t id, float duration, LWOOBJID source, bool addImmunity = false, bool cancelOnDamaged = false,
bool cancelOnDeath = true, bool cancelOnLogout = false, bool cancelOnRemoveBuff = true,
bool cancelOnUi = false, bool cancelOnUnequip = false, bool cancelOnZone = false);
bool cancelOnUi = false, bool cancelOnUnequip = false, bool cancelOnZone = false, bool applyOnTeammates = false);
void ApplyBuffFx(uint32_t buffId, const BuffParameter& buffName);
void RemoveBuffFx(uint32_t buffId, const BuffParameter& buffName);
/**
* Removes a buff from the parent entity, reversing its effects
* @param id the id of the buff to remove
* @param removeImmunity whether or not to remove immunity on removing the buff
*/
void RemoveBuff(int32_t id, bool fromUnEquip = false, bool removeImmunity = false);
void RemoveBuff(int32_t id, bool fromUnEquip = false, bool removeImmunity = false, bool ignoreRefCount = false);
/**
* Returns whether or not the entity has a buff identified by `id`

View File

@ -43,8 +43,8 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
"SoundTriggerComponent.cpp"
"SwitchComponent.cpp"
"TriggerComponent.cpp"
"VehiclePhysicsComponent.cpp"
"HavokVehiclePhysicsComponent.cpp"
"VendorComponent.cpp"
"ZoneControlComponent.cpp"
"MiniGameControlComponent.cpp"
PARENT_SCOPE
)

View File

@ -10,7 +10,7 @@
#include "InventoryComponent.h"
#include "ControllablePhysicsComponent.h"
#include "EntityManager.h"
#include "VehiclePhysicsComponent.h"
#include "HavokVehiclePhysicsComponent.h"
#include "GameMessages.h"
#include "Item.h"
#include "Amf3.h"

View File

@ -796,7 +796,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
}
}
m_Parent->Kill(owner);
m_Parent->Kill(owner, killType);
}
void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) {

View File

@ -1,7 +1,7 @@
#include "VehiclePhysicsComponent.h"
#include "HavokVehiclePhysicsComponent.h"
#include "EntityManager.h"
VehiclePhysicsComponent::VehiclePhysicsComponent(Entity* parent) : PhysicsComponent(parent) {
HavokVehiclePhysicsComponent::HavokVehiclePhysicsComponent(Entity* parent) : PhysicsComponent(parent) {
m_Velocity = NiPoint3::ZERO;
m_AngularVelocity = NiPoint3::ZERO;
m_IsOnGround = true;
@ -12,45 +12,45 @@ VehiclePhysicsComponent::VehiclePhysicsComponent(Entity* parent) : PhysicsCompon
m_EndBehavior = GeneralUtils::GenerateRandomNumber<uint32_t>(0, 7);
}
void VehiclePhysicsComponent::SetVelocity(const NiPoint3& vel) {
void HavokVehiclePhysicsComponent::SetVelocity(const NiPoint3& vel) {
if (vel == m_Velocity) return;
m_DirtyPosition = true;
m_Velocity = vel;
}
void VehiclePhysicsComponent::SetAngularVelocity(const NiPoint3& vel) {
void HavokVehiclePhysicsComponent::SetAngularVelocity(const NiPoint3& vel) {
if (vel == m_AngularVelocity) return;
m_DirtyPosition = true;
m_AngularVelocity = vel;
}
void VehiclePhysicsComponent::SetIsOnGround(bool val) {
void HavokVehiclePhysicsComponent::SetIsOnGround(bool val) {
if (val == m_IsOnGround) return;
m_DirtyPosition = true;
m_IsOnGround = val;
}
void VehiclePhysicsComponent::SetIsOnRail(bool val) {
void HavokVehiclePhysicsComponent::SetIsOnRail(bool val) {
if (val == m_IsOnRail) return;
m_DirtyPosition = true;
m_IsOnRail = val;
}
void VehiclePhysicsComponent::SetRemoteInputInfo(const RemoteInputInfo& remoteInputInfo) {
void HavokVehiclePhysicsComponent::SetRemoteInputInfo(const RemoteInputInfo& remoteInputInfo) {
if (m_RemoteInputInfo == remoteInputInfo) return;
this->m_RemoteInputInfo = remoteInputInfo;
m_DirtyRemoteInput = true;
}
void VehiclePhysicsComponent::SetDirtyVelocity(bool val) {
void HavokVehiclePhysicsComponent::SetDirtyVelocity(bool val) {
m_DirtyVelocity = val;
}
void VehiclePhysicsComponent::SetDirtyAngularVelocity(bool val) {
void HavokVehiclePhysicsComponent::SetDirtyAngularVelocity(bool val) {
m_DirtyAngularVelocity = val;
}
void VehiclePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
void HavokVehiclePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
outBitStream->Write(bIsInitialUpdate || m_DirtyPosition);
if (bIsInitialUpdate || m_DirtyPosition) {
@ -111,7 +111,7 @@ void VehiclePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bI
outBitStream->Write0();
}
void VehiclePhysicsComponent::Update(float deltaTime) {
void HavokVehiclePhysicsComponent::Update(float deltaTime) {
if (m_SoftUpdate > 5) {
Game::entityManager->SerializeEntity(m_Parent);
m_SoftUpdate = 0;

View File

@ -33,11 +33,11 @@ struct RemoteInputInfo {
/**
* Physics component for vehicles.
*/
class VehiclePhysicsComponent : public PhysicsComponent {
class HavokVehiclePhysicsComponent : public PhysicsComponent {
public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::VEHICLE_PHYSICS;
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::HAVOK_VEHICLE_PHYSICS;
VehiclePhysicsComponent(Entity* parentEntity);
HavokVehiclePhysicsComponent(Entity* parentEntity);
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;

View File

@ -19,7 +19,7 @@
#include "PossessorComponent.h"
#include "PossessableComponent.h"
#include "ModuleAssemblyComponent.h"
#include "VehiclePhysicsComponent.h"
#include "HavokVehiclePhysicsComponent.h"
#include "CharacterComponent.h"
#include "dZoneManager.h"
#include "PropertyManagementComponent.h"
@ -981,7 +981,7 @@ void InventoryComponent::HandlePossession(Item* item) {
auto* mount = Game::entityManager->CreateEntity(info, nullptr, m_Parent);
// Check to see if the mount is a vehicle, if so, flip it
auto* vehicleComponent = mount->GetComponent<VehiclePhysicsComponent>();
auto* vehicleComponent = mount->GetComponent<HavokVehiclePhysicsComponent>();
if (vehicleComponent) characterComponent->SetIsRacing(true);
// Setup the destroyable stats

View File

@ -0,0 +1,5 @@
#include "MiniGameControlComponent.h"
void MiniGameControlComponent::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) {
outBitStream->Write<uint32_t>(0x40000000);
}

View File

@ -0,0 +1,15 @@
#ifndef __MINIGAMECONTROLCOMPONENT__H__
#define __MINIGAMECONTROLCOMPONENT__H__
#include "Component.h"
#include "eReplicaComponentType.h"
class MiniGameControlComponent final : public Component {
public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::MINI_GAME_CONTROL;
MiniGameControlComponent(Entity* parent) : Component(parent) {}
void Serialize(RakNet::BitStream* outBitStream, bool isConstruction);
};
#endif //!__MINIGAMECONTROLCOMPONENT__H__

View File

@ -0,0 +1,5 @@
#include "MinigameComponent.h"
void MinigameComponent::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) {
outBitStream->Write<uint32_t>(0x40000000);
}

View File

@ -164,6 +164,8 @@ public:
LWOCLONEID GetCloneId() { return clone_Id; };
LWOOBJID GetId() const noexcept { return propertyId; }
private:
/**
* This

View File

@ -17,7 +17,7 @@
#include "PossessorComponent.h"
#include "eRacingTaskParam.h"
#include "Spawner.h"
#include "VehiclePhysicsComponent.h"
#include "HavokVehiclePhysicsComponent.h"
#include "dServer.h"
#include "dZoneManager.h"
#include "dConfig.h"

View File

@ -1,5 +0,0 @@
#include "ZoneControlComponent.h"
void ZoneControlComponent::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) {
outBitStream->Write<uint32_t>(0x40000000);
}

View File

@ -1,15 +0,0 @@
#ifndef __ZONECONTROLCOMPONENT__H__
#define __ZONECONTROLCOMPONENT__H__
#include "Component.h"
#include "eReplicaComponentType.h"
class ZoneControlComponent final : public Component {
public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::ZONE_CONTROL;
ZoneControlComponent(Entity* parent) : Component(parent) {}
void Serialize(RakNet::BitStream* outBitStream, bool isConstruction);
};
#endif //!__ZONECONTROLCOMPONENT__H__

View File

@ -71,7 +71,7 @@
#include "MovingPlatformComponent.h"
#include "PetComponent.h"
#include "ModuleAssemblyComponent.h"
#include "VehiclePhysicsComponent.h"
#include "HavokVehiclePhysicsComponent.h"
#include "RenderComponent.h"
#include "PossessableComponent.h"
#include "PossessorComponent.h"
@ -944,14 +944,7 @@ void GameMessages::SendResurrect(Entity* entity) {
destroyableComponent->SetImagination(imaginationToRestore);
}
}
});
auto cont = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS));
if (cont && entity->GetLOT() == 1) {
cont->SetPosition(entity->GetRespawnPosition());
cont->SetRotation(entity->GetRespawnRotation());
}
});
CBITSTREAM;
CMSGHEADER;
@ -1144,18 +1137,16 @@ void GameMessages::SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPo
bitStream.Write(position.y);
bitStream.Write(position.z);
auto con = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS));
if (con) {
auto rot = con->GetRotation();
bitStream.Write(rot.x);
bitStream.Write(rot.y);
bitStream.Write(rot.z);
bitStream.Write(rot.w);
const bool isNotIdentity = rotation != NiQuaternion::IDENTITY;
bitStream.Write(isNotIdentity);
if (isNotIdentity) {
bitStream.Write(rotation.w);
bitStream.Write(rotation.x);
bitStream.Write(rotation.y);
bitStream.Write(rotation.z);
}
//bitStream.Write(position);
//bitStream.Write(rotation);
SystemAddress sysAddr = entity->GetSystemAddress();
SEND_PACKET;
}
@ -4486,7 +4477,7 @@ void GameMessages::SendVehicleNotifyFinishedRace(LWOOBJID objectId, const System
void GameMessages::SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uint32_t buffID, uint32_t msDuration,
bool addImmunity, bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout,
bool cancelOnRemoveBuff, bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone,
bool cancelOnRemoveBuff, bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone, bool addedByTeammate, bool applyOnTeammates,
const SystemAddress& sysAddr) {
CBITSTREAM;
CMSGHEADER;
@ -4494,27 +4485,29 @@ void GameMessages::SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uin
bitStream.Write(objectID);
bitStream.Write(eGameMessageType::ADD_BUFF);
bitStream.Write(false); // Added by teammate
bitStream.Write(false); // Apply on teammates
bitStream.Write(false); // Cancel on damage absorb ran out
bitStream.Write(addedByTeammate); // Added by teammate
bitStream.Write(applyOnTeammates); // Apply on teammates
bitStream.Write(cancelOnDamaged);
bitStream.Write(cancelOnDeath);
bitStream.Write(cancelOnLogout);
bitStream.Write(false); // Cancel on move
bitStream.Write(cancelOnRemoveBuff);
bitStream.Write(cancelOnUi);
bitStream.Write(cancelOnUnequip);
bitStream.Write(cancelOnZone);
bitStream.Write(false); // Ignore immunities
bitStream.Write(addImmunity);
bitStream.Write(false); // Use ref count
bitStream.Write(buffID);
bitStream.Write(msDuration);
bitStream.Write(casterID != LWOOBJID_EMPTY);
if (casterID != LWOOBJID_EMPTY) bitStream.Write(casterID);
bitStream.Write(casterID);
bitStream.Write(casterID);
bitStream.Write(buffID);
bitStream.Write(msDuration != 0);
if (msDuration != 0) bitStream.Write(msDuration);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET;

View File

@ -206,7 +206,7 @@ namespace GameMessages {
void SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uint32_t buffID, uint32_t msDuration,
bool addImmunity = false, bool cancelOnDamaged = false, bool cancelOnDeath = true,
bool cancelOnLogout = false, bool cancelOnRemoveBuff = true, bool cancelOnUi = false,
bool cancelOnUnequip = false, bool cancelOnZone = false, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS);
bool cancelOnUnequip = false, bool cancelOnZone = false, bool addedByTeammate = false, bool applyOnTeammates = false, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS);
void SendToggleGMInvis(LWOOBJID objectId, bool enabled, const SystemAddress& sysAddr);

View File

@ -60,7 +60,7 @@
#include "dpShapeSphere.h"
#include "PossessableComponent.h"
#include "PossessorComponent.h"
#include "VehiclePhysicsComponent.h"
#include "HavokVehiclePhysicsComponent.h"
#include "BuffComponent.h"
#include "SkillComponent.h"
#include "VanityUtilities.h"
@ -1023,9 +1023,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
auto* possassableEntity = Game::entityManager->GetEntity(possessorComponent->GetPossessable());
if (possassableEntity != nullptr) {
auto* vehiclePhysicsComponent = possassableEntity->GetComponent<VehiclePhysicsComponent>();
if (vehiclePhysicsComponent) {
vehiclePhysicsComponent->SetPosition(pos);
auto* havokVehiclePhysicsComponent = possassableEntity->GetComponent<HavokVehiclePhysicsComponent>();
if (havokVehiclePhysicsComponent) {
havokVehiclePhysicsComponent->SetPosition(pos);
Game::entityManager->SerializeEntity(possassableEntity);
} else GameMessages::SendTeleport(possassableEntity->GetObjectID(), pos, NiQuaternion(), sysAddr);
}

View File

@ -27,7 +27,7 @@
#include "Zone.h"
#include "PossessorComponent.h"
#include "PossessableComponent.h"
#include "VehiclePhysicsComponent.h"
#include "HavokVehiclePhysicsComponent.h"
#include "dConfig.h"
#include "CharacterComponent.h"
#include "Database.h"
@ -187,17 +187,17 @@ void ClientPackets::HandleClientPositionUpdate(const SystemAddress& sysAddr, Pac
if (possessableComponent->GetPossessionType() != ePossessionType::ATTACHED_VISIBLE) updateChar = false;
}
auto* vehiclePhysicsComponent = possassableEntity->GetComponent<VehiclePhysicsComponent>();
if (vehiclePhysicsComponent != nullptr) {
vehiclePhysicsComponent->SetPosition(position);
vehiclePhysicsComponent->SetRotation(rotation);
vehiclePhysicsComponent->SetIsOnGround(onGround);
vehiclePhysicsComponent->SetIsOnRail(onRail);
vehiclePhysicsComponent->SetVelocity(velocity);
vehiclePhysicsComponent->SetDirtyVelocity(velocityFlag);
vehiclePhysicsComponent->SetAngularVelocity(angVelocity);
vehiclePhysicsComponent->SetDirtyAngularVelocity(angVelocityFlag);
vehiclePhysicsComponent->SetRemoteInputInfo(remoteInput);
auto* havokVehiclePhysicsComponent = possassableEntity->GetComponent<HavokVehiclePhysicsComponent>();
if (havokVehiclePhysicsComponent != nullptr) {
havokVehiclePhysicsComponent->SetPosition(position);
havokVehiclePhysicsComponent->SetRotation(rotation);
havokVehiclePhysicsComponent->SetIsOnGround(onGround);
havokVehiclePhysicsComponent->SetIsOnRail(onRail);
havokVehiclePhysicsComponent->SetVelocity(velocity);
havokVehiclePhysicsComponent->SetDirtyVelocity(velocityFlag);
havokVehiclePhysicsComponent->SetAngularVelocity(angVelocity);
havokVehiclePhysicsComponent->SetDirtyAngularVelocity(angVelocityFlag);
havokVehiclePhysicsComponent->SetRemoteInputInfo(remoteInput);
} else {
// Need to get the mount's controllable physics
auto* controllablePhysicsComponent = possassableEntity->GetComponent<ControllablePhysicsComponent>();

View File

@ -101,7 +101,7 @@ void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) {
missionComponent->Progress(
eMissionTaskType::VISIT_PROPERTY,
mapID.GetMapID(),
mapID.GetCloneID()
PropertyManagementComponent::Instance()->GetId()
);
}
}