mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-11-04 06:32:00 +00:00 
			
		
		
		
	Merge branch 'DarkflameUniverse:main' into MSVCCompilerFlags
This commit is contained in:
		@@ -1682,9 +1682,9 @@ void Entity::PickupItem(const LWOOBJID& objectID) {
 | 
			
		||||
				std::vector<CDObjectSkills> skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == p.second.lot); });
 | 
			
		||||
				for (CDObjectSkills skill : skills) {
 | 
			
		||||
					CDSkillBehaviorTable* skillBehTable = CDClientManager::GetTable<CDSkillBehaviorTable>();
 | 
			
		||||
					CDSkillBehavior behaviorData = skillBehTable->GetSkillByID(skill.skillID);
 | 
			
		||||
 | 
			
		||||
					SkillComponent::HandleUnmanaged(behaviorData.behaviorID, GetObjectID());
 | 
			
		||||
					auto* skillComponent = GetComponent<SkillComponent>();
 | 
			
		||||
					if (skillComponent) skillComponent->CastSkill(skill.skillID, GetObjectID(), GetObjectID());
 | 
			
		||||
 | 
			
		||||
					auto* missionComponent = GetComponent<MissionComponent>();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include "eReplicaPacketType.h"
 | 
			
		||||
#include "PlayerManager.h"
 | 
			
		||||
#include "GhostComponent.h"
 | 
			
		||||
#include <ranges>
 | 
			
		||||
 | 
			
		||||
// Configure which zones have ghosting disabled, mostly small worlds.
 | 
			
		||||
std::vector<LWOMAPID> EntityManager::m_GhostingExcludedZones = {
 | 
			
		||||
@@ -165,8 +166,8 @@ void EntityManager::DestroyEntity(Entity* entity) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EntityManager::SerializeEntities() {
 | 
			
		||||
	for (int32_t i = 0; i < m_EntitiesToSerialize.size(); i++) {
 | 
			
		||||
		const LWOOBJID toSerialize = m_EntitiesToSerialize.at(i);
 | 
			
		||||
	for (size_t i = 0; i < m_EntitiesToSerialize.size(); i++) {
 | 
			
		||||
		const LWOOBJID toSerialize = m_EntitiesToSerialize[i];
 | 
			
		||||
		auto* entity = GetEntity(toSerialize);
 | 
			
		||||
 | 
			
		||||
		if (!entity) continue;
 | 
			
		||||
@@ -195,8 +196,8 @@ void EntityManager::SerializeEntities() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EntityManager::KillEntities() {
 | 
			
		||||
	for (int32_t i = 0; i < m_EntitiesToKill.size(); i++) {
 | 
			
		||||
		const LWOOBJID toKill = m_EntitiesToKill.at(i);
 | 
			
		||||
	for (size_t i = 0; i < m_EntitiesToKill.size(); i++) {
 | 
			
		||||
		const LWOOBJID toKill = m_EntitiesToKill[i];
 | 
			
		||||
		auto* entity = GetEntity(toKill);
 | 
			
		||||
 | 
			
		||||
		if (!entity) {
 | 
			
		||||
@@ -214,8 +215,8 @@ void EntityManager::KillEntities() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EntityManager::DeleteEntities() {
 | 
			
		||||
	for (int32_t i = 0; i < m_EntitiesToDelete.size(); i++) {
 | 
			
		||||
		const LWOOBJID toDelete = m_EntitiesToDelete.at(i);
 | 
			
		||||
	for (size_t i = 0; i < m_EntitiesToDelete.size(); i++) {
 | 
			
		||||
		const LWOOBJID toDelete = m_EntitiesToDelete[i];
 | 
			
		||||
		auto entityToDelete = GetEntity(toDelete);
 | 
			
		||||
		if (entityToDelete) {
 | 
			
		||||
			// Get all this info first before we delete the player.
 | 
			
		||||
@@ -238,8 +239,8 @@ void EntityManager::DeleteEntities() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EntityManager::UpdateEntities(const float deltaTime) {
 | 
			
		||||
	for (const auto& e : m_Entities) {
 | 
			
		||||
		e.second->Update(deltaTime);
 | 
			
		||||
	for (auto* entity : m_Entities | std::views::values) {
 | 
			
		||||
		entity->Update(deltaTime);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SerializeEntities();
 | 
			
		||||
@@ -259,10 +260,10 @@ Entity* EntityManager::GetEntity(const LWOOBJID& objectId) const {
 | 
			
		||||
 | 
			
		||||
std::vector<Entity*> EntityManager::GetEntitiesInGroup(const std::string& group) {
 | 
			
		||||
	std::vector<Entity*> entitiesInGroup;
 | 
			
		||||
	for (const auto& entity : m_Entities) {
 | 
			
		||||
		for (const auto& entityGroup : entity.second->GetGroups()) {
 | 
			
		||||
	for (auto* entity : m_Entities | std::views::values) {
 | 
			
		||||
		for (const auto& entityGroup : entity->GetGroups()) {
 | 
			
		||||
			if (entityGroup == group) {
 | 
			
		||||
				entitiesInGroup.push_back(entity.second);
 | 
			
		||||
				entitiesInGroup.push_back(entity);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -272,10 +273,12 @@ std::vector<Entity*> EntityManager::GetEntitiesInGroup(const std::string& group)
 | 
			
		||||
 | 
			
		||||
std::vector<Entity*> EntityManager::GetEntitiesByComponent(const eReplicaComponentType componentType) const {
 | 
			
		||||
	std::vector<Entity*> withComp;
 | 
			
		||||
	for (const auto& entity : m_Entities) {
 | 
			
		||||
		if (componentType != eReplicaComponentType::INVALID && !entity.second->HasComponent(componentType)) continue;
 | 
			
		||||
	if (componentType != eReplicaComponentType::INVALID) {
 | 
			
		||||
		for (auto* entity : m_Entities | std::views::values) {
 | 
			
		||||
			if (!entity->HasComponent(componentType)) continue;
 | 
			
		||||
 | 
			
		||||
		withComp.push_back(entity.second);
 | 
			
		||||
			withComp.push_back(entity);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return withComp;
 | 
			
		||||
}
 | 
			
		||||
@@ -283,19 +286,19 @@ std::vector<Entity*> EntityManager::GetEntitiesByComponent(const eReplicaCompone
 | 
			
		||||
std::vector<Entity*> EntityManager::GetEntitiesByLOT(const LOT& lot) const {
 | 
			
		||||
	std::vector<Entity*> entities;
 | 
			
		||||
 | 
			
		||||
	for (const auto& entity : m_Entities) {
 | 
			
		||||
		if (entity.second->GetLOT() == lot)
 | 
			
		||||
			entities.push_back(entity.second);
 | 
			
		||||
	for (auto* entity : m_Entities | std::views::values) {
 | 
			
		||||
		if (entity->GetLOT() == lot) entities.push_back(entity);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return entities;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<Entity*> EntityManager::GetEntitiesByProximity(NiPoint3 reference, float radius) const {
 | 
			
		||||
	std::vector<Entity*> entities = {};
 | 
			
		||||
	if (radius > 1000.0f) return entities;
 | 
			
		||||
	for (const auto& entity : m_Entities) {
 | 
			
		||||
		if (NiPoint3::Distance(reference, entity.second->GetPosition()) <= radius) entities.push_back(entity.second);
 | 
			
		||||
	std::vector<Entity*> entities;
 | 
			
		||||
	if (radius <= 1000.0f) { // The client has a 1000 unit limit on this same logic, so we'll use the same limit
 | 
			
		||||
		for (auto* entity : m_Entities | std::views::values) {
 | 
			
		||||
			if (NiPoint3::Distance(reference, entity->GetPosition()) <= radius) entities.push_back(entity);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return entities;
 | 
			
		||||
}
 | 
			
		||||
@@ -309,12 +312,8 @@ Entity* EntityManager::GetSpawnPointEntity(const std::string& spawnName) const {
 | 
			
		||||
	// Lookup the spawn point entity in the map
 | 
			
		||||
	const auto& spawnPoint = m_SpawnPoints.find(spawnName);
 | 
			
		||||
 | 
			
		||||
	if (spawnPoint == m_SpawnPoints.end()) {
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if the spawn point entity is valid just in case
 | 
			
		||||
	return GetEntity(spawnPoint->second);
 | 
			
		||||
	return spawnPoint == m_SpawnPoints.end() ? nullptr : GetEntity(spawnPoint->second);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::unordered_map<std::string, LWOOBJID>& EntityManager::GetSpawnPointEntities() const {
 | 
			
		||||
@@ -340,29 +339,25 @@ void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr
 | 
			
		||||
		entity->SetNetworkId(networkId);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const auto checkGhosting = entity->GetIsGhostingCandidate();
 | 
			
		||||
 | 
			
		||||
	if (checkGhosting) {
 | 
			
		||||
		const auto& iter = std::find(m_EntitiesToGhost.begin(), m_EntitiesToGhost.end(), entity);
 | 
			
		||||
 | 
			
		||||
		if (iter == m_EntitiesToGhost.end()) {
 | 
			
		||||
	if (entity->GetIsGhostingCandidate()) {
 | 
			
		||||
		if (std::find(m_EntitiesToGhost.begin(), m_EntitiesToGhost.end(), entity) == m_EntitiesToGhost.end()) {
 | 
			
		||||
			m_EntitiesToGhost.push_back(entity);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (checkGhosting && sysAddr == UNASSIGNED_SYSTEM_ADDRESS) {
 | 
			
		||||
		if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) {
 | 
			
		||||
			CheckGhosting(entity);
 | 
			
		||||
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m_SerializationCounter++;
 | 
			
		||||
 | 
			
		||||
	RakNet::BitStream stream;
 | 
			
		||||
 | 
			
		||||
	stream.Write<char>(ID_REPLICA_MANAGER_CONSTRUCTION);
 | 
			
		||||
	stream.Write<uint8_t>(ID_REPLICA_MANAGER_CONSTRUCTION);
 | 
			
		||||
	stream.Write(true);
 | 
			
		||||
	stream.Write<unsigned short>(entity->GetNetworkId());
 | 
			
		||||
	stream.Write<uint16_t>(entity->GetNetworkId());
 | 
			
		||||
 | 
			
		||||
	entity->WriteBaseReplicaData(&stream, eReplicaPacketType::CONSTRUCTION);
 | 
			
		||||
	entity->WriteComponents(&stream, eReplicaPacketType::CONSTRUCTION);
 | 
			
		||||
@@ -395,9 +390,9 @@ void EntityManager::ConstructAllEntities(const SystemAddress& sysAddr) {
 | 
			
		||||
	//ZoneControl is special:
 | 
			
		||||
	ConstructEntity(m_ZoneControlEntity, sysAddr);
 | 
			
		||||
 | 
			
		||||
	for (const auto& e : m_Entities) {
 | 
			
		||||
		if (e.second && (e.second->GetSpawnerID() != 0 || e.second->GetLOT() == 1) && !e.second->GetIsGhostingCandidate()) {
 | 
			
		||||
			ConstructEntity(e.second, sysAddr);
 | 
			
		||||
	for (auto* entity : m_Entities | std::views::values) {
 | 
			
		||||
		if (entity && (entity->GetSpawnerID() != 0 || entity->GetLOT() == 1) && !entity->GetIsGhostingCandidate()) {
 | 
			
		||||
			ConstructEntity(entity, sysAddr);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -409,8 +404,8 @@ void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr)
 | 
			
		||||
 | 
			
		||||
	RakNet::BitStream stream;
 | 
			
		||||
 | 
			
		||||
	stream.Write<char>(ID_REPLICA_MANAGER_DESTRUCTION);
 | 
			
		||||
	stream.Write<unsigned short>(entity->GetNetworkId());
 | 
			
		||||
	stream.Write<uint8_t>(ID_REPLICA_MANAGER_DESTRUCTION);
 | 
			
		||||
	stream.Write<uint16_t>(entity->GetNetworkId());
 | 
			
		||||
 | 
			
		||||
	Game::server->Send(&stream, sysAddr, sysAddr == UNASSIGNED_SYSTEM_ADDRESS);
 | 
			
		||||
 | 
			
		||||
@@ -431,8 +426,8 @@ void EntityManager::SerializeEntity(Entity* entity) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EntityManager::DestructAllEntities(const SystemAddress& sysAddr) {
 | 
			
		||||
	for (const auto& e : m_Entities) {
 | 
			
		||||
		DestructEntity(e.second, sysAddr);
 | 
			
		||||
	for (auto* entity : m_Entities | std::views::values) {
 | 
			
		||||
		DestructEntity(entity, sysAddr);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -440,22 +435,12 @@ void EntityManager::SetGhostDistanceMax(float value) {
 | 
			
		||||
	m_GhostDistanceMaxSquared = value * value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float EntityManager::GetGhostDistanceMax() const {
 | 
			
		||||
	return std::sqrt(m_GhostDistanceMaxSquared);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EntityManager::SetGhostDistanceMin(float value) {
 | 
			
		||||
	m_GhostDistanceMinSqaured = value * value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float EntityManager::GetGhostDistanceMin() const {
 | 
			
		||||
	return std::sqrt(m_GhostDistanceMinSqaured);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EntityManager::QueueGhostUpdate(LWOOBJID playerID) {
 | 
			
		||||
	const auto& iter = std::find(m_PlayersToUpdateGhosting.begin(), m_PlayersToUpdateGhosting.end(), playerID);
 | 
			
		||||
 | 
			
		||||
	if (iter == m_PlayersToUpdateGhosting.end()) {
 | 
			
		||||
	if (std::find(m_PlayersToUpdateGhosting.begin(), m_PlayersToUpdateGhosting.end(), playerID) == m_PlayersToUpdateGhosting.end()) {
 | 
			
		||||
		m_PlayersToUpdateGhosting.push_back(playerID);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -475,26 +460,20 @@ void EntityManager::UpdateGhosting() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EntityManager::UpdateGhosting(Entity* player) {
 | 
			
		||||
	if (player == nullptr) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (!player) return;
 | 
			
		||||
 | 
			
		||||
	auto* missionComponent = player->GetComponent<MissionComponent>();
 | 
			
		||||
	auto* ghostComponent = player->GetComponent<GhostComponent>();
 | 
			
		||||
 | 
			
		||||
	if (missionComponent == nullptr || !ghostComponent) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (!missionComponent || !ghostComponent) return;
 | 
			
		||||
 | 
			
		||||
	const auto& referencePoint = ghostComponent->GetGhostReferencePoint();
 | 
			
		||||
	const auto isOverride = ghostComponent->GetGhostOverride();
 | 
			
		||||
 | 
			
		||||
	for (auto* entity : m_EntitiesToGhost) {
 | 
			
		||||
		const auto isAudioEmitter = entity->GetLOT() == 6368;
 | 
			
		||||
 | 
			
		||||
		const auto& entityPoint = entity->GetPosition();
 | 
			
		||||
 | 
			
		||||
		const int32_t id = entity->GetObjectID();
 | 
			
		||||
		const auto id = entity->GetObjectID();
 | 
			
		||||
 | 
			
		||||
		const auto observed = ghostComponent->IsObserved(id);
 | 
			
		||||
 | 
			
		||||
@@ -503,6 +482,7 @@ void EntityManager::UpdateGhosting(Entity* player) {
 | 
			
		||||
		auto ghostingDistanceMax = m_GhostDistanceMaxSquared;
 | 
			
		||||
		auto ghostingDistanceMin = m_GhostDistanceMinSqaured;
 | 
			
		||||
 | 
			
		||||
		const auto isAudioEmitter = entity->GetLOT() == 6368; // https://explorer.lu/objects/6368
 | 
			
		||||
		if (isAudioEmitter) {
 | 
			
		||||
			ghostingDistanceMax = ghostingDistanceMin;
 | 
			
		||||
		}
 | 
			
		||||
@@ -541,30 +521,25 @@ void EntityManager::CheckGhosting(Entity* entity) {
 | 
			
		||||
 | 
			
		||||
	const auto& referencePoint = entity->GetPosition();
 | 
			
		||||
 | 
			
		||||
	auto ghostingDistanceMax = m_GhostDistanceMaxSquared;
 | 
			
		||||
	auto ghostingDistanceMin = m_GhostDistanceMinSqaured;
 | 
			
		||||
 | 
			
		||||
	const auto isAudioEmitter = entity->GetLOT() == 6368;
 | 
			
		||||
 | 
			
		||||
	for (auto* player : PlayerManager::GetAllPlayers()) {
 | 
			
		||||
		auto* ghostComponent = player->GetComponent<GhostComponent>();
 | 
			
		||||
		if (!ghostComponent) continue;
 | 
			
		||||
 | 
			
		||||
		const auto& entityPoint = ghostComponent->GetGhostReferencePoint();
 | 
			
		||||
 | 
			
		||||
		const int32_t id = entity->GetObjectID();
 | 
			
		||||
		const auto id = entity->GetObjectID();
 | 
			
		||||
 | 
			
		||||
		const auto observed = ghostComponent->IsObserved(id);
 | 
			
		||||
 | 
			
		||||
		const auto distance = NiPoint3::DistanceSquared(referencePoint, entityPoint);
 | 
			
		||||
 | 
			
		||||
		if (observed && distance > ghostingDistanceMax) {
 | 
			
		||||
		if (observed && distance > m_GhostDistanceMaxSquared) {
 | 
			
		||||
			ghostComponent->GhostEntity(id);
 | 
			
		||||
 | 
			
		||||
			DestructEntity(entity, player->GetSystemAddress());
 | 
			
		||||
 | 
			
		||||
			entity->SetObservers(entity->GetObservers() - 1);
 | 
			
		||||
		} else if (!observed && ghostingDistanceMin > distance) {
 | 
			
		||||
		} else if (!observed && m_GhostDistanceMinSqaured > distance) {
 | 
			
		||||
			ghostComponent->ObserveEntity(id);
 | 
			
		||||
 | 
			
		||||
			ConstructEntity(entity, player->GetSystemAddress());
 | 
			
		||||
@@ -574,7 +549,7 @@ void EntityManager::CheckGhosting(Entity* entity) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Entity* EntityManager::GetGhostCandidate(int32_t id) {
 | 
			
		||||
Entity* EntityManager::GetGhostCandidate(LWOOBJID id) const {
 | 
			
		||||
	for (auto* entity : m_EntitiesToGhost) {
 | 
			
		||||
		if (entity->GetObjectID() == id) {
 | 
			
		||||
			return entity;
 | 
			
		||||
@@ -600,26 +575,22 @@ void EntityManager::ScheduleForKill(Entity* entity) {
 | 
			
		||||
 | 
			
		||||
	const auto objectId = entity->GetObjectID();
 | 
			
		||||
 | 
			
		||||
	if (std::count(m_EntitiesToKill.begin(), m_EntitiesToKill.end(), objectId)) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (std::find(m_EntitiesToKill.begin(), m_EntitiesToKill.end(), objectId) != m_EntitiesToKill.end()) {
 | 
			
		||||
		m_EntitiesToKill.push_back(objectId);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EntityManager::ScheduleForDeletion(LWOOBJID entity) {
 | 
			
		||||
	if (std::count(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), entity)) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (std::find(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), entity) != m_EntitiesToDelete.end()) {
 | 
			
		||||
		m_EntitiesToDelete.push_back(entity);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void EntityManager::FireEventServerSide(Entity* origin, std::string args) {
 | 
			
		||||
	for (std::pair<LWOOBJID, Entity*> e : m_Entities) {
 | 
			
		||||
		if (e.second) {
 | 
			
		||||
			e.second->OnFireEventServerSide(origin, args);
 | 
			
		||||
	for (const auto entity : m_Entities | std::views::values) {
 | 
			
		||||
		if (entity) {
 | 
			
		||||
			entity->OnFireEventServerSide(origin, args);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -50,14 +50,12 @@ public:
 | 
			
		||||
	void DestructAllEntities(const SystemAddress& sysAddr);
 | 
			
		||||
 | 
			
		||||
	void SetGhostDistanceMax(float value);
 | 
			
		||||
	float GetGhostDistanceMax() const;
 | 
			
		||||
	void SetGhostDistanceMin(float value);
 | 
			
		||||
	float GetGhostDistanceMin() const;
 | 
			
		||||
	void QueueGhostUpdate(LWOOBJID playerID);
 | 
			
		||||
	void UpdateGhosting();
 | 
			
		||||
	void UpdateGhosting(Entity* player);
 | 
			
		||||
	void CheckGhosting(Entity* entity);
 | 
			
		||||
	Entity* GetGhostCandidate(int32_t id);
 | 
			
		||||
	Entity* GetGhostCandidate(LWOOBJID id) const;
 | 
			
		||||
	bool GetGhostingEnabled() const;
 | 
			
		||||
 | 
			
		||||
	void ScheduleForKill(Entity* entity);
 | 
			
		||||
 
 | 
			
		||||
@@ -104,7 +104,7 @@ void Trade::SetAccepted(LWOOBJID participant, bool value) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Complete();
 | 
			
		||||
		TradingManager::Instance()->CancelTrade(m_TradeId);
 | 
			
		||||
		TradingManager::Instance()->CancelTrade(LWOOBJID_EMPTY, m_TradeId, false);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -178,14 +178,14 @@ void Trade::Complete() {
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Trade::Cancel() {
 | 
			
		||||
void Trade::Cancel(const LWOOBJID canceller) {
 | 
			
		||||
	auto* entityA = GetParticipantAEntity();
 | 
			
		||||
	auto* entityB = GetParticipantBEntity();
 | 
			
		||||
 | 
			
		||||
	if (entityA == nullptr || entityB == nullptr) return;
 | 
			
		||||
 | 
			
		||||
	GameMessages::SendServerTradeCancel(entityA->GetObjectID(), entityA->GetSystemAddress());
 | 
			
		||||
	GameMessages::SendServerTradeCancel(entityB->GetObjectID(), entityB->GetSystemAddress());
 | 
			
		||||
	if (entityA->GetObjectID() != canceller || canceller == LWOOBJID_EMPTY) GameMessages::SendServerTradeCancel(entityA->GetObjectID(), entityA->GetSystemAddress());
 | 
			
		||||
	if (entityB->GetObjectID() != canceller || canceller == LWOOBJID_EMPTY) GameMessages::SendServerTradeCancel(entityB->GetObjectID(), entityB->GetSystemAddress());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Trade::SendUpdateToOther(LWOOBJID participant) {
 | 
			
		||||
@@ -262,11 +262,13 @@ Trade* TradingManager::GetPlayerTrade(LWOOBJID playerId) const {
 | 
			
		||||
	return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TradingManager::CancelTrade(LWOOBJID tradeId) {
 | 
			
		||||
void TradingManager::CancelTrade(const LWOOBJID canceller, LWOOBJID tradeId, const bool sendCancelMessage) {
 | 
			
		||||
	auto* trade = GetTrade(tradeId);
 | 
			
		||||
 | 
			
		||||
	if (trade == nullptr) return;
 | 
			
		||||
 | 
			
		||||
	if (sendCancelMessage) trade->Cancel(canceller);
 | 
			
		||||
 | 
			
		||||
	delete trade;
 | 
			
		||||
 | 
			
		||||
	trades.erase(tradeId);
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ public:
 | 
			
		||||
	void SetAccepted(LWOOBJID participant, bool value);
 | 
			
		||||
 | 
			
		||||
	void Complete();
 | 
			
		||||
	void Cancel();
 | 
			
		||||
	void Cancel(const LWOOBJID canceller);
 | 
			
		||||
 | 
			
		||||
	void SendUpdateToOther(LWOOBJID participant);
 | 
			
		||||
 | 
			
		||||
@@ -66,7 +66,7 @@ public:
 | 
			
		||||
 | 
			
		||||
	Trade* GetTrade(LWOOBJID tradeId) const;
 | 
			
		||||
	Trade* GetPlayerTrade(LWOOBJID playerId) const;
 | 
			
		||||
	void CancelTrade(LWOOBJID tradeId);
 | 
			
		||||
	void CancelTrade(const LWOOBJID canceller, LWOOBJID tradeId, const bool sendCancelMessage = true);
 | 
			
		||||
	Trade* NewTrade(LWOOBJID participantA, LWOOBJID participantB);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 
 | 
			
		||||
@@ -301,6 +301,7 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
 | 
			
		||||
 | 
			
		||||
	const auto name = LUWStringName.GetAsString();
 | 
			
		||||
	std::string predefinedName = GetPredefinedName(firstNameIndex, middleNameIndex, lastNameIndex);
 | 
			
		||||
 | 
			
		||||
	LOT shirtLOT = FindCharShirtID(shirtColor, shirtStyle);
 | 
			
		||||
	LOT pantsLOT = FindCharPantsID(pantsColor);
 | 
			
		||||
 | 
			
		||||
@@ -323,7 +324,7 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//Now that the name is ok, we can get an objectID from Master:
 | 
			
		||||
	ObjectIDManager::RequestPersistentID([=, this](uint32_t objectID) {
 | 
			
		||||
	ObjectIDManager::RequestPersistentID([=, this](uint32_t objectID) mutable {
 | 
			
		||||
		if (Database::Get()->GetCharacterInfo(objectID)) {
 | 
			
		||||
			LOG("Character object id unavailable, check object_id_tracker!");
 | 
			
		||||
			WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::OBJECT_ID_UNAVAILABLE);
 | 
			
		||||
@@ -366,6 +367,14 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
 | 
			
		||||
		bool nameOk = IsNamePreapproved(name);
 | 
			
		||||
		if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
 | 
			
		||||
 | 
			
		||||
		// If predefined name is invalid, change it to be their object id
 | 
			
		||||
		// that way more than one player can create characters if the predefined name files are not provided
 | 
			
		||||
		if (predefinedName == "INVALID") {
 | 
			
		||||
			std::stringstream nameObjID;
 | 
			
		||||
			nameObjID << "minifig" << objectID;
 | 
			
		||||
			predefinedName = nameObjID.str();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		std::string_view nameToAssign = !name.empty() && nameOk ? name : predefinedName;
 | 
			
		||||
		std::string pendingName = !name.empty() && !nameOk ? name : "";
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ GhostComponent::GhostComponent(Entity* parent) : Component(parent) {
 | 
			
		||||
 | 
			
		||||
GhostComponent::~GhostComponent() {
 | 
			
		||||
	for (auto& observedEntity : m_ObservedEntities) {
 | 
			
		||||
		if (observedEntity == 0) continue;
 | 
			
		||||
		if (observedEntity == LWOOBJID_EMPTY) continue;
 | 
			
		||||
 | 
			
		||||
		auto* entity = Game::entityManager->GetGhostCandidate(observedEntity);
 | 
			
		||||
		if (!entity) continue;
 | 
			
		||||
@@ -44,14 +44,14 @@ void GhostComponent::ConstructLimboEntities() {
 | 
			
		||||
	m_LimboConstructions.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GhostComponent::ObserveEntity(int32_t id) {
 | 
			
		||||
void GhostComponent::ObserveEntity(LWOOBJID id) {
 | 
			
		||||
	m_ObservedEntities.insert(id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GhostComponent::IsObserved(int32_t id) {
 | 
			
		||||
bool GhostComponent::IsObserved(LWOOBJID id) {
 | 
			
		||||
	return m_ObservedEntities.contains(id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GhostComponent::GhostEntity(int32_t id) {
 | 
			
		||||
void GhostComponent::GhostEntity(LWOOBJID id) {
 | 
			
		||||
	m_ObservedEntities.erase(id);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,18 +33,18 @@ public:
 | 
			
		||||
 | 
			
		||||
	void ConstructLimboEntities();
 | 
			
		||||
 | 
			
		||||
	void ObserveEntity(const int32_t id);
 | 
			
		||||
	void ObserveEntity(const LWOOBJID id);
 | 
			
		||||
 | 
			
		||||
	bool IsObserved(const int32_t id);
 | 
			
		||||
	bool IsObserved(const LWOOBJID id);
 | 
			
		||||
 | 
			
		||||
	void GhostEntity(const int32_t id);
 | 
			
		||||
	void GhostEntity(const LWOOBJID id);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	NiPoint3 m_GhostReferencePoint;
 | 
			
		||||
 | 
			
		||||
	NiPoint3 m_GhostOverridePoint;
 | 
			
		||||
 | 
			
		||||
	std::unordered_set<int32_t> m_ObservedEntities;
 | 
			
		||||
	std::unordered_set<LWOOBJID> m_ObservedEntities;
 | 
			
		||||
 | 
			
		||||
	std::unordered_set<LWOOBJID> m_LimboConstructions;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -156,84 +156,43 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : PhysicsCompon
 | 
			
		||||
		//temp test
 | 
			
		||||
		if (info->physicsAsset == "miscellaneous\\misc_phys_10x1x5.hkx") {
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 10.0f, 5.0f, 1.0f);
 | 
			
		||||
 | 
			
		||||
			m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
			m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
			m_dpEntity->SetPosition(m_Position);
 | 
			
		||||
 | 
			
		||||
			dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
		} else if (info->physicsAsset == "miscellaneous\\misc_phys_640x640.hkx") {
 | 
			
		||||
			// Move this down by 13.521004 units so it is still effectively at the same height as before
 | 
			
		||||
			m_Position = m_Position - NiPoint3Constant::UNIT_Y * 13.521004f;
 | 
			
		||||
			// TODO Fix physics simulation to do simulation at high velocities due to bullet through paper problem...
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1638.4f, 13.521004f * 2.0f, 1638.4f);
 | 
			
		||||
 | 
			
		||||
			m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
			m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
			m_dpEntity->SetPosition(m_Position);
 | 
			
		||||
 | 
			
		||||
			dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
			// Move this down by 13.521004 units so it is still effectively at the same height as before
 | 
			
		||||
			m_Position = m_Position - NiPoint3Constant::UNIT_Y * 13.521004f;
 | 
			
		||||
		} else if (info->physicsAsset == "env\\trigger_wall_tall.hkx") {
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 10.0f, 25.0f, 1.0f);
 | 
			
		||||
			m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
			m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
			m_dpEntity->SetPosition(m_Position);
 | 
			
		||||
			dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
		} else if (info->physicsAsset == "env\\env_gen_placeholderphysics.hkx") {
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 20.0f, 20.0f, 20.0f);
 | 
			
		||||
			m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
			m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
			m_dpEntity->SetPosition(m_Position);
 | 
			
		||||
			dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
		} else if (info->physicsAsset == "env\\POI_trigger_wall.hkx") {
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1.0f, 12.5f, 20.0f); // Not sure what the real size is
 | 
			
		||||
			m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
			m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
			m_dpEntity->SetPosition(m_Position);
 | 
			
		||||
			dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
		} else if (info->physicsAsset == "env\\NG_NinjaGo\\env_ng_gen_gate_chamber_puzzle_ceiling_tile_falling_phantom.hkx") {
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 18.0f, 5.0f, 15.0f);
 | 
			
		||||
			m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
			m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
			m_dpEntity->SetPosition(m_Position + m_Rotation.GetForwardVector() * 7.5f);
 | 
			
		||||
			dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
			m_Position += m_Rotation.GetForwardVector() * 7.5f;
 | 
			
		||||
		} else if (info->physicsAsset == "env\\NG_NinjaGo\\ng_flamejet_brick_phantom.HKX") {
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1.0f, 1.0f, 12.0f);
 | 
			
		||||
			m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
			m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
			m_dpEntity->SetPosition(m_Position + m_Rotation.GetForwardVector() * 6.0f);
 | 
			
		||||
			dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
			m_Position += m_Rotation.GetForwardVector() * 6.0f;
 | 
			
		||||
		} else if (info->physicsAsset == "env\\Ring_Trigger.hkx") {
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 6.0f, 6.0f, 6.0f);
 | 
			
		||||
			m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
			m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
			m_dpEntity->SetPosition(m_Position);
 | 
			
		||||
			dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
		} else if (info->physicsAsset == "env\\vfx_propertyImaginationBall.hkx") {
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 4.5f);
 | 
			
		||||
			m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
			m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
			m_dpEntity->SetPosition(m_Position);
 | 
			
		||||
			dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
		} else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx") {
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true);
 | 
			
		||||
			m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
			m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
			m_Position.y -= (111.467964f * m_Scale) / 2;
 | 
			
		||||
			m_dpEntity->SetPosition(m_Position);
 | 
			
		||||
			dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
		} else {
 | 
			
		||||
			//LOG("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:
 | 
			
		||||
			m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 2.0f, 2.0f, 2.0f);
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
		m_dpEntity->SetScale(m_Scale);
 | 
			
		||||
		m_dpEntity->SetRotation(m_Rotation);
 | 
			
		||||
		m_dpEntity->SetPosition(m_Position);
 | 
			
		||||
		dpWorld::AddEntity(m_dpEntity);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PhantomPhysicsComponent::~PhantomPhysicsComponent() {
 | 
			
		||||
 
 | 
			
		||||
@@ -3270,7 +3270,7 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity*
 | 
			
		||||
 | 
			
		||||
		if (trade != nullptr) {
 | 
			
		||||
			if (!trade->IsParticipant(i64Invitee)) {
 | 
			
		||||
				TradingManager::Instance()->CancelTrade(trade->GetTradeId());
 | 
			
		||||
				TradingManager::Instance()->CancelTrade(entity->GetObjectID(), trade->GetTradeId());
 | 
			
		||||
 | 
			
		||||
				TradingManager::Instance()->NewTrade(entity->GetObjectID(), i64Invitee);
 | 
			
		||||
			}
 | 
			
		||||
@@ -3295,7 +3295,7 @@ void GameMessages::HandleClientTradeCancel(RakNet::BitStream* inStream, Entity*
 | 
			
		||||
 | 
			
		||||
	LOG("Trade canceled from (%llu)", entity->GetObjectID());
 | 
			
		||||
 | 
			
		||||
	TradingManager::Instance()->CancelTrade(trade->GetTradeId());
 | 
			
		||||
	TradingManager::Instance()->CancelTrade(entity->GetObjectID(), trade->GetTradeId());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GameMessages::HandleClientTradeAccept(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
 | 
			
		||||
 
 | 
			
		||||
@@ -631,6 +631,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
 | 
			
		||||
		if (infile.good()) {
 | 
			
		||||
			std::string line;
 | 
			
		||||
			while (std::getline(infile, line)) {
 | 
			
		||||
				// Do this in two separate calls to catch both \n and \r\n
 | 
			
		||||
				line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
 | 
			
		||||
				line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
 | 
			
		||||
				SlashCommandHandler::HandleChatCommand(GeneralUtils::ASCIIToUTF16(line), entity, sysAddr);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
 
 | 
			
		||||
@@ -179,7 +179,7 @@ void BossSpiderQueenEnemyServer::SpiderWaveManager(Entity* self) {
 | 
			
		||||
 | 
			
		||||
	std::vector<LWOOBJID> spiderEggs{};
 | 
			
		||||
 | 
			
		||||
	auto spooders = Game::entityManager->GetEntitiesInGroup("EGG");
 | 
			
		||||
	auto spooders = Game::entityManager->GetEntitiesInGroup("SpiderEggs");
 | 
			
		||||
	for (auto spodder : spooders) {
 | 
			
		||||
		spiderEggs.push_back(spodder->GetObjectID());
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#include "NpcCowboyServer.h"
 | 
			
		||||
#include "eMissionState.h"
 | 
			
		||||
#include "InventoryComponent.h"
 | 
			
		||||
#include "dZoneManager.h"
 | 
			
		||||
 | 
			
		||||
void NpcCowboyServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) {
 | 
			
		||||
	if (missionID != 1880) {
 | 
			
		||||
@@ -23,4 +24,17 @@ void NpcCowboyServer::OnMissionDialogueOK(Entity* self, Entity* target, int miss
 | 
			
		||||
	} else if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) {
 | 
			
		||||
		inventoryComponent->RemoveItem(14378, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Next up hide or show the samples based on the mission state
 | 
			
		||||
	int32_t visible = 1;
 | 
			
		||||
	if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) {
 | 
			
		||||
		visible = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auto spawners = Game::zoneManager->GetSpawnersByName("PlungerGunTargets");
 | 
			
		||||
	for (auto* spawner : spawners) {
 | 
			
		||||
		for (const auto entity : spawner->GetSpawnedObjectIDs())
 | 
			
		||||
			GameMessages::SendNotifyClientObject(entity, u"SetVisibility", visible, 0,
 | 
			
		||||
				target->GetObjectID(), "", target->GetSystemAddress());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,10 @@
 | 
			
		||||
#include "NpcWispServer.h"
 | 
			
		||||
#include "InventoryComponent.h"
 | 
			
		||||
#include "EntityManager.h"
 | 
			
		||||
#include "dZoneManager.h"
 | 
			
		||||
#include "Entity.h"
 | 
			
		||||
#include "GameMessages.h"
 | 
			
		||||
#include "eMissionState.h"
 | 
			
		||||
#include "Spawner.h"
 | 
			
		||||
 | 
			
		||||
void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) {
 | 
			
		||||
	if (missionID != 1849 && missionID != 1883)
 | 
			
		||||
@@ -25,7 +26,7 @@ void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missio
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Next up hide or show the samples based on the mission state
 | 
			
		||||
	auto visible = 1;
 | 
			
		||||
	int32_t visible = 1;
 | 
			
		||||
	if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) {
 | 
			
		||||
		visible = 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -35,9 +36,10 @@ void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missio
 | 
			
		||||
	: std::vector<std::string>{ "MaelstromSamples", "MaelstromSamples2ndary1", "MaelstromSamples2ndary2" };
 | 
			
		||||
 | 
			
		||||
	for (const auto& group : groups) {
 | 
			
		||||
		auto samples = Game::entityManager->GetEntitiesInGroup(group);
 | 
			
		||||
		for (auto* sample : samples) {
 | 
			
		||||
			GameMessages::SendNotifyClientObject(sample->GetObjectID(), u"SetVisibility", visible, 0,
 | 
			
		||||
		auto spawners = Game::zoneManager->GetSpawnersByName(group);
 | 
			
		||||
		for (const auto* spawner : spawners) {
 | 
			
		||||
			for (const auto objId : spawner->GetSpawnedObjectIDs())
 | 
			
		||||
			GameMessages::SendNotifyClientObject(objId, u"SetVisibility", visible, 0,
 | 
			
		||||
				target->GetObjectID(), "", target->GetSystemAddress());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,16 +25,6 @@ Spawner::Spawner(const SpawnerInfo info) {
 | 
			
		||||
 | 
			
		||||
	m_Start = m_Info.noTimedSpawn;
 | 
			
		||||
 | 
			
		||||
	//ssssh...
 | 
			
		||||
	if (m_EntityInfo.lot == 14718) { //AG - MAELSTROM SAMPLE
 | 
			
		||||
		m_Info.groups.emplace_back("MaelstromSamples");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (m_EntityInfo.lot == 14375) //AG - SPIDER BOSS EGG
 | 
			
		||||
	{
 | 
			
		||||
		m_Info.groups.emplace_back("EGG");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int timerCount = m_Info.amountMaintained;
 | 
			
		||||
 | 
			
		||||
	if (m_Info.amountMaintained > m_Info.nodes.size()) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user