Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions dChatServer/PlayerContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,7 @@ void PlayerContainer::RemovePlayer(const LWOOBJID playerID) {
auto* team = TeamContainer::GetTeam(playerID);

if (team != nullptr) {
const auto memberName = GeneralUtils::UTF8ToUTF16(player.playerName);

for (const auto memberId : team->memberIDs) {
const auto& otherMember = GetPlayerData(memberId);

if (!otherMember) continue;

TeamContainer::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 });
}
TeamContainer::RemoveMember(team, playerID, false, false, true);
}

ChatWeb::SendWSPlayerUpdate(player, eActivityType::PlayerLoggedOut);
Expand Down
33 changes: 30 additions & 3 deletions dCommon/Amf3.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include "dCommonVars.h"
#include "Logger.h"
#include "Game.h"

#include <type_traits>
#include <unordered_map>
#include <vector>
Expand Down Expand Up @@ -368,9 +367,37 @@ class AMFArrayValue : public AMFBaseValue {
}

template<typename AmfType = AMFArrayValue>
AmfType& PushDebug(const std::string_view name) {
AmfType& PushDebug(const std::string_view name, const std::string& objectType = "", const uint32_t warningLevel = 0) {
size_t i = 0;
for (; i < m_Dense.size(); i++) {
const auto& cast = dynamic_cast<AMFArrayValue*>(m_Dense[i].get());
if (!cast) continue;

const auto& nameValue = cast->Get<std::string>("name");
if (!nameValue || nameValue->GetValue() != name) continue;

if (!objectType.empty()) {
cast->Insert<std::string>("type", objectType);
}

if (warningLevel != 0) {
cast->Insert<double>("warningLevel", warningLevel);
}

// found a duplicate, return this instead
auto valueCast = dynamic_cast<AmfType*>(cast->Get("value"));
if (valueCast) return *valueCast;
}

auto* value = PushArray();
value->Insert("name", name.data());
value->Insert<std::string>("name", name.data());
if (!objectType.empty()) {
value->Insert<std::string>("type", objectType);
}

if (warningLevel != 0) {
value->Insert<double>("warningLevel", warningLevel);
}
return value->Insert<AmfType>("value", std::make_unique<AmfType>());
}

Expand Down
8 changes: 8 additions & 0 deletions dCommon/LDFFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,14 @@ struct LwoNameValue {
this->Erase(GeneralUtils::ASCIIToUTF16(key));
}

ValueType::iterator find(const ValueType::key_type& key) {
return this->values.find(key);
}

ValueType::const_iterator find(const ValueType::key_type& key) const {
return this->values.find(key);
}

LwoNameValue() = default;

LwoNameValue(const LwoNameValue& other) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,11 @@ std::vector<CDObjectSkills> CDObjectSkillsTable::Query(std::function<bool(CDObje

return data;
}

std::vector<CDObjectSkills> CDObjectSkillsTable::Get(const LOT lot) const {
std::vector<CDObjectSkills> toReturn;
for (const auto& entry : GetEntries()) {
if (entry.objectTemplate == lot) toReturn.push_back(entry);
}
return toReturn;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
#include "CDTable.h"

#include <cstdint>
#include <vector>

struct CDObjectSkills {
uint32_t objectTemplate; //!< The LOT of the item
uint32_t skillID; //!< The Skill ID of the object
uint32_t castOnType; //!< ???
uint32_t AICombatWeight; //!< ???
int32_t AICombatWeight; //!< ???
};

class CDObjectSkillsTable : public CDTable<CDObjectSkillsTable, std::vector<CDObjectSkills>> {
public:
void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause
std::vector<CDObjectSkills> Query(std::function<bool(CDObjectSkills)> predicate);
std::vector<CDObjectSkills> Get(const LOT lot) const;
};

37 changes: 23 additions & 14 deletions dGame/Entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,15 +316,16 @@ void Entity::Initialize() {
controllablePhysics->LoadFromXml(m_Character->GetXMLDoc());

const auto mapID = Game::server->GetZoneID();
const auto& targetSceneName = m_Character->GetTargetScene();

//If we came from another zone, put us in the starting loc
if (m_Character->GetZoneID() != Game::server->GetZoneID() || mapID == 1603) { // Exception for Moon Base as you tend to spawn on the roof.
// Exception for Moon Base as you tend to spawn on the roof.
// second exception if we have a specified targetScene since that would only be possible in a test map
if (m_Character->GetZoneID() != Game::server->GetZoneID() || mapID == 1603 || !targetSceneName.empty()) {
NiPoint3 pos;
NiQuaternion rot = QuatUtils::IDENTITY;

const auto& targetSceneName = m_Character->GetTargetScene();
auto* targetScene = Game::entityManager->GetSpawnPointEntity(targetSceneName);

if (m_Character->HasBeenToWorld(mapID) && targetSceneName.empty()) {
pos = m_Character->GetRespawnPoint(mapID);
rot = Game::zoneManager->GetZone()->GetSpawnRot();
Expand Down Expand Up @@ -612,14 +613,15 @@ void Entity::Initialize() {

if (rebuildResetTime != 0.0f) {
quickBuildComponent->SetResetTime(rebuildResetTime);

// Known bug with moving platform in FV that casues it to build at the end instead of the start.
// This extends the smash time so players can ride up the lift.
if (m_TemplateID == 9483) {
quickBuildComponent->SetResetTime(quickBuildComponent->GetResetTime() + 25);
}
}

const auto objectID = GetObjectID();
// FV tree handler for when built so it sets the state to moving at the correct time
if (GetLOT() == 9483) quickBuildComponent->AddQuickBuildCompleteCallback([objectID](Entity* user) {
auto* const entity = Game::entityManager->GetEntity(objectID);
if (entity) GameMessages::SendPlatformResync(entity, UNASSIGNED_SYSTEM_ADDRESS, false, 0, 1, 1, eMovementPlatformState::Moving, true);
});

const auto activityID = GetVar<int32_t>(u"activityID");

if (activityID > 0) {
Expand Down Expand Up @@ -1017,6 +1019,7 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream& outBitStream, eReplicaPacke
const bool hasParent = m_ParentEntity != nullptr || m_SpawnerID != 0;
outBitStream.Write(hasParent);
if (hasParent) {
// 触るな!
if (m_ParentEntity != nullptr) outBitStream.Write(GeneralUtils::SetBit(m_ParentEntity->GetObjectID(), static_cast<uint32_t>(eObjectBits::CLIENT)));
else if (m_Spawner != nullptr && m_Spawner->m_Info.isNetwork) outBitStream.Write(m_SpawnerID);
else outBitStream.Write(GeneralUtils::SetBit(m_SpawnerID, static_cast<uint32_t>(eObjectBits::CLIENT)));
Expand Down Expand Up @@ -1615,7 +1618,7 @@ void Entity::Kill(Entity* murderer, const eKillType killType) {

const auto& grpNameQBShowBricks = GetVarAsString(u"grpNameQBShowBricks");
if (!grpNameQBShowBricks.empty()) {
for (auto* const spawner : Game::zoneManager->GetSpawnersByName(grpNameQBShowBricks)) if (spawner) spawner->Spawn();
for (auto* const spawner : Game::zoneManager->GetSpawnersByName(grpNameQBShowBricks)) if (spawner) spawner->Spawn();
for (auto* const spawner : Game::zoneManager->GetSpawnersInGroup(grpNameQBShowBricks)) if (spawner) spawner->Spawn();
}

Expand Down Expand Up @@ -2233,10 +2236,16 @@ bool Entity::MsgRequestServerObjectInfo(GameMessages::RequestServerObjectInfo& r

const auto& objTableInfo = table->GetByID(GetLOT());

objectInfo.PushDebug<AMFStringValue>("Name") = objTableInfo.name;
objectInfo.PushDebug<AMFIntValue>("Template ID(LOT)") = GetLOT();
objectInfo.PushDebug<AMFStringValue>("Object ID") = std::to_string(GetObjectID());
objectInfo.PushDebug<AMFStringValue>("Spawner's Object ID") = std::to_string(GetSpawnerID());
objectInfo.PushDebug<AMFStringValue>("Name", "name") = objTableInfo.name;
objectInfo.PushDebug<AMFIntValue>("Template ID(LOT)", "LOT") = GetLOT();
objectInfo.PushDebug<AMFStringValue>("Object ID", "LWOOBJID") = std::to_string(GetObjectID());
objectInfo.PushDebug<AMFStringValue>("Spawner's Object ID", "LWOOBJID") = std::to_string(GetSpawnerID());
objectInfo.PushDebug<AMFStringValue>("Owner override", "LWOOBJID") = std::to_string(m_OwnerOverride);
auto& children = objectInfo.PushDebug("Child Objects");
int i = 1;
for (const auto* child : m_ChildEntities) {
if (child) children.PushDebug<AMFStringValue>("Child " + std::to_string(i++), "LWOOBJID") = std::to_string(child->GetObjectID());
}

auto& componentDetails = objectInfo.PushDebug("Component Information");
for (const auto [id, component] : m_Components) {
Expand Down
30 changes: 25 additions & 5 deletions dGame/dBehaviors/NpcCombatSkillBehavior.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,40 @@

void NpcCombatSkillBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) {
context->skillTime = this->m_npcSkillTime;
const auto* const targetEntity = Game::entityManager->GetEntity(branch.target);
const auto* const sourceEntity = Game::entityManager->GetEntity(context->caster);

for (auto* behavior : this->m_behaviors) {
behavior->Calculate(context, bit_stream, branch);
bool cast = true;
// Check that the target is within the cast range
if (targetEntity && sourceEntity && this->m_maxRange != 0.0f) {
const auto targetPos = targetEntity->GetPosition();
const auto sourcePos = sourceEntity->GetPosition();
const auto distance = NiPoint3::DistanceSquared(targetPos, sourcePos);
cast = distance >= this->m_minRange && distance <= this->m_maxRange;
}

if (cast) {
for (auto* behavior : this->m_behaviors) {
behavior->Calculate(context, bit_stream, branch);
}
} else {
// We failed to find a valid target, do not continue the behavior
context->foundTarget = false;
}
}

void NpcCombatSkillBehavior::Load() {
this->m_npcSkillTime = GetFloat("npc skill time");
this->m_minRange = GetFloat("min range") * 0.9f; // Make the min and max 10% smaller to account for server/client position disagreements
this->m_minRange *= this->m_minRange;
this->m_maxRange = GetFloat("max range") * 0.9f; // Make the min and max 10% smaller to account for server/client position disagreements
this->m_maxRange *= this->m_maxRange;

const auto parameters = GetParameterNames();

for (const auto& parameter : parameters) {
if (parameter.first.rfind("behavior", 0) == 0) {
auto* action = GetAction(parameter.second);
for (const auto& [parameter, value] : parameters) {
if (parameter.rfind("behavior", 0) == 0) {
auto* action = GetAction(value);

this->m_behaviors.push_back(action);
}
Expand Down
3 changes: 3 additions & 0 deletions dGame/dBehaviors/NpcCombatSkillBehavior.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ class NpcCombatSkillBehavior final : public Behavior

float m_npcSkillTime;

float m_maxRange{};
float m_minRange{};

/*
* Inherited
*/
Expand Down
3 changes: 2 additions & 1 deletion dGame/dBehaviors/VerifyBehavior.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void VerifyBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitS

const auto distance = Vector3::DistanceSquared(self->GetPosition(), entity->GetPosition());

if (distance > this->m_range * this->m_range) {
if (distance > this->m_range) {
success = false;
}
} else if (this->m_blockCheck) {
Expand Down Expand Up @@ -57,4 +57,5 @@ void VerifyBehavior::Load() {
this->m_action = GetAction("action");

this->m_range = GetFloat("range");
this->m_range = this->m_range * this->m_range * 0.9f; // Range checks are slightly smaller than the actual range to account for client/server discrepancies
}
Loading
Loading