mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-17 03:37:08 -06:00
Compare commits
16 Commits
fix-empty-
...
v3.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3890c0a86c | ||
|
|
c083f21e44 | ||
|
|
c9e95839ee | ||
|
|
dd957ed0c7 | ||
|
|
12296ce553 | ||
|
|
24f4c9d413 | ||
|
|
ba964932b7 | ||
|
|
4c42eea819 | ||
|
|
6b52cf67a0 | ||
|
|
71f708f1b5 | ||
|
|
49aa632d42 | ||
|
|
5ec4142ca1 | ||
|
|
5e9fe40bec | ||
|
|
9524198044 | ||
|
|
a5d0788488 | ||
|
|
a1ba5b8f12 |
@@ -187,7 +187,8 @@ Now that you are logged in, run the following commands.
|
||||
```bash
|
||||
# Creates a user for this computer which uses a password and grant said user all privileges.
|
||||
# Change mydarkflameuser to a custom username and password to a custom password.
|
||||
GRANT ALL ON *.* TO 'mydarkflameuser'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION;
|
||||
CREATE USER 'mydarkflameuser'@'localhost' IDENTIFIED BY 'password';
|
||||
GRANT ALL ON *.* TO 'mydarkflameuser'@'localhost' WITH GRANT OPTION;
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
# Then create a database for Darkflame Universe to use.
|
||||
|
||||
@@ -237,6 +237,57 @@ bool GeneralUtils::ReplaceInString(std::string& str, const std::string_view from
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::wstring> GeneralUtils::SplitString(const std::wstring_view str, const wchar_t delimiter) {
|
||||
std::vector<std::wstring> vector = std::vector<std::wstring>();
|
||||
std::wstring current;
|
||||
|
||||
for (const wchar_t c : str) {
|
||||
if (c == delimiter) {
|
||||
vector.push_back(current);
|
||||
current = L"";
|
||||
} else {
|
||||
current += c;
|
||||
}
|
||||
}
|
||||
|
||||
vector.push_back(std::move(current));
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string_view str, const char16_t delimiter) {
|
||||
std::vector<std::u16string> vector = std::vector<std::u16string>();
|
||||
std::u16string current;
|
||||
|
||||
for (const char16_t c : str) {
|
||||
if (c == delimiter) {
|
||||
vector.push_back(current);
|
||||
current = u"";
|
||||
} else {
|
||||
current += c;
|
||||
}
|
||||
}
|
||||
|
||||
vector.push_back(std::move(current));
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::vector<std::string> GeneralUtils::SplitString(const std::string_view str, const char delimiter) {
|
||||
std::vector<std::string> vector = std::vector<std::string>();
|
||||
std::string current = "";
|
||||
|
||||
for (const char c : str) {
|
||||
if (c == delimiter) {
|
||||
vector.push_back(current);
|
||||
current = "";
|
||||
} else {
|
||||
current += c;
|
||||
}
|
||||
}
|
||||
|
||||
vector.push_back(std::move(current));
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) {
|
||||
uint32_t length;
|
||||
inStream.Read<uint32_t>(length);
|
||||
|
||||
@@ -130,23 +130,11 @@ namespace GeneralUtils {
|
||||
|
||||
std::u16string ReadWString(RakNet::BitStream& inStream);
|
||||
|
||||
template<typename StringType, typename CharType = typename StringType::value_type>
|
||||
std::vector<std::basic_string<CharType>> SplitString(const StringType& str, const typename StringType::value_type delimiter) {
|
||||
std::vector<std::basic_string<CharType>> toReturn{};
|
||||
std::vector<std::wstring> SplitString(const std::wstring_view str, const wchar_t delimiter);
|
||||
|
||||
toReturn.emplace_back();
|
||||
auto itr = toReturn.rbegin();
|
||||
for (const auto c : str) {
|
||||
if (c == delimiter) {
|
||||
toReturn.emplace_back();
|
||||
itr = toReturn.rbegin();
|
||||
} else {
|
||||
(*itr).push_back(c);
|
||||
}
|
||||
}
|
||||
std::vector<std::u16string> SplitString(const std::u16string_view str, const char16_t delimiter);
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
std::vector<std::string> SplitString(const std::string_view str, const char delimiter);
|
||||
|
||||
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string_view folder);
|
||||
|
||||
@@ -312,6 +300,12 @@ namespace GeneralUtils {
|
||||
return T();
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
inline Container::value_type GetRandomElement(const Container& container) {
|
||||
DluAssert(!container.empty());
|
||||
return container[GenerateRandomNumber<typename Container::value_type>(0, container.size() - 1)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts the value of an enum entry to its underlying type
|
||||
* @param entry Enum entry to cast
|
||||
|
||||
@@ -97,6 +97,8 @@
|
||||
#include "CDSkillBehaviorTable.h"
|
||||
#include "CDZoneTableTable.h"
|
||||
|
||||
#include "StringifiedEnum.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
Observable<Entity*, const PositionUpdate&> Entity::OnPlayerPositionUpdate;
|
||||
@@ -187,6 +189,7 @@ Entity::~Entity() {
|
||||
}
|
||||
|
||||
void Entity::Initialize() {
|
||||
RegisterMsg(MessageType::Game::REQUEST_SERVER_OBJECT_INFO, this, &Entity::MsgRequestServerObjectInfo);
|
||||
/**
|
||||
* Setup trigger
|
||||
*/
|
||||
@@ -920,7 +923,7 @@ void Entity::WriteLDFData(const std::vector<LDFBaseData*>& ldf, RakNet::BitStrea
|
||||
numberOfValidKeys--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now write it to the main bitstream
|
||||
outBitStream.Write<uint32_t>(settingStream.GetNumberOfBytesUsed() + 1 + sizeof(uint32_t));
|
||||
outBitStream.Write<uint8_t>(0); //no compression used
|
||||
@@ -1662,11 +1665,9 @@ void Entity::PickupItem(const LWOOBJID& objectID) const {
|
||||
auto* const skillsTable = CDClientManager::GetTable<CDObjectSkillsTable>();
|
||||
const auto skills = skillsTable->Query([&info](CDObjectSkills entry) {return (entry.objectTemplate == info.lot); });
|
||||
for (const auto& skill : skills) {
|
||||
auto* skillComponent = GetComponent<SkillComponent>();
|
||||
const auto [skillComponent, missionComponent] = GetComponentsMut<SkillComponent, MissionComponent>();
|
||||
if (skillComponent) skillComponent->CastSkill(skill.skillID, GetObjectID(), GetObjectID(), skill.castOnType, NiQuaternion(0, 0, 0, 0));
|
||||
|
||||
auto* missionComponent = GetComponent<MissionComponent>();
|
||||
|
||||
if (missionComponent != nullptr) {
|
||||
missionComponent->Progress(eMissionTaskType::POWERUP, skill.skillID);
|
||||
}
|
||||
@@ -2211,3 +2212,38 @@ bool Entity::HandleMsg(GameMessages::GameMsg& msg) const {
|
||||
void Entity::RegisterMsg(const MessageType::Game msgId, std::function<bool(GameMessages::GameMsg&)> handler) {
|
||||
m_MsgHandlers.emplace(msgId, handler);
|
||||
}
|
||||
|
||||
bool Entity::MsgRequestServerObjectInfo(GameMessages::GameMsg& msg) {
|
||||
auto& requestInfo = static_cast<GameMessages::RequestServerObjectInfo&>(msg);
|
||||
AMFArrayValue response;
|
||||
response.Insert("visible", true);
|
||||
response.Insert("objectID", std::to_string(m_ObjectID));
|
||||
response.Insert("serverInfo", true);
|
||||
GameMessages::GetObjectReportInfo info{};
|
||||
info.info = response.InsertArray("data");
|
||||
auto& objectInfo = info.info->PushDebug("Object Details");
|
||||
auto* table = CDClientManager::GetTable<CDObjectsTable>();
|
||||
|
||||
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());
|
||||
|
||||
auto& componentDetails = objectInfo.PushDebug("Component Information");
|
||||
for (const auto [id, component] : m_Components) {
|
||||
componentDetails.PushDebug<AMFStringValue>(StringifiedEnum::ToString(id)) = "";
|
||||
}
|
||||
|
||||
auto& configData = objectInfo.PushDebug("Config Data");
|
||||
for (const auto config : m_Settings) {
|
||||
configData.PushDebug<AMFStringValue>(GeneralUtils::UTF16ToWTF8(config->GetKey())) = config->GetValueAsString();
|
||||
|
||||
}
|
||||
HandleMsg(info);
|
||||
|
||||
auto* client = Game::entityManager->GetEntity(requestInfo.clientId);
|
||||
if (client) GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, client->GetSystemAddress());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
@@ -161,6 +162,12 @@ public:
|
||||
template<typename T>
|
||||
T* GetComponent() const;
|
||||
|
||||
template<typename... T>
|
||||
auto GetComponents() const;
|
||||
|
||||
template<typename... T>
|
||||
auto GetComponentsMut() const;
|
||||
|
||||
template<typename T>
|
||||
bool TryGetComponent(eReplicaComponentType componentId, T*& component) const;
|
||||
|
||||
@@ -168,6 +175,8 @@ public:
|
||||
|
||||
void AddComponent(eReplicaComponentType componentId, Component* component);
|
||||
|
||||
bool MsgRequestServerObjectInfo(GameMessages::GameMsg& msg);
|
||||
|
||||
// This is expceted to never return nullptr, an assert checks this.
|
||||
CppScripts::Script* const GetScript() const;
|
||||
|
||||
@@ -329,6 +338,10 @@ public:
|
||||
|
||||
bool HandleMsg(GameMessages::GameMsg& msg) const;
|
||||
|
||||
void RegisterMsg(const MessageType::Game msgId, auto* self, const auto handler) {
|
||||
RegisterMsg(msgId, std::bind(handler, self, std::placeholders::_1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The observable for player entity position updates.
|
||||
*/
|
||||
@@ -579,3 +592,13 @@ inline ComponentType* Entity::AddComponent(VaArgs... args) {
|
||||
// To allow a static cast here instead of a dynamic one.
|
||||
return dynamic_cast<ComponentType*>(componentToReturn);
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
auto Entity::GetComponents() const {
|
||||
return GetComponentsMut<const T...>();
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
auto Entity::GetComponentsMut() const {
|
||||
return std::tuple{GetComponent<T>()...};
|
||||
}
|
||||
|
||||
@@ -129,6 +129,8 @@ Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentE
|
||||
// Set the zone control entity if the entity is a zone control object, this should only happen once
|
||||
if (controller) {
|
||||
m_ZoneControlEntity = entity;
|
||||
// Proooooobably shouldn't ghost zoneControl
|
||||
m_ZoneControlEntity->SetIsGhostingCandidate(false);
|
||||
}
|
||||
|
||||
// Check if this entity is a respawn point, if so add it to the registry
|
||||
@@ -279,6 +281,8 @@ std::vector<Entity*> EntityManager::GetEntitiesByComponent(const eReplicaCompone
|
||||
|
||||
withComp.push_back(entity);
|
||||
}
|
||||
} else {
|
||||
for (auto* const entity : m_Entities | std::views::values) withComp.push_back(entity);
|
||||
}
|
||||
return withComp;
|
||||
}
|
||||
@@ -394,7 +398,7 @@ void EntityManager::ConstructAllEntities(const SystemAddress& sysAddr) {
|
||||
}
|
||||
}
|
||||
|
||||
UpdateGhosting(PlayerManager::GetPlayer(sysAddr), true);
|
||||
UpdateGhosting(PlayerManager::GetPlayer(sysAddr));
|
||||
}
|
||||
|
||||
void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) {
|
||||
@@ -463,7 +467,7 @@ void EntityManager::UpdateGhosting() {
|
||||
m_PlayersToUpdateGhosting.clear();
|
||||
}
|
||||
|
||||
void EntityManager::UpdateGhosting(Entity* player, const bool constructAll) {
|
||||
void EntityManager::UpdateGhosting(Entity* player) {
|
||||
if (!player) return;
|
||||
|
||||
auto* missionComponent = player->GetComponent<MissionComponent>();
|
||||
@@ -513,9 +517,6 @@ void EntityManager::UpdateGhosting(Entity* player, const bool constructAll) {
|
||||
|
||||
entity->SetObservers(entity->GetObservers() + 1);
|
||||
|
||||
// TODO: figure out if zone control should be ghosted at all
|
||||
if (constructAll && entity->GetObjectID() == GetZoneControlEntity()->GetObjectID()) continue;
|
||||
|
||||
ConstructEntity(entity, player->GetSystemAddress());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
void SetGhostDistanceMin(float value);
|
||||
void QueueGhostUpdate(LWOOBJID playerID);
|
||||
void UpdateGhosting();
|
||||
void UpdateGhosting(Entity* player, const bool constructAll = false);
|
||||
void UpdateGhosting(Entity* player);
|
||||
void CheckGhosting(Entity* entity);
|
||||
Entity* GetGhostCandidate(LWOOBJID id) const;
|
||||
bool GetGhostingEnabled() const;
|
||||
|
||||
@@ -28,8 +28,11 @@
|
||||
#include "CDActivitiesTable.h"
|
||||
#include "LeaderboardManager.h"
|
||||
#include "CharacterComponent.h"
|
||||
#include "Amf3.h"
|
||||
|
||||
ActivityComponent::ActivityComponent(Entity* parent, int32_t activityID) : Component(parent) {
|
||||
using namespace GameMessages;
|
||||
RegisterMsg<GetObjectReportInfo>(this, &ActivityComponent::OnGetObjectReportInfo);
|
||||
/*
|
||||
* This is precisely what the client does functionally
|
||||
* Use the component id as the default activity id and load its data from the database
|
||||
@@ -348,14 +351,13 @@ bool ActivityComponent::CheckCost(Entity* player) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActivityComponent::TakeCost(Entity* player) const{
|
||||
|
||||
bool ActivityComponent::TakeCost(Entity* player) const {
|
||||
|
||||
auto* inventoryComponent = player->GetComponent<InventoryComponent>();
|
||||
if (CheckCost(player)) {
|
||||
inventoryComponent->RemoveItem(m_ActivityInfo.optionalCostLOT, m_ActivityInfo.optionalCostCount);
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
void ActivityComponent::PlayerReady(Entity* player, bool bReady) {
|
||||
@@ -618,3 +620,91 @@ void ActivityInstance::SetScore(uint32_t score) {
|
||||
Entity* LobbyPlayer::GetEntity() const {
|
||||
return Game::entityManager->GetEntity(entityID);
|
||||
}
|
||||
|
||||
bool ActivityComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) {
|
||||
auto& reportInfo = static_cast<GameMessages::GetObjectReportInfo&>(msg);
|
||||
|
||||
auto& activityInfo = reportInfo.info->PushDebug("Activity");
|
||||
|
||||
auto& instances = activityInfo.PushDebug("Instances: " + std::to_string(m_Instances.size()));
|
||||
size_t i = 0;
|
||||
for (const auto& activityInstance : m_Instances) {
|
||||
if (!activityInstance) continue;
|
||||
auto& instance = instances.PushDebug("Instance " + std::to_string(i++));
|
||||
instance.PushDebug<AMFIntValue>("Score") = activityInstance->GetScore();
|
||||
instance.PushDebug<AMFIntValue>("Next Zone Clone ID") = activityInstance->GetNextZoneCloneID();
|
||||
|
||||
{
|
||||
auto& activityInfo = instance.PushDebug("Activity Info");
|
||||
const auto& instanceActInfo = activityInstance->GetActivityInfo();
|
||||
activityInfo.PushDebug<AMFIntValue>("ActivityID") = instanceActInfo.ActivityID;
|
||||
activityInfo.PushDebug<AMFIntValue>("locStatus") = instanceActInfo.locStatus;
|
||||
activityInfo.PushDebug<AMFIntValue>("instanceMapID") = instanceActInfo.instanceMapID;
|
||||
activityInfo.PushDebug<AMFIntValue>("minTeams") = instanceActInfo.minTeams;
|
||||
activityInfo.PushDebug<AMFIntValue>("maxTeams") = instanceActInfo.maxTeams;
|
||||
activityInfo.PushDebug<AMFIntValue>("minTeamSize") = instanceActInfo.minTeamSize;
|
||||
activityInfo.PushDebug<AMFIntValue>("maxTeamSize") = instanceActInfo.maxTeamSize;
|
||||
activityInfo.PushDebug<AMFIntValue>("waitTime") = instanceActInfo.waitTime;
|
||||
activityInfo.PushDebug<AMFIntValue>("startDelay") = instanceActInfo.startDelay;
|
||||
activityInfo.PushDebug<AMFBoolValue>("requiresUniqueData") = instanceActInfo.requiresUniqueData;
|
||||
activityInfo.PushDebug<AMFIntValue>("leaderboardType") = instanceActInfo.leaderboardType;
|
||||
activityInfo.PushDebug<AMFBoolValue>("localize") = instanceActInfo.localize;
|
||||
activityInfo.PushDebug<AMFIntValue>("optionalCostLOT") = instanceActInfo.optionalCostLOT;
|
||||
activityInfo.PushDebug<AMFIntValue>("optionalCostCount") = instanceActInfo.optionalCostCount;
|
||||
activityInfo.PushDebug<AMFBoolValue>("showUIRewards") = instanceActInfo.showUIRewards;
|
||||
activityInfo.PushDebug<AMFIntValue>("CommunityActivityFlagID") = instanceActInfo.CommunityActivityFlagID;
|
||||
activityInfo.PushDebug<AMFStringValue>("gate_version") = instanceActInfo.gate_version;
|
||||
activityInfo.PushDebug<AMFBoolValue>("noTeamLootOnDeath") = instanceActInfo.noTeamLootOnDeath;
|
||||
activityInfo.PushDebug<AMFDoubleValue>("optionalPercentage") = instanceActInfo.optionalPercentage;
|
||||
}
|
||||
|
||||
auto& participants = instance.PushDebug("Participants");
|
||||
for (const auto* participant : activityInstance->GetParticipants()) {
|
||||
if (!participant) continue;
|
||||
auto* character = participant->GetCharacter();
|
||||
if (!character) continue;
|
||||
participants.PushDebug<AMFStringValue>(std::to_string(participant->GetObjectID()) + ": " + character->GetName()) = "";
|
||||
}
|
||||
}
|
||||
|
||||
auto& queue = activityInfo.PushDebug("Queue");
|
||||
i = 0;
|
||||
for (const auto& lobbyQueue : m_Queue) {
|
||||
auto& lobby = queue.PushDebug("Lobby " + std::to_string(i++));
|
||||
lobby.PushDebug<AMFDoubleValue>("Timer") = lobbyQueue->timer;
|
||||
|
||||
auto& players = lobby.PushDebug("Players");
|
||||
for (const auto* player : lobbyQueue->players) {
|
||||
if (!player) continue;
|
||||
auto* playerEntity = player->GetEntity();
|
||||
if (!playerEntity) continue;
|
||||
auto* character = playerEntity->GetCharacter();
|
||||
if (!character) continue;
|
||||
|
||||
players.PushDebug<AMFStringValue>(std::to_string(playerEntity->GetObjectID()) + ": " + character->GetName()) = player->ready ? "Ready" : "Not Ready";
|
||||
}
|
||||
}
|
||||
|
||||
auto& activityPlayers = activityInfo.PushDebug("Activity Players");
|
||||
for (const auto* activityPlayer : m_ActivityPlayers) {
|
||||
if (!activityPlayer) continue;
|
||||
auto* const activityPlayerEntity = Game::entityManager->GetEntity(activityPlayer->playerID);
|
||||
if (!activityPlayerEntity) continue;
|
||||
auto* character = activityPlayerEntity->GetCharacter();
|
||||
if (!character) continue;
|
||||
|
||||
auto& playerData = activityPlayers.PushDebug(std::to_string(activityPlayer->playerID) + " " + character->GetName());
|
||||
|
||||
auto& scores = playerData.PushDebug("Scores");
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
scores.PushDebug<AMFDoubleValue>(std::to_string(i)) = activityPlayer->values[i];
|
||||
}
|
||||
}
|
||||
|
||||
auto& lootMatrices = activityInfo.PushDebug("Loot Matrices");
|
||||
for (const auto& [activityRating, lootMatrixID] : m_ActivityLootMatrices) {
|
||||
lootMatrices.PushDebug<AMFIntValue>("Loot Matrix " + std::to_string(activityRating)) = lootMatrixID;
|
||||
}
|
||||
activityInfo.PushDebug<AMFIntValue>("ActivityID") = m_ActivityID;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
#include "CDActivitiesTable.h"
|
||||
|
||||
namespace GameMessages {
|
||||
class GameMsg;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an instance of an activity, having participants and score
|
||||
*/
|
||||
@@ -60,6 +64,10 @@ public:
|
||||
* Currently unused
|
||||
*/
|
||||
void SetScore(uint32_t score);
|
||||
|
||||
[[nodiscard]] uint32_t GetNextZoneCloneID() const noexcept { return m_NextZoneCloneID; }
|
||||
|
||||
const CDActivities& GetActivityInfo() const noexcept { return m_ActivityInfo; }
|
||||
private:
|
||||
|
||||
/**
|
||||
@@ -75,12 +83,12 @@ private:
|
||||
/**
|
||||
* The database information for this activity
|
||||
*/
|
||||
CDActivities m_ActivityInfo;
|
||||
CDActivities m_ActivityInfo{};
|
||||
|
||||
/**
|
||||
* The entity that owns this activity (the entity that has the ScriptedActivityComponent)
|
||||
*/
|
||||
Entity* m_Parent;
|
||||
Entity* m_Parent{};
|
||||
|
||||
/**
|
||||
* All the participants of this activity
|
||||
@@ -341,6 +349,7 @@ public:
|
||||
uint32_t GetLootMatrixForTeamSize(uint32_t teamSize) { return m_ActivityLootMatrices[teamSize]; }
|
||||
private:
|
||||
|
||||
bool OnGetObjectReportInfo(GameMessages::GameMsg& msg);
|
||||
/**
|
||||
* The database information for this activity
|
||||
*/
|
||||
|
||||
@@ -49,19 +49,13 @@ CharacterComponent::CharacterComponent(Entity* parent, Character* character, con
|
||||
m_LastUpdateTimestamp = std::time(nullptr);
|
||||
m_SystemAddress = systemAddress;
|
||||
|
||||
RegisterMsg(MessageType::Game::REQUEST_SERVER_OBJECT_INFO, this, &CharacterComponent::OnRequestServerObjectInfo);
|
||||
RegisterMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, this, &CharacterComponent::OnGetObjectReportInfo);
|
||||
}
|
||||
|
||||
bool CharacterComponent::OnRequestServerObjectInfo(GameMessages::GameMsg& msg) {
|
||||
auto& request = static_cast<GameMessages::RequestServerObjectInfo&>(msg);
|
||||
AMFArrayValue response;
|
||||
bool CharacterComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) {
|
||||
auto& reportInfo = static_cast<GameMessages::GetObjectReportInfo&>(msg);
|
||||
|
||||
response.Insert("visible", true);
|
||||
response.Insert("objectID", std::to_string(request.targetForReport));
|
||||
response.Insert("serverInfo", true);
|
||||
|
||||
auto& data = *response.InsertArray("data");
|
||||
auto& cmptType = data.PushDebug("Character");
|
||||
auto& cmptType = reportInfo.info->PushDebug("Character");
|
||||
|
||||
cmptType.PushDebug<AMFIntValue>("Component ID") = GeneralUtils::ToUnderlying(ComponentType);
|
||||
cmptType.PushDebug<AMFIntValue>("Character's account ID") = m_Character->GetParentUser()->GetAccountID();
|
||||
@@ -72,6 +66,13 @@ bool CharacterComponent::OnRequestServerObjectInfo(GameMessages::GameMsg& msg) {
|
||||
cmptType.PushDebug<AMFStringValue>("Total currency") = std::to_string(m_Character->GetCoins());
|
||||
cmptType.PushDebug<AMFStringValue>("Currency able to be picked up") = std::to_string(m_DroppedCoins);
|
||||
cmptType.PushDebug<AMFStringValue>("Tooltip flags value") = "0";
|
||||
auto& vl = cmptType.PushDebug("Visited Levels");
|
||||
for (const auto zoneID : m_VisitedLevels) {
|
||||
std::stringstream sstream;
|
||||
sstream << "MapID: " << zoneID.GetMapID() << " CloneID: " << zoneID.GetCloneID();
|
||||
vl.PushDebug<AMFStringValue>(sstream.str()) = "";
|
||||
}
|
||||
|
||||
// visited locations
|
||||
cmptType.PushDebug<AMFBoolValue>("is a GM") = m_GMLevel > eGameMasterLevel::CIVILIAN;
|
||||
cmptType.PushDebug<AMFBoolValue>("Has PVP flag turned on") = m_PvpEnabled;
|
||||
@@ -83,9 +84,6 @@ bool CharacterComponent::OnRequestServerObjectInfo(GameMessages::GameMsg& msg) {
|
||||
cmptType.PushDebug<AMFIntValue>("Current Activity Type") = GeneralUtils::ToUnderlying(m_CurrentActivity);
|
||||
cmptType.PushDebug<AMFDoubleValue>("Property Clone ID") = m_Character->GetPropertyCloneID();
|
||||
|
||||
GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, m_Parent->GetSystemAddress());
|
||||
|
||||
LOG("Handled!");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ public:
|
||||
void LoadVisitedLevelsXml(const tinyxml2::XMLElement& doc);
|
||||
private:
|
||||
|
||||
bool OnRequestServerObjectInfo(GameMessages::GameMsg& msg);
|
||||
bool OnGetObjectReportInfo(GameMessages::GameMsg& msg);
|
||||
|
||||
/**
|
||||
* The map of active venture vision effects
|
||||
|
||||
@@ -56,10 +56,16 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
void RegisterMsg(const MessageType::Game msgId, auto* self, const auto handler) {
|
||||
inline void RegisterMsg(const MessageType::Game msgId, auto* self, const auto handler) {
|
||||
m_Parent->RegisterMsg(msgId, std::bind(handler, self, std::placeholders::_1));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void RegisterMsg(auto* self, const auto handler) {
|
||||
T msg;
|
||||
RegisterMsg(msg.msgId, self, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* The entity that owns this component
|
||||
*/
|
||||
|
||||
@@ -14,8 +14,12 @@
|
||||
#include "dZoneManager.h"
|
||||
#include "LevelProgressionComponent.h"
|
||||
#include "eStateChangeType.h"
|
||||
#include "StringifiedEnum.h"
|
||||
#include "Amf3.h"
|
||||
|
||||
ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity, int32_t componentId) : PhysicsComponent(entity, componentId) {
|
||||
RegisterMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, this, &ControllablePhysicsComponent::OnGetObjectReportInfo);
|
||||
|
||||
m_Velocity = {};
|
||||
m_AngularVelocity = {};
|
||||
m_InJetpackMode = false;
|
||||
@@ -354,3 +358,58 @@ void ControllablePhysicsComponent::SetStunImmunity(
|
||||
bImmuneToStunUseItem
|
||||
);
|
||||
}
|
||||
|
||||
bool ControllablePhysicsComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) {
|
||||
PhysicsComponent::OnGetObjectReportInfo(msg);
|
||||
auto& reportInfo = static_cast<GameMessages::GetObjectReportInfo&>(msg);
|
||||
auto& info = reportInfo.subCategory->PushDebug("Controllable Info");
|
||||
|
||||
auto& vel = info.PushDebug("Velocity");
|
||||
vel.PushDebug<AMFDoubleValue>("x") = m_Velocity.x;
|
||||
vel.PushDebug<AMFDoubleValue>("y") = m_Velocity.y;
|
||||
vel.PushDebug<AMFDoubleValue>("z") = m_Velocity.z;
|
||||
|
||||
auto& angularVelocity = info.PushDebug("Angular Velocity");
|
||||
angularVelocity.PushDebug<AMFDoubleValue>("x") = m_AngularVelocity.x;
|
||||
angularVelocity.PushDebug<AMFDoubleValue>("y") = m_AngularVelocity.y;
|
||||
angularVelocity.PushDebug<AMFDoubleValue>("z") = m_AngularVelocity.z;
|
||||
|
||||
info.PushDebug<AMFBoolValue>("Is On Ground") = m_IsOnGround;
|
||||
info.PushDebug<AMFBoolValue>("Is On Rail") = m_IsOnRail;
|
||||
info.PushDebug<AMFBoolValue>("Is In Jetpack Mode") = m_InJetpackMode;
|
||||
info.PushDebug<AMFBoolValue>("Is Jetpack Flying") = m_JetpackFlying;
|
||||
info.PushDebug<AMFBoolValue>("Is Bypassing Jetpack Checks") = m_JetpackBypassChecks;
|
||||
info.PushDebug<AMFIntValue>("Jetpack Effect ID") = m_JetpackEffectID;
|
||||
info.PushDebug<AMFDoubleValue>("Speed Multiplier") = m_SpeedMultiplier;
|
||||
info.PushDebug<AMFDoubleValue>("Gravity Scale") = m_GravityScale;
|
||||
info.PushDebug<AMFBoolValue>("Is Static") = m_Static;
|
||||
|
||||
auto& pickupRadii = info.PushDebug("Active Pickup Radius Scales");
|
||||
|
||||
size_t i = 0;
|
||||
for (const auto& scale : m_ActivePickupRadiusScales) {
|
||||
pickupRadii.PushDebug<AMFStringValue>(std::to_string(i++) + " " + std::to_string(scale)) = "";
|
||||
}
|
||||
|
||||
info.PushDebug<AMFDoubleValue>("Largest Pickup Radius") = m_PickupRadius;
|
||||
info.PushDebug<AMFBoolValue>("Is Teleporting") = m_IsTeleporting;
|
||||
|
||||
auto& activeSpeedBoosts = info.PushDebug("Active Speed Boosts");
|
||||
i = 0;
|
||||
for (const auto& boost : m_ActiveSpeedBoosts) {
|
||||
activeSpeedBoosts.PushDebug<AMFStringValue>(std::to_string(i++) + " " + std::to_string(boost)) = "";
|
||||
}
|
||||
|
||||
info.PushDebug<AMFDoubleValue>("Speed Boost") = m_SpeedBoost;
|
||||
info.PushDebug<AMFBoolValue>("Is In Bubble") = m_IsInBubble;
|
||||
info.PushDebug<AMFStringValue>("Bubble Type") = StringifiedEnum::ToString(m_BubbleType).data();
|
||||
info.PushDebug<AMFBoolValue>("Special Anims") = m_SpecialAnims;
|
||||
info.PushDebug<AMFIntValue>("Immune To Stun Attack Count") = m_ImmuneToStunAttackCount;
|
||||
info.PushDebug<AMFIntValue>("Immune To Stun Equip Count") = m_ImmuneToStunEquipCount;
|
||||
info.PushDebug<AMFIntValue>("Immune To Stun Interact Count") = m_ImmuneToStunInteractCount;
|
||||
info.PushDebug<AMFIntValue>("Immune To Stun Jump Count") = m_ImmuneToStunJumpCount;
|
||||
info.PushDebug<AMFIntValue>("Immune To Stun Move Count") = m_ImmuneToStunMoveCount;
|
||||
info.PushDebug<AMFIntValue>("Immune To Stun Turn Count") = m_ImmuneToStunTurnCount;
|
||||
info.PushDebug<AMFIntValue>("Immune To Stun UseItem Count") = m_ImmuneToStunUseItemCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
#ifndef CONTROLLABLEPHYSICSCOMPONENT_H
|
||||
#define CONTROLLABLEPHYSICSCOMPONENT_H
|
||||
|
||||
#include "PhysicsComponent.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "dCommonVars.h"
|
||||
#include "RakNetTypes.h"
|
||||
#include "NiPoint3.h"
|
||||
#include "NiQuaternion.h"
|
||||
#include "tinyxml2.h"
|
||||
#include "PhysicsComponent.h"
|
||||
#include "dpCollisionChecks.h"
|
||||
#include "PhantomPhysicsComponent.h"
|
||||
#include "eBubbleType.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
|
||||
namespace tinyxml2 {
|
||||
class XMLDocument;
|
||||
}
|
||||
|
||||
class Entity;
|
||||
class dpEntity;
|
||||
@@ -281,6 +283,8 @@ public:
|
||||
const bool GetImmuneToStunUseItem() { return m_ImmuneToStunUseItemCount > 0;};
|
||||
|
||||
private:
|
||||
|
||||
bool OnGetObjectReportInfo(GameMessages::GameMsg& msg);
|
||||
/**
|
||||
* The entity that owns this component
|
||||
*/
|
||||
@@ -374,7 +378,7 @@ private:
|
||||
/**
|
||||
* The active speed boost for this entity
|
||||
*/
|
||||
float m_SpeedBoost;
|
||||
float m_SpeedBoost = 500.0f;
|
||||
|
||||
/*
|
||||
* If Bubble info is dirty
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "BuffComponent.h"
|
||||
#include "SkillComponent.h"
|
||||
#include "Item.h"
|
||||
#include "Amf3.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include "CharacterComponent.h"
|
||||
#include "PossessableComponent.h"
|
||||
#include "PossessorComponent.h"
|
||||
#include "ModelComponent.h"
|
||||
#include "InventoryComponent.h"
|
||||
#include "dZoneManager.h"
|
||||
#include "WorldConfig.h"
|
||||
@@ -42,6 +44,7 @@ Implementation<bool, const Entity*> DestroyableComponent::IsEnemyImplentation;
|
||||
Implementation<bool, const Entity*> DestroyableComponent::IsFriendImplentation;
|
||||
|
||||
DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
|
||||
using namespace GameMessages;
|
||||
m_iArmor = 0;
|
||||
m_fMaxArmor = 0.0f;
|
||||
m_iImagination = 0;
|
||||
@@ -78,6 +81,9 @@ DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
|
||||
m_DeathBehavior = -1;
|
||||
|
||||
m_DamageCooldownTimer = 0.0f;
|
||||
|
||||
RegisterMsg<GetObjectReportInfo>(this, &DestroyableComponent::OnGetObjectReportInfo);
|
||||
RegisterMsg<GameMessages::SetFaction>(this, &DestroyableComponent::OnSetFaction);
|
||||
}
|
||||
|
||||
DestroyableComponent::~DestroyableComponent() {
|
||||
@@ -575,6 +581,14 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
|
||||
return;
|
||||
}
|
||||
|
||||
// Client does the same check, so we're doing it too
|
||||
auto* const modelComponent = m_Parent->GetComponent<ModelComponent>();
|
||||
if (modelComponent) {
|
||||
modelComponent->OnHit();
|
||||
// Don't actually deal the damage so the model doesn't die
|
||||
return;
|
||||
}
|
||||
|
||||
// If this entity has damage reduction, reduce the damage to a minimum of 1
|
||||
if (m_DamageReduction > 0 && damage > 0) {
|
||||
if (damage > m_DamageReduction) {
|
||||
@@ -1031,3 +1045,65 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DestroyableComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) {
|
||||
auto& reportInfo = static_cast<GameMessages::GetObjectReportInfo&>(msg);
|
||||
|
||||
auto& destroyableInfo = reportInfo.info->PushDebug("Destroyable");
|
||||
destroyableInfo.PushDebug<AMFIntValue>("Health") = m_iHealth;
|
||||
destroyableInfo.PushDebug<AMFDoubleValue>("Max Health") = m_fMaxHealth;
|
||||
destroyableInfo.PushDebug<AMFIntValue>("Armor") = m_iArmor;
|
||||
destroyableInfo.PushDebug<AMFDoubleValue>("Max Armor") = m_fMaxArmor;
|
||||
destroyableInfo.PushDebug<AMFIntValue>("Imagination") = m_iImagination;
|
||||
destroyableInfo.PushDebug<AMFDoubleValue>("Max Imagination") = m_fMaxImagination;
|
||||
destroyableInfo.PushDebug<AMFIntValue>("Damage To Absorb") = m_DamageToAbsorb;
|
||||
destroyableInfo.PushDebug<AMFBoolValue>("Is GM Immune") = m_IsGMImmune;
|
||||
destroyableInfo.PushDebug<AMFBoolValue>("Is Shielded") = m_IsShielded;
|
||||
destroyableInfo.PushDebug<AMFIntValue>("Attacks To Block") = m_AttacksToBlock;
|
||||
destroyableInfo.PushDebug<AMFIntValue>("Damage Reduction") = m_DamageReduction;
|
||||
auto& factions = destroyableInfo.PushDebug("Factions");
|
||||
size_t i = 0;
|
||||
for (const auto factionID : m_FactionIDs) {
|
||||
factions.PushDebug<AMFStringValue>(std::to_string(i++) + " " + std::to_string(factionID)) = "";
|
||||
}
|
||||
auto& enemyFactions = destroyableInfo.PushDebug("Enemy Factions");
|
||||
i = 0;
|
||||
for (const auto enemyFactionID : m_EnemyFactionIDs) {
|
||||
enemyFactions.PushDebug<AMFStringValue>(std::to_string(i++) + " " + std::to_string(enemyFactionID)) = "";
|
||||
}
|
||||
destroyableInfo.PushDebug<AMFBoolValue>("Is Smashable") = m_IsSmashable;
|
||||
destroyableInfo.PushDebug<AMFBoolValue>("Is Dead") = m_IsDead;
|
||||
destroyableInfo.PushDebug<AMFBoolValue>("Is Smashed") = m_IsSmashed;
|
||||
destroyableInfo.PushDebug<AMFBoolValue>("Is Module Assembly") = m_IsModuleAssembly;
|
||||
destroyableInfo.PushDebug<AMFDoubleValue>("Explode Factor") = m_ExplodeFactor;
|
||||
destroyableInfo.PushDebug<AMFBoolValue>("Has Threats") = m_HasThreats;
|
||||
destroyableInfo.PushDebug<AMFIntValue>("Loot Matrix ID") = m_LootMatrixID;
|
||||
destroyableInfo.PushDebug<AMFIntValue>("Min Coins") = m_MinCoins;
|
||||
destroyableInfo.PushDebug<AMFIntValue>("Max Coins") = m_MaxCoins;
|
||||
destroyableInfo.PushDebug<AMFStringValue>("Killer ID") = std::to_string(m_KillerID);
|
||||
|
||||
// "Scripts"; idk what to do about scripts yet
|
||||
auto& immuneCounts = destroyableInfo.PushDebug("Immune Counts");
|
||||
immuneCounts.PushDebug<AMFIntValue>("Basic Attack") = m_ImmuneToBasicAttackCount;
|
||||
immuneCounts.PushDebug<AMFIntValue>("Damage Over Time") = m_ImmuneToDamageOverTimeCount;
|
||||
immuneCounts.PushDebug<AMFIntValue>("Knockback") = m_ImmuneToKnockbackCount;
|
||||
immuneCounts.PushDebug<AMFIntValue>("Interrupt") = m_ImmuneToInterruptCount;
|
||||
immuneCounts.PushDebug<AMFIntValue>("Speed") = m_ImmuneToSpeedCount;
|
||||
immuneCounts.PushDebug<AMFIntValue>("Imagination Gain") = m_ImmuneToImaginationGainCount;
|
||||
immuneCounts.PushDebug<AMFIntValue>("Imagination Loss") = m_ImmuneToImaginationLossCount;
|
||||
immuneCounts.PushDebug<AMFIntValue>("Quickbuild Interrupt") = m_ImmuneToQuickbuildInterruptCount;
|
||||
immuneCounts.PushDebug<AMFIntValue>("Pull To Point") = m_ImmuneToPullToPointCount;
|
||||
|
||||
destroyableInfo.PushDebug<AMFIntValue>("Death Behavior") = m_DeathBehavior;
|
||||
destroyableInfo.PushDebug<AMFDoubleValue>("Damage Cooldown Timer") = m_DamageCooldownTimer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DestroyableComponent::OnSetFaction(GameMessages::GameMsg& msg) {
|
||||
auto& modifyFaction = static_cast<GameMessages::SetFaction&>(msg);
|
||||
m_DirtyHealth = true;
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
SetFaction(modifyFaction.factionID, modifyFaction.bIgnoreChecks);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "Implementation.h"
|
||||
|
||||
namespace GameMessages {
|
||||
struct GetObjectReportInfo;
|
||||
};
|
||||
|
||||
namespace CppScripts {
|
||||
class Script;
|
||||
}; //! namespace CppScripts
|
||||
@@ -464,6 +468,9 @@ public:
|
||||
// handle hardcode mode drops
|
||||
void DoHardcoreModeDrops(const LWOOBJID source);
|
||||
|
||||
bool OnGetObjectReportInfo(GameMessages::GameMsg& msg);
|
||||
bool OnSetFaction(GameMessages::GameMsg& msg);
|
||||
|
||||
static Implementation<bool, const Entity*> IsEnemyImplentation;
|
||||
static Implementation<bool, const Entity*> IsFriendImplentation;
|
||||
|
||||
@@ -591,7 +598,7 @@ private:
|
||||
/**
|
||||
* The ID of the entity that smashed this entity, if any
|
||||
*/
|
||||
LWOOBJID m_KillerID;
|
||||
LWOOBJID m_KillerID{};
|
||||
|
||||
/**
|
||||
* The list of callbacks that will be called when this entity gets hit
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "HavokVehiclePhysicsComponent.h"
|
||||
#include "EntityManager.h"
|
||||
#include "Amf3.h"
|
||||
|
||||
HavokVehiclePhysicsComponent::HavokVehiclePhysicsComponent(Entity* parent, int32_t componentId) : PhysicsComponent(parent, componentId) {
|
||||
RegisterMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, this, &HavokVehiclePhysicsComponent::OnGetObjectReportInfo);
|
||||
|
||||
m_Velocity = NiPoint3Constant::ZERO;
|
||||
m_AngularVelocity = NiPoint3Constant::ZERO;
|
||||
m_IsOnGround = true;
|
||||
@@ -98,3 +101,34 @@ void HavokVehiclePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bo
|
||||
|
||||
outBitStream.Write0();
|
||||
}
|
||||
|
||||
bool HavokVehiclePhysicsComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) {
|
||||
PhysicsComponent::OnGetObjectReportInfo(msg);
|
||||
auto& reportInfo = static_cast<GameMessages::GetObjectReportInfo&>(msg);
|
||||
if (!reportInfo.subCategory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& info = reportInfo.subCategory->PushDebug("Havok Vehicle Physics Info");
|
||||
|
||||
auto& velocity = info.PushDebug("Velocity");
|
||||
velocity.PushDebug<AMFDoubleValue>("x") = m_Velocity.x;
|
||||
velocity.PushDebug<AMFDoubleValue>("y") = m_Velocity.y;
|
||||
velocity.PushDebug<AMFDoubleValue>("z") = m_Velocity.z;
|
||||
|
||||
auto& angularVelocity = info.PushDebug("Angular Velocity");
|
||||
angularVelocity.PushDebug<AMFDoubleValue>("x") = m_AngularVelocity.x;
|
||||
angularVelocity.PushDebug<AMFDoubleValue>("y") = m_AngularVelocity.y;
|
||||
angularVelocity.PushDebug<AMFDoubleValue>("z") = m_AngularVelocity.z;
|
||||
|
||||
info.PushDebug<AMFBoolValue>("Is On Ground") = m_IsOnGround;
|
||||
info.PushDebug<AMFBoolValue>("Is On Rail") = m_IsOnRail;
|
||||
info.PushDebug<AMFIntValue>("End Behavior") = m_EndBehavior;
|
||||
|
||||
auto& remoteInputInfo = info.PushDebug("Remote Input Info");
|
||||
remoteInputInfo.PushDebug<AMFDoubleValue>("Remote Input X") = m_RemoteInputInfo.m_RemoteInputX;
|
||||
remoteInputInfo.PushDebug<AMFDoubleValue>("Remote Input Y") = m_RemoteInputInfo.m_RemoteInputY;
|
||||
remoteInputInfo.PushDebug<AMFBoolValue>("Is Powersliding") = m_RemoteInputInfo.m_IsPowersliding;
|
||||
remoteInputInfo.PushDebug<AMFBoolValue>("Is Modified") = m_RemoteInputInfo.m_IsModified;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ public:
|
||||
void SetRemoteInputInfo(const RemoteInputInfo&);
|
||||
|
||||
private:
|
||||
bool OnGetObjectReportInfo(GameMessages::GameMsg& msg);
|
||||
|
||||
NiPoint3 m_Velocity;
|
||||
NiPoint3 m_AngularVelocity;
|
||||
|
||||
|
||||
@@ -1777,7 +1777,7 @@ void InventoryComponent::LoadGroupXml(const tinyxml2::XMLElement& groups) {
|
||||
group.groupId = groupId;
|
||||
group.groupName = groupName;
|
||||
|
||||
for (const auto& lotStr : GeneralUtils::SplitString(std::string_view(lots), ' ')) {
|
||||
for (const auto& lotStr : GeneralUtils::SplitString(lots, ' ')) {
|
||||
auto lot = GeneralUtils::TryParse<LOT>(lotStr);
|
||||
if (lot) group.lots.insert(*lot);
|
||||
}
|
||||
|
||||
@@ -15,14 +15,15 @@
|
||||
#include "DluAssert.h"
|
||||
|
||||
ModelComponent::ModelComponent(Entity* parent) : Component(parent) {
|
||||
using namespace GameMessages;
|
||||
m_OriginalPosition = m_Parent->GetDefaultPosition();
|
||||
m_OriginalRotation = m_Parent->GetDefaultRotation();
|
||||
m_IsPaused = false;
|
||||
m_NumListeningInteract = 0;
|
||||
|
||||
m_userModelID = m_Parent->GetVarAs<LWOOBJID>(u"userModelID");
|
||||
RegisterMsg(MessageType::Game::REQUEST_USE, this, &ModelComponent::OnRequestUse);
|
||||
RegisterMsg(MessageType::Game::RESET_MODEL_TO_DEFAULTS, this, &ModelComponent::OnResetModelToDefaults);
|
||||
RegisterMsg<RequestUse>(this, &ModelComponent::OnRequestUse);
|
||||
RegisterMsg<ResetModelToDefaults>(this, &ModelComponent::OnResetModelToDefaults);
|
||||
}
|
||||
|
||||
bool ModelComponent::OnResetModelToDefaults(GameMessages::GameMsg& msg) {
|
||||
@@ -40,6 +41,14 @@ bool ModelComponent::OnResetModelToDefaults(GameMessages::GameMsg& msg) {
|
||||
m_Speed = 3.0f;
|
||||
m_NumListeningInteract = 0;
|
||||
m_NumActiveUnSmash = 0;
|
||||
|
||||
m_NumActiveAttack = 0;
|
||||
GameMessages::SetFaction set{};
|
||||
set.target = m_Parent->GetObjectID();
|
||||
set.factionID = -1; // Default faction for smashables
|
||||
set.bIgnoreChecks = true; // Remove the attack faction
|
||||
set.Send();
|
||||
|
||||
m_Dirty = true;
|
||||
Game::entityManager->SerializeEntity(GetParent());
|
||||
|
||||
@@ -297,3 +306,35 @@ void ModelComponent::SetVelocity(const NiPoint3& velocity) const {
|
||||
void ModelComponent::OnChatMessageReceived(const std::string& sMessage) {
|
||||
for (auto& behavior : m_Behaviors) behavior.OnChatMessageReceived(sMessage);
|
||||
}
|
||||
|
||||
void ModelComponent::OnHit() {
|
||||
for (auto& behavior : m_Behaviors) {
|
||||
behavior.OnHit();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelComponent::AddAttack() {
|
||||
LOG_DEBUG("Adding attack %i", m_NumActiveAttack);
|
||||
m_Dirty = true;
|
||||
if (m_NumActiveAttack == 0) {
|
||||
GameMessages::SetFaction set{};
|
||||
set.target = m_Parent->GetObjectID();
|
||||
set.factionID = 6; // Default faction for smashables
|
||||
set.Send();
|
||||
}
|
||||
m_NumActiveAttack++;
|
||||
}
|
||||
|
||||
void ModelComponent::RemoveAttack() {
|
||||
LOG_DEBUG("Removing attack %i", m_NumActiveAttack);
|
||||
DluAssert(m_NumActiveAttack > 0);
|
||||
m_Dirty = true;
|
||||
m_NumActiveAttack--;
|
||||
if (m_NumActiveAttack == 0) {
|
||||
GameMessages::SetFaction set{};
|
||||
set.target = m_Parent->GetObjectID();
|
||||
set.factionID = -1; // Default faction for smashables
|
||||
set.bIgnoreChecks = true; // Remove the attack faction
|
||||
set.Send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,11 +146,21 @@ public:
|
||||
|
||||
void OnChatMessageReceived(const std::string& sMessage);
|
||||
|
||||
void OnHit();
|
||||
|
||||
// Sets the speed of the model
|
||||
void SetSpeed(const float newSpeed) { m_Speed = newSpeed; }
|
||||
|
||||
// Whether or not to restart at the end of the frame
|
||||
void RestartAtEndOfFrame() { m_RestartAtEndOfFrame = true; }
|
||||
|
||||
// Increments the number of strips listening for an attack.
|
||||
// If this is the first strip adding an attack, it will set the factions to the correct values.
|
||||
void AddAttack();
|
||||
|
||||
// Decrements the number of strips listening for an attack.
|
||||
// If this is the last strip removing an attack, it will reset the factions to the default of -1.
|
||||
void RemoveAttack();
|
||||
private:
|
||||
|
||||
// Loads a behavior from the database.
|
||||
@@ -168,6 +178,9 @@ private:
|
||||
// The number of strips listening for a RequestUse GM to come in.
|
||||
uint32_t m_NumListeningInteract{};
|
||||
|
||||
// The number of strips listening for an attack.
|
||||
uint32_t m_NumActiveAttack{};
|
||||
|
||||
// Whether or not the model is paused and should reject all interactions regarding behaviors.
|
||||
bool m_IsPaused{};
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "dZoneManager.h"
|
||||
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
#include "QuickBuildComponent.h"
|
||||
#include "CDPhysicsComponentTable.h"
|
||||
|
||||
#include "dNavMesh.h"
|
||||
@@ -89,6 +90,9 @@ void MovementAIComponent::Resume() {
|
||||
void MovementAIComponent::Update(const float deltaTime) {
|
||||
if (m_Paused) return;
|
||||
|
||||
auto* const quickBuildComponent = m_Parent->GetComponent<QuickBuildComponent>();
|
||||
if (quickBuildComponent && quickBuildComponent->GetState() != eQuickBuildState::COMPLETED) return;
|
||||
|
||||
if (m_PullingToPoint) {
|
||||
const auto source = GetCurrentWaypoint();
|
||||
|
||||
@@ -154,6 +158,7 @@ void MovementAIComponent::Update(const float deltaTime) {
|
||||
}
|
||||
} else {
|
||||
// Check if there are more waypoints in the queue, if so set our next destination to the next waypoint
|
||||
const auto waypointNum = m_IsBounced ? m_CurrentPath.size() : m_CurrentPathWaypointCount - m_CurrentPath.size() - 1;
|
||||
if (m_CurrentPath.empty()) {
|
||||
if (m_Path) {
|
||||
if (m_Path->pathBehavior == PathBehavior::Loop) {
|
||||
@@ -161,20 +166,24 @@ void MovementAIComponent::Update(const float deltaTime) {
|
||||
} else if (m_Path->pathBehavior == PathBehavior::Bounce) {
|
||||
m_IsBounced = !m_IsBounced;
|
||||
std::vector<PathWaypoint> waypoints = m_Path->pathWaypoints;
|
||||
if (m_IsBounced) std::reverse(waypoints.begin(), waypoints.end());
|
||||
if (m_IsBounced) std::ranges::reverse(waypoints);
|
||||
SetPath(waypoints);
|
||||
} else if (m_Path->pathBehavior == PathBehavior::Once) {
|
||||
m_Parent->GetScript()->OnWaypointReached(m_Parent, waypointNum);
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
m_Parent->GetScript()->OnWaypointReached(m_Parent, waypointNum);
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
SetDestination(m_CurrentPath.top().position);
|
||||
} else {
|
||||
m_Parent->GetScript()->OnWaypointReached(m_Parent, waypointNum);
|
||||
SetDestination(m_CurrentPath.top().position);
|
||||
|
||||
m_CurrentPath.pop();
|
||||
m_CurrentPath.pop();
|
||||
}
|
||||
}
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
@@ -250,6 +259,7 @@ void MovementAIComponent::Stop() {
|
||||
|
||||
m_InterpolatedWaypoints.clear();
|
||||
while (!m_CurrentPath.empty()) m_CurrentPath.pop();
|
||||
m_CurrentPathWaypointCount = 0;
|
||||
|
||||
m_PathIndex = 0;
|
||||
|
||||
@@ -272,6 +282,7 @@ void MovementAIComponent::SetPath(std::vector<PathWaypoint> path) {
|
||||
this->m_CurrentPath.push(point);
|
||||
});
|
||||
|
||||
m_CurrentPathWaypointCount = path.size();
|
||||
SetDestination(path.front().position);
|
||||
}
|
||||
|
||||
|
||||
@@ -209,6 +209,8 @@ public:
|
||||
*/
|
||||
static float GetBaseSpeed(LOT lot);
|
||||
|
||||
bool IsPaused() const { return m_Paused; }
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
@@ -323,6 +325,9 @@ private:
|
||||
NiPoint3 m_SavedVelocity;
|
||||
|
||||
bool m_IsBounced{};
|
||||
|
||||
// The number of waypoints that were on the path in the call to SetPath
|
||||
uint32_t m_CurrentPathWaypointCount{ 0 };
|
||||
};
|
||||
|
||||
#endif // MOVEMENTAICOMPONENT_H
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "CDPhysicsComponentTable.h"
|
||||
#include "dServer.h"
|
||||
#include "EntityInfo.h"
|
||||
#include "Amf3.h"
|
||||
|
||||
#include "dpWorld.h"
|
||||
#include "dpEntity.h"
|
||||
@@ -28,6 +29,8 @@
|
||||
#include "dpShapeSphere.h"
|
||||
|
||||
PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent, int32_t componentId) : PhysicsComponent(parent, componentId) {
|
||||
RegisterMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, this, &PhantomPhysicsComponent::OnGetObjectReportInfo);
|
||||
|
||||
m_Position = m_Parent->GetDefaultPosition();
|
||||
m_Rotation = m_Parent->GetDefaultRotation();
|
||||
m_Scale = m_Parent->GetDefaultScale();
|
||||
@@ -238,3 +241,43 @@ void PhantomPhysicsComponent::SetRotation(const NiQuaternion& rot) {
|
||||
PhysicsComponent::SetRotation(rot);
|
||||
if (m_dpEntity) m_dpEntity->SetRotation(rot);
|
||||
}
|
||||
|
||||
bool PhantomPhysicsComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) {
|
||||
PhysicsComponent::OnGetObjectReportInfo(msg);
|
||||
auto& reportInfo = static_cast<GameMessages::GetObjectReportInfo&>(msg);
|
||||
if (!reportInfo.subCategory) {
|
||||
return false;
|
||||
}
|
||||
auto& info = reportInfo.subCategory->PushDebug("Phantom Physics Info");
|
||||
info.PushDebug<AMFDoubleValue>("Scale") = m_Scale;
|
||||
info.PushDebug<AMFBoolValue>("Is Physics Effect Active") = m_IsPhysicsEffectActive;
|
||||
info.PushDebug<AMFIntValue>("Effect Type") = static_cast<int>(m_EffectType);
|
||||
info.PushDebug<AMFDoubleValue>("Directional Multiplier") = m_DirectionalMultiplier;
|
||||
info.PushDebug<AMFBoolValue>("Is Directional") = m_IsDirectional;
|
||||
auto& direction = info.PushDebug("Direction");
|
||||
direction.PushDebug<AMFDoubleValue>("x") = m_Direction.x;
|
||||
direction.PushDebug<AMFDoubleValue>("y") = m_Direction.y;
|
||||
direction.PushDebug<AMFDoubleValue>("z") = m_Direction.z;
|
||||
|
||||
if (m_MinMax) {
|
||||
auto& minMaxInfo = info.PushDebug("Min Max Info");
|
||||
minMaxInfo.PushDebug<AMFIntValue>("Min") = m_Min;
|
||||
minMaxInfo.PushDebug<AMFIntValue>("Max") = m_Max;
|
||||
}
|
||||
|
||||
if (m_IsRespawnVolume) {
|
||||
auto& respawnInfo = info.PushDebug("Respawn Info");
|
||||
respawnInfo.PushDebug<AMFBoolValue>("Is Respawn Volume") = m_IsRespawnVolume;
|
||||
auto& respawnPos = respawnInfo.PushDebug("Respawn Position");
|
||||
respawnPos.PushDebug<AMFDoubleValue>("x") = m_RespawnPos.x;
|
||||
respawnPos.PushDebug<AMFDoubleValue>("y") = m_RespawnPos.y;
|
||||
respawnPos.PushDebug<AMFDoubleValue>("z") = m_RespawnPos.z;
|
||||
auto& respawnRot = respawnInfo.PushDebug("Respawn Rotation");
|
||||
respawnRot.PushDebug<AMFDoubleValue>("w") = m_RespawnRot.w;
|
||||
respawnRot.PushDebug<AMFDoubleValue>("x") = m_RespawnRot.x;
|
||||
respawnRot.PushDebug<AMFDoubleValue>("y") = m_RespawnRot.y;
|
||||
respawnRot.PushDebug<AMFDoubleValue>("z") = m_RespawnRot.z;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#include "NiQuaternion.h"
|
||||
#include "BitStream.h"
|
||||
#include <vector>
|
||||
#include "CppScripts.h"
|
||||
#include "InvalidScript.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "PhysicsComponent.h"
|
||||
|
||||
@@ -118,6 +116,8 @@ public:
|
||||
void SetMax(uint32_t max);
|
||||
|
||||
private:
|
||||
bool OnGetObjectReportInfo(GameMessages::GameMsg& msg);
|
||||
|
||||
/**
|
||||
* A scale to apply to the size of the physics object
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "dpShapeSphere.h"
|
||||
|
||||
#include "EntityInfo.h"
|
||||
#include "Amf3.h"
|
||||
|
||||
PhysicsComponent::PhysicsComponent(Entity* parent, int32_t componentId) : Component(parent) {
|
||||
m_Position = NiPoint3Constant::ZERO;
|
||||
@@ -97,9 +98,9 @@ dpEntity* PhysicsComponent::CreatePhysicsEntity(eReplicaComponentType type) {
|
||||
} else if (info->physicsAsset == "env\\GFTrack_DeathVolume2_RoadGaps.hkx") {
|
||||
toReturn = new dpEntity(m_Parent->GetObjectID(), 48.386536f, 50.363434f, 259.361755f);
|
||||
} */ else {
|
||||
// LOG_DEBUG("This one is supposed to have %s", info->physicsAsset.c_str());
|
||||
// LOG_DEBUG("This one is supposed to have %s", info->physicsAsset.c_str());
|
||||
|
||||
//add fallback cube:
|
||||
//add fallback cube:
|
||||
toReturn = new dpEntity(m_Parent->GetObjectID(), 2.0f, 2.0f, 2.0f);
|
||||
}
|
||||
return toReturn;
|
||||
@@ -243,3 +244,24 @@ void PhysicsComponent::SpawnVertices(dpEntity* entity) const {
|
||||
Game::entityManager->ConstructEntity(newEntity);
|
||||
}
|
||||
}
|
||||
|
||||
bool PhysicsComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) {
|
||||
auto& reportInfo = static_cast<GameMessages::GetObjectReportInfo&>(msg);
|
||||
auto& info = reportInfo.info->PushDebug("Physics");
|
||||
reportInfo.subCategory = &info;
|
||||
|
||||
auto& pos = info.PushDebug("Position");
|
||||
pos.PushDebug<AMFDoubleValue>("x") = m_Position.x;
|
||||
pos.PushDebug<AMFDoubleValue>("y") = m_Position.y;
|
||||
pos.PushDebug<AMFDoubleValue>("z") = m_Position.z;
|
||||
|
||||
auto& rot = info.PushDebug("Rotation");
|
||||
rot.PushDebug<AMFDoubleValue>("w") = m_Rotation.w;
|
||||
rot.PushDebug<AMFDoubleValue>("x") = m_Rotation.x;
|
||||
rot.PushDebug<AMFDoubleValue>("y") = m_Rotation.y;
|
||||
rot.PushDebug<AMFDoubleValue>("z") = m_Rotation.z;
|
||||
|
||||
info.PushDebug<AMFIntValue>("CollisionGroup") = m_CollisionGroup;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#include "NiPoint3.h"
|
||||
#include "NiQuaternion.h"
|
||||
|
||||
namespace GameMessages {
|
||||
struct GetObjectReportInfo;
|
||||
};
|
||||
|
||||
namespace Raknet {
|
||||
class BitStream;
|
||||
};
|
||||
@@ -29,6 +33,8 @@ public:
|
||||
int32_t GetCollisionGroup() const noexcept { return m_CollisionGroup; }
|
||||
void SetCollisionGroup(int32_t group) noexcept { m_CollisionGroup = group; }
|
||||
protected:
|
||||
bool OnGetObjectReportInfo(GameMessages::GameMsg& msg);
|
||||
|
||||
dpEntity* CreatePhysicsEntity(eReplicaComponentType type);
|
||||
|
||||
dpEntity* CreatePhysicsLnv(const float scale, const eReplicaComponentType type) const;
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
#include "dpWorld.h"
|
||||
#include "dpShapeBox.h"
|
||||
#include "dpShapeSphere.h"
|
||||
#include"EntityInfo.h"
|
||||
#include "EntityInfo.h"
|
||||
#include "Amf3.h"
|
||||
|
||||
RigidbodyPhantomPhysicsComponent::RigidbodyPhantomPhysicsComponent(Entity* parent, int32_t componentId) : PhysicsComponent(parent, componentId) {
|
||||
RegisterMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, this, &RigidbodyPhantomPhysicsComponent::OnGetObjectReportInfo);
|
||||
|
||||
m_Position = m_Parent->GetDefaultPosition();
|
||||
m_Rotation = m_Parent->GetDefaultRotation();
|
||||
m_Scale = m_Parent->GetDefaultScale();
|
||||
@@ -55,3 +58,11 @@ void RigidbodyPhantomPhysicsComponent::SpawnVertices() const {
|
||||
}
|
||||
PhysicsComponent::SpawnVertices(m_dpEntity);
|
||||
}
|
||||
|
||||
bool RigidbodyPhantomPhysicsComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) {
|
||||
PhysicsComponent::OnGetObjectReportInfo(msg);
|
||||
auto& reportInfo = static_cast<GameMessages::GetObjectReportInfo&>(msg);
|
||||
auto& info = reportInfo.subCategory->PushDebug("Rigidbody Phantom Info");
|
||||
info.PushDebug<AMFDoubleValue>("Scale") = m_Scale;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ public:
|
||||
|
||||
void SpawnVertices() const;
|
||||
private:
|
||||
bool OnGetObjectReportInfo(GameMessages::GameMsg& msg);
|
||||
|
||||
float m_Scale{};
|
||||
|
||||
dpEntity* m_dpEntity{};
|
||||
|
||||
@@ -12,8 +12,12 @@
|
||||
#include "CDPhysicsComponentTable.h"
|
||||
|
||||
#include "Entity.h"
|
||||
#include "StringifiedEnum.h"
|
||||
#include "Amf3.h"
|
||||
|
||||
SimplePhysicsComponent::SimplePhysicsComponent(Entity* parent, int32_t componentID) : PhysicsComponent(parent, componentID) {
|
||||
RegisterMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, this, &SimplePhysicsComponent::OnGetObjectReportInfo);
|
||||
|
||||
m_Position = m_Parent->GetDefaultPosition();
|
||||
m_Rotation = m_Parent->GetDefaultRotation();
|
||||
|
||||
@@ -71,3 +75,20 @@ void SimplePhysicsComponent::SetPhysicsMotionState(uint32_t value) {
|
||||
m_DirtyPhysicsMotionState = m_PhysicsMotionState != value;
|
||||
m_PhysicsMotionState = value;
|
||||
}
|
||||
|
||||
bool SimplePhysicsComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) {
|
||||
PhysicsComponent::OnGetObjectReportInfo(msg);
|
||||
auto& reportInfo = static_cast<GameMessages::GetObjectReportInfo&>(msg);
|
||||
auto& info = reportInfo.subCategory->PushDebug("Simple Physics Info");
|
||||
auto& velocity = info.PushDebug("Velocity");
|
||||
velocity.PushDebug<AMFDoubleValue>("x") = m_Velocity.x;
|
||||
velocity.PushDebug<AMFDoubleValue>("y") = m_Velocity.y;
|
||||
velocity.PushDebug<AMFDoubleValue>("z") = m_Velocity.z;
|
||||
auto& angularVelocity = info.PushDebug("Angular Velocity");
|
||||
angularVelocity.PushDebug<AMFDoubleValue>("x") = m_AngularVelocity.x;
|
||||
angularVelocity.PushDebug<AMFDoubleValue>("y") = m_AngularVelocity.y;
|
||||
angularVelocity.PushDebug<AMFDoubleValue>("z") = m_AngularVelocity.z;
|
||||
info.PushDebug<AMFIntValue>("Physics Motion State") = m_PhysicsMotionState;
|
||||
info.PushDebug<AMFStringValue>("Climbable Type") = StringifiedEnum::ToString(m_ClimbableType).data();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@ public:
|
||||
void SetClimbableType(const eClimbableType& value) { m_ClimbableType = value; }
|
||||
|
||||
private:
|
||||
bool OnGetObjectReportInfo(GameMessages::GameMsg& msg);
|
||||
|
||||
/**
|
||||
* The current velocity of the entity
|
||||
*/
|
||||
|
||||
@@ -6165,12 +6165,9 @@ void GameMessages::HandleRemoveDonationItem(RakNet::BitStream& inStream, Entity*
|
||||
}
|
||||
|
||||
void GameMessages::HandleConfirmDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity) {
|
||||
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
|
||||
if (!inventoryComponent) return;
|
||||
auto* missionComponent = entity->GetComponent<MissionComponent>();
|
||||
if (!missionComponent) return;
|
||||
auto* characterComponent = entity->GetComponent<CharacterComponent>();
|
||||
if (!characterComponent || !characterComponent->GetCurrentInteracting()) return;
|
||||
const auto [inventoryComponent, missionComponent, characterComponent] = entity->GetComponentsMut<InventoryComponent, MissionComponent, CharacterComponent>();
|
||||
if (!inventoryComponent || !missionComponent || !characterComponent || !characterComponent->GetCurrentInteracting()) return;
|
||||
|
||||
auto* donationEntity = Game::entityManager->GetEntity(characterComponent->GetCurrentInteracting());
|
||||
if (!donationEntity) return;
|
||||
auto* donationVendorComponent = donationEntity->GetComponent<DonationVendorComponent>();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "eGameMasterLevel.h"
|
||||
|
||||
class AMFBaseValue;
|
||||
class AMFArrayValue;
|
||||
class Entity;
|
||||
class Item;
|
||||
class NiQuaternion;
|
||||
@@ -788,6 +789,14 @@ namespace GameMessages {
|
||||
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
||||
};
|
||||
|
||||
struct GetObjectReportInfo : public GameMsg {
|
||||
AMFArrayValue* info{};
|
||||
AMFArrayValue* subCategory{};
|
||||
bool bVerbose{};
|
||||
|
||||
GetObjectReportInfo() : GameMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, eGameMasterLevel::DEVELOPER) {}
|
||||
};
|
||||
|
||||
struct RequestUse : public GameMsg {
|
||||
RequestUse() : GameMsg(MessageType::Game::REQUEST_USE) {}
|
||||
|
||||
@@ -854,5 +863,13 @@ namespace GameMessages {
|
||||
|
||||
NiPoint3 pos{};
|
||||
};
|
||||
|
||||
struct SetFaction : public GameMsg {
|
||||
SetFaction() : GameMsg(MessageType::Game::SET_FACTION) {}
|
||||
|
||||
int32_t factionID{};
|
||||
|
||||
bool bIgnoreChecks{ false };
|
||||
};
|
||||
};
|
||||
#endif // GAMEMESSAGES_H
|
||||
|
||||
@@ -96,20 +96,18 @@ void Mission::LoadFromXmlCur(const tinyxml2::XMLElement& element) {
|
||||
if (index >= m_Tasks.size()) {
|
||||
break;
|
||||
}
|
||||
auto* const curTask = m_Tasks[index];
|
||||
|
||||
const auto type = m_Tasks[index]->GetType();
|
||||
const auto type = curTask->GetType();
|
||||
|
||||
if (type == eMissionTaskType::COLLECTION ||
|
||||
type == eMissionTaskType::VISIT_PROPERTY) {
|
||||
auto value = std::stoul(task->Attribute("v"));
|
||||
curTask->SetProgress(value, false);
|
||||
task = task->NextSiblingElement();
|
||||
|
||||
// Collection tasks and visit property tasks store each of the collected/visited targets after the progress value
|
||||
if (type == eMissionTaskType::COLLECTION || type == eMissionTaskType::VISIT_PROPERTY) {
|
||||
std::vector<uint32_t> uniques;
|
||||
|
||||
const auto value = std::stoul(task->Attribute("v"));
|
||||
|
||||
m_Tasks[index]->SetProgress(value, false);
|
||||
|
||||
task = task->NextSiblingElement();
|
||||
|
||||
while (task != nullptr) {
|
||||
while (task != nullptr && value > 0) {
|
||||
const auto unique = std::stoul(task->Attribute("v"));
|
||||
|
||||
uniques.push_back(unique);
|
||||
@@ -119,19 +117,10 @@ void Mission::LoadFromXmlCur(const tinyxml2::XMLElement& element) {
|
||||
}
|
||||
|
||||
task = task->NextSiblingElement();
|
||||
value--;
|
||||
}
|
||||
|
||||
m_Tasks[index]->SetUnique(uniques);
|
||||
|
||||
m_Tasks[index]->SetProgress(uniques.size(), false);
|
||||
|
||||
break;
|
||||
} else {
|
||||
const auto value = std::stoul(task->Attribute("v"));
|
||||
|
||||
m_Tasks[index]->SetProgress(value, false);
|
||||
|
||||
task = task->NextSiblingElement();
|
||||
curTask->SetUnique(uniques);
|
||||
}
|
||||
|
||||
index++;
|
||||
@@ -163,31 +152,19 @@ void Mission::UpdateXmlCur(tinyxml2::XMLElement& element) {
|
||||
|
||||
if (IsComplete()) return;
|
||||
|
||||
for (auto* task : m_Tasks) {
|
||||
if (task->GetType() == eMissionTaskType::COLLECTION ||
|
||||
task->GetType() == eMissionTaskType::VISIT_PROPERTY) {
|
||||
|
||||
auto* child = element.GetDocument()->NewElement("sv");
|
||||
|
||||
child->SetAttribute("v", static_cast<unsigned int>(task->GetProgress()));
|
||||
|
||||
element.LinkEndChild(child);
|
||||
|
||||
for (auto unique : task->GetUnique()) {
|
||||
auto* uniqueElement = element.GetDocument()->NewElement("sv");
|
||||
|
||||
uniqueElement->SetAttribute("v", static_cast<unsigned int>(unique));
|
||||
|
||||
element.LinkEndChild(uniqueElement);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
auto* child = element.GetDocument()->NewElement("sv");
|
||||
|
||||
for (const auto* const task : m_Tasks) {
|
||||
auto* const child = element.InsertNewChildElement("sv");
|
||||
child->SetAttribute("v", static_cast<unsigned int>(task->GetProgress()));
|
||||
|
||||
element.LinkEndChild(child);
|
||||
// Collection and visit property tasks then need to store the collected/visited items after the progress
|
||||
const auto taskType = task->GetType();
|
||||
if (taskType == eMissionTaskType::COLLECTION || taskType == eMissionTaskType::VISIT_PROPERTY) {
|
||||
for (const auto unique : task->GetUnique()) {
|
||||
auto* uniqueElement = element.InsertNewChildElement("sv");
|
||||
|
||||
uniqueElement->SetAttribute("v", static_cast<unsigned int>(unique));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,11 +484,6 @@ void Mission::YieldRewards() {
|
||||
// If a mission rewards zero of an item, make it reward 1.
|
||||
auto count = pair.second > 0 ? pair.second : 1;
|
||||
|
||||
// Sanity check, 6 is the max any mission yields
|
||||
if (count > 6) {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
inventoryComponent->AddItem(pair.first, count, IsMission() ? eLootSourceType::MISSION : eLootSourceType::ACHIEVEMENT);
|
||||
}
|
||||
|
||||
@@ -540,11 +512,6 @@ void Mission::YieldRewards() {
|
||||
// If a mission rewards zero of an item, make it reward 1.
|
||||
auto count = pair.second > 0 ? pair.second : 1;
|
||||
|
||||
// Sanity check, 6 is the max any mission yields
|
||||
if (count > 6) {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
inventoryComponent->AddItem(pair.first, count, IsMission() ? eLootSourceType::MISSION : eLootSourceType::ACHIEVEMENT);
|
||||
}
|
||||
|
||||
|
||||
@@ -184,3 +184,7 @@ void PropertyBehavior::Update(float deltaTime, ModelComponent& modelComponent) {
|
||||
void PropertyBehavior::OnChatMessageReceived(const std::string& sMessage) {
|
||||
for (auto& state : m_States | std::views::values) state.OnChatMessageReceived(sMessage);
|
||||
}
|
||||
|
||||
void PropertyBehavior::OnHit() {
|
||||
for (auto& state : m_States | std::views::values) state.OnHit();
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
|
||||
void Update(float deltaTime, ModelComponent& modelComponent);
|
||||
void OnChatMessageReceived(const std::string& sMessage);
|
||||
void OnHit();
|
||||
|
||||
private:
|
||||
// The current active behavior state. Behaviors can only be in ONE state at a time.
|
||||
|
||||
@@ -170,3 +170,7 @@ void State::Update(float deltaTime, ModelComponent& modelComponent) {
|
||||
void State::OnChatMessageReceived(const std::string& sMessage) {
|
||||
for (auto& strip : m_Strips) strip.OnChatMessageReceived(sMessage);
|
||||
}
|
||||
|
||||
void State::OnHit() {
|
||||
for (auto& strip : m_Strips) strip.OnHit();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
void Update(float deltaTime, ModelComponent& modelComponent);
|
||||
|
||||
void OnChatMessageReceived(const std::string& sMessage);
|
||||
void OnHit();
|
||||
private:
|
||||
|
||||
// The strips contained within this state.
|
||||
|
||||
@@ -118,6 +118,16 @@ void Strip::OnChatMessageReceived(const std::string& sMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
void Strip::OnHit() {
|
||||
if (m_PausedTime > 0.0f || !HasMinimumActions()) return;
|
||||
|
||||
const auto& nextAction = GetNextAction();
|
||||
if (nextAction.GetType() == "OnAttack") {
|
||||
IncrementAction();
|
||||
m_WaitingForAction = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Strip::IncrementAction() {
|
||||
if (m_Actions.empty()) return;
|
||||
m_NextActionIndex++;
|
||||
@@ -259,6 +269,8 @@ void Strip::RemoveStates(ModelComponent& modelComponent) const {
|
||||
if (prevActionType == "OnInteract") {
|
||||
modelComponent.RemoveInteract();
|
||||
Game::entityManager->SerializeEntity(modelComponent.GetParent());
|
||||
} else if (prevActionType == "OnAttack") {
|
||||
modelComponent.RemoveAttack();
|
||||
} else if (prevActionType == "UnSmash") {
|
||||
modelComponent.RemoveUnSmash();
|
||||
}
|
||||
@@ -336,13 +348,14 @@ void Strip::Update(float deltaTime, ModelComponent& modelComponent) {
|
||||
if (m_NextActionIndex == 0) {
|
||||
if (nextAction.GetType() == "OnInteract") {
|
||||
modelComponent.AddInteract();
|
||||
Game::entityManager->SerializeEntity(entity);
|
||||
m_WaitingForAction = true;
|
||||
|
||||
} else if (nextAction.GetType() == "OnChat") {
|
||||
Game::entityManager->SerializeEntity(entity);
|
||||
m_WaitingForAction = true;
|
||||
// logic here if needed
|
||||
} else if (nextAction.GetType() == "OnAttack") {
|
||||
modelComponent.AddAttack();
|
||||
}
|
||||
Game::entityManager->SerializeEntity(entity);
|
||||
m_WaitingForAction = true;
|
||||
} else { // should be a normal block
|
||||
ProcNormalAction(deltaTime, modelComponent);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
bool HasMinimumActions() const { return m_Actions.size() >= 2; }
|
||||
|
||||
void OnChatMessageReceived(const std::string& sMessage);
|
||||
void OnHit();
|
||||
private:
|
||||
// Indicates this Strip is waiting for an action to be taken upon it to progress to its actions
|
||||
bool m_WaitingForAction{ false };
|
||||
|
||||
@@ -1445,12 +1445,28 @@ void SlashCommandHandler::Startup() {
|
||||
};
|
||||
RegisterCommand(removeIgnoreCommand);
|
||||
|
||||
Command shutdownCommand{
|
||||
Command command{
|
||||
.help = "Shuts this world down",
|
||||
.info = "Shuts this world down",
|
||||
.aliases = {"shutdown"},
|
||||
.handle = DEVGMCommands::Shutdown,
|
||||
.requiredLevel = eGameMasterLevel::DEVELOPER
|
||||
};
|
||||
RegisterCommand(shutdownCommand);
|
||||
RegisterCommand(command);
|
||||
|
||||
RegisterCommand({
|
||||
.help = "Turns all players' pvp mode on",
|
||||
.info = "Turns all players' pvp mode on",
|
||||
.aliases = {"barfight"},
|
||||
.handle = DEVGMCommands::Barfight,
|
||||
.requiredLevel = eGameMasterLevel::DEVELOPER
|
||||
});
|
||||
|
||||
RegisterCommand({
|
||||
.help = "Despawns an object by id",
|
||||
.info = "Despawns an object by id",
|
||||
.aliases = {"despawn"},
|
||||
.handle = DEVGMCommands::Despawn,
|
||||
.requiredLevel = eGameMasterLevel::DEVELOPER
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "DEVGMCommands.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
// Classes
|
||||
#include "AssetManager.h"
|
||||
#include "Character.h"
|
||||
@@ -42,12 +44,14 @@
|
||||
#include "SkillComponent.h"
|
||||
#include "TriggerComponent.h"
|
||||
#include "RigidbodyPhantomPhysicsComponent.h"
|
||||
#include "PhantomPhysicsComponent.h"
|
||||
|
||||
// Enums
|
||||
#include "eGameMasterLevel.h"
|
||||
#include "MessageType/Master.h"
|
||||
#include "eInventoryType.h"
|
||||
#include "ePlayerFlag.h"
|
||||
#include "StringifiedEnum.h"
|
||||
|
||||
|
||||
namespace DEVGMCommands {
|
||||
@@ -759,6 +763,7 @@ namespace DEVGMCommands {
|
||||
info.spawner = nullptr;
|
||||
info.spawnerID = entity->GetObjectID();
|
||||
info.spawnerNodeID = 0;
|
||||
info.settings = { new LDFData<bool>(u"SpawnedFromSlashCommand", true) };
|
||||
|
||||
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
|
||||
|
||||
@@ -800,6 +805,7 @@ namespace DEVGMCommands {
|
||||
info.spawner = nullptr;
|
||||
info.spawnerID = entity->GetObjectID();
|
||||
info.spawnerNodeID = 0;
|
||||
info.settings = { new LDFData<bool>(u"SpawnedFromSlashCommand", true) };
|
||||
|
||||
auto playerPosition = entity->GetPosition();
|
||||
while (numberToSpawn > 0) {
|
||||
@@ -1514,7 +1520,13 @@ namespace DEVGMCommands {
|
||||
}
|
||||
|
||||
if (!closest) return;
|
||||
LOG("%llu", closest->GetObjectID());
|
||||
|
||||
GameMessages::RequestServerObjectInfo objectInfo;
|
||||
objectInfo.bVerbose = true;
|
||||
objectInfo.target = closest->GetObjectID();
|
||||
objectInfo.targetForReport = closest->GetObjectID();
|
||||
objectInfo.clientId = entity->GetObjectID();
|
||||
closest->HandleMsg(objectInfo);
|
||||
|
||||
Game::entityManager->SerializeEntity(closest);
|
||||
|
||||
@@ -1528,16 +1540,6 @@ namespace DEVGMCommands {
|
||||
|
||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(header.str()));
|
||||
|
||||
for (const auto& pair : closest->GetComponents()) {
|
||||
auto id = pair.first;
|
||||
|
||||
std::stringstream stream;
|
||||
|
||||
stream << "Component [" << std::to_string(static_cast<uint32_t>(id)) << "]";
|
||||
|
||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(stream.str()));
|
||||
}
|
||||
|
||||
if (splitArgs.size() >= 2) {
|
||||
if (splitArgs[1] == "-m" && splitArgs.size() >= 3) {
|
||||
auto* const movingPlatformComponent = closest->GetComponent<MovingPlatformComponent>();
|
||||
@@ -1557,13 +1559,6 @@ namespace DEVGMCommands {
|
||||
Game::entityManager->SerializeEntity(closest);
|
||||
} else if (splitArgs[1] == "-a" && splitArgs.size() >= 3) {
|
||||
RenderComponent::PlayAnimation(closest, splitArgs.at(2));
|
||||
} else if (splitArgs[1] == "-s") {
|
||||
for (auto* entry : closest->GetSettings()) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(entry->GetString()));
|
||||
}
|
||||
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"------");
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Spawner ID: " + GeneralUtils::to_u16string(closest->GetSpawnerID()));
|
||||
} else if (splitArgs[1] == "-p") {
|
||||
const auto postion = closest->GetPosition();
|
||||
|
||||
@@ -1633,4 +1628,40 @@ namespace DEVGMCommands {
|
||||
if (character) LOG("Mythran (%s) has shutdown the world", character->GetName().c_str());
|
||||
Game::OnSignal(-1);
|
||||
}
|
||||
|
||||
void Barfight(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||
auto* const characterComponent = entity->GetComponent<CharacterComponent>();
|
||||
if (!characterComponent) return;
|
||||
|
||||
for (auto* const player : PlayerManager::GetAllPlayers()) {
|
||||
auto* const pCharacterComponent = player->GetComponent<CharacterComponent>();
|
||||
if (pCharacterComponent) pCharacterComponent->SetPvpEnabled(true);
|
||||
Game::entityManager->SerializeEntity(player);
|
||||
}
|
||||
const auto msg = u"Pvp has been turned on for all players by " + GeneralUtils::ASCIIToUTF16(characterComponent->GetName());
|
||||
ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, msg, true);
|
||||
}
|
||||
|
||||
void Despawn(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||
if (args.empty()) return;
|
||||
|
||||
const auto splitArgs = GeneralUtils::SplitString(args, ' ');
|
||||
const auto objId = GeneralUtils::TryParse<LWOOBJID>(splitArgs[0]);
|
||||
if (!objId) return;
|
||||
|
||||
auto* const target = Game::entityManager->GetEntity(*objId);
|
||||
if (!target) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Entity not found: " + GeneralUtils::UTF8ToUTF16(splitArgs[0]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target->GetVar<bool>(u"SpawnedFromSlashCommand")) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"You cannot despawn this entity as it was not despawned from a slash command.");
|
||||
return;
|
||||
}
|
||||
|
||||
target->Smash(LWOOBJID_EMPTY, eKillType::SILENT);
|
||||
LOG("Despawned entity (%llu)", target->GetObjectID());
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Despawned entity: " + GeneralUtils::to_u16string(target->GetObjectID()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,6 +74,8 @@ namespace DEVGMCommands {
|
||||
void CastSkill(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||
void DeleteInven(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||
void Shutdown(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||
void Barfight(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||
void Despawn(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||
}
|
||||
|
||||
#endif //!DEVGMCOMMANDS_H
|
||||
|
||||
@@ -14,24 +14,21 @@
|
||||
|
||||
#include "Start.h"
|
||||
|
||||
InstanceManager::InstanceManager(Logger* logger, const std::string& externalIP) {
|
||||
mLogger = logger;
|
||||
mExternalIP = externalIP;
|
||||
using std::make_unique;
|
||||
|
||||
namespace {
|
||||
const InstancePtr g_Empty{ nullptr };
|
||||
}
|
||||
|
||||
InstanceManager::InstanceManager(const std::string& externalIP) : mExternalIP{ externalIP } {
|
||||
m_LastPort =
|
||||
GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("world_port_start")).value_or(m_LastPort);
|
||||
m_LastInstanceID = LWOINSTANCEID_INVALID;
|
||||
}
|
||||
|
||||
InstanceManager::~InstanceManager() {
|
||||
for (Instance* i : m_Instances) {
|
||||
delete i;
|
||||
i = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneID) {
|
||||
const InstancePtr& InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneID) {
|
||||
LOG("Searching for an instance for mapID %i/%i", mapID, cloneID);
|
||||
Instance* instance = FindInstance(mapID, isFriendTransfer, cloneID);
|
||||
auto& instance = FindInstance(mapID, isFriendTransfer, cloneID);
|
||||
if (instance) return instance;
|
||||
|
||||
// If we are shutting down, return a nullptr so a new instance is not created.
|
||||
@@ -40,7 +37,7 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW
|
||||
mapID,
|
||||
m_LastInstanceID + 1,
|
||||
cloneID);
|
||||
return nullptr;
|
||||
return g_Empty;
|
||||
}
|
||||
//TODO: Update this so that the IP is read from a configuration file instead
|
||||
|
||||
@@ -56,23 +53,23 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW
|
||||
}
|
||||
|
||||
uint32_t port = GetFreePort();
|
||||
instance = new Instance(mExternalIP, port, mapID, ++m_LastInstanceID, cloneID, softCap, maxPlayers);
|
||||
auto newInstance = make_unique<Instance>(mExternalIP, port, mapID, ++m_LastInstanceID, cloneID, softCap, maxPlayers);
|
||||
|
||||
//Start the actual process:
|
||||
StartWorldServer(mapID, port, m_LastInstanceID, maxPlayers, cloneID);
|
||||
|
||||
m_Instances.push_back(instance);
|
||||
m_Instances.push_back(std::move(newInstance));
|
||||
|
||||
if (instance) {
|
||||
if (m_Instances.back()) {
|
||||
LOG("Created new instance: %i/%i/%i with min/max %i/%i", mapID, m_LastInstanceID, cloneID, softCap, maxPlayers);
|
||||
return instance;
|
||||
return m_Instances.back();
|
||||
} else LOG("Failed to create a new instance!");
|
||||
|
||||
return nullptr;
|
||||
return g_Empty;
|
||||
}
|
||||
|
||||
bool InstanceManager::IsPortInUse(uint32_t port) {
|
||||
for (Instance* i : m_Instances) {
|
||||
for (const auto& i : m_Instances) {
|
||||
if (i && i->GetPort() == port) {
|
||||
return true;
|
||||
}
|
||||
@@ -84,7 +81,7 @@ bool InstanceManager::IsPortInUse(uint32_t port) {
|
||||
uint32_t InstanceManager::GetFreePort() {
|
||||
uint32_t port = m_LastPort;
|
||||
std::vector<uint32_t> usedPorts;
|
||||
for (Instance* i : m_Instances) {
|
||||
for (const auto& i : m_Instances) {
|
||||
usedPorts.push_back(i->GetPort());
|
||||
}
|
||||
|
||||
@@ -101,7 +98,7 @@ uint32_t InstanceManager::GetFreePort() {
|
||||
}
|
||||
|
||||
void InstanceManager::AddPlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINSTANCEID instanceID) {
|
||||
Instance* inst = FindInstance(mapID, instanceID);
|
||||
const auto& inst = FindInstance(mapID, instanceID);
|
||||
if (inst) {
|
||||
Player player;
|
||||
player.addr = systemAddr;
|
||||
@@ -111,7 +108,7 @@ void InstanceManager::AddPlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINS
|
||||
}
|
||||
|
||||
void InstanceManager::RemovePlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINSTANCEID instanceID) {
|
||||
Instance* inst = FindInstance(mapID, instanceID);
|
||||
const auto& inst = FindInstance(mapID, instanceID);
|
||||
if (inst) {
|
||||
Player player;
|
||||
player.addr = systemAddr;
|
||||
@@ -120,25 +117,23 @@ void InstanceManager::RemovePlayer(SystemAddress systemAddr, LWOMAPID mapID, LWO
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Instance*> InstanceManager::GetInstances() const {
|
||||
const std::vector<InstancePtr>& InstanceManager::GetInstances() const {
|
||||
return m_Instances;
|
||||
}
|
||||
|
||||
void InstanceManager::AddInstance(Instance* instance) {
|
||||
void InstanceManager::AddInstance(InstancePtr& instance) {
|
||||
if (instance == nullptr) return;
|
||||
|
||||
m_Instances.push_back(instance);
|
||||
m_Instances.push_back(std::move(instance));
|
||||
}
|
||||
|
||||
void InstanceManager::RemoveInstance(Instance* instance) {
|
||||
void InstanceManager::RemoveInstance(const InstancePtr& instance) {
|
||||
for (uint32_t i = 0; i < m_Instances.size(); ++i) {
|
||||
if (m_Instances[i] == instance) {
|
||||
instance->SetShutdownComplete(true);
|
||||
|
||||
if (!Game::ShouldShutdown()) RedirectPendingRequests(instance);
|
||||
|
||||
delete m_Instances[i];
|
||||
|
||||
m_Instances.erase(m_Instances.begin() + i);
|
||||
|
||||
break;
|
||||
@@ -146,7 +141,7 @@ void InstanceManager::RemoveInstance(Instance* instance) {
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceManager::ReadyInstance(Instance* instance) {
|
||||
void InstanceManager::ReadyInstance(const InstancePtr& instance) {
|
||||
instance->SetIsReady(true);
|
||||
|
||||
auto& pending = instance->GetPendingRequests();
|
||||
@@ -172,7 +167,7 @@ void InstanceManager::ReadyInstance(Instance* instance) {
|
||||
pending.clear();
|
||||
}
|
||||
|
||||
void InstanceManager::RequestAffirmation(Instance* instance, const PendingInstanceRequest& request) {
|
||||
void InstanceManager::RequestAffirmation(const InstancePtr& instance, const PendingInstanceRequest& request) {
|
||||
instance->GetPendingAffirmations().push_back(request);
|
||||
|
||||
CBITSTREAM;
|
||||
@@ -189,7 +184,7 @@ void InstanceManager::RequestAffirmation(Instance* instance, const PendingInstan
|
||||
);
|
||||
}
|
||||
|
||||
void InstanceManager::AffirmTransfer(Instance* instance, const uint64_t transferID) {
|
||||
void InstanceManager::AffirmTransfer(const InstancePtr& instance, const uint64_t transferID) {
|
||||
auto& pending = instance->GetPendingAffirmations();
|
||||
|
||||
for (auto i = 0u; i < pending.size(); ++i) {
|
||||
@@ -217,11 +212,11 @@ void InstanceManager::AffirmTransfer(Instance* instance, const uint64_t transfer
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceManager::RedirectPendingRequests(Instance* instance) {
|
||||
void InstanceManager::RedirectPendingRequests(const InstancePtr& instance) {
|
||||
const auto& zoneId = instance->GetZoneID();
|
||||
|
||||
for (const auto& request : instance->GetPendingAffirmations()) {
|
||||
auto* in = Game::im->GetInstance(zoneId.GetMapID(), false, zoneId.GetCloneID());
|
||||
const auto& in = Game::im->GetInstance(zoneId.GetMapID(), false, zoneId.GetCloneID());
|
||||
|
||||
if (in && !in->GetIsReady()) // Instance not ready, make a pending request
|
||||
{
|
||||
@@ -234,57 +229,48 @@ void InstanceManager::RedirectPendingRequests(Instance* instance) {
|
||||
}
|
||||
}
|
||||
|
||||
Instance* InstanceManager::GetInstanceBySysAddr(SystemAddress& sysAddr) {
|
||||
for (uint32_t i = 0; i < m_Instances.size(); ++i) {
|
||||
if (m_Instances[i] && m_Instances[i]->GetSysAddr() == sysAddr) {
|
||||
return m_Instances[i];
|
||||
const InstancePtr& InstanceManager::GetInstanceBySysAddr(SystemAddress& sysAddr) {
|
||||
for (const auto& instance : m_Instances) {
|
||||
if (instance && instance->GetSysAddr() == sysAddr) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return g_Empty;
|
||||
}
|
||||
|
||||
bool InstanceManager::IsInstanceFull(Instance* instance, bool isFriendTransfer) {
|
||||
if (!isFriendTransfer && instance->GetSoftCap() > instance->GetCurrentClientCount())
|
||||
return false;
|
||||
else if (isFriendTransfer && instance->GetHardCap() > instance->GetCurrentClientCount())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Instance* InstanceManager::FindInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneId) {
|
||||
for (Instance* i : m_Instances) {
|
||||
if (i && i->GetMapID() == mapID && i->GetCloneID() == cloneId && !IsInstanceFull(i, isFriendTransfer) && !i->GetIsPrivate() && !i->GetShutdownComplete() && !i->GetIsShuttingDown()) {
|
||||
const InstancePtr& InstanceManager::FindInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneId) {
|
||||
for (const auto& i : m_Instances) {
|
||||
if (i && i->GetMapID() == mapID && i->GetCloneID() == cloneId && !i->IsFull(isFriendTransfer) && !i->GetIsPrivate() && !i->GetShutdownComplete() && !i->GetIsShuttingDown()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return g_Empty;
|
||||
}
|
||||
|
||||
Instance* InstanceManager::FindInstance(LWOMAPID mapID, LWOINSTANCEID instanceID) {
|
||||
for (Instance* i : m_Instances) {
|
||||
const InstancePtr& InstanceManager::FindInstance(LWOMAPID mapID, LWOINSTANCEID instanceID) {
|
||||
for (const auto& i : m_Instances) {
|
||||
if (i && i->GetMapID() == mapID && i->GetInstanceID() == instanceID && !i->GetIsPrivate() && !i->GetShutdownComplete() && !i->GetIsShuttingDown()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return g_Empty;
|
||||
}
|
||||
|
||||
Instance* InstanceManager::FindInstanceWithPrivate(LWOMAPID mapID, LWOINSTANCEID instanceID) {
|
||||
for (Instance* i : m_Instances) {
|
||||
const InstancePtr& InstanceManager::FindInstanceWithPrivate(LWOMAPID mapID, LWOINSTANCEID instanceID) {
|
||||
for (const auto& i : m_Instances) {
|
||||
if (i && i->GetMapID() == mapID && i->GetInstanceID() == instanceID && !i->GetShutdownComplete() && !i->GetIsShuttingDown()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return g_Empty;
|
||||
}
|
||||
|
||||
Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID cloneID, const std::string& password) {
|
||||
auto* instance = FindPrivateInstance(password);
|
||||
const InstancePtr& InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID cloneID, const std::string& password) {
|
||||
const auto& instance = FindPrivateInstance(password);
|
||||
|
||||
if (instance != nullptr) {
|
||||
return instance;
|
||||
@@ -295,27 +281,27 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon
|
||||
mapID,
|
||||
m_LastInstanceID + 1,
|
||||
cloneID);
|
||||
return nullptr;
|
||||
return g_Empty;
|
||||
}
|
||||
|
||||
int maxPlayers = 999;
|
||||
|
||||
uint32_t port = GetFreePort();
|
||||
instance = new Instance(mExternalIP, port, mapID, ++m_LastInstanceID, cloneID, maxPlayers, maxPlayers, true, password);
|
||||
auto newInstance = make_unique<Instance>(mExternalIP, port, mapID, ++m_LastInstanceID, cloneID, maxPlayers, maxPlayers, true, password);
|
||||
|
||||
//Start the actual process:
|
||||
StartWorldServer(mapID, port, m_LastInstanceID, maxPlayers, cloneID);
|
||||
|
||||
m_Instances.push_back(instance);
|
||||
m_Instances.push_back(std::move(newInstance));
|
||||
|
||||
if (instance) return instance;
|
||||
if (m_Instances.back()) return m_Instances.back();
|
||||
else LOG("Failed to create a new instance!");
|
||||
|
||||
return instance;
|
||||
return g_Empty;
|
||||
}
|
||||
|
||||
Instance* InstanceManager::FindPrivateInstance(const std::string& password) {
|
||||
for (auto* instance : m_Instances) {
|
||||
const InstancePtr& InstanceManager::FindPrivateInstance(const std::string& password) {
|
||||
for (const auto& instance : m_Instances) {
|
||||
if (!instance) continue;
|
||||
|
||||
if (!instance->GetIsPrivate()) {
|
||||
@@ -329,7 +315,7 @@ Instance* InstanceManager::FindPrivateInstance(const std::string& password) {
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return g_Empty;
|
||||
}
|
||||
|
||||
int InstanceManager::GetSoftCap(LWOMAPID mapID) {
|
||||
@@ -363,3 +349,14 @@ void Instance::Shutdown() {
|
||||
|
||||
LOG("Triggered world shutdown for zone/clone/instance %i/%i/%i", GetMapID(), GetCloneID(), GetInstanceID());
|
||||
}
|
||||
|
||||
|
||||
bool Instance::IsFull(bool isFriendTransfer) const {
|
||||
if (!isFriendTransfer && GetSoftCap() > GetCurrentClientCount())
|
||||
return false;
|
||||
else if (isFriendTransfer && GetHardCap() > GetCurrentClientCount())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@ public:
|
||||
|
||||
void Shutdown();
|
||||
|
||||
bool IsFull(bool isFriendTransfer) const;
|
||||
|
||||
private:
|
||||
std::string m_IP{};
|
||||
uint32_t m_Port{};
|
||||
@@ -99,42 +101,42 @@ private:
|
||||
//Private functions:
|
||||
};
|
||||
|
||||
using InstancePtr = std::unique_ptr<Instance>;
|
||||
|
||||
class InstanceManager {
|
||||
public:
|
||||
InstanceManager(Logger* logger, const std::string& externalIP);
|
||||
~InstanceManager();
|
||||
InstanceManager(const std::string& externalIP);
|
||||
|
||||
Instance* GetInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneID); //Creates an instance if none found
|
||||
const InstancePtr& GetInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneID); //Creates an instance if none found
|
||||
bool IsPortInUse(uint32_t port);
|
||||
uint32_t GetFreePort();
|
||||
|
||||
void AddPlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINSTANCEID instanceID);
|
||||
void RemovePlayer(SystemAddress systemAddr, LWOMAPID mapID, LWOINSTANCEID instanceID);
|
||||
|
||||
std::vector<Instance*> GetInstances() const;
|
||||
void AddInstance(Instance* instance);
|
||||
void RemoveInstance(Instance* instance);
|
||||
const std::vector<InstancePtr>& GetInstances() const;
|
||||
void AddInstance(InstancePtr& instance);
|
||||
void RemoveInstance(const InstancePtr& instance);
|
||||
|
||||
void ReadyInstance(Instance* instance);
|
||||
void RequestAffirmation(Instance* instance, const PendingInstanceRequest& request);
|
||||
void AffirmTransfer(Instance* instance, uint64_t transferID);
|
||||
void ReadyInstance(const InstancePtr& instance);
|
||||
void RequestAffirmation(const InstancePtr& instance, const PendingInstanceRequest& request);
|
||||
void AffirmTransfer(const InstancePtr& instance, uint64_t transferID);
|
||||
|
||||
void RedirectPendingRequests(Instance* instance);
|
||||
void RedirectPendingRequests(const InstancePtr& instance);
|
||||
|
||||
Instance* GetInstanceBySysAddr(SystemAddress& sysAddr);
|
||||
const InstancePtr& GetInstanceBySysAddr(SystemAddress& sysAddr);
|
||||
|
||||
Instance* FindInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneId = 0);
|
||||
Instance* FindInstance(LWOMAPID mapID, LWOINSTANCEID instanceID);
|
||||
Instance* FindInstanceWithPrivate(LWOMAPID mapID, LWOINSTANCEID instanceID);
|
||||
const InstancePtr& FindInstance(LWOMAPID mapID, bool isFriendTransfer, LWOCLONEID cloneId = 0);
|
||||
const InstancePtr& FindInstance(LWOMAPID mapID, LWOINSTANCEID instanceID);
|
||||
const InstancePtr& FindInstanceWithPrivate(LWOMAPID mapID, LWOINSTANCEID instanceID);
|
||||
|
||||
Instance* CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID cloneID, const std::string& password);
|
||||
Instance* FindPrivateInstance(const std::string& password);
|
||||
const InstancePtr& CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID cloneID, const std::string& password);
|
||||
const InstancePtr& FindPrivateInstance(const std::string& password);
|
||||
void SetIsShuttingDown(bool value) { this->m_IsShuttingDown = value; };
|
||||
|
||||
private:
|
||||
Logger* mLogger;
|
||||
std::string mExternalIP;
|
||||
std::vector<Instance*> m_Instances;
|
||||
std::vector<std::unique_ptr<Instance>> m_Instances;
|
||||
uint16_t m_LastPort = 3000;
|
||||
LWOINSTANCEID m_LastInstanceID;
|
||||
|
||||
@@ -144,7 +146,6 @@ private:
|
||||
bool m_IsShuttingDown = false;
|
||||
|
||||
//Private functions:
|
||||
bool IsInstanceFull(Instance* instance, bool isFriendTransfer);
|
||||
int GetSoftCap(LWOMAPID mapID);
|
||||
int GetHardCap(LWOMAPID mapID);
|
||||
};
|
||||
|
||||
@@ -359,7 +359,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
//Create additional objects here:
|
||||
PersistentIDManager::Initialize();
|
||||
Game::im = new InstanceManager(Game::logger, Game::server->GetIP());
|
||||
Game::im = new InstanceManager(Game::server->GetIP());
|
||||
|
||||
//Get CDClient initial information
|
||||
try {
|
||||
@@ -434,9 +434,9 @@ int main(int argc, char** argv) {
|
||||
framesSinceKillUniverseCommand++;
|
||||
}
|
||||
|
||||
const auto instances = Game::im->GetInstances();
|
||||
const auto& instances = Game::im->GetInstances();
|
||||
|
||||
for (auto* instance : instances) {
|
||||
for (const auto& instance : instances) {
|
||||
if (instance == nullptr) {
|
||||
break;
|
||||
}
|
||||
@@ -460,7 +460,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
//Remove dead instances
|
||||
for (auto* instance : instances) {
|
||||
for (const auto& instance : instances) {
|
||||
if (instance == nullptr) {
|
||||
break;
|
||||
}
|
||||
@@ -489,7 +489,7 @@ void HandlePacket(Packet* packet) {
|
||||
|
||||
//Since this disconnection is intentional, we'll just delete it as
|
||||
//we'll start a new one anyway if needed:
|
||||
Instance* instance =
|
||||
const auto& instance =
|
||||
Game::im->GetInstanceBySysAddr(packet->systemAddress);
|
||||
if (instance) {
|
||||
LOG("Actually disconnected from zone %i clone %i instance %i port %i", instance->GetMapID(), instance->GetCloneID(), instance->GetInstanceID(), instance->GetPort());
|
||||
@@ -510,7 +510,7 @@ void HandlePacket(Packet* packet) {
|
||||
if (packet->data[0] == ID_CONNECTION_LOST) {
|
||||
LOG("A server has lost the connection");
|
||||
|
||||
Instance* instance =
|
||||
const auto& instance =
|
||||
Game::im->GetInstanceBySysAddr(packet->systemAddress);
|
||||
if (instance) {
|
||||
LWOZONEID zoneID = instance->GetZoneID(); //Get the zoneID so we can recreate a server
|
||||
@@ -561,9 +561,9 @@ void HandlePacket(Packet* packet) {
|
||||
LOG("Shutdown sequence has been started. Not creating a new zone.");
|
||||
break;
|
||||
}
|
||||
Instance* in = Game::im->GetInstance(zoneID, false, zoneClone);
|
||||
const auto& in = Game::im->GetInstance(zoneID, false, zoneClone);
|
||||
|
||||
for (auto* instance : Game::im->GetInstances()) {
|
||||
for (const auto& instance : Game::im->GetInstances()) {
|
||||
LOG("Instance: %i/%i/%i -> %i %s", instance->GetMapID(), instance->GetCloneID(), instance->GetInstanceID(), instance == in, instance->GetSysAddr().ToString());
|
||||
}
|
||||
|
||||
@@ -603,12 +603,12 @@ void HandlePacket(Packet* packet) {
|
||||
|
||||
if (theirServerType == ServerType::World) {
|
||||
if (!Game::im->IsPortInUse(theirPort)) {
|
||||
Instance* in = new Instance(theirIP.string, theirPort, theirZoneID, theirInstanceID, 0, 12, 12);
|
||||
auto in = std::make_unique<Instance>(theirIP.string, theirPort, theirZoneID, theirInstanceID, 0, 12, 12);
|
||||
|
||||
in->SetSysAddr(packet->systemAddress);
|
||||
Game::im->AddInstance(in);
|
||||
} else {
|
||||
auto* instance = Game::im->FindInstanceWithPrivate(theirZoneID, static_cast<LWOINSTANCEID>(theirInstanceID));
|
||||
const auto& instance = Game::im->FindInstanceWithPrivate(theirZoneID, static_cast<LWOINSTANCEID>(theirInstanceID));
|
||||
if (instance) {
|
||||
instance->SetSysAddr(packet->systemAddress);
|
||||
}
|
||||
@@ -682,7 +682,7 @@ void HandlePacket(Packet* packet) {
|
||||
inStream.Read(theirZoneID);
|
||||
inStream.Read(theirInstanceID);
|
||||
|
||||
auto instance =
|
||||
const auto& instance =
|
||||
Game::im->FindInstance(theirZoneID, theirInstanceID);
|
||||
if (instance) {
|
||||
instance->AddPlayer(Player());
|
||||
@@ -702,7 +702,7 @@ void HandlePacket(Packet* packet) {
|
||||
inStream.Read(theirZoneID);
|
||||
inStream.Read(theirInstanceID);
|
||||
|
||||
auto instance =
|
||||
const auto& instance =
|
||||
Game::im->FindInstance(theirZoneID, theirInstanceID);
|
||||
if (instance) {
|
||||
instance->RemovePlayer(Player());
|
||||
@@ -728,7 +728,7 @@ void HandlePacket(Packet* packet) {
|
||||
inStream.Read<char>(character);
|
||||
password += character;
|
||||
}
|
||||
auto* newInst = Game::im->CreatePrivateInstance(mapId, cloneId, password.c_str());
|
||||
const auto& newInst = Game::im->CreatePrivateInstance(mapId, cloneId, password.c_str());
|
||||
LOG("Creating private zone %i/%i/%i with password %s", newInst->GetMapID(), newInst->GetCloneID(), newInst->GetInstanceID(), password.c_str());
|
||||
|
||||
break;
|
||||
@@ -754,9 +754,9 @@ void HandlePacket(Packet* packet) {
|
||||
password += character;
|
||||
}
|
||||
|
||||
auto* instance = Game::im->FindPrivateInstance(password.c_str());
|
||||
const auto& instance = Game::im->FindPrivateInstance(password.c_str());
|
||||
|
||||
LOG("Join private zone: %llu %d %s %p", requestID, mythranShift, password.c_str(), instance);
|
||||
LOG("Join private zone: %llu %d %s %p", requestID, mythranShift, password.c_str(), instance.get());
|
||||
|
||||
if (instance == nullptr) {
|
||||
return;
|
||||
@@ -781,7 +781,7 @@ void HandlePacket(Packet* packet) {
|
||||
|
||||
LOG("Got world ready %i %i", zoneID, instanceID);
|
||||
|
||||
auto* instance = Game::im->FindInstance(zoneID, instanceID);
|
||||
const auto& instance = Game::im->FindInstance(zoneID, instanceID);
|
||||
|
||||
if (instance == nullptr) {
|
||||
LOG("Failed to find zone to ready");
|
||||
@@ -819,7 +819,7 @@ void HandlePacket(Packet* packet) {
|
||||
|
||||
LOG("Got affirmation of transfer %llu", requestID);
|
||||
|
||||
auto* instance = Game::im->GetInstanceBySysAddr(packet->systemAddress);
|
||||
const auto& instance = Game::im->GetInstanceBySysAddr(packet->systemAddress);
|
||||
|
||||
if (instance == nullptr)
|
||||
return;
|
||||
@@ -832,7 +832,7 @@ void HandlePacket(Packet* packet) {
|
||||
case MessageType::Master::SHUTDOWN_RESPONSE: {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
|
||||
auto* instance = Game::im->GetInstanceBySysAddr(packet->systemAddress);
|
||||
const auto& instance = Game::im->GetInstanceBySysAddr(packet->systemAddress);
|
||||
LOG("Got shutdown response from %s", packet->systemAddress.ToString());
|
||||
if (instance == nullptr) {
|
||||
return;
|
||||
@@ -882,13 +882,13 @@ int ShutdownSequence(int32_t signal) {
|
||||
LOG("Saved ObjectIDTracker to DB");
|
||||
|
||||
// A server might not be finished spinning up yet, remove all of those here.
|
||||
for (auto* instance : Game::im->GetInstances()) {
|
||||
for (const auto& instance : Game::im->GetInstances()) {
|
||||
if (!instance) continue;
|
||||
|
||||
if (!instance->GetIsReady()) {
|
||||
Game::im->RemoveInstance(instance);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* instance : Game::im->GetInstances()) {
|
||||
|
||||
instance->SetIsShuttingDown(true);
|
||||
}
|
||||
|
||||
@@ -909,7 +909,7 @@ int ShutdownSequence(int32_t signal) {
|
||||
|
||||
allInstancesShutdown = true;
|
||||
|
||||
for (auto* instance : Game::im->GetInstances()) {
|
||||
for (const auto& instance : Game::im->GetInstances()) {
|
||||
if (instance == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void HTTPMonitorInfo::Serialize(RakNet::BitStream &bitStream) const {
|
||||
void HTTPMonitorInfo::Serialize(RakNet::BitStream& bitStream) const {
|
||||
bitStream.Write(port);
|
||||
bitStream.Write<uint8_t>(openWeb);
|
||||
bitStream.Write<uint8_t>(supportsSum);
|
||||
@@ -81,32 +81,29 @@ void WorldPackets::SendServerState(const SystemAddress& sysAddr) {
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, int64_t reputation, LWOOBJID player, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm) {
|
||||
void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, int64_t reputation, LWOOBJID player, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm, const LWOCLONEID cloneID) {
|
||||
using namespace std;
|
||||
RakNet::BitStream bitStream;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::CREATE_CHARACTER);
|
||||
|
||||
RakNet::BitStream data;
|
||||
data.Write<uint32_t>(7); //LDF key count
|
||||
|
||||
std::unique_ptr<LDFData<LWOOBJID>> objid(new LDFData<LWOOBJID>(u"objid", player));
|
||||
std::unique_ptr<LDFData<LOT>> lot(new LDFData<LOT>(u"template", 1));
|
||||
std::unique_ptr<LDFData<std::string>> xmlConfigData(new LDFData<std::string>(u"xmlData", xmlData));
|
||||
std::unique_ptr<LDFData<std::u16string>> name(new LDFData<std::u16string>(u"name", username));
|
||||
std::unique_ptr<LDFData<int32_t>> gmlevel(new LDFData<int32_t>(u"gmlevel", static_cast<int32_t>(gm)));
|
||||
std::unique_ptr<LDFData<int32_t>> chatmode(new LDFData<int32_t>(u"chatmode", static_cast<int32_t>(gm)));
|
||||
std::unique_ptr<LDFData<int64_t>> reputationLdf(new LDFData<int64_t>(u"reputation", reputation));
|
||||
|
||||
objid->WriteToPacket(data);
|
||||
lot->WriteToPacket(data);
|
||||
name->WriteToPacket(data);
|
||||
gmlevel->WriteToPacket(data);
|
||||
chatmode->WriteToPacket(data);
|
||||
xmlConfigData->WriteToPacket(data);
|
||||
reputationLdf->WriteToPacket(data);
|
||||
std::vector<std::unique_ptr<LDFBaseData>> ldfData;
|
||||
ldfData.push_back(std::move(make_unique<LDFData<LWOOBJID>>(u"objid", player)));
|
||||
ldfData.push_back(std::move(make_unique<LDFData<LOT>>(u"template", 1)));
|
||||
ldfData.push_back(std::move(make_unique<LDFData<string>>(u"xmlData", xmlData)));
|
||||
ldfData.push_back(std::move(make_unique<LDFData<u16string>>(u"name", username)));
|
||||
ldfData.push_back(std::move(make_unique<LDFData<int32_t>>(u"gmlevel", static_cast<int32_t>(gm))));
|
||||
ldfData.push_back(std::move(make_unique<LDFData<int32_t>>(u"chatmode", static_cast<int32_t>(gm))));
|
||||
ldfData.push_back(std::move(make_unique<LDFData<int64_t>>(u"reputation", reputation)));
|
||||
ldfData.push_back(std::move(make_unique<LDFData<int32_t>>(u"propertycloneid", cloneID)));
|
||||
|
||||
data.Write<uint32_t>(ldfData.size());
|
||||
for (const auto& toSerialize : ldfData) toSerialize->WriteToPacket(data);
|
||||
|
||||
//Compress the data before sending:
|
||||
const uint32_t reservedSize = ZCompression::GetMaxCompressedLength(data.GetNumberOfBytesUsed());
|
||||
uint8_t* compressedData = new uint8_t[reservedSize];
|
||||
const uint32_t reservedSize = ZCompression::GetMaxCompressedLength(data.GetNumberOfBytesUsed());
|
||||
uint8_t* compressedData = new uint8_t[reservedSize];
|
||||
|
||||
// TODO There should be better handling here for not enough memory...
|
||||
if (!compressedData) return;
|
||||
@@ -177,7 +174,7 @@ void WorldPackets::SendHTTPMonitorInfo(const SystemAddress& sysAddr, const HTTPM
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void WorldPackets::SendDebugOuput(const SystemAddress& sysAddr, const std::string& data){
|
||||
void WorldPackets::SendDebugOuput(const SystemAddress& sysAddr, const std::string& data) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::DEBUG_OUTPUT);
|
||||
bitStream.Write<uint32_t>(data.size());
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace WorldPackets {
|
||||
void SendCharacterDeleteResponse(const SystemAddress& sysAddr, bool response);
|
||||
void SendTransferToWorld(const SystemAddress& sysAddr, const std::string& serverIP, uint32_t serverPort, bool mythranShift);
|
||||
void SendServerState(const SystemAddress& sysAddr);
|
||||
void SendCreateCharacter(const SystemAddress& sysAddr, int64_t reputation, LWOOBJID player, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm);
|
||||
void SendCreateCharacter(const SystemAddress& sysAddr, int64_t reputation, LWOOBJID player, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm, const LWOCLONEID cloneID);
|
||||
void SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::set<std::pair<uint8_t, uint8_t>> unacceptedItems);
|
||||
void SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel);
|
||||
void SendHTTPMonitorInfo(const SystemAddress& sysAddr, const HTTPMonitorInfo& info);
|
||||
|
||||
@@ -1040,7 +1040,7 @@ void HandlePacket(Packet* packet) {
|
||||
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
||||
if (!characterComponent) return;
|
||||
|
||||
WorldPackets::SendCreateCharacter(packet->systemAddress, player->GetComponent<CharacterComponent>()->GetReputation(), player->GetObjectID(), c->GetXMLData(), username, c->GetGMLevel());
|
||||
WorldPackets::SendCreateCharacter(packet->systemAddress, player->GetComponent<CharacterComponent>()->GetReputation(), player->GetObjectID(), c->GetXMLData(), username, c->GetGMLevel(), c->GetPropertyCloneID());
|
||||
WorldPackets::SendServerState(packet->systemAddress);
|
||||
|
||||
const auto respawnPoint = player->GetCharacter()->GetRespawnPoint(Game::zoneManager->GetZone()->GetWorldID());
|
||||
|
||||
@@ -114,21 +114,23 @@ These commands are primarily for development and testing. The usage of many of t
|
||||
|addfaction|`/addfaction <faction id>`|Add the faction to the users list of factions|8|
|
||||
|getfactions|`/getfactions`|Shows the player's factions|8|
|
||||
|setrewardcode|`/setrewardcode <code>`|Sets the rewardcode for the account you are logged into if it's a valid rewardcode, See cdclient table `RewardCodes`|8|
|
||||
|barfight|`/barfight start`|Starts a barfight (turns everyones pvp on)|8|
|
||||
|despawn|`/despawn <objectID>`|Despawns the entity objectID IF it was spawned in through a slash command.|8|
|
||||
|crash|`/crash`|Crashes the server.|9|
|
||||
|rollloot|`/rollloot <loot matrix index> <item id> <amount>`|Given a `loot matrix index`, look for `item id` in that matrix `amount` times and print to the chat box statistics of rolling that loot matrix.|9|
|
||||
|castskill|`/castskill <skill id>`|Casts the skill as the player|9|
|
||||
|
||||
## Detailed `/inspect` Usage
|
||||
|
||||
`/inspect <component> (-m <waypoint> | -a <animation> | -s | -p | -f (faction) | -t)`
|
||||
`/inspect <component> (-m <waypoint> | -a <animation> | -p | -f (faction) | -t)`
|
||||
|
||||
Finds the closest entity with the given component or LDF variable (ignoring players and racing cars), printing its ID, distance from the player, and whether it is sleeping, as well as the the IDs of all components the entity has.
|
||||
This info is then shown in a window on the client which the user can navigate
|
||||
|
||||
### `/inspect` Options
|
||||
|
||||
* `-m`: If the entity has a moving platform component, sends it to the given waypoint, or stops the platform if `waypoint` is `-1`.
|
||||
* `-a`: Plays the given animation on the entity.
|
||||
* `-s`: Prints the entity's settings and spawner ID.
|
||||
* `-p`: Prints the entity's position
|
||||
* `-f`: If the entity has a destroyable component, prints whether the entity is smashable and its friendly and enemy faction IDs; if `faction` is specified, adds that faction to the entity.
|
||||
* `-cf`: check if the entity is enemy or friend
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
<location zone="1400" x="-696.957" y="-3.206" z="-452.441" rw="0.884105" rx="0.00" ry="0.467288" rz="0.00" />
|
||||
<!--CP Sentinel Point Zeta-->
|
||||
<location zone="1800" x="-222.634" y="92.373" z="568.392" rw="-0.435024" rx="0.00" ry="0.900419" rz="0.00" />
|
||||
<!--CP Monastery-->
|
||||
<location zone="1800" x="-74.633" y="98.449" z="-650.531" rw="0.705469" rx="0.00" ry="0.708741" rz="0.00" />
|
||||
<!--NJ Monastery Courtyard-->
|
||||
<location zone="2000" x="-63.487" y="208.270" z="379.195" rw="0.00" rx="0.00" ry="1" rz="0.00" />
|
||||
</locations>
|
||||
|
||||
Reference in New Issue
Block a user