From 98822d400f028768845832e1eacc2ee34832931a Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 17 Nov 2023 23:15:31 -0800 Subject: [PATCH 1/3] fix: ChatServer crash on startup (#1303) --- dChatServer/ChatServer.cpp | 2 ++ dChatServer/PlayerContainer.cpp | 2 +- dChatServer/PlayerContainer.h | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index 5fc861b6..b41ad4ec 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -108,6 +108,8 @@ int main(int argc, char** argv) { Game::randomEngine = std::mt19937(time(0)); + playerContainer.Initialize(); + //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; diff --git a/dChatServer/PlayerContainer.cpp b/dChatServer/PlayerContainer.cpp index 8b9eb744..d9b33825 100644 --- a/dChatServer/PlayerContainer.cpp +++ b/dChatServer/PlayerContainer.cpp @@ -13,7 +13,7 @@ #include "ChatPackets.h" #include "dConfig.h" -PlayerContainer::PlayerContainer() { +void PlayerContainer::Initialize() { GeneralUtils::TryParse(Game::config->GetValue("max_number_of_best_friends"), m_MaxNumberOfBestFriends); GeneralUtils::TryParse(Game::config->GetValue("max_number_of_friends"), m_MaxNumberOfFriends); } diff --git a/dChatServer/PlayerContainer.h b/dChatServer/PlayerContainer.h index 000164ac..d055ed95 100644 --- a/dChatServer/PlayerContainer.h +++ b/dChatServer/PlayerContainer.h @@ -29,9 +29,9 @@ struct TeamData { class PlayerContainer { public: - PlayerContainer(); ~PlayerContainer(); + void Initialize(); void InsertPlayer(Packet* packet); void RemovePlayer(Packet* packet); void MuteUpdate(Packet* packet); From 57e3a4f4ef9e8ce3914723d5401238b6adb3a4d5 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 17 Nov 2023 23:15:47 -0800 Subject: [PATCH 2/3] fix: general issues with dismantling (#1304) --- dGame/dInventory/Item.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index 3b6b5c42..438bec2f 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -294,13 +294,13 @@ void Item::UseNonEquip(Item* item) { const auto type = static_cast(info->itemType); if (type == eItemType::MOUNT) { - if (Game::zoneManager->GetMountsAllowed()){ + if (Game::zoneManager->GetMountsAllowed()) { playerInventoryComponent->HandlePossession(this); } else { ChatPackets::SendSystemMessage(playerEntity->GetSystemAddress(), u"Mounts are not allowed in this zone"); } - } else if (type == eItemType::PET_INVENTORY_ITEM && subKey != LWOOBJID_EMPTY ) { - if (Game::zoneManager->GetPetsAllowed()){ + } else if (type == eItemType::PET_INVENTORY_ITEM && subKey != LWOOBJID_EMPTY) { + if (Game::zoneManager->GetPetsAllowed()) { const auto& databasePet = playerInventoryComponent->GetDatabasePet(subKey); if (databasePet.lot != LOT_NULL) { playerInventoryComponent->SpawnPet(this); @@ -410,12 +410,19 @@ void Item::DisassembleModel(uint32_t numToDismantle) { } std::string renderAsset = std::string(result.getStringField(0)); + + // normalize path slashes + for (auto& c : renderAsset) { + if (c == '\\') c = '/'; + } + std::string lxfmlFolderName = std::string(result.getStringField(1)); + if (!lxfmlFolderName.empty()) lxfmlFolderName.insert(0, "/"); - std::vector renderAssetSplit = GeneralUtils::SplitString(renderAsset, '\\'); - if (renderAssetSplit.size() == 0) return; + std::vector renderAssetSplit = GeneralUtils::SplitString(renderAsset, '/'); + if (renderAssetSplit.empty()) return; - std::string lxfmlPath = "BrickModels/" + lxfmlFolderName + "/" + GeneralUtils::SplitString(renderAssetSplit.back(), '.').at(0) + ".lxfml"; + std::string lxfmlPath = "BrickModels" + lxfmlFolderName + "/" + GeneralUtils::SplitString(renderAssetSplit.back(), '.').at(0) + ".lxfml"; auto buffer = Game::assetManager->GetFileAsBuffer(lxfmlPath.c_str()); if (!buffer.m_Success) { @@ -461,8 +468,8 @@ void Item::DisassembleModel(uint32_t numToDismantle) { auto* model = scene->FirstChildElement("Model"); if (!model) return; - auto* group = model->FirstChildElement("Group"); - if (!group) return; + bricks = model->FirstChildElement("Group"); + if (!bricks) return; } auto* currentBrick = bricks->FirstChildElement(searchTerm.c_str()); @@ -486,7 +493,7 @@ void Item::DisassembleModel(uint32_t numToDismantle) { auto* brickIDTable = CDClientManager::Instance().GetTable(); // Second iteration actually distributes the bricks - for (const auto&[part, count] : parts) { + for (const auto& [part, count] : parts) { const auto partLocal = part; const auto brickID = brickIDTable->Query([&](const CDBrickIDTable& entry) { return entry.LEGOBrickID == partLocal; From 8e84cafdfac1e56d3feae32c7bf7926d790ca760 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Sat, 18 Nov 2023 03:33:23 -0600 Subject: [PATCH 3/3] feat: add configurable feature and versions (#1298) * feat: add configurable feature and versions to allow for easily swithing it out to enable features in the client for funsies tested that this doesn't break anything and added test * cleanup --- dCommon/GeneralUtils.h | 5 ++ .../CDClientTables/CDFeatureGatingTable.cpp | 4 +- .../CDClientTables/CDFeatureGatingTable.h | 8 ++- dNet/AuthPackets.cpp | 29 ++++++---- dZoneManager/Level.cpp | 23 ++++++-- resources/sharedconfig.ini | 15 +++++ tests/dCommonTests/CMakeLists.txt | 1 + .../dCommonTests/TestCDFeatureGatingTable.cpp | 55 +++++++++++++++++++ 8 files changed, 122 insertions(+), 18 deletions(-) create mode 100644 tests/dCommonTests/TestCDFeatureGatingTable.cpp diff --git a/dCommon/GeneralUtils.h b/dCommon/GeneralUtils.h index 7acb15b8..d93fd0e7 100644 --- a/dCommon/GeneralUtils.h +++ b/dCommon/GeneralUtils.h @@ -151,6 +151,11 @@ namespace GeneralUtils { return std::stod(value); } + template <> + inline uint16_t Parse(const char* value) { + return std::stoul(value); + } + template <> inline uint32_t Parse(const char* value) { return std::stoul(value); diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.cpp index 5013dd13..1a9338a0 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.cpp @@ -42,9 +42,9 @@ std::vector CDFeatureGatingTable::Query(std::function= feature) { return true; } } diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.h index 9a978218..5df202e3 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDFeatureGatingTable.h @@ -9,6 +9,12 @@ struct CDFeatureGating { int32_t current; int32_t minor; std::string description; + + bool operator>=(const CDFeatureGating& b) const { + return (this->major > b.major) || + (this->major == b.major && this->current > b.current) || + (this->major == b.major && this->current == b.current && this->minor >= b.minor); + } }; class CDFeatureGatingTable : public CDTable { @@ -21,7 +27,7 @@ public: // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - bool FeatureUnlocked(const std::string& feature) const; + bool FeatureUnlocked(const CDFeatureGating& feature) const; const std::vector& GetEntries(void) const; }; diff --git a/dNet/AuthPackets.cpp b/dNet/AuthPackets.cpp index 12f140d6..f0b22b4e 100644 --- a/dNet/AuthPackets.cpp +++ b/dNet/AuthPackets.cpp @@ -138,18 +138,25 @@ void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAdd packet.Write(static_cast(responseCode)); // Event Gating - packet.Write(LUString("Talk_Like_A_Pirate")); - packet.Write(LUString("")); - packet.Write(LUString("")); - packet.Write(LUString("")); - packet.Write(LUString("")); - packet.Write(LUString("")); - packet.Write(LUString("")); - packet.Write(LUString("")); + packet.Write(LUString(Game::config->GetValue("event_1"))); + packet.Write(LUString(Game::config->GetValue("event_2"))); + packet.Write(LUString(Game::config->GetValue("event_3"))); + packet.Write(LUString(Game::config->GetValue("event_4"))); + packet.Write(LUString(Game::config->GetValue("event_5"))); + packet.Write(LUString(Game::config->GetValue("event_6"))); + packet.Write(LUString(Game::config->GetValue("event_7"))); + packet.Write(LUString(Game::config->GetValue("event_8"))); - packet.Write(static_cast(1)); // Version Major - packet.Write(static_cast(10)); // Version Current - packet.Write(static_cast(64)); // Version Minor + uint16_t version_major = 1; + uint16_t version_current = 10; + uint16_t version_minor = 64; + GeneralUtils::TryParse(Game::config->GetValue("version_major"), version_major); + GeneralUtils::TryParse(Game::config->GetValue("version_current"), version_current); + GeneralUtils::TryParse(Game::config->GetValue("version_minor"), version_minor); + + packet.Write(version_major); + packet.Write(version_current); + packet.Write(version_minor); // Writes the user key uint32_t sessionKey = GeneralUtils::GenerateRandomNumber(); diff --git a/dZoneManager/Level.cpp b/dZoneManager/Level.cpp index 4c83d494..8202b760 100644 --- a/dZoneManager/Level.cpp +++ b/dZoneManager/Level.cpp @@ -14,6 +14,7 @@ #include "CDFeatureGatingTable.h" #include "CDClientManager.h" #include "AssetManager.h" +#include "dConfig.h" Level::Level(Zone* parentZone, const std::string& filepath) { m_ParentZone = parentZone; @@ -234,6 +235,14 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) { CDFeatureGatingTable* featureGatingTable = CDClientManager::Instance().GetTable(); + CDFeatureGating gating; + gating.major = 1; + gating.current = 10; + gating.minor = 64; + GeneralUtils::TryParse(Game::config->GetValue("version_major"), gating.major); + GeneralUtils::TryParse(Game::config->GetValue("version_current"), gating.current); + GeneralUtils::TryParse(Game::config->GetValue("version_minor"), gating.minor); + for (uint32_t i = 0; i < objectsCount; ++i) { SceneObject obj; BinaryIO::BinaryRead(file, obj.id); @@ -279,11 +288,17 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) { bool gated = false; for (LDFBaseData* data : obj.settings) { if (data->GetKey() == u"gatingOnFeature") { - std::string featureGate = data->GetValueAsString(); - - if (!featureGatingTable->FeatureUnlocked(featureGate)) { + gating.featureName = data->GetValueAsString(); + if (gating.featureName == Game::config->GetValue("event_1")) break; + else if (gating.featureName == Game::config->GetValue("event_2")) break; + else if (gating.featureName == Game::config->GetValue("event_3")) break; + else if (gating.featureName == Game::config->GetValue("event_4")) break; + else if (gating.featureName == Game::config->GetValue("event_5")) break; + else if (gating.featureName == Game::config->GetValue("event_6")) break; + else if (gating.featureName == Game::config->GetValue("event_7")) break; + else if (gating.featureName == Game::config->GetValue("event_8")) break; + else if (!featureGatingTable->FeatureUnlocked(gating)) { gated = true; - break; } } diff --git a/resources/sharedconfig.ini b/resources/sharedconfig.ini index 46b11470..2e2b6120 100644 --- a/resources/sharedconfig.ini +++ b/resources/sharedconfig.ini @@ -47,3 +47,18 @@ client_net_version=171022 # Turn to 0 to default teams to use the live accurate Shared Loot (0) by default as opposed to Free for All (1) # This is used in both Chat and World servers. default_team_loot=1 + +# event gating for login response and luz gating +event_1=Talk_Like_A_Pirate +event_2= +event_3= +event_4= +event_5= +event_6= +event_7= +event_8= + +# version for login response and luz gating +version_major=1 +version_current=10 +version_minor=64 diff --git a/tests/dCommonTests/CMakeLists.txt b/tests/dCommonTests/CMakeLists.txt index 006102fa..b39d130c 100644 --- a/tests/dCommonTests/CMakeLists.txt +++ b/tests/dCommonTests/CMakeLists.txt @@ -2,6 +2,7 @@ set(DCOMMONTEST_SOURCES "AMFDeserializeTests.cpp" "Amf3Tests.cpp" "HeaderSkipTest.cpp" + "TestCDFeatureGatingTable.cpp" "TestLDFFormat.cpp" "TestNiPoint3.cpp" "TestEncoding.cpp" diff --git a/tests/dCommonTests/TestCDFeatureGatingTable.cpp b/tests/dCommonTests/TestCDFeatureGatingTable.cpp new file mode 100644 index 00000000..560f87be --- /dev/null +++ b/tests/dCommonTests/TestCDFeatureGatingTable.cpp @@ -0,0 +1,55 @@ +#include +#include "CDFeatureGatingTable.h" + + +TEST(dCommonTests, CDFeaturingGatingComparison){ + CDFeatureGating a; + a.major = 1; + a.current = 10; + a.minor = 64; + + CDFeatureGating b; + b.major = 999; + b.current = 999; + b.minor = 999; + EXPECT_TRUE(b >= a); + EXPECT_FALSE(a >= b); + + // below + b.major = 0; + b.current = 10; + b.minor = 64; + EXPECT_FALSE(b >= a); + EXPECT_TRUE(a >= b); + + b.major = 1; + b.current = 9; + b.minor = 64; + EXPECT_FALSE(b >= a); + EXPECT_TRUE(a >= b); + + b.major = 1; + b.current = 10; + b.minor = 63; + EXPECT_FALSE(b >= a); + EXPECT_TRUE(a >= b); + + // above + b.major = 2; + b.current = 10; + b.minor = 64; + EXPECT_TRUE(b >= a); + EXPECT_FALSE(a >= b); + + b.major = 1; + b.current = 11; + b.minor = 64; + EXPECT_TRUE(b >= a); + EXPECT_FALSE(a >= b); + + b.major = 1; + b.current = 10; + b.minor = 65; + EXPECT_TRUE(b >= a); + EXPECT_FALSE(a >= b); +}