mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-11-03 22:21:59 +00:00 
			
		
		
		
	Merge branch 'DarkflameUniverse:main' into PetFixes
This commit is contained in:
		@@ -108,6 +108,8 @@ int main(int argc, char** argv) {
 | 
				
			|||||||
	
 | 
						
 | 
				
			||||||
	Game::randomEngine = std::mt19937(time(0));
 | 
						Game::randomEngine = std::mt19937(time(0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						playerContainer.Initialize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Run it until server gets a kill message from Master:
 | 
						//Run it until server gets a kill message from Master:
 | 
				
			||||||
	auto t = std::chrono::high_resolution_clock::now();
 | 
						auto t = std::chrono::high_resolution_clock::now();
 | 
				
			||||||
	Packet* packet = nullptr;
 | 
						Packet* packet = nullptr;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@
 | 
				
			|||||||
#include "ChatPackets.h"
 | 
					#include "ChatPackets.h"
 | 
				
			||||||
#include "dConfig.h"
 | 
					#include "dConfig.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PlayerContainer::PlayerContainer() {
 | 
					void PlayerContainer::Initialize() {
 | 
				
			||||||
	GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends"), m_MaxNumberOfBestFriends);
 | 
						GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends"), m_MaxNumberOfBestFriends);
 | 
				
			||||||
	GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends"), m_MaxNumberOfFriends);
 | 
						GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends"), m_MaxNumberOfFriends);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,9 +29,9 @@ struct TeamData {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class PlayerContainer {
 | 
					class PlayerContainer {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	PlayerContainer();
 | 
					 | 
				
			||||||
	~PlayerContainer();
 | 
						~PlayerContainer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void Initialize();
 | 
				
			||||||
	void InsertPlayer(Packet* packet);
 | 
						void InsertPlayer(Packet* packet);
 | 
				
			||||||
	void RemovePlayer(Packet* packet);
 | 
						void RemovePlayer(Packet* packet);
 | 
				
			||||||
	void MuteUpdate(Packet* packet);
 | 
						void MuteUpdate(Packet* packet);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -151,6 +151,11 @@ namespace GeneralUtils {
 | 
				
			|||||||
		return std::stod(value);
 | 
							return std::stod(value);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template <>
 | 
				
			||||||
 | 
						inline uint16_t Parse(const char* value) {
 | 
				
			||||||
 | 
							return std::stoul(value);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template <>
 | 
						template <>
 | 
				
			||||||
	inline uint32_t Parse(const char* value) {
 | 
						inline uint32_t Parse(const char* value) {
 | 
				
			||||||
		return std::stoul(value);
 | 
							return std::stoul(value);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,9 +42,9 @@ std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFe
 | 
				
			|||||||
	return data;
 | 
						return data;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const {
 | 
					bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const {
 | 
				
			||||||
	for (const auto& entry : entries) {
 | 
						for (const auto& entry : entries) {
 | 
				
			||||||
		if (entry.featureName == feature) {
 | 
							if (entry.featureName == feature.featureName && entry >= feature) {
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,12 @@ struct CDFeatureGating {
 | 
				
			|||||||
	int32_t current;
 | 
						int32_t current;
 | 
				
			||||||
	int32_t minor;
 | 
						int32_t minor;
 | 
				
			||||||
	std::string description;
 | 
						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<CDFeatureGatingTable> {
 | 
					class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable> {
 | 
				
			||||||
@@ -21,7 +27,7 @@ public:
 | 
				
			|||||||
	// Queries the table with a custom "where" clause
 | 
						// Queries the table with a custom "where" clause
 | 
				
			||||||
	std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate);
 | 
						std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool FeatureUnlocked(const std::string& feature) const;
 | 
						bool FeatureUnlocked(const CDFeatureGating& feature) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const std::vector<CDFeatureGating>& GetEntries(void) const;
 | 
						const std::vector<CDFeatureGating>& GetEntries(void) const;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -294,13 +294,13 @@ void Item::UseNonEquip(Item* item) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	const auto type = static_cast<eItemType>(info->itemType);
 | 
						const auto type = static_cast<eItemType>(info->itemType);
 | 
				
			||||||
	if (type == eItemType::MOUNT) {
 | 
						if (type == eItemType::MOUNT) {
 | 
				
			||||||
		if (Game::zoneManager->GetMountsAllowed()){
 | 
							if (Game::zoneManager->GetMountsAllowed()) {
 | 
				
			||||||
			playerInventoryComponent->HandlePossession(this);
 | 
								playerInventoryComponent->HandlePossession(this);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			ChatPackets::SendSystemMessage(playerEntity->GetSystemAddress(), u"Mounts are not allowed in this zone");
 | 
								ChatPackets::SendSystemMessage(playerEntity->GetSystemAddress(), u"Mounts are not allowed in this zone");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (type == eItemType::PET_INVENTORY_ITEM && subKey != LWOOBJID_EMPTY ) {
 | 
						} else if (type == eItemType::PET_INVENTORY_ITEM && subKey != LWOOBJID_EMPTY) {
 | 
				
			||||||
		if (Game::zoneManager->GetPetsAllowed()){
 | 
							if (Game::zoneManager->GetPetsAllowed()) {
 | 
				
			||||||
			const auto& databasePet = playerInventoryComponent->GetDatabasePet(subKey);
 | 
								const auto& databasePet = playerInventoryComponent->GetDatabasePet(subKey);
 | 
				
			||||||
			if (databasePet.lot != LOT_NULL) {
 | 
								if (databasePet.lot != LOT_NULL) {
 | 
				
			||||||
				playerInventoryComponent->SpawnPet(this);
 | 
									playerInventoryComponent->SpawnPet(this);
 | 
				
			||||||
@@ -410,12 +410,19 @@ void Item::DisassembleModel(uint32_t numToDismantle) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::string renderAsset = std::string(result.getStringField(0));
 | 
						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));
 | 
						std::string lxfmlFolderName = std::string(result.getStringField(1));
 | 
				
			||||||
 | 
						if (!lxfmlFolderName.empty()) lxfmlFolderName.insert(0, "/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::vector<std::string> renderAssetSplit = GeneralUtils::SplitString(renderAsset, '\\');
 | 
						std::vector<std::string> renderAssetSplit = GeneralUtils::SplitString(renderAsset, '/');
 | 
				
			||||||
	if (renderAssetSplit.size() == 0) return;
 | 
						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());
 | 
						auto buffer = Game::assetManager->GetFileAsBuffer(lxfmlPath.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!buffer.m_Success) {
 | 
						if (!buffer.m_Success) {
 | 
				
			||||||
@@ -461,8 +468,8 @@ void Item::DisassembleModel(uint32_t numToDismantle) {
 | 
				
			|||||||
		auto* model = scene->FirstChildElement("Model");
 | 
							auto* model = scene->FirstChildElement("Model");
 | 
				
			||||||
		if (!model) return;
 | 
							if (!model) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto* group = model->FirstChildElement("Group");
 | 
							bricks = model->FirstChildElement("Group");
 | 
				
			||||||
		if (!group) return;
 | 
							if (!bricks) return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto* currentBrick = bricks->FirstChildElement(searchTerm.c_str());
 | 
						auto* currentBrick = bricks->FirstChildElement(searchTerm.c_str());
 | 
				
			||||||
@@ -486,7 +493,7 @@ void Item::DisassembleModel(uint32_t numToDismantle) {
 | 
				
			|||||||
	auto* brickIDTable = CDClientManager::Instance().GetTable<CDBrickIDTableTable>();
 | 
						auto* brickIDTable = CDClientManager::Instance().GetTable<CDBrickIDTableTable>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Second iteration actually distributes the bricks
 | 
						// Second iteration actually distributes the bricks
 | 
				
			||||||
	for (const auto&[part, count] : parts) {
 | 
						for (const auto& [part, count] : parts) {
 | 
				
			||||||
		const auto partLocal = part;
 | 
							const auto partLocal = part;
 | 
				
			||||||
		const auto brickID = brickIDTable->Query([&](const CDBrickIDTable& entry) {
 | 
							const auto brickID = brickIDTable->Query([&](const CDBrickIDTable& entry) {
 | 
				
			||||||
			return entry.LEGOBrickID == partLocal;
 | 
								return entry.LEGOBrickID == partLocal;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,18 +138,25 @@ void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAdd
 | 
				
			|||||||
	packet.Write(static_cast<uint8_t>(responseCode));
 | 
						packet.Write(static_cast<uint8_t>(responseCode));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Event Gating
 | 
						// Event Gating
 | 
				
			||||||
	packet.Write(LUString("Talk_Like_A_Pirate"));
 | 
						packet.Write(LUString(Game::config->GetValue("event_1")));
 | 
				
			||||||
	packet.Write(LUString(""));
 | 
						packet.Write(LUString(Game::config->GetValue("event_2")));
 | 
				
			||||||
	packet.Write(LUString(""));
 | 
						packet.Write(LUString(Game::config->GetValue("event_3")));
 | 
				
			||||||
	packet.Write(LUString(""));
 | 
						packet.Write(LUString(Game::config->GetValue("event_4")));
 | 
				
			||||||
	packet.Write(LUString(""));
 | 
						packet.Write(LUString(Game::config->GetValue("event_5")));
 | 
				
			||||||
	packet.Write(LUString(""));
 | 
						packet.Write(LUString(Game::config->GetValue("event_6")));
 | 
				
			||||||
	packet.Write(LUString(""));
 | 
						packet.Write(LUString(Game::config->GetValue("event_7")));
 | 
				
			||||||
	packet.Write(LUString(""));
 | 
						packet.Write(LUString(Game::config->GetValue("event_8")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	packet.Write(static_cast<uint16_t>(1));         // Version Major
 | 
						uint16_t version_major = 1;
 | 
				
			||||||
	packet.Write(static_cast<uint16_t>(10));        // Version Current
 | 
						uint16_t version_current = 10;
 | 
				
			||||||
	packet.Write(static_cast<uint16_t>(64));        // Version Minor
 | 
						uint16_t version_minor = 64;
 | 
				
			||||||
 | 
						GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("version_major"), version_major);
 | 
				
			||||||
 | 
						GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("version_current"), version_current);
 | 
				
			||||||
 | 
						GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("version_minor"), version_minor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						packet.Write(version_major);
 | 
				
			||||||
 | 
						packet.Write(version_current);
 | 
				
			||||||
 | 
						packet.Write(version_minor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Writes the user key
 | 
						// Writes the user key
 | 
				
			||||||
	uint32_t sessionKey = GeneralUtils::GenerateRandomNumber<uint32_t>();
 | 
						uint32_t sessionKey = GeneralUtils::GenerateRandomNumber<uint32_t>();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@
 | 
				
			|||||||
#include "CDFeatureGatingTable.h"
 | 
					#include "CDFeatureGatingTable.h"
 | 
				
			||||||
#include "CDClientManager.h"
 | 
					#include "CDClientManager.h"
 | 
				
			||||||
#include "AssetManager.h"
 | 
					#include "AssetManager.h"
 | 
				
			||||||
 | 
					#include "dConfig.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Level::Level(Zone* parentZone, const std::string& filepath) {
 | 
					Level::Level(Zone* parentZone, const std::string& filepath) {
 | 
				
			||||||
	m_ParentZone = parentZone;
 | 
						m_ParentZone = parentZone;
 | 
				
			||||||
@@ -234,6 +235,14 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	CDFeatureGatingTable* featureGatingTable = CDClientManager::Instance().GetTable<CDFeatureGatingTable>();
 | 
						CDFeatureGatingTable* featureGatingTable = CDClientManager::Instance().GetTable<CDFeatureGatingTable>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CDFeatureGating gating;
 | 
				
			||||||
 | 
						gating.major = 1;
 | 
				
			||||||
 | 
						gating.current = 10;
 | 
				
			||||||
 | 
						gating.minor = 64;
 | 
				
			||||||
 | 
						GeneralUtils::TryParse<int32_t>(Game::config->GetValue("version_major"), gating.major);
 | 
				
			||||||
 | 
						GeneralUtils::TryParse<int32_t>(Game::config->GetValue("version_current"), gating.current);
 | 
				
			||||||
 | 
						GeneralUtils::TryParse<int32_t>(Game::config->GetValue("version_minor"), gating.minor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (uint32_t i = 0; i < objectsCount; ++i) {
 | 
						for (uint32_t i = 0; i < objectsCount; ++i) {
 | 
				
			||||||
		SceneObject obj;
 | 
							SceneObject obj;
 | 
				
			||||||
		BinaryIO::BinaryRead(file, obj.id);
 | 
							BinaryIO::BinaryRead(file, obj.id);
 | 
				
			||||||
@@ -279,11 +288,17 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
 | 
				
			|||||||
		bool gated = false;
 | 
							bool gated = false;
 | 
				
			||||||
		for (LDFBaseData* data : obj.settings) {
 | 
							for (LDFBaseData* data : obj.settings) {
 | 
				
			||||||
			if (data->GetKey() == u"gatingOnFeature") {
 | 
								if (data->GetKey() == u"gatingOnFeature") {
 | 
				
			||||||
				std::string featureGate = data->GetValueAsString();
 | 
									gating.featureName = data->GetValueAsString();
 | 
				
			||||||
 | 
									if (gating.featureName == Game::config->GetValue("event_1")) break;
 | 
				
			||||||
				if (!featureGatingTable->FeatureUnlocked(featureGate)) {
 | 
									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;
 | 
										gated = true;
 | 
				
			||||||
 | 
					 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
					# 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.
 | 
					# This is used in both Chat and World servers.
 | 
				
			||||||
default_team_loot=1
 | 
					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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ set(DCOMMONTEST_SOURCES
 | 
				
			|||||||
	"AMFDeserializeTests.cpp"
 | 
						"AMFDeserializeTests.cpp"
 | 
				
			||||||
	"Amf3Tests.cpp"
 | 
						"Amf3Tests.cpp"
 | 
				
			||||||
	"HeaderSkipTest.cpp"
 | 
						"HeaderSkipTest.cpp"
 | 
				
			||||||
 | 
						"TestCDFeatureGatingTable.cpp"
 | 
				
			||||||
	"TestLDFFormat.cpp"
 | 
						"TestLDFFormat.cpp"
 | 
				
			||||||
	"TestNiPoint3.cpp"
 | 
						"TestNiPoint3.cpp"
 | 
				
			||||||
	"TestEncoding.cpp"
 | 
						"TestEncoding.cpp"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										55
									
								
								tests/dCommonTests/TestCDFeatureGatingTable.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								tests/dCommonTests/TestCDFeatureGatingTable.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					#include <gtest/gtest.h>
 | 
				
			||||||
 | 
					#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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user