diff --git a/CMakeVariables.txt b/CMakeVariables.txt index 99742a07..b50b4446 100644 --- a/CMakeVariables.txt +++ b/CMakeVariables.txt @@ -1,6 +1,6 @@ PROJECT_VERSION_MAJOR=1 PROJECT_VERSION_MINOR=0 -PROJECT_VERSION_PATCH=1 +PROJECT_VERSION_PATCH=2 # LICENSE LICENSE=AGPL-3.0 # The network version. diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 75d8d8b6..132a0eb7 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -22,6 +22,7 @@ #include "Component.h" #include "ControllablePhysicsComponent.h" #include "RenderComponent.h" +#include "RocketLaunchLupComponent.h" #include "CharacterComponent.h" #include "DestroyableComponent.h" #include "BuffComponent.h" @@ -456,9 +457,10 @@ void Entity::Initialize() else comp = new InventoryComponent(this); m_Components.insert(std::make_pair(COMPONENT_TYPE_INVENTORY, comp)); } - - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ROCKET_LAUNCH_LUP) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_ROCKET_LAUNCH_LUP, nullptr)); + // if this component exists, then we initialize it. it's value is always 0 + if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ROCKET_LAUNCH_LUP, -1) != -1) { + auto comp = new RocketLaunchLupComponent(this); + m_Components.insert(std::make_pair(COMPONENT_TYPE_ROCKET_LAUNCH_LUP, comp)); } /** @@ -495,13 +497,6 @@ void Entity::Initialize() std::string customScriptServer; bool hasCustomServerScript = false; - // Custom script for the LUP teleporter - if (m_TemplateID == 14333) - { - hasCustomServerScript = true; - customScriptServer = "scripts\\02_server\\DLU\\L_SB_LUP_TELEPORT.lua"; - } - const auto customScriptServerName = GetVarAsString(u"custom_script_server"); const auto customScriptClientName = GetVarAsString(u"custom_script_client"); diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index 8fb75fb2..aacb2bc8 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -24,12 +24,13 @@ EntityManager* EntityManager::m_Address = nullptr; std::vector EntityManager::m_GhostingExcludedZones = { // Small zones 1000, - + // Racing zones 1203, + 1261, 1303, 1403, - + // Property zones 1150, 1151, diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index 815a3d59..f7941af8 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -13,6 +13,7 @@ #include "PossessorComponent.h" #include "VehiclePhysicsComponent.h" #include "GameMessages.h" +#include "Item.h" CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) { m_Character = character; @@ -448,6 +449,56 @@ void CharacterComponent::SetLastRocketConfig(std::u16string config) { m_LastRocketConfig = config; } +Item* CharacterComponent::GetRocket(Entity* player) { + Item* rocket = nullptr; + + auto* inventoryComponent = player->GetComponent(); + + if (!inventoryComponent) return rocket; + + // Select the rocket + if (!rocket){ + rocket = inventoryComponent->FindItemById(GetLastRocketItemID()); + } + + if (!rocket) { + rocket = inventoryComponent->FindItemByLot(6416); + } + + if (!rocket) { + Game::logger->Log("CharacterComponent", "Unable to find rocket to equip!\n"); + return rocket; + } + return rocket; +} + +Item* CharacterComponent::RocketEquip(Entity* player) { + Item* rocket = GetRocket(player); + if (!rocket) return rocket; + + // build and define the rocket config + for (LDFBaseData* data : rocket->GetConfig()) { + if (data->GetKey() == u"assemblyPartLOTs") { + std::string newRocketStr = data->GetValueAsString() + ";"; + GeneralUtils::ReplaceInString(newRocketStr, "+", ";"); + SetLastRocketConfig(GeneralUtils::ASCIIToUTF16(newRocketStr)); + } + } + + // Store the last used rocket item's ID + SetLastRocketItemID(rocket->GetId()); + // carry the rocket + rocket->Equip(true); + return rocket; +} + +void CharacterComponent::RocketUnEquip(Entity* player) { + Item* rocket = GetRocket(player); + if (!rocket) return; + // We don't want to carry it anymore + rocket->UnEquip(); +} + void CharacterComponent::TrackMissionCompletion(bool isAchievement) { UpdatePlayerStatistic(MissionsCompleted); diff --git a/dGame/dComponents/CharacterComponent.h b/dGame/dComponents/CharacterComponent.h index 04245bf9..99c8a098 100644 --- a/dGame/dComponents/CharacterComponent.h +++ b/dGame/dComponents/CharacterComponent.h @@ -5,6 +5,7 @@ #include "RakNetTypes.h" #include "Character.h" #include "Component.h" +#include "Item.h" #include #include "CDMissionsTable.h" #include "tinyxml2.h" @@ -74,6 +75,26 @@ public: */ void SetLastRocketConfig(std::u16string config); + /** + * Find a player's rocket + * @param player the entity that triggered the event + * @return rocket + */ + Item* GetRocket(Entity* player); + + /** + * Equip a player's rocket + * @param player the entity that triggered the event + * @return rocket + */ + Item* RocketEquip(Entity* player); + + /** + * Find a player's rocket and unequip it + * @param player the entity that triggered the event + */ + void RocketUnEquip(Entity* player); + /** * Gets the current level of the entity * @return the current level of the entity diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index d2292168..7235d2db 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -1,4 +1,4 @@ -#include "InventoryComponent.h" +#include "InventoryComponent.h" #include @@ -794,10 +794,29 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b outBitStream->Write(item.slot != 0); if (item.slot != 0) outBitStream->Write(item.slot); - + outBitStream->Write0(); - - outBitStream->Write0(); //TODO: This is supposed to be true and write the assemblyPartLOTs when they're present. + + bool flag = !item.config.empty(); + outBitStream->Write(flag); + if (flag) { + RakNet::BitStream ldfStream; + ldfStream.Write(item.config.size()); // Key count + for (LDFBaseData* data : item.config) { + if (data->GetKey() == u"assemblyPartLOTs") { + std::string newRocketStr = data->GetValueAsString() + ";"; + GeneralUtils::ReplaceInString(newRocketStr, "+", ";"); + LDFData* ldf_data = new LDFData(u"assemblyPartLOTs", GeneralUtils::ASCIIToUTF16(newRocketStr)); + ldf_data->WriteToPacket(&ldfStream); + delete ldf_data; + } else { + data->WriteToPacket(&ldfStream); + } + } + outBitStream->Write(ldfStream.GetNumberOfBytesUsed() + 1); + outBitStream->Write(0); // Don't compress + outBitStream->Write(ldfStream); + } outBitStream->Write1(); } @@ -1043,7 +1062,7 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) GenerateProxies(item); - UpdateSlot(item->GetInfo().equipLocation, { item->GetId(), item->GetLot(), item->GetCount(), item->GetSlot() }); + UpdateSlot(item->GetInfo().equipLocation, { item->GetId(), item->GetLot(), item->GetCount(), item->GetSlot(), item->GetConfig() }); ApplyBuff(item); diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 97c7e95b..39d7eb60 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -75,6 +75,12 @@ PetComponent::PetComponent(Entity* parent, uint32_t componentId) : Component(par m_MovementAI = nullptr; m_TresureTime = 0; m_Preconditions = nullptr; + + std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parent->GetVar(u"CheckPrecondition")); + + if (!checkPreconditions.empty()) { + SetPreconditions(checkPreconditions); + } } void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) diff --git a/dGame/dComponents/PropertyEntranceComponent.cpp b/dGame/dComponents/PropertyEntranceComponent.cpp index 728cdc9e..6779d1c3 100644 --- a/dGame/dComponents/PropertyEntranceComponent.cpp +++ b/dGame/dComponents/PropertyEntranceComponent.cpp @@ -1,4 +1,4 @@ -#include "PropertyEntranceComponent.h" +#include "PropertyEntranceComponent.h" #include @@ -8,6 +8,7 @@ #include "PropertyManagementComponent.h" #include "PropertySelectQueryProperty.h" #include "RocketLaunchpadControlComponent.h" +#include "CharacterComponent.h" #include "UserManager.h" #include "dLogger.h" @@ -22,20 +23,25 @@ PropertyEntranceComponent::PropertyEntranceComponent(uint32_t componentID, Entit this->m_PropertyName = entry.propertyName; } -void PropertyEntranceComponent::OnUse(Entity* entity) -{ - GameMessages::SendPropertyEntranceBegin(m_Parent->GetObjectID(), entity->GetSystemAddress()); +void PropertyEntranceComponent::OnUse(Entity* entity) { + auto* characterComponent = entity->GetComponent(); + if (!characterComponent) return; - AMFArrayValue args; + auto* rocket = entity->GetComponent()->RocketEquip(entity); + if (!rocket) return; + + GameMessages::SendPropertyEntranceBegin(m_Parent->GetObjectID(), entity->GetSystemAddress()); + + AMFArrayValue args; auto* state = new AMFStringValue(); state->SetStringValue("property_menu"); args.InsertValue("state", state); - GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", &args); + GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", &args); - delete state; + delete state; } void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr) @@ -75,7 +81,7 @@ void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, launcher->SetSelectedCloneId(entity->GetObjectID(), cloneId); - launcher->Launch(entity, LWOOBJID_EMPTY, launcher->GetTargetZone(), cloneId); + launcher->Launch(entity, launcher->GetTargetZone(), cloneId); } PropertySelectQueryProperty PropertyEntranceComponent::SetPropertyValues(PropertySelectQueryProperty property, LWOCLONEID cloneId, std::string ownerName, std::string propertyName, std::string propertyDescription, float reputation, bool isBFF, bool isFriend, bool isModeratorApproved, bool isAlt, bool isOwned, uint32_t privacyOption, uint32_t timeLastUpdated, float performanceCost) { diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index ef970d98..abee5e16 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -45,7 +45,14 @@ void RebuildComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitia outBitStream->Write(false); } - + // If build state is completed and we've already serialized once in the completed state, + // don't serializing this component anymore as this will cause the build to jump again. + // If state changes, serialization will begin again. + if (!m_StateDirty && m_State == REBUILD_COMPLETED) { + outBitStream->Write0(); + outBitStream->Write0(); + return; + } // BEGIN Scripted Activity outBitStream->Write1(); @@ -79,6 +86,7 @@ void RebuildComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitia outBitStream->Write(m_ActivatorPosition); outBitStream->Write(m_RepositionPlayer); } + m_StateDirty = false; } void RebuildComponent::Update(float deltaTime) { @@ -139,7 +147,6 @@ void RebuildComponent::Update(float deltaTime) { } if (m_Timer >= m_ResetTime) { - m_Builder = LWOOBJID_EMPTY; GameMessages::SendDieNoImplCode(m_Parent, LWOOBJID_EMPTY, LWOOBJID_EMPTY, eKillType::VIOLENT, u"", 0.0f, 0.0f, 0.0f, false, true); @@ -384,7 +391,7 @@ void RebuildComponent::StartRebuild(Entity* user) { GameMessages::SendEnableRebuild(m_Parent, true, false, false, eFailReason::REASON_NOT_GIVEN, 0.0f, user->GetObjectID()); m_State = eRebuildState::REBUILD_BUILDING; - + m_StateDirty = true; EntityManager::Instance()->SerializeEntity(m_Parent); auto* movingPlatform = m_Parent->GetComponent(); @@ -427,6 +434,7 @@ void RebuildComponent::CompleteRebuild(Entity* user) { m_State = eRebuildState::REBUILD_COMPLETED; + m_StateDirty = true; m_Timer = 0.0f; m_DrainedImagination = 0; @@ -455,8 +463,6 @@ void RebuildComponent::CompleteRebuild(Entity* user) { LootGenerator::Instance().DropActivityLoot(builder, m_Parent, m_ActivityId, 1); } - m_Builder = LWOOBJID_EMPTY; - // Notify scripts for (auto* script : CppScripts::GetEntityScripts(m_Parent)) { script->OnRebuildComplete(m_Parent, user); @@ -501,12 +507,11 @@ void RebuildComponent::ResetRebuild(bool failed) { GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::REBUILD_RESETTING, LWOOBJID_EMPTY); m_State = eRebuildState::REBUILD_RESETTING; + m_StateDirty = true; m_Timer = 0.0f; m_TimerIncomplete = 0.0f; m_ShowResetEffect = false; m_DrainedImagination = 0; - - m_Builder = LWOOBJID_EMPTY; EntityManager::Instance()->SerializeEntity(m_Parent); @@ -541,6 +546,7 @@ void RebuildComponent::CancelRebuild(Entity* entity, eFailReason failReason, boo // Now update the component itself m_State = eRebuildState::REBUILD_INCOMPLETE; + m_StateDirty = true; // Notify scripts and possible subscribers for (auto* script : CppScripts::GetEntityScripts(m_Parent)) diff --git a/dGame/dComponents/RebuildComponent.h b/dGame/dComponents/RebuildComponent.h index c177f42c..72c57bb0 100644 --- a/dGame/dComponents/RebuildComponent.h +++ b/dGame/dComponents/RebuildComponent.h @@ -216,7 +216,11 @@ public: */ void CancelRebuild(Entity* builder, eFailReason failReason, bool skipChecks = false); private: - + /** + * Whether or not the quickbuild state has been changed since we last serialized it. + */ + bool m_StateDirty = true; + /** * The state the rebuild is currently in */ @@ -235,7 +239,7 @@ private: /** * The position that the rebuild activator is spawned at */ - NiPoint3 m_ActivatorPosition {}; + NiPoint3 m_ActivatorPosition = NiPoint3::ZERO; /** * The entity that represents the rebuild activator diff --git a/dGame/dComponents/RocketLaunchLupComponent.cpp b/dGame/dComponents/RocketLaunchLupComponent.cpp new file mode 100644 index 00000000..fa2a5b16 --- /dev/null +++ b/dGame/dComponents/RocketLaunchLupComponent.cpp @@ -0,0 +1,40 @@ +#include "RocketLaunchLupComponent.h" +#include "CDClientDatabase.h" +#include "RocketLaunchpadControlComponent.h" +#include "InventoryComponent.h" +#include "CharacterComponent.h" + +RocketLaunchLupComponent::RocketLaunchLupComponent(Entity* parent) : Component(parent) { + m_Parent = parent; + + // get the lup worlds from the cdclient + std::string query = "SELECT * FROM LUPZoneIDs;"; + auto results = CDClientDatabase::ExecuteQuery(query); + while (!results.eof()) { + // fallback to 1600 incase there is an issue + m_LUPWorlds.push_back(results.getIntField(0, 1600)); + results.nextRow(); + } + results.finalize(); +} + +RocketLaunchLupComponent::~RocketLaunchLupComponent() {} + +void RocketLaunchLupComponent::OnUse(Entity* originator) { + auto* rocket = originator->GetComponent()->RocketEquip(originator); + if (!rocket) return; + + // the LUP world menu is just the property menu, the client knows how to handle it + GameMessages::SendPropertyEntranceBegin(m_Parent->GetObjectID(), m_Parent->GetSystemAddress()); +} + +void RocketLaunchLupComponent::OnSelectWorld(Entity* originator, uint32_t index) { + // Add one to index because the actual LUP worlds start at index 1. + index++; + + auto* rocketLaunchpadControlComponent = m_Parent->GetComponent(); + + if (!rocketLaunchpadControlComponent) return; + + rocketLaunchpadControlComponent->Launch(originator, m_LUPWorlds[index], 0); +} diff --git a/dGame/dComponents/RocketLaunchLupComponent.h b/dGame/dComponents/RocketLaunchLupComponent.h new file mode 100644 index 00000000..ce915d70 --- /dev/null +++ b/dGame/dComponents/RocketLaunchLupComponent.h @@ -0,0 +1,39 @@ +#pragma once + +#include "Entity.h" +#include "GameMessages.h" +#include "Component.h" + +/** + * Component that handles the LUP/WBL rocket launchpad that can be interacted with to travel to WBL worlds. + * + */ +class RocketLaunchLupComponent : public Component { +public: + static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_ROCKET_LAUNCH_LUP; + + /** + * Constructor for this component, builds the m_LUPWorlds vector + * @param parent parent that contains this component + */ + RocketLaunchLupComponent(Entity* parent); + ~RocketLaunchLupComponent() override; + + /** + * Handles an OnUse event from some entity, preparing it for launch to some other world + * @param originator the entity that triggered the event + */ + void OnUse(Entity* originator) override; + + /** + * Handles an OnUse event from some entity, preparing it for launch to some other world + * @param originator the entity that triggered the event + * @param index index of the world that was selected + */ + void OnSelectWorld(Entity* originator, uint32_t index); +private: + /** + * vector of the LUP World Zone IDs, built from CDServer's LUPZoneIDs table + */ + std::vector m_LUPWorlds {}; +}; diff --git a/dGame/dComponents/RocketLaunchpadControlComponent.cpp b/dGame/dComponents/RocketLaunchpadControlComponent.cpp index 049a44b6..8585815f 100644 --- a/dGame/dComponents/RocketLaunchpadControlComponent.cpp +++ b/dGame/dComponents/RocketLaunchpadControlComponent.cpp @@ -13,6 +13,7 @@ #include "ChatPackets.h" #include "MissionComponent.h" #include "PropertyEntranceComponent.h" +#include "RocketLaunchLupComponent.h" #include "dServer.h" #include "dMessageIdentifiers.h" #include "PacketUtils.h" @@ -40,19 +41,7 @@ RocketLaunchpadControlComponent::~RocketLaunchpadControlComponent() { delete m_AltPrecondition; } -void RocketLaunchpadControlComponent::RocketEquip(Entity* entity, LWOOBJID rocketID) { - if (m_PlayersInRadius.find(entity->GetObjectID()) != m_PlayersInRadius.end()) { - Launch(entity, rocketID); - - //Go ahead and save the player - //This causes a double-save, but it should prevent players from not being saved - //before the next world server starts loading their data. - if (entity->GetCharacter()) - entity->GetCharacter()->SaveXMLToDatabase(); - } -} - -void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOOBJID optionalRocketID, LWOMAPID mapId, LWOCLONEID cloneId) { +void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOMAPID mapId, LWOCLONEID cloneId) { auto zone = mapId == LWOMAPID_INVALID ? m_TargetZone : mapId; if (zone == 0) @@ -60,53 +49,22 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOOBJID option return; } - TellMasterToPrepZone(zone); - // This also gets triggered by a proximity monitor + item equip, I will set that up when havok is ready - auto* inventoryComponent = originator->GetComponent(); auto* characterComponent = originator->GetComponent(); - auto* character = originator->GetCharacter(); - if (inventoryComponent == nullptr || characterComponent == nullptr || character == nullptr) { + if (!characterComponent || !character) return; + + auto* rocket = characterComponent->GetRocket(originator); + if (!rocket) { + Game::logger->Log("RocketLaunchpadControlComponent", "Unable to find rocket!\n"); return; } - // Select the rocket - - Item* rocket = nullptr; - - if (optionalRocketID != LWOOBJID_EMPTY) - { - rocket = inventoryComponent->FindItemById(optionalRocketID); - } - - if (rocket == nullptr) - { - rocket = inventoryComponent->FindItemById(characterComponent->GetLastRocketItemID()); - } - - if (rocket == nullptr) - { - rocket = inventoryComponent->FindItemByLot(6416); - } - - if (rocket == nullptr) - { - Game::logger->Log("RocketLaunchpadControlComponent", "Unable to find rocket (%llu)!\n", optionalRocketID); - - return; - } - - if (rocket->GetConfig().empty()) // Sanity check - { - rocket->SetCount(0, false, false); - - return; - } + // we have the ability to launch, so now we prep the zone + TellMasterToPrepZone(zone); // Achievement unlocked: "All zones unlocked" - if (!m_AltLandingScene.empty() && m_AltPrecondition->Check(originator)) { character->SetTargetScene(m_AltLandingScene); } @@ -114,27 +72,6 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOOBJID option character->SetTargetScene(m_TargetScene); } - if (characterComponent) { - for (LDFBaseData* data : rocket->GetConfig()) { - if (data->GetKey() == u"assemblyPartLOTs") { - std::string newRocketStr; - for (char character : data->GetValueAsString()) { - if (character == '+') { - newRocketStr.push_back(';'); - } - else { - newRocketStr.push_back(character); - } - } - newRocketStr.push_back(';'); - characterComponent->SetLastRocketConfig(GeneralUtils::ASCIIToUTF16(newRocketStr)); - } - } - } - - // Store the last used rocket item's ID - characterComponent->SetLastRocketItemID(rocket->GetId()); - characterComponent->UpdatePlayerStatistic(RocketsUsed); character->SaveXMLToDatabase(); @@ -143,23 +80,31 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOOBJID option GameMessages::SendFireEventClientSide(m_Parent->GetObjectID(), originator->GetSystemAddress(), u"RocketEquipped", rocket->GetId(), cloneId, -1, originator->GetObjectID()); - rocket->Equip(true); - GameMessages::SendChangeObjectWorldState(rocket->GetId(), WORLDSTATE_ATTACHED, UNASSIGNED_SYSTEM_ADDRESS); EntityManager::Instance()->SerializeEntity(originator); } void RocketLaunchpadControlComponent::OnUse(Entity* originator) { + // If we are have the property or the LUP component, we don't want to immediately launch + // instead we let their OnUse handlers do their things + // which components of an Object have their OnUse called when using them + // so we don't need to call it here auto* propertyEntrance = m_Parent->GetComponent(); - - if (propertyEntrance != nullptr) - { - propertyEntrance->OnUse(originator); - + if (propertyEntrance) { return; } + auto* rocketLaunchLUP = m_Parent->GetComponent(); + if (rocketLaunchLUP) { + return; + } + + // No rocket no launch + auto* rocket = originator->GetComponent()->RocketEquip(originator); + if (!rocket) { + return; + } Launch(originator); } diff --git a/dGame/dComponents/RocketLaunchpadControlComponent.h b/dGame/dComponents/RocketLaunchpadControlComponent.h index c9ee0691..7fdf4b32 100644 --- a/dGame/dComponents/RocketLaunchpadControlComponent.h +++ b/dGame/dComponents/RocketLaunchpadControlComponent.h @@ -22,21 +22,13 @@ public: RocketLaunchpadControlComponent(Entity* parent, int rocketId); ~RocketLaunchpadControlComponent() override; - /** - * Launches the passed entity using the passed rocket and saves their data - * @param entity the entity to launch - * @param rocketID the ID of the rocket to use - */ - void RocketEquip(Entity* entity, LWOOBJID rocketID); - /** * Launches some entity to another world * @param originator the entity to launch - * @param optionalRocketID the ID of the rocket to launch * @param mapId the world to go to * @param cloneId the clone ID (for properties) */ - void Launch(Entity* originator, LWOOBJID optionalRocketID = LWOOBJID_EMPTY, LWOMAPID mapId = LWOMAPID_INVALID, LWOCLONEID cloneId = LWOCLONEID_INVALID); + void Launch(Entity* originator, LWOMAPID mapId = LWOMAPID_INVALID, LWOCLONEID cloneId = LWOCLONEID_INVALID); /** * Handles an OnUse event from some entity, preparing it for launch to some other world diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index e8e84931..a813f6d3 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -26,6 +26,7 @@ #include "TeamManager.h" #include "ChatPackets.h" #include "GameConfig.h" +#include "RocketLaunchLupComponent.h" #include #include @@ -2726,10 +2727,15 @@ void GameMessages::HandleEnterProperty(RakNet::BitStream* inStream, Entity* enti auto* player = Player::GetPlayer(sysAddr); auto* entranceComponent = entity->GetComponent(); + if (entranceComponent != nullptr) { + entranceComponent->OnEnterProperty(player, index, returnToZone, sysAddr); + return; + } - if (entranceComponent == nullptr) return; - - entranceComponent->OnEnterProperty(player, index, returnToZone, sysAddr); + auto rocketLaunchLupComponent = entity->GetComponent(); + if (rocketLaunchLupComponent != nullptr) { + rocketLaunchLupComponent->OnSelectWorld(player, index); + } } void GameMessages::HandleSetConsumableItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) @@ -5323,21 +5329,11 @@ void GameMessages::HandleEquipItem(RakNet::BitStream* inStream, Entity* entity) Item* item = inv->FindItemById(objectID); if (!item) return; - /*if (item->GetLot() == 6416) { // if it's a rocket - std::vector rocketPads = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_ROCKET_LAUNCH); - for (Entity* rocketPad : rocketPads) { - RocketLaunchpadControlComponent* rocketComp = static_cast(rocketPad->GetComponent(COMPONENT_TYPE_ROCKET_LAUNCH)); - if (rocketComp) { - rocketComp->RocketEquip(entity, objectID); - } - } - } - else*/ { + item->Equip(); EntityManager::Instance()->SerializeEntity(entity); } -} void GameMessages::HandleUnequipItem(RakNet::BitStream* inStream, Entity* entity) { bool immediate; diff --git a/dGame/dInventory/EquippedItem.h b/dGame/dInventory/EquippedItem.h index 0d1d191f..cf5ba253 100644 --- a/dGame/dInventory/EquippedItem.h +++ b/dGame/dInventory/EquippedItem.h @@ -1,6 +1,7 @@ -#pragma once +#pragma once #include "dCommonVars.h" +#include "LDFFormat.h" /** * An item that's equipped, generally as a smaller return type than the regular Item class @@ -26,4 +27,9 @@ struct EquippedItem * The slot this item is stored in */ uint32_t slot = 0; + + /** + * The configuration of the item with any extra data + */ + std::vector config = {}; }; diff --git a/dScripts/AmTeapotServer.cpp b/dScripts/AmTeapotServer.cpp new file mode 100644 index 00000000..17b95eeb --- /dev/null +++ b/dScripts/AmTeapotServer.cpp @@ -0,0 +1,15 @@ +#include "AmTeapotServer.h" +#include "InventoryComponent.h" +#include "GameMessages.h" + + +void AmTeapotServer::OnUse(Entity* self, Entity* user) { + auto* inventoryComponent = user->GetComponent(); + if (!inventoryComponent) return; + + if (inventoryComponent->GetLotCount(BLUE_FLOWER_LEAVES) >= 10){ + inventoryComponent->RemoveItem(BLUE_FLOWER_LEAVES, 10); + inventoryComponent->AddItem(WU_S_IMAGINATION_TEA, 1); + } + GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); +} diff --git a/dScripts/AmTeapotServer.h b/dScripts/AmTeapotServer.h new file mode 100644 index 00000000..19cb5639 --- /dev/null +++ b/dScripts/AmTeapotServer.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class AmTeapotServer : public CppScripts::Script { + public: + void OnUse(Entity* self, Entity* user) override; + private: + LOT BLUE_FLOWER_LEAVES = 12317; + LOT WU_S_IMAGINATION_TEA = 12109; +}; diff --git a/dScripts/BaseConsoleTeleportServer.cpp b/dScripts/BaseConsoleTeleportServer.cpp index a9cd74e8..ef2d00e0 100644 --- a/dScripts/BaseConsoleTeleportServer.cpp +++ b/dScripts/BaseConsoleTeleportServer.cpp @@ -19,21 +19,6 @@ void BaseConsoleTeleportServer::BaseOnMessageBoxResponse(Entity* self, Entity* s if (button == 1) { - if (self->GetLOT() == 14333) - { - auto* rocketLaunchComponent = self->GetComponent(); - - if (rocketLaunchComponent == nullptr) - { - return; - } - - const auto& teleportZone = self->GetVar(u"transferZoneID"); - - rocketLaunchComponent->Launch(player, LWOOBJID_EMPTY, std::stoi(GeneralUtils::UTF16ToWTF8(teleportZone))); - - return; - } GameMessages::SendSetStunned(player->GetObjectID(), PUSH, player->GetSystemAddress(), player->GetObjectID(), true, true, true, true, true, true, true diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index 1f01a0e1..a87f027d 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -147,6 +147,7 @@ #include "FvNinjaGuard.h" #include "FvPassThroughWall.h" #include "FvBounceOverWall.h" +#include "FvFong.h" // FB Scripts #include "AgJetEffectServer.h" @@ -202,7 +203,6 @@ #include "NtSleepingGuard.h" // DLU Scripts -#include "SbLupTeleport.h" #include "DLUVanityNPC.h" // AM Scripts @@ -226,6 +226,7 @@ #include "AmSkullkinTower.h" #include "AmDarklingDragon.h" #include "AmBlueX.h" +#include "AmTeapotServer.h" // NJ Scripts #include "NjGarmadonCelebration.h" @@ -568,6 +569,8 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new FvPassThroughWall(); else if (scriptName == "scripts\\ai\\FV\\L_ACT_BOUNCE_OVER_WALL.lua") script = new FvBounceOverWall(); + else if (scriptName == "scripts\\02_server\\Map\\FV\\L_NPC_FONG.lua") + script = new FvFong(); //Misc: if (scriptName == "scripts\\02_server\\Map\\General\\L_EXPLODING_ASSET.lua") @@ -702,6 +705,8 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new BaseEnemyApe(); else if (scriptName == "scripts\\02_server\\Map\\AM\\L_BLUE_X.lua") script = new AmBlueX(); + else if (scriptName == "scripts\\02_server\\Map\\AM\\L_TEAPOT_SERVER.lua") + script = new AmTeapotServer(); // Ninjago else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_GARMADON_CELEBRATION_SERVER.lua") @@ -764,8 +769,6 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new NjNyaMissionitems(); //DLU: - else if (scriptName == "scripts\\02_server\\DLU\\L_SB_LUP_TELEPORT.lua") - script = new SbLupTeleport(); else if (scriptName == "scripts\\02_server\\DLU\\DLUVanityNPC.lua") script = new DLUVanityNPC(); diff --git a/dScripts/Darkitect.cpp b/dScripts/Darkitect.cpp new file mode 100644 index 00000000..c4e1e45d --- /dev/null +++ b/dScripts/Darkitect.cpp @@ -0,0 +1,35 @@ +#include "Darkitect.h" +#include "MissionComponent.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "Character.h" + +void Darkitect::Reveal(Entity* self, Entity* player) +{ + const auto playerID = player->GetObjectID(); + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"reveal", 0, 0, playerID, "", player->GetSystemAddress()); + + self->AddCallbackTimer(20, [this, self, playerID]() { + auto* player = EntityManager::Instance()->GetEntity(playerID); + + if (!player) return; + + auto* destroyableComponent = player->GetComponent(); + auto* missionComponent = player->GetComponent(); + auto* character = player->GetCharacter(); + + if (destroyableComponent != nullptr && missionComponent != nullptr && character != nullptr) { + destroyableComponent->SetArmor(0); + destroyableComponent->SetHealth(1); + destroyableComponent->SetImagination(0); + + if (missionComponent->GetMissionState(1295) == MissionState::MISSION_STATE_ACTIVE) { + character->SetPlayerFlag(1911, true); + } + + EntityManager::Instance()->SerializeEntity(player); + } + }); +} diff --git a/dScripts/Darkitect.h b/dScripts/Darkitect.h new file mode 100644 index 00000000..f0d19648 --- /dev/null +++ b/dScripts/Darkitect.h @@ -0,0 +1,9 @@ +#pragma once + +class Entity; + +class Darkitect +{ +public: + void Reveal(Entity* self, Entity* player); +}; diff --git a/dScripts/FvFong.cpp b/dScripts/FvFong.cpp new file mode 100644 index 00000000..890bf0ff --- /dev/null +++ b/dScripts/FvFong.cpp @@ -0,0 +1,12 @@ +#include "FvFong.h" +#include "Darkitect.h" +#include "MissionComponent.h" + +void FvFong::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) +{ + if (missionID == 734 && missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) + { + Darkitect Baron; + Baron.Reveal(self, target); + } +} diff --git a/dScripts/FvFong.h b/dScripts/FvFong.h new file mode 100644 index 00000000..fc47b484 --- /dev/null +++ b/dScripts/FvFong.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class FvFong : public CppScripts::Script +{ + public: + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; +}; diff --git a/dScripts/NtDarkitectRevealServer.cpp b/dScripts/NtDarkitectRevealServer.cpp index 2bfbb063..b8afa510 100644 --- a/dScripts/NtDarkitectRevealServer.cpp +++ b/dScripts/NtDarkitectRevealServer.cpp @@ -1,53 +1,16 @@ #include "NtDarkitectRevealServer.h" +#include "Darkitect.h" #include "MissionComponent.h" -#include "DestroyableComponent.h" -#include "EntityManager.h" -#include "GameMessages.h" -#include "Character.h" - -void NtDarkitectRevealServer::OnUse(Entity* self, Entity* user) +void NtDarkitectRevealServer::OnUse(Entity* self, Entity* user) { - Darkitect(self, user); + Darkitect Baron; + Baron.Reveal(self, user); - auto* missionComponent = user->GetComponent(); + auto* missionComponent = user->GetComponent(); - if (missionComponent != nullptr) - { - missionComponent->ForceProgressTaskType(1344, 1, 14293); - } -} - -void NtDarkitectRevealServer::Darkitect(Entity* self, Entity* player) -{ - const auto playerID = player->GetObjectID(); - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"reveal", 0, 0, playerID, "", player->GetSystemAddress()); - - self->AddCallbackTimer(20, [this, self, playerID]() { - auto* player = EntityManager::Instance()->GetEntity(playerID); - - if (player == nullptr) - { - return; - } - - auto* destroyableComponent = player->GetComponent(); - auto* missionComponent = player->GetComponent(); - auto* character = player->GetCharacter(); - - if (destroyableComponent != nullptr && missionComponent != nullptr && character != nullptr) - { - destroyableComponent->SetArmor(0); - destroyableComponent->SetHealth(1); - destroyableComponent->SetImagination(0); - - if (missionComponent->GetMissionState(1295) == MissionState::MISSION_STATE_ACTIVE) - { - character->SetPlayerFlag(1911, true); - } - - EntityManager::Instance()->SerializeEntity(player); - } - }); + if (missionComponent != nullptr) + { + missionComponent->ForceProgressTaskType(1344, 1, 14293); + } } diff --git a/dScripts/NtDarkitectRevealServer.h b/dScripts/NtDarkitectRevealServer.h index 60d89934..2b954671 100644 --- a/dScripts/NtDarkitectRevealServer.h +++ b/dScripts/NtDarkitectRevealServer.h @@ -4,6 +4,5 @@ class NtDarkitectRevealServer : public CppScripts::Script { public: - void OnUse(Entity* self, Entity* user) override; - void Darkitect(Entity* self, Entity* player); + void OnUse(Entity* self, Entity* user) override; }; diff --git a/dScripts/SbLupTeleport.cpp b/dScripts/SbLupTeleport.cpp deleted file mode 100644 index 2ea9c1fc..00000000 --- a/dScripts/SbLupTeleport.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include "SbLupTeleport.h" -#include "dZoneManager.h" -#include "EntityManager.h" -#include "GeneralUtils.h" -#include "GameMessages.h" - -void SbLupTeleport::OnStartup(Entity* self) -{ - self->SetVar(u"currentZone", (int32_t) dZoneManager::Instance()->GetZoneID().GetMapID()); - self->SetVar(u"choiceZone", m_ChoiceZoneID); - self->SetVar(u"teleportAnim", m_TeleportAnim); - self->SetVar(u"teleportString", m_TeleportString); - self->SetVar(u"spawnPoint", m_SpawnPoint); - - args = {}; - - AMFStringValue* callbackClient = new AMFStringValue(); - callbackClient->SetStringValue(std::to_string(self->GetObjectID())); - args.InsertValue("callbackClient", callbackClient); - - AMFStringValue* strIdentifier = new AMFStringValue(); - strIdentifier->SetStringValue("choiceDoor"); - args.InsertValue("strIdentifier", strIdentifier); - - AMFStringValue* title = new AMFStringValue(); - title->SetStringValue("%[LUP_Starbase3001_Launchpad]"); - args.InsertValue("title", title); - - AMFArrayValue* choiceOptions = new AMFArrayValue(); - - { - AMFArrayValue* nsArgs = new AMFArrayValue(); - - AMFStringValue* image = new AMFStringValue(); - image->SetStringValue("textures/ui/zone_thumnails/Deep_Freeze.dds"); - nsArgs->InsertValue("image", image); - - AMFStringValue* caption = new AMFStringValue(); - caption->SetStringValue("%[ZoneTable_1601_DisplayDescription]"); - nsArgs->InsertValue("caption", caption); - - AMFStringValue* identifier = new AMFStringValue(); - identifier->SetStringValue("zoneID_1601"); - nsArgs->InsertValue("identifier", identifier); - - AMFStringValue* tooltipText = new AMFStringValue(); - tooltipText->SetStringValue("%[ZoneTable_1601_summary]"); - nsArgs->InsertValue("tooltipText", tooltipText); - - choiceOptions->PushBackValue(nsArgs); - } - - { - AMFArrayValue* ntArgs = new AMFArrayValue(); - - AMFStringValue* image = new AMFStringValue(); - image->SetStringValue("textures/ui/zone_thumnails/Robot_City.dds"); - ntArgs->InsertValue("image", image); - - AMFStringValue* caption = new AMFStringValue(); - caption->SetStringValue("%[ZoneTable_1602_DisplayDescription]"); - ntArgs->InsertValue("caption", caption); - - AMFStringValue* identifier = new AMFStringValue(); - identifier->SetStringValue("zoneID_1602"); - ntArgs->InsertValue("identifier", identifier); - - AMFStringValue* tooltipText = new AMFStringValue(); - tooltipText->SetStringValue("%[ZoneTable_1602_summary]"); - ntArgs->InsertValue("tooltipText", tooltipText); - - choiceOptions->PushBackValue(ntArgs); - } - - { - AMFArrayValue* ntArgs = new AMFArrayValue(); - - AMFStringValue* image = new AMFStringValue(); - image->SetStringValue("textures/ui/zone_thumnails/Moon_Base.dds"); - ntArgs->InsertValue("image", image); - - AMFStringValue* caption = new AMFStringValue(); - caption->SetStringValue("%[ZoneTable_1603_DisplayDescription]"); - ntArgs->InsertValue("caption", caption); - - AMFStringValue* identifier = new AMFStringValue(); - identifier->SetStringValue("zoneID_1603"); - ntArgs->InsertValue("identifier", identifier); - - AMFStringValue* tooltipText = new AMFStringValue(); - tooltipText->SetStringValue("%[ZoneTable_1603_summary]"); - ntArgs->InsertValue("tooltipText", tooltipText); - - choiceOptions->PushBackValue(ntArgs); - } - - { - AMFArrayValue* ntArgs = new AMFArrayValue(); - - AMFStringValue* image = new AMFStringValue(); - image->SetStringValue("textures/ui/zone_thumnails/Porto_Bello.dds"); - ntArgs->InsertValue("image", image); - - AMFStringValue* caption = new AMFStringValue(); - caption->SetStringValue("%[ZoneTable_1604_DisplayDescription]"); - ntArgs->InsertValue("caption", caption); - - AMFStringValue* identifier = new AMFStringValue(); - identifier->SetStringValue("zoneID_1604"); - ntArgs->InsertValue("identifier", identifier); - - AMFStringValue* tooltipText = new AMFStringValue(); - tooltipText->SetStringValue("%[ZoneTable_1604_summary]"); - ntArgs->InsertValue("tooltipText", tooltipText); - - choiceOptions->PushBackValue(ntArgs); - } - - args.InsertValue("options", choiceOptions); -} - -void SbLupTeleport::OnUse(Entity* self, Entity* user) -{ - auto* player = user; - - //if (CheckChoice(self, player)) - { - GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", &args); - } - /*else - { - BaseOnUse(self, player); - }*/ -} - -void SbLupTeleport::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) -{ - BaseOnMessageBoxResponse(self, sender, button, identifier, userData); -} - -void SbLupTeleport::OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) -{ - BaseChoiceBoxRespond(self, sender, button, buttonIdentifier, identifier); -} - -void SbLupTeleport::OnTimerDone(Entity* self, std::string timerName) -{ - BaseOnTimerDone(self, timerName); -} - -void SbLupTeleport::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) -{ - BaseOnFireEventServerSide(self, sender, args, param1, param2, param3); -} diff --git a/dScripts/SbLupTeleport.h b/dScripts/SbLupTeleport.h deleted file mode 100644 index f6c868d4..00000000 --- a/dScripts/SbLupTeleport.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "CppScripts.h" -#include "ChooseYourDestinationNsToNt.h" -#include "BaseConsoleTeleportServer.h" -#include "AMFFormat.h" - -class SbLupTeleport : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer -{ -public: - void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; - void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override; - void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) override; - void OnTimerDone(Entity* self, std::string timerName) override; - void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; - -private: - int32_t m_ChoiceZoneID = 1600; - std::string m_SpawnPoint = "NS_LW"; - std::u16string m_TeleportAnim = u"lup-teleport"; - std::u16string m_TeleportString = u"UI_TRAVEL_TO_LUP_STATION"; - AMFArrayValue args = {}; -}; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 9d0c84cc..c23b44b7 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -102,7 +102,7 @@ int main(int argc, char** argv) { // Triggers the shutdown sequence at application exit std::atexit(WorldShutdownSequence); - + signal(SIGINT, [](int){ WorldShutdownSequence(); }); signal(SIGTERM, [](int){ WorldShutdownSequence(); }); @@ -125,7 +125,7 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(zoneID, instanceID); if (!Game::logger) return 0; - + Game::logger->SetLogToConsole(true); //We want this info to always be logged. Game::logger->Log("WorldServer", "Starting World server...\n"); Game::logger->Log("WorldServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); @@ -151,7 +151,7 @@ int main(int argc, char** argv) { Game::logger->Log("WorldServer", "Error Code: %i\n", e.errorCode()); return -1; } - + CDClientManager::Instance()->Initialize(); //Connect to the MySQL Database @@ -197,7 +197,7 @@ int main(int argc, char** argv) { //Connect to the chat server: int chatPort = 1501; if (config.GetValue("chat_server_port") != "") chatPort = std::atoi(config.GetValue("chat_server_port").c_str()); - + auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0); Game::chatServer = RakNetworkFactory::GetRakPeerInterface(); Game::chatServer->Startup(1, 30, &chatSock, 1); @@ -218,7 +218,7 @@ int main(int argc, char** argv) { int framesSinceLastUsersSave = 0; int framesSinceLastSQLPing = 0; int framesSinceLastUser = 0; - + const float maxPacketProcessingTime = 1.5f; //0.015f; const int maxPacketsToProcess = 1024; @@ -249,7 +249,7 @@ int main(int argc, char** argv) { "res/CDClient.fdb", "res/cdclient.fdb", }; - + for (const auto& file : aliases) { fileStream.open(file, std::ios::binary | std::ios::in); if (fileStream.is_open()) { @@ -259,7 +259,7 @@ int main(int argc, char** argv) { const int bufferSize = 1024; MD5* md5 = new MD5(); - + char fileStreamBuffer[1024] = {}; while (!fileStream.eof()) { @@ -274,7 +274,7 @@ int main(int argc, char** argv) { md5->update(nullTerminateBuffer, 1); // null terminate the data md5->finalize(); databaseChecksum = md5->hexdigest(); - + delete md5; Game::logger->Log("WorldServer", "FDB Checksum calculated as: %s\n", databaseChecksum.c_str()); @@ -360,7 +360,7 @@ int main(int argc, char** argv) { //Check for packets here: packet = Game::server->ReceiveFromMaster(); if (packet) { //We can get messages not handle-able by the dServer class, so handle them if we returned anything. - HandlePacket(packet); + HandlePacket(packet); Game::server->DeallocateMasterPacket(packet); } @@ -459,13 +459,13 @@ int main(int argc, char** argv) { t += std::chrono::milliseconds(currentFramerate); std::this_thread::sleep_until(t); - + Metrics::EndMeasurement(MetricVariable::Sleep); if (!ready && Game::server->GetIsConnectedToMaster()) { // Some delay is required here or else we crash the client? - + framesSinceMasterStatus++; if (framesSinceMasterStatus >= 200) @@ -505,7 +505,7 @@ dLogger * SetupLogger(int zoneID, int instanceID) { void HandlePacketChat(Packet* packet) { if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { Game::logger->Log("WorldServer", "Lost our connection to chat, zone(%i), instance(%i)\n", Game::server->GetZoneID(), Game::server->GetInstanceID()); - + chatConnected = false; } @@ -579,7 +579,7 @@ void HandlePacketChat(Packet* packet) { inStream.Read(playerId); inStream.Read(playerId); inStream.Read(expire); - + auto* entity = EntityManager::Instance()->GetEntity(playerId); if (entity != nullptr) @@ -829,7 +829,7 @@ void HandlePacket(Packet* packet) { } if (packet->data[1] != WORLD) return; - + switch (packet->data[3]) { case MSG_WORLD_CLIENT_VALIDATION: { std::string username = PacketUtils::ReadString(0x08, packet, true); @@ -844,7 +844,7 @@ void HandlePacket(Packet* packet) { uint32_t gmLevel = 0; auto* stmt = Database::CreatePreppedStmt("SELECT gm_level FROM accounts WHERE name=? LIMIT 1;"); stmt->setString(1, username.c_str()); - + auto* res = stmt->executeQuery(); while (res->next()) { gmLevel = res->getInt(1); @@ -860,7 +860,7 @@ void HandlePacket(Packet* packet) { return; } } - + //Request the session info from Master: CBITSTREAM; PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_REQUEST_SESSION_KEY); @@ -872,7 +872,7 @@ void HandlePacket(Packet* packet) { info.sysAddr = SystemAddress(packet->systemAddress); info.hash = sessionKey; m_PendingUsers.insert(std::make_pair(username, info)); - + break; } @@ -885,7 +885,7 @@ void HandlePacket(Packet* packet) { } //This loops prevents users who aren't authenticated to double-request the char list, which - //would make the login screen freeze sometimes. + //would make the login screen freeze sometimes. if (m_PendingUsers.size() > 0) { for (auto it : m_PendingUsers) { if (it.second.sysAddr == packet->systemAddress) { @@ -900,18 +900,18 @@ void HandlePacket(Packet* packet) { case MSG_WORLD_CLIENT_GAME_MSG: { RakNet::BitStream bitStream(packet->data, packet->length, false); - + uint64_t header; LWOOBJID objectID; uint16_t messageID; - + bitStream.Read(header); bitStream.Read(objectID); bitStream.Read(messageID); - + RakNet::BitStream dataStream; bitStream.Read(dataStream, bitStream.GetNumberOfUnreadBits()); - + GameMessageHandler::HandleMessage(&dataStream, packet->systemAddress, objectID, GAME_MSG(messageID)); break; } @@ -924,7 +924,7 @@ void HandlePacket(Packet* packet) { case MSG_WORLD_CLIENT_LOGIN_REQUEST: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); - + LWOOBJID playerID = 0; inStream.Read(playerID); playerID = GeneralUtils::ClearBit(playerID, OBJECT_BIT_CHARACTER); @@ -939,7 +939,7 @@ void HandlePacket(Packet* packet) { UserManager::Instance()->RequestCharacterList(packet->systemAddress); break; } - + case MSG_WORLD_CLIENT_CHARACTER_RENAME_REQUEST: { UserManager::Instance()->RenameCharacter(packet->systemAddress, packet); break; @@ -950,10 +950,10 @@ void HandlePacket(Packet* packet) { User* user = UserManager::Instance()->GetUser(packet->systemAddress); if (user) { Character* c = user->GetLastUsedChar(); - if (c != nullptr) { + if (c != nullptr) { std::u16string username = GeneralUtils::ASCIIToUTF16(c->GetName()); Game::server->GetReplicaManager()->AddParticipant(packet->systemAddress); - + EntityInfo info {}; info.lot = 1; Entity* player = EntityManager::Instance()->CreateEntity(info, UserManager::Instance()->GetUser(packet->systemAddress)); @@ -962,20 +962,23 @@ void HandlePacket(Packet* packet) { WorldPackets::SendServerState(packet->systemAddress); const auto respawnPoint = player->GetCharacter()->GetRespawnPoint(dZoneManager::Instance()->GetZone()->GetWorldID()); - + EntityManager::Instance()->ConstructEntity(player, UNASSIGNED_SYSTEM_ADDRESS, true); - + if (respawnPoint != NiPoint3::ZERO) { GameMessages::SendPlayerReachedRespawnCheckpoint(player, respawnPoint, NiQuaternion::IDENTITY); } - - EntityManager::Instance()->ConstructAllEntities(packet->systemAddress); - player->GetComponent()->SetLastRocketConfig(u""); - + EntityManager::Instance()->ConstructAllEntities(packet->systemAddress); + + auto* characterComponent = player->GetComponent(); + if (characterComponent) { + player->GetComponent()->RocketUnEquip(player); + } + c->SetRetroactiveFlags(); - + player->RetroactiveVaultSize(); player->GetCharacter()->SetTargetScene(""); @@ -1012,7 +1015,7 @@ void HandlePacket(Packet* packet) { int templateId = result.getIntField(0); result.finalize(); - + auto* propertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE template_id = ? AND clone_id = ?;"); propertyLookup->setInt(1, templateId); @@ -1037,7 +1040,7 @@ void HandlePacket(Packet* packet) { stmtL->setUInt(1, res->getUInt(1)); auto lxres = stmtL->executeQuery(); - + while (lxres->next()) { auto lxfml = lxres->getBlob(1); @@ -1089,7 +1092,7 @@ void HandlePacket(Packet* packet) { noBBB: // Tell the client it's done loading: - GameMessages::SendInvalidZoneTransferList(player, packet->systemAddress, u"https://forms.zohopublic.eu/virtualoffice204/form/DLUInGameSurvey/formperma/kpU-IL5v2-Wt41QcB5UFnYjzlLp-j2LEisF8e11PisU", u"", false, false); + GameMessages::SendInvalidZoneTransferList(player, packet->systemAddress, GeneralUtils::ASCIIToUTF16(Game::config->GetValue("source")), u"", false, false); GameMessages::SendServerDoneLoadingAllObjects(player, packet->systemAddress); //Send the player it's mail count: @@ -1109,9 +1112,9 @@ void HandlePacket(Packet* packet) { { bitStream.Write(playerName[i]); } - + //bitStream.Write(playerName); - + auto zone = dZoneManager::Instance()->GetZone()->GetZoneID(); bitStream.Write(zone.GetMapID()); bitStream.Write(zone.GetInstanceID());