2021-12-05 17:54:36 +00:00
|
|
|
#include "Player.h"
|
|
|
|
|
|
|
|
#include <ctime>
|
|
|
|
|
|
|
|
#include "Character.h"
|
|
|
|
#include "Database.h"
|
|
|
|
#include "MissionComponent.h"
|
|
|
|
#include "UserManager.h"
|
|
|
|
#include "EntityManager.h"
|
2023-10-21 23:31:55 +00:00
|
|
|
#include "Logger.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
#include "ZoneInstanceManager.h"
|
|
|
|
#include "WorldPackets.h"
|
|
|
|
#include "dZoneManager.h"
|
|
|
|
#include "CharacterComponent.h"
|
|
|
|
#include "Mail.h"
|
2023-01-07 05:17:05 +00:00
|
|
|
#include "User.h"
|
2022-06-19 07:14:33 +00:00
|
|
|
#include "CppScripts.h"
|
2023-01-07 05:17:05 +00:00
|
|
|
#include "Loot.h"
|
2023-03-04 07:16:37 +00:00
|
|
|
#include "eReplicaComponentType.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
std::vector<Player*> Player::m_Players = {};
|
|
|
|
|
|
|
|
Player::Player(const LWOOBJID& objectID, const EntityInfo info, User* user, Entity* parentEntity) : Entity(objectID, info, parentEntity) {
|
|
|
|
m_ParentUser = user;
|
|
|
|
m_Character = m_ParentUser->GetLastUsedChar();
|
|
|
|
m_ParentUser->SetLoggedInChar(objectID);
|
|
|
|
m_GMLevel = m_Character->GetGMLevel();
|
|
|
|
m_SystemAddress = m_ParentUser->GetSystemAddress();
|
|
|
|
m_DroppedLoot = {};
|
2021-12-11 13:21:00 +00:00
|
|
|
m_DroppedCoins = 0;
|
2022-07-25 02:26:51 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_GhostReferencePoint = NiPoint3::ZERO;
|
|
|
|
m_GhostOverridePoint = NiPoint3::ZERO;
|
|
|
|
m_GhostOverride = false;
|
|
|
|
m_ObservedEntitiesLength = 256;
|
|
|
|
m_ObservedEntitiesUsed = 0;
|
|
|
|
m_ObservedEntities.resize(m_ObservedEntitiesLength);
|
|
|
|
|
|
|
|
m_Character->SetEntity(this);
|
|
|
|
|
|
|
|
const auto& iter = std::find(m_Players.begin(), m_Players.end(), this);
|
|
|
|
|
|
|
|
if (iter != m_Players.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Players.push_back(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
User* Player::GetParentUser() const {
|
|
|
|
return m_ParentUser;
|
|
|
|
}
|
|
|
|
|
|
|
|
SystemAddress Player::GetSystemAddress() const {
|
|
|
|
return m_SystemAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SetSystemAddress(const SystemAddress& value) {
|
|
|
|
m_SystemAddress = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SetRespawnPos(const NiPoint3 position) {
|
2023-12-22 04:12:52 +00:00
|
|
|
if (!m_Character) return;
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_respawnPos = position;
|
|
|
|
|
2023-07-17 22:55:33 +00:00
|
|
|
m_Character->SetRespawnPoint(Game::zoneManager->GetZone()->GetWorldID(), position);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SetRespawnRot(const NiQuaternion rotation) {
|
|
|
|
m_respawnRot = rotation;
|
|
|
|
}
|
|
|
|
|
|
|
|
NiPoint3 Player::GetRespawnPosition() const {
|
|
|
|
return m_respawnPos;
|
|
|
|
}
|
|
|
|
|
|
|
|
NiQuaternion Player::GetRespawnRotation() const {
|
|
|
|
return m_respawnRot;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SendMail(const LWOOBJID sender, const std::string& senderName, const std::string& subject, const std::string& body, LOT attachment, uint16_t attachmentCount) const {
|
|
|
|
Mail::SendMail(sender, senderName, this, subject, body, attachment, attachmentCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) {
|
|
|
|
const auto objid = GetObjectID();
|
|
|
|
|
|
|
|
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneId, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) {
|
2023-07-15 20:56:33 +00:00
|
|
|
auto* entity = Game::entityManager->GetEntity(objid);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
if (entity == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto sysAddr = entity->GetSystemAddress();
|
|
|
|
|
|
|
|
auto* character = entity->GetCharacter();
|
|
|
|
auto* characterComponent = entity->GetComponent<CharacterComponent>();
|
|
|
|
|
|
|
|
if (character != nullptr && characterComponent != nullptr) {
|
|
|
|
character->SetZoneID(zoneID);
|
|
|
|
character->SetZoneInstance(zoneInstance);
|
|
|
|
character->SetZoneClone(zoneClone);
|
|
|
|
|
|
|
|
characterComponent->SetLastRocketConfig(u"");
|
|
|
|
|
|
|
|
character->SaveXMLToDatabase();
|
|
|
|
}
|
|
|
|
|
|
|
|
WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift);
|
|
|
|
|
2023-07-15 20:56:33 +00:00
|
|
|
Game::entityManager->DestructEntity(entity);
|
2021-12-05 17:54:36 +00:00
|
|
|
return;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
void Player::AddLimboConstruction(LWOOBJID objectId) {
|
2021-12-05 17:54:36 +00:00
|
|
|
const auto& iter = std::find(m_LimboConstructions.begin(), m_LimboConstructions.end(), objectId);
|
|
|
|
|
|
|
|
if (iter != m_LimboConstructions.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_LimboConstructions.push_back(objectId);
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
void Player::RemoveLimboConstruction(LWOOBJID objectId) {
|
2021-12-05 17:54:36 +00:00
|
|
|
const auto& iter = std::find(m_LimboConstructions.begin(), m_LimboConstructions.end(), objectId);
|
|
|
|
|
|
|
|
if (iter == m_LimboConstructions.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_LimboConstructions.erase(iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::ConstructLimboEntities() {
|
|
|
|
for (const auto objectId : m_LimboConstructions) {
|
2023-07-15 20:56:33 +00:00
|
|
|
auto* entity = Game::entityManager->GetEntity(objectId);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
if (entity == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-07-15 20:56:33 +00:00
|
|
|
Game::entityManager->ConstructEntity(entity, m_SystemAddress);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
2022-07-25 02:26:51 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_LimboConstructions.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<LWOOBJID, Loot::Info>& Player::GetDroppedLoot() {
|
|
|
|
return m_DroppedLoot;
|
|
|
|
}
|
|
|
|
|
|
|
|
const NiPoint3& Player::GetGhostReferencePoint() const {
|
|
|
|
return m_GhostOverride ? m_GhostOverridePoint : m_GhostReferencePoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
const NiPoint3& Player::GetOriginGhostReferencePoint() const {
|
|
|
|
return m_GhostReferencePoint;
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
void Player::SetGhostReferencePoint(const NiPoint3& value) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_GhostReferencePoint = value;
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
void Player::SetGhostOverridePoint(const NiPoint3& value) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_GhostOverridePoint = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
const NiPoint3& Player::GetGhostOverridePoint() const {
|
|
|
|
return m_GhostOverridePoint;
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
void Player::SetGhostOverride(bool value) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_GhostOverride = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Player::GetGhostOverride() const {
|
|
|
|
return m_GhostOverride;
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
void Player::ObserveEntity(int32_t id) {
|
2021-12-05 17:54:36 +00:00
|
|
|
for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) {
|
|
|
|
if (m_ObservedEntities[i] == 0 || m_ObservedEntities[i] == id) {
|
|
|
|
m_ObservedEntities[i] = id;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto index = m_ObservedEntitiesUsed++;
|
|
|
|
|
|
|
|
if (m_ObservedEntitiesUsed > m_ObservedEntitiesLength) {
|
|
|
|
m_ObservedEntities.resize(m_ObservedEntitiesLength + m_ObservedEntitiesLength);
|
|
|
|
|
|
|
|
m_ObservedEntitiesLength = m_ObservedEntitiesLength + m_ObservedEntitiesLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ObservedEntities[index] = id;
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
bool Player::IsObserved(int32_t id) {
|
2021-12-05 17:54:36 +00:00
|
|
|
for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) {
|
|
|
|
if (m_ObservedEntities[i] == id) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
void Player::GhostEntity(int32_t id) {
|
2021-12-05 17:54:36 +00:00
|
|
|
for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) {
|
|
|
|
if (m_ObservedEntities[i] == id) {
|
|
|
|
m_ObservedEntities[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Player* Player::GetPlayer(const SystemAddress& sysAddr) {
|
|
|
|
auto* entity = UserManager::Instance()->GetUser(sysAddr)->GetLastUsedChar()->GetEntity();
|
|
|
|
|
|
|
|
return static_cast<Player*>(entity);
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
Player* Player::GetPlayer(const std::string& name) {
|
2023-07-15 20:56:33 +00:00
|
|
|
const auto characters = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CHARACTER);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
for (auto* character : characters) {
|
|
|
|
if (!character->IsPlayer()) continue;
|
2023-11-16 01:29:00 +00:00
|
|
|
|
|
|
|
if (GeneralUtils::CaseInsensitiveStringCompare(name, character->GetCharacter()->GetName())) {
|
|
|
|
return dynamic_cast<Player*>(character);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
Player* Player::GetPlayer(LWOOBJID playerID) {
|
2021-12-05 17:54:36 +00:00
|
|
|
for (auto* player : m_Players) {
|
|
|
|
if (player->GetObjectID() == playerID) {
|
|
|
|
return player;
|
|
|
|
}
|
|
|
|
}
|
2022-07-25 02:26:51 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2022-07-25 02:26:51 +00:00
|
|
|
const std::vector<Player*>& Player::GetAllPlayers() {
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_Players;
|
|
|
|
}
|
|
|
|
|
2021-12-11 13:21:00 +00:00
|
|
|
uint64_t Player::GetDroppedCoins() {
|
|
|
|
return m_DroppedCoins;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::SetDroppedCoins(uint64_t value) {
|
|
|
|
m_DroppedCoins = value;
|
|
|
|
}
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
Player::~Player() {
|
2023-10-21 23:31:55 +00:00
|
|
|
LOG("Deleted player");
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
for (int32_t i = 0; i < m_ObservedEntitiesUsed; i++) {
|
|
|
|
const auto id = m_ObservedEntities[i];
|
|
|
|
|
|
|
|
if (id == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-07-15 20:56:33 +00:00
|
|
|
auto* entity = Game::entityManager->GetGhostCandidate(id);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
if (entity != nullptr) {
|
|
|
|
entity->SetObservers(entity->GetObservers() - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_LimboConstructions.clear();
|
|
|
|
|
|
|
|
const auto& iter = std::find(m_Players.begin(), m_Players.end(), this);
|
|
|
|
|
|
|
|
if (iter == m_Players.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-19 07:14:33 +00:00
|
|
|
if (IsPlayer()) {
|
2023-07-15 20:56:33 +00:00
|
|
|
Entity* zoneControl = Game::entityManager->GetZoneControlEntity();
|
2022-06-19 07:14:33 +00:00
|
|
|
for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) {
|
|
|
|
script->OnPlayerExit(zoneControl, this);
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2023-07-15 20:56:33 +00:00
|
|
|
std::vector<Entity*> scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY);
|
2022-06-19 07:14:33 +00:00
|
|
|
for (Entity* scriptEntity : scriptedActs) {
|
|
|
|
if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds
|
|
|
|
for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) {
|
|
|
|
script->OnPlayerExit(scriptEntity, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_Players.erase(iter);
|
|
|
|
}
|