DarkflameServer/dScripts/BaseSurvivalServer.cpp
David Markowitz 455f9470a5
Move EntityManager to Game namespace (#1140)
* Move EntityManager to Game namespace

* move initialization to later

Need to wait for dZoneManager to be initialized.

* Fix bugs

- Cannot delete from a RandomAccessIterator while in a range based for loop.

Touchup zone manager initialize

replace magic numbers with better named constants
replace magic zonecontrol id with a more readable hex alternative
condense stack variables
move initializers closer to their use
initialize entity manager with zone control

change initialize timings

If zone is not zero we expect to initialize the entity manager during zone manager initialization

Add constexpr for zone control LOT

* Add proper error handling

* revert vanity changes

* Update WorldServer.cpp

* Update dZoneManager.cpp
2023-07-15 13:56:33 -07:00

575 lines
20 KiB
C++

#include "BaseSurvivalServer.h"
#include "GameMessages.h"
#include "DestroyableComponent.h"
#include "EntityManager.h"
#include "dZoneManager.h"
#include "Player.h"
#include "eMissionTaskType.h"
#include "eMissionState.h"
#include "MissionComponent.h"
#include "Character.h"
void BaseSurvivalServer::SetGameVariables(Entity* self) {
this->constants = std::move(GetConstants());
this->mobSets = std::move(GetMobSets());
this->spawnerNetworks = std::move(GetSpawnerNetworks());
this->missionsToUpdate = std::move(GetMissionsToUpdate());
}
void BaseSurvivalServer::BasePlayerLoaded(Entity* self, Entity* player) {
const auto& waitingIter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID());
const auto& playersIter = std::find(state.players.begin(), state.players.end(), player->GetObjectID());
if (waitingIter != state.waitingPlayers.end() || playersIter != state.players.end()) {
static_cast<Player*>(player)->SendToZone(player->GetCharacter()->GetLastNonInstanceZoneID());
return;
}
state.waitingPlayers.push_back(player->GetObjectID());
state.players.push_back(player->GetObjectID());
self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) + 1);
self->SetNetworkVar<std::string>(DefinePlayerToUIVariable, std::to_string(player->GetObjectID()), player->GetSystemAddress());
// Notify the players of all other players
if (!self->GetNetworkVar<bool>(WavesStartedVariable)) {
auto counter = 1;
for (const auto& playerID : state.players) {
self->SetNetworkVar<std::string>(UpdateScoreboardPlayersVariable + GeneralUtils::to_u16string(counter), std::to_string(playerID));
counter++;
}
self->SetNetworkVar<bool>(ShowScoreboardVariable, true);
}
SetPlayerSpawnPoints();
if (!self->GetNetworkVar<bool>(WavesStartedVariable)) {
PlayerConfirmed(self);
} else {
UpdatePlayer(self, player->GetObjectID());
GetLeaderboardData(self, player->GetObjectID(), GetActivityID(self), 50);
ResetStats(player->GetObjectID());
}
player->AddCallbackTimer(5.0f, [this, self, player]() {
self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable));
self->SetNetworkVar<std::string>(DefinePlayerToUIVariable, std::to_string(player->GetObjectID()), player->GetSystemAddress());
if (!self->GetNetworkVar<bool>(WavesStartedVariable)) {
auto counter = 1;
for (const auto& playerID : state.players) {
self->SetNetworkVar<std::string>(UpdateScoreboardPlayersVariable + GeneralUtils::to_u16string(counter), std::to_string(playerID));
counter++;
}
self->SetNetworkVar<bool>(ShowScoreboardVariable, true);
}
});
}
void BaseSurvivalServer::BaseStartup(Entity* self) {
self->SetVar<uint32_t>(PlayersAcceptedVariable, 0);
self->SetVar<bool>(PlayersReadyVariable, false);
}
void BaseSurvivalServer::BasePlayerExit(Entity* self, Entity* player) {
const auto& waitingIter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID());
const auto& playersIter = std::find(state.players.begin(), state.players.end(), player->GetObjectID());
if (waitingIter != state.waitingPlayers.end()) {
state.waitingPlayers.erase(waitingIter);
}
if (playersIter != state.players.end()) {
state.players.erase(playersIter);
}
if (waitingIter == state.waitingPlayers.end() && playersIter == state.players.end()) {
return;
}
if (!self->GetNetworkVar<bool>(WavesStartedVariable)) {
PlayerConfirmed(self);
if (state.players.empty())
return;
if (state.waitingPlayers.empty()) {
ActivityTimerStopAllTimers(self);
ActivityTimerStart(self, AllAcceptedDelayTimer, 1.0f, constants.startDelay);
} else if (state.players.size() > state.waitingPlayers.size()) {
if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) {
self->SetVar<bool>(AcceptedDelayStartedVariable, true);
ActivityTimerStart(self, AcceptedDelayTimer, 1.0f, constants.acceptedDelay);
}
}
} else {
UpdatePlayer(self, player->GetObjectID(), true);
if (CheckAllPlayersDead()) {
GameOver(self);
}
}
SetActivityValue(self, player->GetObjectID(), 1, 0);
self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable,
std::min((uint32_t)0, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) - 1));
}
void BaseSurvivalServer::BaseFireEvent(Entity* self, Entity* sender, const std::string& args, int32_t param1, int32_t param2,
int32_t param3) {
if (args == "start") {
StartWaves(self);
} else if (args == "DeactivateRewards") {
SpawnerReset(spawnerNetworks.rewardNetworks);
} else if (sender != nullptr && IsPlayerInActivity(self, sender->GetObjectID())) {
auto currentScore = GetActivityValue(self, sender->GetObjectID(), 0);
SetActivityValue(self, sender->GetObjectID(), 0, currentScore + param1);
}
}
void BaseSurvivalServer::BasePlayerDied(Entity* self, Entity* player) {
if (self->GetNetworkVar<bool>(WavesStartedVariable)) {
const auto finalTime = ActivityTimerGetCurrentTime(self, ClockTickTimer);
SetActivityValue(self, player->GetObjectID(), 1, finalTime);
auto paramString = CheckAllPlayersDead() ? "true" : "false";
GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Died", finalTime, 0,
player->GetObjectID(), paramString, player->GetSystemAddress());
GameOver(self);
} else {
player->Resurrect();
SetPlayerSpawnPoints();
}
}
void BaseSurvivalServer::BasePlayerResurrected(Entity* self, Entity* player) {
self->SetNetworkVar<bool>(ShowScoreboardVariable, true);
}
void BaseSurvivalServer::BaseMessageBoxResponse(Entity* self, Entity* sender, int32_t button,
const std::u16string& identifier, const std::u16string& userData) {
if (identifier == u"RePlay") {
PlayerAccepted(self, sender->GetObjectID());
PlayerConfirmed(self);
} else if (identifier == u"Exit_Question" && button == 1) {
ResetStats(sender->GetObjectID());
self->SetNetworkVar<std::string>(ExitWavesVariable, std::to_string(sender->GetObjectID()));
if (sender->IsPlayer()) {
auto* character = sender->GetCharacter();
if (character != nullptr) {
auto* player = dynamic_cast<Player*>(sender);
player->SendToZone(character->GetLastNonInstanceZoneID());
}
}
}
}
void BaseSurvivalServer::OnActivityTimerUpdate(Entity* self, const std::string& name, float_t remainingTime, float_t elapsedTime) {
if (name == AcceptedDelayTimer) {
self->SetNetworkVar<uint64_t>(UpdateDefaultStartTimerVariable, remainingTime);
} else if (name == ClockTickTimer) {
self->SetNetworkVar<float_t>(UpdateTimerVariable, elapsedTime);
} else if (name == SpawnTickTimer && !self->GetVar<bool>(IsCooldownVariable)) {
SpawnMobs(self);
}
}
void BaseSurvivalServer::OnActivityTimerDone(Entity* self, const std::string& name) {
auto cooldownTime = constants.rewardInterval * constants.waveTime;
if (name == AcceptedDelayTimer) {
self->SetNetworkVar<uint64_t>(UpdateDefaultStartTimerVariable, 0);
ActivityTimerStart(self, AllAcceptedDelayTimer, 1, 1);
} else if (name == AllAcceptedDelayTimer) {
self->SetNetworkVar<bool>(ClearScoreboardVariable, true);
ActivityTimerStart(self, StartDelayTimer, 3, 3);
StartWaves(self);
} else if (name == StartDelayTimer) {
ActivityTimerStart(self, ClockTickTimer, 1);
ActivityTimerStart(self, SpawnTickTimer, constants.waveTime);
SpawnMobs(self);
ActivityTimerStart(self, PlaySpawnSoundTimer, 3, 3);
ActivityTimerStart(self, CoolDownStartTimer, cooldownTime, cooldownTime);
} else if (name == CoolDownStartTimer) {
self->SetVar<bool>(IsCooldownVariable, true);
ActivityTimerStop(self, SpawnTickTimer);
ActivityTimerStart(self, CoolDownStopTimer, 1, constants.coolDownTime);
ActivateSpawnerNetwork(spawnerNetworks.rewardNetworks);
SpawnerReset(spawnerNetworks.baseNetworks, false);
SpawnerReset(spawnerNetworks.randomNetworks, false);
} else if (name == CoolDownStopTimer) {
self->SetVar<bool>(IsCooldownVariable, false);
ActivityTimerStart(self, SpawnTickTimer, constants.waveTime);
ActivityTimerStart(self, CoolDownStartTimer, cooldownTime, cooldownTime);
SpawnMobs(self);
ActivityTimerStart(self, PlaySpawnSoundTimer, 3, 3);
} else if (name == PlaySpawnSoundTimer) {
for (const auto& playerID : state.players) {
auto* player = Game::entityManager->GetEntity(playerID);
if (player != nullptr) {
GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), spawnSoundGUID);
}
}
}
}
void BaseSurvivalServer::ResetStats(LWOOBJID playerID) {
auto* player = Game::entityManager->GetEntity(playerID);
if (player != nullptr) {
// Boost all the player stats when loading in
auto* destroyableComponent = player->GetComponent<DestroyableComponent>();
if (destroyableComponent != nullptr) {
destroyableComponent->SetHealth(destroyableComponent->GetMaxHealth());
destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor());
destroyableComponent->SetImagination(destroyableComponent->GetMaxImagination());
}
}
}
void BaseSurvivalServer::PlayerConfirmed(Entity* self) {
std::vector<LWOOBJID> confirmedPlayers{};
for (const auto& playerID : state.players) {
auto pass = false;
for (const auto& waitingPlayerID : state.waitingPlayers) {
if (waitingPlayerID == playerID)
pass = true;
}
if (!pass)
confirmedPlayers.push_back(playerID);
}
auto playerIndex = 1;
for (const auto& playerID : confirmedPlayers) {
self->SetNetworkVar<std::string>(PlayerConfirmVariable + GeneralUtils::to_u16string(playerIndex), std::to_string(playerID));
playerIndex++;
}
}
void BaseSurvivalServer::PlayerAccepted(Entity* self, LWOOBJID playerID) {
const auto& iter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), playerID);
if (iter == state.waitingPlayers.end()) {
return;
}
state.waitingPlayers.erase(iter);
if (state.waitingPlayers.empty() && state.players.size() >= self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable)) {
ActivityTimerStopAllTimers(self);
ActivityTimerStart(self, AllAcceptedDelayTimer, 1, constants.startDelay);
} else if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) {
self->SetVar<bool>(AcceptedDelayStartedVariable, true);
ActivityTimerStart(self, AcceptedDelayTimer, 1, constants.acceptedDelay);
}
}
void BaseSurvivalServer::StartWaves(Entity* self) {
GameMessages::SendActivityStart(self->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
self->SetVar<bool>(PlayersReadyVariable, true);
self->SetVar<uint32_t>(BaseMobSetIndexVariable, 0);
self->SetVar<uint32_t>(RandMobSetIndexVariable, 0);
self->SetVar<bool>(AcceptedDelayStartedVariable, false);
state.waitingPlayers.clear();
for (const auto& playerID : state.players) {
const auto player = Game::entityManager->GetEntity(playerID);
if (player != nullptr) {
state.waitingPlayers.push_back(playerID);
UpdatePlayer(self, playerID);
GetLeaderboardData(self, playerID, GetActivityID(self), 50);
ResetStats(playerID);
if (!self->GetVar<bool>(FirstTimeDoneVariable)) {
TakeActivityCost(self, playerID);
}
GameMessages::SendPlayerSetCameraCyclingMode(playerID, player->GetSystemAddress());
}
}
self->SetVar<bool>(FirstTimeDoneVariable, true);
self->SetVar<std::string>(MissionTypeVariable, state.players.size() == 1 ? "survival_time_solo" : "survival_time_team");
ActivateSpawnerNetwork(spawnerNetworks.smashNetworks);
self->SetNetworkVar<bool>(WavesStartedVariable, true);
self->SetNetworkVar<std::string>(StartWaveMessageVariable, "Start!");
}
bool BaseSurvivalServer::CheckAllPlayersDead() {
auto deadPlayers = 0;
for (const auto& playerID : state.players) {
auto* player = Game::entityManager->GetEntity(playerID);
if (player == nullptr || player->GetIsDead()) {
deadPlayers++;
}
}
return deadPlayers >= state.players.size();
}
void BaseSurvivalServer::SetPlayerSpawnPoints() {
auto spawnerIndex = 1;
for (const auto& playerID : state.players) {
auto* player = Game::entityManager->GetEntity(playerID);
if (player != nullptr) {
auto possibleSpawners = Game::entityManager->GetEntitiesInGroup("P" + std::to_string(spawnerIndex) + "_Spawn");
if (!possibleSpawners.empty()) {
auto* spawner = possibleSpawners.at(0);
GameMessages::SendTeleport(playerID, spawner->GetPosition(), spawner->GetRotation(), player->GetSystemAddress(), true);
}
}
spawnerIndex++;
}
}
void BaseSurvivalServer::GameOver(Entity* self) {
if (!CheckAllPlayersDead())
return;
ActivityTimerStopAllTimers(self);
// Reset all the spawners
SpawnerReset(spawnerNetworks.baseNetworks);
SpawnerReset(spawnerNetworks.randomNetworks);
SpawnerReset(spawnerNetworks.rewardNetworks);
for (const auto& playerID : state.players) {
auto* player = Game::entityManager->GetEntity(playerID);
if (player == nullptr)
continue;
const auto score = GetActivityValue(self, playerID, 0);
const auto time = GetActivityValue(self, playerID, 1);
GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Update_ScoreBoard", time, 0,
playerID, std::to_string(score), UNASSIGNED_SYSTEM_ADDRESS);
player->Resurrect();
// Update all mission progression
auto* missionComponent = player->GetComponent<MissionComponent>();
if (missionComponent != nullptr) {
missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, time, self->GetObjectID(),
self->GetVar<std::string>(MissionTypeVariable));
for (const auto& survivalMission : missionsToUpdate) {
auto* mission = missionComponent->GetMission(survivalMission.first);
if (mission != nullptr && (uint32_t)time >= survivalMission.second
&& (mission->GetMissionState() == eMissionState::ACTIVE
|| mission->GetMissionState() == eMissionState::COMPLETE_ACTIVE)) {
mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT());
}
}
}
StopActivity(self, playerID, score, time);
}
state.waveNumber = 1;
state.rewardTick = 1;
state.totalSpawned = 0;
self->SetNetworkVar<bool>(WavesStartedVariable, false);
if (constants.useMobLots) {
constants.lotPhase = 0;
UpdateMobLots(spawnerNetworks.baseNetworks);
UpdateMobLots(spawnerNetworks.randomNetworks);
}
SetPlayerSpawnPoints();
}
void BaseSurvivalServer::SpawnerReset(SpawnerNetworkCollection& spawnerNetworkCollection, bool hardReset) {
auto totalSpawned = 0;
for (auto& spawner : spawnerNetworkCollection.networks) {
for (auto& spawnerName : spawner.names) {
auto spawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName + spawner.number);
if (!spawners.empty()) {
auto* spawnerObject = spawners.at(0);
auto amountSpawned = spawnerObject->GetAmountSpawned();
totalSpawned += amountSpawned;
spawner.isActive = false;
if (hardReset) {
spawnerObject->Reset();
} else {
spawnerObject->SoftReset();
}
spawnerObject->Deactivate();
}
}
}
state.totalSpawned = std::max((uint32_t)totalSpawned, state.totalSpawned);
}
void BaseSurvivalServer::SpawnerUpdate(Entity* self, SpawnerNetworkCollection& spawnerNetworkCollection, uint32_t amount) {
if (spawnerNetworkCollection.networks.empty())
return;
// If we want to spawn something specific now
if (amount != 0) {
auto spawnerNetwork = spawnerNetworkCollection.networks.at(0);
auto possibleSpawners = dZoneManager::Instance()->GetSpawnersByName(spawnerNetwork.names.at(0) + spawnerNetwork.number);
if (!possibleSpawners.empty()) {
SpawnNow(possibleSpawners.at(0), amount);
return;
}
}
auto setNumber = self->GetVar<uint32_t>(GeneralUtils::ASCIIToUTF16(spawnerNetworkCollection.mobSetName + "Num"));
auto newSet = GetRandomMobSet(spawnerNetworkCollection, setNumber);
if (!newSet.empty()) {
auto spawnerNetwork = GetRandomSpawner(spawnerNetworkCollection);
for (auto i = 0; i < spawnerNetwork.names.size(); i++) {
const auto& name = spawnerNetwork.names.at(i);
const auto& toSpawn = newSet.at(i);
auto possibleSpawners = dZoneManager::Instance()->GetSpawnersByName(name + spawnerNetwork.number);
if (!possibleSpawners.empty()) {
SpawnNow(possibleSpawners.front(), toSpawn);
}
}
}
}
void BaseSurvivalServer::SpawnNow(Spawner* spawner, uint32_t amount) {
if (spawner != nullptr) {
if (!spawner->m_Active) {
spawner->m_Info.amountMaintained = amount;
spawner->Activate();
} else {
spawner->m_Info.amountMaintained = amount;
}
}
}
std::vector<uint32_t> BaseSurvivalServer::GetRandomMobSet(SpawnerNetworkCollection& spawnerNetworkCollection,
uint32_t setNumber) {
if (mobSets.sets.find(spawnerNetworkCollection.mobSetName) != mobSets.sets.end()) {
auto mobSet = mobSets.sets.at(spawnerNetworkCollection.mobSetName);
if (setNumber < mobSet.size()) {
return mobSet.at(setNumber).at(rand() % mobSet.at(setNumber).size());
}
}
return {};
}
SpawnerNetwork BaseSurvivalServer::GetRandomSpawner(SpawnerNetworkCollection& spawnerNetworkCollection) {
std::vector<SpawnerNetwork> validSpawners{};
for (const auto& spawner : spawnerNetworkCollection.networks) {
if (!spawner.isLocked)
validSpawners.push_back(spawner);
}
if (!validSpawners.empty()) {
auto spawner = validSpawners.at(rand() % validSpawners.size());
spawner.isActive = true;
return spawner;
}
return {};
}
void BaseSurvivalServer::ActivateSpawnerNetwork(SpawnerNetworkCollection& spawnerNetworkCollection) {
for (auto& spawner : spawnerNetworkCollection.networks) {
for (const auto& spawnerName : spawner.names) {
auto possibleSpawners = dZoneManager::Instance()->GetSpawnersByName(spawnerName + spawner.number);
if (!possibleSpawners.empty()) {
auto* spawnerObject = possibleSpawners.at(0);
spawnerObject->Activate();
spawnerObject->Reset();
}
}
}
}
void BaseSurvivalServer::UpdateMobLots(SpawnerNetworkCollection& spawnerNetworkCollection) {
for (auto& spawner : spawnerNetworkCollection.networks) {
for (auto& spawnerName : spawner.names) {
if (!spawnerName.empty()) {
auto spawnerObjects = dZoneManager::Instance()->GetSpawnersByName(spawnerName + spawner.number);
if (!spawnerObjects.empty()) {
auto splitName = GeneralUtils::SplitString(spawnerName, '_');
auto cleanName = splitName.size() > 1 ? splitName.at(1) : splitName.at(0);
if (!cleanName.empty()) {
auto spawnerObject = spawnerObjects.at(0);
spawnerObject->SetSpawnLot(mobSets.mobLots.at(cleanName).at(constants.lotPhase));
}
}
}
}
}
}
void BaseSurvivalServer::SpawnMobs(Entity* self) {
if (!self->GetNetworkVar<bool>(WavesStartedVariable))
return;
state.waveNumber++;
auto spawnNumber = state.waveNumber > constants.rewardInterval ? state.waveNumber - state.rewardTick - 1 : state.waveNumber;
for (const auto& tier : constants.baseMobsStartTier) {
if (tier == spawnNumber)
self->SetVar<uint32_t>(BaseMobSetIndexVariable, (self->GetVar<uint32_t>(BaseMobSetIndexVariable) + 1)
% (constants.baseMobsStartTier.size() - 1));
}
for (const auto& tier : constants.randMobsStartTier) {
if (tier == spawnNumber)
self->SetVar<uint32_t>(RandMobSetIndexVariable, (self->GetVar<uint32_t>(RandMobSetIndexVariable) + 1)
% (constants.randMobsStartTier.size() - 1));
}
if (state.waveNumber == constants.unlockNetwork3)
spawnerNetworks.randomNetworks.networks.at(2).isLocked = false;
SpawnerReset(spawnerNetworks.baseNetworks, false);
SpawnerReset(spawnerNetworks.randomNetworks, false);
SpawnerUpdate(self, spawnerNetworks.baseNetworks);
if (spawnNumber >= constants.mobSet2Wave) {
if (spawnNumber == constants.mobSet2Wave)
self->SetNetworkVar<std::string>(SpawnMobVariable, "2");
SpawnerUpdate(self, spawnerNetworks.randomNetworks);
}
if (spawnNumber >= constants.mobSet3Wave) {
if (spawnNumber == constants.mobSet3Wave)
self->SetNetworkVar<std::string>(SpawnMobVariable, "3");
SpawnerUpdate(self, spawnerNetworks.randomNetworks);
}
// If we reached the end of the spawn phase we increase the lost to make it more difficult
if (constants.useMobLots && constants.lotPhase < (mobSets.mobLots.begin()->second.size() - 1)
&& spawnNumber >= constants.baseMobsStartTier.back()) {
state.waveNumber = 1;
constants.lotPhase++;
UpdateMobLots(spawnerNetworks.baseNetworks);
UpdateMobLots(spawnerNetworks.randomNetworks);
}
}