This commit is contained in:
Aaron Kimbre 2023-05-09 10:58:57 -05:00
parent 7aad6e4bc2
commit 17aab41a9e
2 changed files with 238 additions and 344 deletions

View File

@ -33,7 +33,9 @@
RacingControlComponent::RacingControlComponent(Entity* parent) RacingControlComponent::RacingControlComponent(Entity* parent)
: Component(parent) { : Component(parent) {
m_PathName = u"MainPath"; m_PathName = u"MainPath";
m_DirtyPathName = true;
m_RemainingLaps = 3; m_RemainingLaps = 3;
m_DirtyRaceInfo = true;
m_LeadingPlayer = LWOOBJID_EMPTY; m_LeadingPlayer = LWOOBJID_EMPTY;
m_RaceBestTime = 0; m_RaceBestTime = 0;
m_RaceBestLap = 0; m_RaceBestLap = 0;
@ -77,36 +79,27 @@ void RacingControlComponent::OnPlayerLoaded(Entity* player) {
m_LoadedPlayers); m_LoadedPlayers);
m_LobbyPlayers.push_back(objectID); m_LobbyPlayers.push_back(objectID);
m_DirtyLoadPlayer = true;
} }
void RacingControlComponent::LoadPlayerVehicle(Entity* player, void RacingControlComponent::LoadPlayerVehicle(Entity* player, uint32_t positionNumber, bool initialLoad) {
uint32_t positionNumber, bool initialLoad) {
// Load the player's vehicle. // Load the player's vehicle.
if (player == nullptr) { if (!player) return;
return;
}
auto* inventoryComponent = player->GetComponent<InventoryComponent>();
if (inventoryComponent == nullptr) {
return;
}
// Find the player's vehicle. // Find the player's vehicle.
auto* inventoryComponent = player->GetComponent<InventoryComponent>();
if (!inventoryComponent) return;
auto* item = inventoryComponent->FindItemByLot(8092); auto* item = inventoryComponent->FindItemByLot(8092);
if (item == nullptr) { if (!item) {
Game::logger->Log("RacingControlComponent", "Failed to find item"); Game::logger->Log("RacingControlComponent", "Failed to find item");
return; return;
} }
// Calculate the vehicle's starting position. // Calculate the vehicle's starting position.
auto* path = dZoneManager::Instance()->GetZone()->GetPath( auto* path = dZoneManager::Instance()->GetZone()->GetPath(GeneralUtils::UTF16ToWTF8(m_PathName));
GeneralUtils::UTF16ToWTF8(m_PathName));
auto spawnPointEntities = EntityManager::Instance()->GetEntitiesByLOT(4843); auto spawnPointEntities = EntityManager::Instance()->GetEntitiesByLOT(4843);
auto startPosition = NiPoint3::ZERO; auto startPosition = NiPoint3::ZERO;
@ -123,9 +116,13 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
// Make sure the player is at the correct position. // Make sure the player is at the correct position.
GameMessages::SendTeleport(player->GetObjectID(), startPosition, GameMessages::SendTeleport(
startRotation, player->GetSystemAddress(), true, player->GetObjectID(),
true); startPosition,
startRotation,
player->GetSystemAddress(),
true, true
);
// Spawn the vehicle entity. // Spawn the vehicle entity.
@ -135,32 +132,26 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
info.rot = startRotation; info.rot = startRotation;
info.spawnerID = m_Parent->GetObjectID(); info.spawnerID = m_Parent->GetObjectID();
auto* carEntity = auto* carEntity = EntityManager::Instance()->CreateEntity(info, nullptr, m_Parent);
EntityManager::Instance()->CreateEntity(info, nullptr, m_Parent);
// Make the vehicle a child of the racing controller. // Make the vehicle a child of the racing controller.
m_Parent->AddChild(carEntity); m_Parent->AddChild(carEntity);
auto* destroyableComponent = auto* destroyableComponent = carEntity->GetComponent<DestroyableComponent>();
carEntity->GetComponent<DestroyableComponent>();
// Setup the vehicle stats. // Setup the vehicle stats.
if (destroyableComponent != nullptr) { if (destroyableComponent) {
destroyableComponent->SetMaxImagination(60); destroyableComponent->SetMaxImagination(60);
destroyableComponent->SetImagination(0); destroyableComponent->SetImagination(0);
} }
// Setup the vehicle as being possessed by the player. // Setup the vehicle as being possessed by the player.
auto* possessableComponent = auto* possessableComponent = carEntity->GetComponent<PossessableComponent>();
carEntity->GetComponent<PossessableComponent>();
if (possessableComponent != nullptr) { if (possessableComponent) possessableComponent->SetPossessor(player->GetObjectID());
possessableComponent->SetPossessor(player->GetObjectID());
}
// Load the vehicle's assemblyPartLOTs for display. // Load the vehicle's assemblyPartLOTs for display.
auto* moduleAssemblyComponent = auto* moduleAssemblyComponent = carEntity->GetComponent<ModuleAssemblyComponent>();
carEntity->GetComponent<ModuleAssemblyComponent>();
if (moduleAssemblyComponent) { if (moduleAssemblyComponent) {
moduleAssemblyComponent->SetSubKey(item->GetSubKey()); moduleAssemblyComponent->SetSubKey(item->GetSubKey());
@ -177,7 +168,7 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
// Setup the player as possessing the vehicle. // Setup the player as possessing the vehicle.
auto* possessorComponent = player->GetComponent<PossessorComponent>(); auto* possessorComponent = player->GetComponent<PossessorComponent>();
if (possessorComponent != nullptr) { if (possessorComponent) {
possessorComponent->SetPossessable(carEntity->GetObjectID()); possessorComponent->SetPossessable(carEntity->GetObjectID());
possessorComponent->SetPossessableType(ePossessionType::ATTACHED_VISIBLE); // for racing it's always Attached_Visible possessorComponent->SetPossessableType(ePossessionType::ATTACHED_VISIBLE); // for racing it's always Attached_Visible
} }
@ -185,24 +176,19 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
// Set the player's current activity as racing. // Set the player's current activity as racing.
auto* characterComponent = player->GetComponent<CharacterComponent>(); auto* characterComponent = player->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) { if (characterComponent) characterComponent->SetIsRacing(true);
characterComponent->SetIsRacing(true);
}
// Init the player's racing entry. // Init the player's racing entry.
if (initialLoad) { if (initialLoad) {
m_RacingPlayers.push_back( m_RacingPlayers.push_back(
{ player->GetObjectID(), {
carEntity->GetObjectID(), player->GetObjectID(),
static_cast<uint32_t>(m_RacingPlayers.size()), carEntity->GetObjectID(),
false, static_cast<uint32_t>(m_RacingPlayers.size()),
{}, false, {}, startPosition, startRotation, 0, 0, 0, 0
startPosition, }
startRotation, );
0, m_DirtyLoadPlayer = true;
0,
0,
0 });
} }
// Construct and serialize everything when done. // Construct and serialize everything when done.
@ -212,42 +198,50 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
EntityManager::Instance()->SerializeEntity(m_Parent); EntityManager::Instance()->SerializeEntity(m_Parent);
GameMessages::SendRacingSetPlayerResetInfo( GameMessages::SendRacingSetPlayerResetInfo(
m_Parent->GetObjectID(), 0, 0, player->GetObjectID(), startPosition, 1, m_Parent->GetObjectID(), 0, 0,
UNASSIGNED_SYSTEM_ADDRESS); player->GetObjectID(), startPosition, 1,
UNASSIGNED_SYSTEM_ADDRESS
);
const auto playerID = player->GetObjectID(); const auto playerID = player->GetObjectID();
// Reset the player to the start position during downtime, in case something // Reset the player to the start position during downtime, in case something
// went wrong. // went wrong.
m_Parent->AddCallbackTimer(1, [this, playerID]() { m_Parent->AddCallbackTimer(1, [this, playerID]() {
auto* player = EntityManager::Instance()->GetEntity(playerID); auto* player = EntityManager::Instance()->GetEntity(playerID);
if (!player) return;
if (player == nullptr) { GameMessages::SendRacingResetPlayerToLastReset(
return; m_Parent->GetObjectID(), playerID,
UNASSIGNED_SYSTEM_ADDRESS
);
} }
);
GameMessages::SendRacingResetPlayerToLastReset(
m_Parent->GetObjectID(), playerID, UNASSIGNED_SYSTEM_ADDRESS);
});
GameMessages::SendSetJetPackMode(player, false); GameMessages::SendSetJetPackMode(player, false);
// Set the vehicle's state. // Set the vehicle's state.
GameMessages::SendNotifyVehicleOfRacingObject(carEntity->GetObjectID(), GameMessages::SendNotifyVehicleOfRacingObject(
carEntity->GetObjectID(),
m_Parent->GetObjectID(), m_Parent->GetObjectID(),
UNASSIGNED_SYSTEM_ADDRESS); UNASSIGNED_SYSTEM_ADDRESS
);
GameMessages::SendVehicleSetWheelLockState(carEntity->GetObjectID(), false, GameMessages::SendVehicleSetWheelLockState(
initialLoad, carEntity->GetObjectID(), false, initialLoad,
UNASSIGNED_SYSTEM_ADDRESS); UNASSIGNED_SYSTEM_ADDRESS
);
// Make sure everything has the correct position. // Make sure everything has the correct position.
GameMessages::SendTeleport(player->GetObjectID(), startPosition, GameMessages::SendTeleport(
startRotation, player->GetSystemAddress(), true, player->GetObjectID(), startPosition,
true); startRotation, player->GetSystemAddress(),
GameMessages::SendTeleport(carEntity->GetObjectID(), startPosition, true, true
startRotation, player->GetSystemAddress(), true, );
true); GameMessages::SendTeleport(
carEntity->GetObjectID(), startPosition,
startRotation, player->GetSystemAddress(),
true, true
);
} }
void RacingControlComponent::OnRacingClientReady(Entity* player) { void RacingControlComponent::OnRacingClientReady(Entity* player) {
@ -257,18 +251,23 @@ void RacingControlComponent::OnRacingClientReady(Entity* player) {
if (racingPlayer.playerID != player->GetObjectID()) { if (racingPlayer.playerID != player->GetObjectID()) {
if (racingPlayer.playerLoaded) { if (racingPlayer.playerLoaded) {
GameMessages::SendRacingPlayerLoaded( GameMessages::SendRacingPlayerLoaded(
m_Parent->GetObjectID(), racingPlayer.playerID, m_Parent->GetObjectID(),
racingPlayer.vehicleID, UNASSIGNED_SYSTEM_ADDRESS); racingPlayer.playerID,
racingPlayer.vehicleID,
UNASSIGNED_SYSTEM_ADDRESS
);
} }
continue; continue;
} }
racingPlayer.playerLoaded = true; racingPlayer.playerLoaded = true;
GameMessages::SendRacingPlayerLoaded( GameMessages::SendRacingPlayerLoaded(
m_Parent->GetObjectID(), racingPlayer.playerID, m_Parent->GetObjectID(),
racingPlayer.vehicleID, UNASSIGNED_SYSTEM_ADDRESS); racingPlayer.playerID,
racingPlayer.vehicleID,
UNASSIGNED_SYSTEM_ADDRESS
);
} }
EntityManager::Instance()->SerializeEntity(m_Parent); EntityManager::Instance()->SerializeEntity(m_Parent);
@ -279,19 +278,20 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
// them. // them.
for (auto& racingPlayer : m_RacingPlayers) { for (auto& racingPlayer : m_RacingPlayers) {
if (racingPlayer.playerID != player->GetObjectID()) { if (racingPlayer.playerID != player->GetObjectID()) continue;
continue;
}
auto* vehicle = auto* vehicle = EntityManager::Instance()->GetEntity(racingPlayer.vehicleID);
EntityManager::Instance()->GetEntity(racingPlayer.vehicleID);
if (!vehicle) return; if (!vehicle) return;
if (!racingPlayer.noSmashOnReload) { if (!racingPlayer.noSmashOnReload) {
racingPlayer.smashedTimes++; racingPlayer.smashedTimes++;
GameMessages::SendDie(vehicle, vehicle->GetObjectID(), LWOOBJID_EMPTY, true, GameMessages::SendDie(
eKillType::VIOLENT, u"", 0, 0, 90.0f, false, true, 0); vehicle, vehicle->GetObjectID(),
LWOOBJID_EMPTY, true,
eKillType::VIOLENT, u"", 0, 0, 90.0f,
false, true, 0
);
auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>(); auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>();
uint32_t respawnImagination = 0; uint32_t respawnImagination = 0;
@ -306,8 +306,10 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
vehicle->AddCallbackTimer(2.0f, [=]() { vehicle->AddCallbackTimer(2.0f, [=]() {
if (!vehicle || !this->m_Parent) return; if (!vehicle || !this->m_Parent) return;
GameMessages::SendRacingResetPlayerToLastReset( GameMessages::SendRacingResetPlayerToLastReset(
m_Parent->GetObjectID(), racingPlayer.playerID, m_Parent->GetObjectID(),
UNASSIGNED_SYSTEM_ADDRESS); racingPlayer.playerID,
UNASSIGNED_SYSTEM_ADDRESS
);
GameMessages::SendVehicleStopBoost(vehicle, player->GetSystemAddress(), true); GameMessages::SendVehicleStopBoost(vehicle, player->GetSystemAddress(), true);
@ -315,7 +317,8 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
m_Parent->GetObjectID(), racingPlayer.lap, m_Parent->GetObjectID(), racingPlayer.lap,
racingPlayer.respawnIndex, player->GetObjectID(), racingPlayer.respawnIndex, player->GetObjectID(),
racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1,
UNASSIGNED_SYSTEM_ADDRESS); UNASSIGNED_SYSTEM_ADDRESS
);
GameMessages::SendResurrect(vehicle); GameMessages::SendResurrect(vehicle);
auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>(); auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>();
@ -325,50 +328,37 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
}); });
auto* characterComponent = player->GetComponent<CharacterComponent>(); auto* characterComponent = player->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) { if (characterComponent) characterComponent->UpdatePlayerStatistic(RacingTimesWrecked);
characterComponent->UpdatePlayerStatistic(RacingTimesWrecked);
}
} else { } else {
GameMessages::SendRacingSetPlayerResetInfo( GameMessages::SendRacingSetPlayerResetInfo(
m_Parent->GetObjectID(), racingPlayer.lap, m_Parent->GetObjectID(), racingPlayer.lap,
racingPlayer.respawnIndex, player->GetObjectID(), racingPlayer.respawnIndex, player->GetObjectID(),
racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1,
UNASSIGNED_SYSTEM_ADDRESS); UNASSIGNED_SYSTEM_ADDRESS
);
GameMessages::SendRacingResetPlayerToLastReset( GameMessages::SendRacingResetPlayerToLastReset(
m_Parent->GetObjectID(), racingPlayer.playerID, m_Parent->GetObjectID(),
UNASSIGNED_SYSTEM_ADDRESS); racingPlayer.playerID,
UNASSIGNED_SYSTEM_ADDRESS
);
} }
} }
} }
void RacingControlComponent::OnRacingPlayerInfoResetFinished(Entity* player) { void RacingControlComponent::OnRacingPlayerInfoResetFinished(Entity* player) {
// When the player has respawned. // When the player has respawned.
for (auto& racingPlayer : m_RacingPlayers) { for (auto& racingPlayer : m_RacingPlayers) {
if (racingPlayer.playerID != player->GetObjectID()) { if (racingPlayer.playerID != player->GetObjectID()) continue;
continue; auto* vehicle = EntityManager::Instance()->GetEntity(racingPlayer.vehicleID);
} if (!vehicle) return;
auto* vehicle =
EntityManager::Instance()->GetEntity(racingPlayer.vehicleID);
if (vehicle == nullptr) {
return;
}
racingPlayer.noSmashOnReload = false; racingPlayer.noSmashOnReload = false;
return; return;
} }
} }
void RacingControlComponent::HandleMessageBoxResponse(Entity* player, void RacingControlComponent::HandleMessageBoxResponse(Entity* player, const std::string& id) {
const std::string& id) {
auto* data = GetPlayerData(player->GetObjectID()); auto* data = GetPlayerData(player->GetObjectID());
if (!data) return;
if (data == nullptr) {
return;
}
if (id == "rewardButton") { if (id == "rewardButton") {
if (data->collectedRewards) { if (data->collectedRewards) {
@ -384,13 +374,15 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player,
// Giving rewards // Giving rewards
GameMessages::SendNotifyRacingClient( GameMessages::SendNotifyRacingClient(
m_Parent->GetObjectID(), 2, 0, LWOOBJID_EMPTY, u"", m_Parent->GetObjectID(), 2, 0,
player->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); LWOOBJID_EMPTY, u"",
player->GetObjectID(),
UNASSIGNED_SYSTEM_ADDRESS
);
auto* missionComponent = player->GetComponent<MissionComponent>(); auto* missionComponent = player->GetComponent<MissionComponent>();
if (missionComponent == nullptr) return; if (!missionComponent) return;
missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::COMPETED_IN_RACE); // Progress task for competing in a race missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::COMPETED_IN_RACE); // Progress task for competing in a race
missionComponent->Progress(eMissionTaskType::RACING, data->smashedTimes, (LWOOBJID)eRacingTaskParam::SAFE_DRIVER); // Finish a race without being smashed. missionComponent->Progress(eMissionTaskType::RACING, data->smashedTimes, (LWOOBJID)eRacingTaskParam::SAFE_DRIVER); // Finish a race without being smashed.
@ -406,87 +398,105 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player,
} }
} }
} else if (id == "ACT_RACE_EXIT_THE_RACE?" || id == "Exit") { } else if (id == "ACT_RACE_EXIT_THE_RACE?" || id == "Exit") {
Game::logger->Log("RacingControlComponent", "exiting race");
auto* vehicle = EntityManager::Instance()->GetEntity(data->vehicleID); auto* vehicle = EntityManager::Instance()->GetEntity(data->vehicleID);
if (!vehicle) return;
if (vehicle == nullptr) {
return;
}
// Exiting race // Exiting race
GameMessages::SendNotifyRacingClient( GameMessages::SendNotifyRacingClient(
m_Parent->GetObjectID(), 3, 0, LWOOBJID_EMPTY, u"", m_Parent->GetObjectID(), 3, 0,
player->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); LWOOBJID_EMPTY, u"",
player->GetObjectID(),
UNASSIGNED_SYSTEM_ADDRESS
);
auto* playerInstance = dynamic_cast<Player*>(player); auto* playerInstance = dynamic_cast<Player*>(player);
playerInstance->SendToZone(m_MainWorld); playerInstance->SendToZone(m_MainWorld);
vehicle->Kill(); vehicle->Kill();
} }
} }
void RacingControlComponent::Serialize(RakNet::BitStream* outBitStream, void RacingControlComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
bool bIsInitialUpdate,
unsigned int& flags) {
// BEGIN Scripted Activity // BEGIN Scripted Activity
outBitStream->Write1(); outBitStream->Write1();
outBitStream->Write(static_cast<uint32_t>(m_RacingPlayers.size())); outBitStream->Write(static_cast<uint32_t>(m_RacingPlayers.size()));
for (const auto& player : m_RacingPlayers) { for (const auto& player : m_RacingPlayers) {
outBitStream->Write(player.playerID); outBitStream->Write(player.playerID);
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
outBitStream->Write(player.data[i]); outBitStream->Write(player.data[i]);
} }
} }
// END Scripted Activity // END Scripted Activity
// BEGIN Base Race Control
outBitStream->Write1(); // Dirty? outBitStream->Write(m_DirtyLobby || bIsInitialUpdate);
outBitStream->Write(static_cast<uint16_t>(m_RacingPlayers.size())); if (m_DirtyLobby || bIsInitialUpdate) {
outBitStream->Write(static_cast<uint16_t>(m_LobbyPlayers.size()));
m_DirtyLobby = false;
}
outBitStream->Write(!m_RacingPlayers.empty()); outBitStream->Write(m_DirtyLoadPlayer || bIsInitialUpdate);
if (!m_RacingPlayers.empty()) { if (m_DirtyLoadPlayer || bIsInitialUpdate) {
for (const auto& player : m_RacingPlayers) { for (const auto& player : m_RacingPlayers) {
outBitStream->Write1(); // Has more date if (player.playerLoaded) {
outBitStream->Write1(); // Has more data
outBitStream->Write(player.playerID); outBitStream->Write(player.playerID);
outBitStream->Write(player.vehicleID); outBitStream->Write(player.vehicleID);
outBitStream->Write(player.playerIndex); outBitStream->Write(player.rank);
outBitStream->Write(player.playerLoaded); outBitStream->Write(player.playerLoaded);
}
} }
outBitStream->Write0(); // No more data outBitStream->Write0(); // No more data
m_DirtyLoadPlayer = false;
} }
outBitStream->Write(!m_RacingPlayers.empty()); outBitStream->Write(m_DirtyRank || bIsInitialUpdate);
if (!m_RacingPlayers.empty()) { if (m_DirtyRank || bIsInitialUpdate) {
for (const auto& player : m_RacingPlayers) { for (const auto& player : m_RacingPlayers) {
outBitStream->Write1(); // Has more date outBitStream->Write1(); // Has more data
outBitStream->Write(player.playerID); outBitStream->Write(player.playerID);
outBitStream->Write<uint32_t>(0); outBitStream->Write(player.rank);
} }
outBitStream->Write0(); // No more data outBitStream->Write0(); // No more data
m_DirtyRank = false;
} }
outBitStream->Write1(); // Dirty? // END Base Race Control
// BEGIN Race Control
outBitStream->Write(m_RemainingLaps); outBitStream->Write(m_DirtyRaceInfo || bIsInitialUpdate);
if (m_DirtyRaceInfo || bIsInitialUpdate) {
outBitStream->Write(m_RemainingLaps);
outBitStream->Write(static_cast<uint16_t>(m_PathName.size())); if (m_DirtyPathName){
for (const auto character : m_PathName) { outBitStream->Write(static_cast<uint16_t>(m_PathName.size()));
outBitStream->Write(character); for (const auto character : m_PathName) {
outBitStream->Write(character);
}
m_DirtyPathName = false;
} else {
// once we set the path, we don't need to send it every time unless it changes
outBitStream->Write<uint16_t>(0);
}
m_DirtyRaceInfo = false;
} }
outBitStream->Write1(); // ??? outBitStream->Write(m_DirtyEndOfRaceInfo || bIsInitialUpdate);
outBitStream->Write1(); // ??? if (m_DirtyEndOfRaceInfo || bIsInitialUpdate){
for (const auto& player : m_RacingPlayers) {
outBitStream->Write(m_LeadingPlayer); if (player.finished > 0) {
outBitStream->Write(m_RaceBestLap); outBitStream->Write1(); // Has more data
outBitStream->Write(m_RaceBestTime); outBitStream->Write(player.playerID);
outBitStream->Write(player.bestLapTime);
outBitStream->Write(player.raceTime);
}
}
outBitStream->Write0(); // No more data
m_DirtyEndOfRaceInfo = false;
}
// END Race Control
} }
RacingPlayerInfo* RacingControlComponent::GetPlayerData(LWOOBJID playerID) { RacingPlayerInfo* RacingControlComponent::GetPlayerData(LWOOBJID playerID) {
@ -506,71 +516,46 @@ void RacingControlComponent::Update(float deltaTime) {
if (!m_Loaded) { if (!m_Loaded) {
// Check if any players has disconnected before loading in // Check if any players has disconnected before loading in
for (size_t i = 0; i < m_LobbyPlayers.size(); i++) { for (size_t i = 0; i < m_LobbyPlayers.size(); i++) {
auto* playerEntity = auto* playerEntity = EntityManager::Instance()->GetEntity(m_LobbyPlayers[i]);
EntityManager::Instance()->GetEntity(m_LobbyPlayers[i]); if (!playerEntity) {
if (playerEntity == nullptr) {
--m_LoadedPlayers; --m_LoadedPlayers;
m_LobbyPlayers.erase(m_LobbyPlayers.begin() + i); m_LobbyPlayers.erase(m_LobbyPlayers.begin() + i);
m_DirtyLoadPlayer = true;
return; return;
} }
} }
if (m_LoadedPlayers >= 2 || (m_LoadedPlayers == 1 && m_SoloRacing)) { if (m_LoadedPlayers >= 2 || (m_LoadedPlayers == 1 && m_SoloRacing)) m_LoadTimer += deltaTime;
m_LoadTimer += deltaTime; else m_EmptyTimer += deltaTime;
} else {
m_EmptyTimer += deltaTime;
}
// If a player happens to be left alone for more then 30 seconds without // If a player happens to be left alone for more then 30 seconds without
// anyone else loading in, send them back to the main world // anyone else loading in, send them back to the main world
if (m_EmptyTimer >= 30) { if (m_EmptyTimer >= 30) {
for (const auto player : m_LobbyPlayers) { for (const auto player : m_LobbyPlayers) {
auto* playerEntity = auto* playerEntity = EntityManager::Instance()->GetEntity(player);
EntityManager::Instance()->GetEntity(player); if (playerEntity) continue;
if (playerEntity == nullptr) {
continue;
}
auto* playerInstance = dynamic_cast<Player*>(playerEntity); auto* playerInstance = dynamic_cast<Player*>(playerEntity);
playerInstance->SendToZone(m_MainWorld); playerInstance->SendToZone(m_MainWorld);
} }
m_LobbyPlayers.clear(); m_LobbyPlayers.clear();
} }
// From the first 2 players loading in the rest have a max of 15 seconds // From the first 2 players loading in the rest have a max of 15 seconds
// to load in, can raise this if it's too low // to load in, can raise this if it's too low
if (m_LoadTimer >= 15) { if (m_LoadTimer >= 15) {
Game::logger->Log("RacingControlComponent", Game::logger->Log("RacingControlComponent", "Loading all players...");
"Loading all players...");
for (size_t positionNumber = 0; positionNumber < m_LobbyPlayers.size(); positionNumber++) { for (size_t positionNumber = 0; positionNumber < m_LobbyPlayers.size(); positionNumber++) {
Game::logger->Log("RacingControlComponent", Game::logger->Log("RacingControlComponent", "Loading player now!");
"Loading player now!");
auto* player = auto* player = EntityManager::Instance()->GetEntity(m_LobbyPlayers[positionNumber]);
EntityManager::Instance()->GetEntity(m_LobbyPlayers[positionNumber]); if (!player) return;
if (player == nullptr) {
return;
}
Game::logger->Log("RacingControlComponent",
"Loading player now NOW!");
Game::logger->Log("RacingControlComponent", "Loading player now NOW!");
LoadPlayerVehicle(player, positionNumber + 1, true); LoadPlayerVehicle(player, positionNumber + 1, true);
m_Loaded = true; m_Loaded = true;
} }
m_Loaded = true; m_Loaded = true;
} }
return; return;
} }
@ -578,14 +563,11 @@ void RacingControlComponent::Update(float deltaTime) {
if (!m_Started) { if (!m_Started) {
// Check if anyone has disconnected during this period // Check if anyone has disconnected during this period
for (size_t i = 0; i < m_RacingPlayers.size(); i++) { for (size_t i = 0; i < m_RacingPlayers.size(); i++) {
auto* playerEntity = EntityManager::Instance()->GetEntity( auto* playerEntity = EntityManager::Instance()->GetEntity(m_RacingPlayers[i].playerID);
m_RacingPlayers[i].playerID);
if (playerEntity == nullptr) { if (!playerEntity) {
m_RacingPlayers.erase(m_RacingPlayers.begin() + i); m_RacingPlayers.erase(m_RacingPlayers.begin() + i);
--m_LoadedPlayers; --m_LoadedPlayers;
return; return;
} }
} }
@ -593,29 +575,18 @@ void RacingControlComponent::Update(float deltaTime) {
// If less then 2 players are left, send the rest back to the main world // If less then 2 players are left, send the rest back to the main world
if (m_LoadedPlayers < 2 && !(m_LoadedPlayers == 1 && m_SoloRacing)) { if (m_LoadedPlayers < 2 && !(m_LoadedPlayers == 1 && m_SoloRacing)) {
for (const auto player : m_LobbyPlayers) { for (const auto player : m_LobbyPlayers) {
auto* playerEntity = auto* playerEntity = EntityManager::Instance()->GetEntity(player);
EntityManager::Instance()->GetEntity(player); if (!playerEntity) continue;
if (playerEntity == nullptr) {
continue;
}
auto* playerInstance = dynamic_cast<Player*>(playerEntity); auto* playerInstance = dynamic_cast<Player*>(playerEntity);
playerInstance->SendToZone(m_MainWorld); playerInstance->SendToZone(m_MainWorld);
} }
return; return;
} }
// Check if all players have send a ready message // Check if all players have send a ready message
int32_t readyPlayers = 0; int32_t readyPlayers = 0;
for (const auto& player : m_RacingPlayers) { for (const auto& player : m_RacingPlayers) {
if (player.playerLoaded) { if (player.playerLoaded) ++readyPlayers;
++readyPlayers;
}
} }
if (readyPlayers >= m_LoadedPlayers) { if (readyPlayers >= m_LoadedPlayers) {
@ -623,67 +594,43 @@ void RacingControlComponent::Update(float deltaTime) {
if (m_StartTimer == 0) { if (m_StartTimer == 0) {
GameMessages::SendNotifyRacingClient( GameMessages::SendNotifyRacingClient(
m_Parent->GetObjectID(), 1, 0, LWOOBJID_EMPTY, u"", m_Parent->GetObjectID(), 1, 0, LWOOBJID_EMPTY, u"",
LWOOBJID_EMPTY, UNASSIGNED_SYSTEM_ADDRESS); LWOOBJID_EMPTY, UNASSIGNED_SYSTEM_ADDRESS
);
for (const auto& player : m_RacingPlayers) { for (const auto& player : m_RacingPlayers) {
auto* vehicle = auto* vehicle = EntityManager::Instance()->GetEntity(player.vehicleID);
EntityManager::Instance()->GetEntity(player.vehicleID); auto* playerEntity = EntityManager::Instance()->GetEntity(player.playerID);
auto* playerEntity = if (vehicle && playerEntity) {
EntityManager::Instance()->GetEntity(player.playerID);
if (vehicle != nullptr && playerEntity != nullptr) {
GameMessages::SendTeleport( GameMessages::SendTeleport(
player.playerID, player.respawnPosition, player.playerID, player.respawnPosition,
player.respawnRotation, player.respawnRotation,
playerEntity->GetSystemAddress(), true, true); playerEntity->GetSystemAddress(), true, true
);
vehicle->SetPosition(player.respawnPosition); vehicle->SetPosition(player.respawnPosition);
vehicle->SetRotation(player.respawnRotation); vehicle->SetRotation(player.respawnRotation);
auto* destroyableComponent = auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>();
vehicle->GetComponent<DestroyableComponent>(); if (destroyableComponent)destroyableComponent->SetImagination(0);
if (destroyableComponent != nullptr) {
destroyableComponent->SetImagination(0);
}
EntityManager::Instance()->SerializeEntity(vehicle); EntityManager::Instance()->SerializeEntity(vehicle);
EntityManager::Instance()->SerializeEntity( EntityManager::Instance()->SerializeEntity(playerEntity);
playerEntity);
} }
} }
// Spawn imagination pickups // Spawn imagination pickups
auto* minSpawner = dZoneManager::Instance()->GetSpawnersByName( auto* minSpawner = dZoneManager::Instance()->GetSpawnersByName("ImaginationSpawn_Min")[0];
"ImaginationSpawn_Min")[0]; auto* medSpawner = dZoneManager::Instance()->GetSpawnersByName("ImaginationSpawn_Med")[0];
auto* medSpawner = dZoneManager::Instance()->GetSpawnersByName( auto* maxSpawner = dZoneManager::Instance()->GetSpawnersByName("ImaginationSpawn_Max")[0];
"ImaginationSpawn_Med")[0];
auto* maxSpawner = dZoneManager::Instance()->GetSpawnersByName(
"ImaginationSpawn_Max")[0];
minSpawner->Activate(); minSpawner->Activate();
if (m_LoadedPlayers > 2) medSpawner->Activate();
if (m_LoadedPlayers > 2) { if (m_LoadedPlayers > 4) maxSpawner->Activate();
medSpawner->Activate();
}
if (m_LoadedPlayers > 4) {
maxSpawner->Activate();
}
// Reset players to their start location, without smashing them // Reset players to their start location, without smashing them
for (auto& player : m_RacingPlayers) { for (auto& player : m_RacingPlayers) {
auto* vehicleEntity = auto* vehicleEntity = EntityManager::Instance()->GetEntity(player.vehicleID);
EntityManager::Instance()->GetEntity(player.vehicleID); auto* playerEntity = EntityManager::Instance()->GetEntity(player.playerID);
auto* playerEntity = if (!vehicleEntity || !playerEntity) continue;
EntityManager::Instance()->GetEntity(player.playerID);
if (vehicleEntity == nullptr || playerEntity == nullptr) {
continue;
}
player.noSmashOnReload = true; player.noSmashOnReload = true;
OnRequestDie(playerEntity); OnRequestDie(playerEntity);
} }
} }
@ -692,64 +639,45 @@ void RacingControlComponent::Update(float deltaTime) {
else if (m_StartTimer >= 6) { else if (m_StartTimer >= 6) {
// Activate the players movement // Activate the players movement
for (auto& player : m_RacingPlayers) { for (auto& player : m_RacingPlayers) {
auto* vehicleEntity = auto* vehicleEntity = EntityManager::Instance()->GetEntity(player.vehicleID);
EntityManager::Instance()->GetEntity(player.vehicleID); auto* playerEntity = EntityManager::Instance()->GetEntity(player.playerID);
auto* playerEntity = if (!vehicleEntity || !playerEntity) continue;
EntityManager::Instance()->GetEntity(player.playerID); GameMessages::SendVehicleUnlockInput(player.vehicleID, false, UNASSIGNED_SYSTEM_ADDRESS);
if (vehicleEntity == nullptr || playerEntity == nullptr) {
continue;
}
GameMessages::SendVehicleUnlockInput(
player.vehicleID, false, UNASSIGNED_SYSTEM_ADDRESS);
} }
// Start the race // Start the race
GameMessages::SendActivityStart(m_Parent->GetObjectID(), GameMessages::SendActivityStart(m_Parent->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
UNASSIGNED_SYSTEM_ADDRESS);
m_Started = true; m_Started = true;
Game::logger->Log("RacingControlComponent", "Starting race"); Game::logger->Log("RacingControlComponent", "Starting race");
EntityManager::Instance()->SerializeEntity(m_Parent); EntityManager::Instance()->SerializeEntity(m_Parent);
m_StartTime = std::time(nullptr); m_StartTime = std::time(nullptr);
} }
m_StartTimer += deltaTime; m_StartTimer += deltaTime;
} else { } else m_StartTimer = 0;
m_StartTimer = 0;
}
return; return;
} }
// Race routines // Race routines
auto* path = dZoneManager::Instance()->GetZone()->GetPath( auto* path = dZoneManager::Instance()->GetZone()->GetPath(GeneralUtils::UTF16ToWTF8(m_PathName));
GeneralUtils::UTF16ToWTF8(m_PathName));
for (auto& player : m_RacingPlayers) { for (auto& player : m_RacingPlayers) {
auto* vehicle = EntityManager::Instance()->GetEntity(player.vehicleID); auto* vehicle = EntityManager::Instance()->GetEntity(player.vehicleID);
auto* playerEntity = auto* playerEntity = EntityManager::Instance()->GetEntity(player.playerID);
EntityManager::Instance()->GetEntity(player.playerID);
if (vehicle == nullptr || playerEntity == nullptr) {
continue;
}
if (!vehicle || !playerEntity) continue;
const auto vehiclePosition = vehicle->GetPosition(); const auto vehiclePosition = vehicle->GetPosition();
// If the player is this far below the map, safe to assume they should // If the player is this far below the map, safe to assume they should
// be smashed by death plane // be smashed by death plane
if (vehiclePosition.y < -500) { if (vehiclePosition.y < -500) {
GameMessages::SendDie(vehicle, m_Parent->GetObjectID(), GameMessages::SendDie(
LWOOBJID_EMPTY, true, eKillType::VIOLENT, u"", 0, 0, 0, vehicle, m_Parent->GetObjectID(),
true, false, 0); LWOOBJID_EMPTY, true, eKillType::VIOLENT,
u"", 0, 0, 0, true, false, 0
);
OnRequestDie(playerEntity); OnRequestDie(playerEntity);
continue; continue;
} }
@ -757,13 +685,10 @@ void RacingControlComponent::Update(float deltaTime) {
// new checkpoint // new checkpoint
uint32_t respawnIndex = 0; uint32_t respawnIndex = 0;
for (const auto& waypoint : path->pathWaypoints) { for (const auto& waypoint : path->pathWaypoints) {
if (player.lap == 3) { if (player.lap == 3) break;
break;
}
if (player.respawnIndex == respawnIndex) { if (player.respawnIndex == respawnIndex) {
++respawnIndex; ++respawnIndex;
continue; continue;
} }
@ -772,23 +697,19 @@ void RacingControlComponent::Update(float deltaTime) {
if (std::abs((int)respawnIndex - (int)player.respawnIndex) > 10 && if (std::abs((int)respawnIndex - (int)player.respawnIndex) > 10 &&
player.respawnIndex != path->pathWaypoints.size() - 1) { player.respawnIndex != path->pathWaypoints.size() - 1) {
++respawnIndex; ++respawnIndex;
continue; continue;
} }
if (Vector3::DistanceSquared(position, vehiclePosition) > 50 * 50) { if (Vector3::DistanceSquared(position, vehiclePosition) > 50 * 50) {
++respawnIndex; ++respawnIndex;
continue; continue;
} }
// Only go upwards, except if we've lapped // Only go upwards, except if we've lapped
// Not sure how we are supposed to check if they've reach a // Not sure how we are supposed to check if they've reach a
// checkpoint, within 50 units seems safe // checkpoint, within 50 units seems safe
if (!(respawnIndex > player.respawnIndex || if (!(respawnIndex > player.respawnIndex || player.respawnIndex == path->pathWaypoints.size() - 1)) {
player.respawnIndex == path->pathWaypoints.size() - 1)) {
++respawnIndex; ++respawnIndex;
continue; continue;
} }
@ -801,28 +722,17 @@ void RacingControlComponent::Update(float deltaTime) {
// Reached the start point, lapped // Reached the start point, lapped
if (respawnIndex == 0) { if (respawnIndex == 0) {
time_t lapTime = std::time(nullptr) - (player.lap == 0 ? m_StartTime : player.lapTime); time_t lapTime = std::time(nullptr) - (player.lap == 0 ? m_StartTime : player.lapTime);
// Cheating check // Cheating check
if (lapTime < 40) { if (lapTime < 40) continue;
continue;
}
player.lap++; player.lap++;
player.lapTime = std::time(nullptr); player.lapTime = std::time(nullptr);
if (player.bestLapTime == 0 || player.bestLapTime > lapTime) { if (player.bestLapTime == 0 || player.bestLapTime > lapTime) {
player.bestLapTime = lapTime; player.bestLapTime = lapTime;
Game::logger->Log("RacingControlComponent", "Best lap time (%llu)", lapTime);
Game::logger->Log("RacingControlComponent",
"Best lap time (%llu)", lapTime);
} }
auto* missionComponent = auto* missionComponent = playerEntity->GetComponent<MissionComponent>();
playerEntity->GetComponent<MissionComponent>(); if (missionComponent) {
if (missionComponent != nullptr) {
// Progress lap time tasks // Progress lap time tasks
missionComponent->Progress(eMissionTaskType::RACING, (lapTime) * 1000, (LWOOBJID)eRacingTaskParam::LAP_TIME); missionComponent->Progress(eMissionTaskType::RACING, (lapTime) * 1000, (LWOOBJID)eRacingTaskParam::LAP_TIME);
@ -830,36 +740,20 @@ void RacingControlComponent::Update(float deltaTime) {
m_Finished++; m_Finished++;
player.finished = m_Finished; player.finished = m_Finished;
const auto raceTime =
(std::time(nullptr) - m_StartTime);
player.raceTime = raceTime;
Game::logger->Log("RacingControlComponent",
"Completed time %llu, %llu",
raceTime, raceTime * 1000);
// Entire race time // Entire race time
const auto raceTime = (std::time(nullptr) - m_StartTime);
player.raceTime = raceTime;
Game::logger->Log("RacingControlComponent", "Completed time %llu, %llu", raceTime, raceTime * 1000);
missionComponent->Progress(eMissionTaskType::RACING, (raceTime) * 1000, (LWOOBJID)eRacingTaskParam::TOTAL_TRACK_TIME); missionComponent->Progress(eMissionTaskType::RACING, (raceTime) * 1000, (LWOOBJID)eRacingTaskParam::TOTAL_TRACK_TIME);
auto* characterComponent = playerEntity->GetComponent<CharacterComponent>(); auto* characterComponent = playerEntity->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) { if (characterComponent) characterComponent->TrackRaceCompleted(m_Finished == 1);
characterComponent->TrackRaceCompleted(m_Finished == 1); m_DirtyEndOfRaceInfo = true;
}
// TODO: Figure out how to update the GUI leaderboard.
} }
} }
Game::logger->Log("RacingControlComponent", "Lapped (%i) in (%llu)", player.lap, lapTime);
Game::logger->Log("RacingControlComponent",
"Lapped (%i) in (%llu)", player.lap,
lapTime);
} }
Game::logger->Log("RacingControlComponent", "Reached point (%i)/(%i)", player.respawnIndex, path->pathWaypoints.size());
Game::logger->Log("RacingControlComponent",
"Reached point (%i)/(%i)", player.respawnIndex,
path->pathWaypoints.size());
break; break;
} }
} }
@ -873,19 +767,12 @@ std::string RacingControlComponent::FormatTimeString(time_t time) {
std::string minText; std::string minText;
std::string secText; std::string secText;
if (min <= 0) { if (min <= 0) minText = "0";
minText = "0"; else minText = std::to_string(min);
} else {
minText = std::to_string(min);
}
if (sec <= 0) { if (sec <= 0) secText = "00";
secText = "00"; else if (sec <= 9) secText = "0" + std::to_string(sec);
} else if (sec <= 9) { else secText = std::to_string(sec);
secText = "0" + std::to_string(sec);
} else {
secText = std::to_string(sec);
}
return minText + ":" + secText + ".00"; return minText + ":" + secText + ".00";
} }

View File

@ -25,9 +25,9 @@ struct RacingPlayerInfo {
LWOOBJID vehicleID; LWOOBJID vehicleID;
/** /**
* The index of this player in the list of players * The rank of a player
*/ */
uint32_t playerIndex; uint32_t rank;
/** /**
* Whether the player has finished loading or not * Whether the player has finished loading or not
@ -246,4 +246,11 @@ private:
float m_EmptyTimer; float m_EmptyTimer;
bool m_SoloRacing; bool m_SoloRacing;
bool m_DirtyEndOfRaceInfo;
bool m_DirtyRaceInfo;
bool m_DirtyPathName;
bool m_DirtyRank;
bool m_DirtyLoadPlayer;
bool m_DirtyLobby;
}; };