Переглянути джерело

Add specific objects and configure their frequency / value

Tomasz Zieliński 1 рік тому
батько
коміт
4b263b6d41

+ 23 - 31
lib/mapObjectConstructors/CObjectClassesHandler.cpp

@@ -40,6 +40,8 @@
 #include "../texts/CGeneralTextHandler.h"
 #include "../texts/CLegacyConfigParser.h"
 
+#include <vstd/StringUtils.h>
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 CObjectClassesHandler::CObjectClassesHandler()
@@ -396,6 +398,9 @@ CompoundMapObjectID CObjectClassesHandler::getCompoundIdentifier(const std::stri
 
 	if(id)
 	{
+		if (subtype.empty())
+			return CompoundMapObjectID(id.value(), 0);
+
 		const auto & object = objects.at(id.value());
 		std::optional<si32> subID = VLC->identifiers()->getIdentifier(scope, object->getJsonKey(), subtype);
 
@@ -410,45 +415,32 @@ CompoundMapObjectID CObjectClassesHandler::getCompoundIdentifier(const std::stri
 
 CompoundMapObjectID CObjectClassesHandler::getCompoundIdentifier(const std::string & objectName) const
 {
-	// FIXME: Crash with no further log
-
-	// TODO: Use existing utilities for parsing id?	
-	JsonNode node(objectName);
-	auto modScope = node.getModScope();
+	// TODO: Use existing utilities for parsing id:
+	// CIdentifierStorage::ObjectCallback::fromNameAndType
 
-	std::string scope, type, subtype;
-	size_t firstColon = objectName.find(':');
-	size_t lastDot = objectName.find_last_of('.');
+	std::string subtype = "object"; //Default for objects with no subIds
+	std::string type;
 
-	// TODO: Ignore object class, there should not be objects with same names within one scope anyway
+	auto scopeAndFullName = vstd::splitStringToPair(objectName, ':');
+	logGlobal->debug("scopeAndFullName: %s, %s", scopeAndFullName.first, scopeAndFullName.second);
 	
-	if(firstColon != std::string::npos)
+	auto typeAndName = vstd::splitStringToPair(scopeAndFullName.second, '.');
+	logGlobal->debug("typeAndName: %s, %s", typeAndName.first, typeAndName.second);
+	
+	auto nameAndSubtype = vstd::splitStringToPair(typeAndName.second, '.');
+	logGlobal->debug("nameAndSubtype: %s, %s", nameAndSubtype.first, nameAndSubtype.second);
+
+	if (!nameAndSubtype.first.empty())
 	{
-		scope = objectName.substr(0, firstColon);
-		if(lastDot != std::string::npos && lastDot > firstColon)
-		{
-			type = objectName.substr(firstColon + 1, lastDot - firstColon - 1);
-			subtype = objectName.substr(lastDot + 1);
-		}
-		else
-		{
-			type = objectName.substr(firstColon + 1);
-		}
+		type = nameAndSubtype.first;
+		subtype = nameAndSubtype.second;
 	}
 	else
 	{
-		if(lastDot != std::string::npos)
-		{
-			type = objectName.substr(0, lastDot);
-			subtype = objectName.substr(lastDot + 1);
-		}
-		else
-		{
-			type = objectName;
-		}
+		type = typeAndName.second;
 	}
-
-	return getCompoundIdentifier(scope, type, subtype);
+	
+	return getCompoundIdentifier(scopeAndFullName.first, type, subtype);
 }
 
 std::set<MapObjectID> CObjectClassesHandler::knownObjects() const

+ 2 - 0
lib/mapObjects/ObjectTemplate.h

@@ -46,6 +46,8 @@ public:
 	/// H3 ID/subID of this object
 	MapObjectID id;
 	MapObjectSubID subid;
+
+	// TODO: get compound id
 	/// print priority, objects with higher priority will be print first, below everything else
 	si32 printPriority;
 	/// animation file that should be used to display object

+ 99 - 44
lib/rmg/ObjectInfo.cpp

@@ -50,6 +50,15 @@ ObjectInfo & ObjectInfo::operator=(const ObjectInfo & other)
 	return *this;
 }
 
+void ObjectInfo::setAllTemplates(MapObjectID type, MapObjectSubID subtype)
+{
+	auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype);
+	if(!templHandler)
+		return;
+	
+	templates = templHandler->getTemplates();
+}
+
 void ObjectInfo::setTemplates(MapObjectID type, MapObjectSubID subtype, TerrainId terrainType)
 {
 	auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype);
@@ -68,6 +77,20 @@ void ObjectConfig::addBannedObject(const CompoundMapObjectID & objid)
 	logGlobal->info("Banned object of type %d.%d", objid.primaryID, objid.secondaryID);
 }
 
+void ObjectConfig::addCustomObject(const ObjectInfo & object, const CompoundMapObjectID & objid)
+{
+	// FIXME: Need id / subId
+
+	// FIXME: Add templates and possibly other info
+	customObjects.push_back(object);
+	auto & lastObject = customObjects.back();
+	lastObject.setAllTemplates(objid.primaryID, objid.secondaryID);
+
+	assert(lastObject.templates.size() > 0);
+	auto temp = lastObject.templates.front();
+	logGlobal->info("Added custom object of type %d.%d", temp->id, temp->subid);
+}
+
 void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
 {
 	// TODO: We need serializer utility for list of enum values
@@ -87,73 +110,105 @@ void ObjectConfig::serializeJson(JsonSerializeFormat & handler)
 		(EObjectCategory::QUEST_ARTIFACT, "questArtifact")
 		(EObjectCategory::SEER_HUT, "seerHut");
 
-	auto categories = handler.enterArray("bannedCategories");
-	if (handler.saving)
+
+	// TODO: Separate into individual methods to enforce RAII destruction?
 	{
-		for (const auto& category : bannedObjectCategories)
+		auto categories = handler.enterArray("bannedCategories");
+		if (handler.saving)
 		{
-			auto str = OBJECT_CATEGORY_STRINGS.left.at(category);
-			categories.serializeString(categories.size(), str);
+			for (const auto& category : bannedObjectCategories)
+			{
+				auto str = OBJECT_CATEGORY_STRINGS.left.at(category);
+				categories.serializeString(categories.size(), str);
+			}
 		}
-	}
-	else
-	{
-		std::vector<std::string> categoryNames;
-		categories.serializeArray(categoryNames);
-
-		for (const auto & categoryName : categoryNames)
+		else
 		{
-			auto it = OBJECT_CATEGORY_STRINGS.right.find(categoryName);
-			if (it != OBJECT_CATEGORY_STRINGS.right.end())
+			std::vector<std::string> categoryNames;
+			categories.serializeArray(categoryNames);
+
+			for (const auto & categoryName : categoryNames)
 			{
-				bannedObjectCategories.push_back(it->second);
+				auto it = OBJECT_CATEGORY_STRINGS.right.find(categoryName);
+				if (it != OBJECT_CATEGORY_STRINGS.right.end())
+				{
+					bannedObjectCategories.push_back(it->second);
+				}
 			}
 		}
 	}
+
+	// FIXME: Doesn't seem to use this field at all
 	
-	auto bannedObjectData = handler.enterArray("bannedObjects");	
-	if (handler.saving)
 	{
-
-		// FIXME: Do we even need to serialize / store banned objects?
-		/*
-		for (const auto & object : bannedObjects)
+		auto bannedObjectData = handler.enterArray("bannedObjects");	
+		if (handler.saving)
 		{
-			// TODO: Translate id back to string?
+
+			// FIXME: Do we even need to serialize / store banned objects?
+			/*
+			for (const auto & object : bannedObjects)
+			{
+				// TODO: Translate id back to string?
 
 
-			JsonNode node;
-			node.String() = VLC->objtypeh->getHandlerFor(object.primaryID, object.secondaryID);
-			// TODO: Check if AI-generated code is right
+				JsonNode node;
+				node.String() = VLC->objtypeh->getHandlerFor(object.primaryID, object.secondaryID);
+				// TODO: Check if AI-generated code is right
 
 
+			}
+			// handler.serializeRaw("bannedObjects", node, std::nullopt);
+
+			*/
 		}
-		// handler.serializeRaw("bannedObjects", node, std::nullopt);
+		else
+		{
+			std::vector<std::string> objectNames;
+			bannedObjectData.serializeArray(objectNames);
 
-		*/
-	}
-	else
-	{
-		/*
-			auto zonesData = handler.enterStruct("zones");
-			for(const auto & idAndZone : zonesData->getCurrent().Struct())
+			for (const auto & objectName : objectNames)
 			{
-				auto guard = handler.enterStruct(idAndZone.first);
-				auto zone = std::make_shared<ZoneOptions>();
-				zone->setId(decodeZoneId(idAndZone.first));
-				zone->serializeJson(handler);
-				zones[zone->getId()] = zone;
+				VLC->objtypeh->resolveObjectCompoundId(objectName,
+					[this](CompoundMapObjectID objid)
+					{
+						addBannedObject(objid);
+					}
+				);
+				
 			}
-		*/
-		std::vector<std::string> objectNames;
-		bannedObjectData.serializeArray(objectNames);
+		}
+	}
+
+	auto commonObjectData = handler.getCurrent()["commonObjects"].Vector();	
+	if (handler.saving)
+	{
 
-		for (const auto & objectName : objectNames)
+		//TODO?
+	}
+	else
+	{
+		for (const auto & objectConfig : commonObjectData)
 		{
+			auto objectName = objectConfig["id"].String();
+			auto rmg = objectConfig["rmg"].Struct();
+
+			// TODO: Use common code with default rmg config
+			auto objectValue = rmg["value"].Integer();
+			auto objectProbability = rmg["rarity"].Integer();
+			auto objectMaxPerZone = rmg["zoneLimit"].Integer();
+
 			VLC->objtypeh->resolveObjectCompoundId(objectName,
-				[this](CompoundMapObjectID objid)
+				[this, objectValue, objectProbability, objectMaxPerZone](CompoundMapObjectID objid)
 				{
-					addBannedObject(objid);
+					ObjectInfo object;
+					
+					// TODO: Configure basic generateObject function
+
+					object.value = objectValue;
+					object.probability = objectProbability;
+					object.maxPerZone = objectMaxPerZone;
+					addCustomObject(object, objid);
 				}
 			);
 			

+ 2 - 1
lib/rmg/ObjectInfo.h

@@ -32,6 +32,7 @@ struct DLL_LINKAGE ObjectInfo
 	std::function<CGObjectInstance *()> generateObject;
 	std::function<void(CGObjectInstance *)> destroyObject;
 	
+	void setAllTemplates(MapObjectID type, MapObjectSubID subtype);
 	void setTemplates(MapObjectID type, MapObjectSubID subtype, TerrainId terrain);
 
 	//bool matchesId(const CompoundMapObjectID & id) const;
@@ -61,7 +62,7 @@ public:
 	};
 
 	void addBannedObject(const CompoundMapObjectID & objid);
-	void addCustomObject(const ObjectInfo & object);
+	void addCustomObject(const ObjectInfo & object, const CompoundMapObjectID & objid);
 	void clearBannedObjects();
 	void clearCustomObjects();
 	const std::vector<CompoundMapObjectID> & getBannedObjects() const;

+ 35 - 10
lib/rmg/modificators/TreasurePlacer.cpp

@@ -50,7 +50,7 @@ void TreasurePlacer::process()
 	// Get default objects
 	addAllPossibleObjects();
 	// Override with custom objects
-	objects.patchWithZoneConfig(zone);
+	objects.patchWithZoneConfig(zone, this);
 
 	auto * m = zone.getModificator<ObjectManager>();
 	if(m)
@@ -65,6 +65,8 @@ void TreasurePlacer::init()
 	DEPENDENCY_ALL(PrisonHeroPlacer);
 	DEPENDENCY(RoadPlacer);
 
+	// FIXME: Starting zones get Pandoras with neutral creatures
+
 	// Add all native creatures
 	for(auto const & cre : VLC->creh->objects)
 	{
@@ -79,7 +81,6 @@ void TreasurePlacer::init()
 
 void TreasurePlacer::addObjectToRandomPool(const ObjectInfo& oi)
 {
-	// FIXME: It is never the case - objects must be erased or badly copied after this
 	if (oi.templates.empty())
 	{
 		logGlobal->error("Attempt to add ObjectInfo with no templates! Value: %d", oi.value);
@@ -126,14 +127,11 @@ void TreasurePlacer::addCommonObjects()
 					//Skip objects with per-map limit here
 					continue;
 				}
+				setBasicProperties(oi, CompoundMapObjectID(primaryID, secondaryID));
 
-				oi.generateObject = [this, primaryID, secondaryID]() -> CGObjectInstance *
-				{
-					return VLC->objtypeh->getHandlerFor(primaryID, secondaryID)->create(map.mapInstance->cb, nullptr);
-				};
 				oi.value = rmgInfo.value;
 				oi.probability = rmgInfo.rarity;
-				oi.setTemplates(primaryID, secondaryID, zone.getTerrainType());
+
 				oi.maxPerZone = rmgInfo.zoneLimit;
 				if(!oi.templates.empty())
 					addObjectToRandomPool(oi);
@@ -142,6 +140,15 @@ void TreasurePlacer::addCommonObjects()
 	}
 }
 
+void TreasurePlacer::setBasicProperties(ObjectInfo & oi, CompoundMapObjectID objid) const
+{
+	oi.generateObject = [this, objid]() -> CGObjectInstance *
+	{
+		return VLC->objtypeh->getHandlerFor(objid)->create(map.mapInstance->cb, nullptr);
+	};
+	oi.setTemplates(objid.primaryID, objid.secondaryID, zone.getTerrainType());
+}
+
 void TreasurePlacer::addPrisons()
 {
 	//Generate Prison on water only if it has a template
@@ -1116,7 +1123,7 @@ void TreasurePlacer::ObjectPool::updateObject(MapObjectID id, MapObjectSubID sub
 	customObjects[CompoundMapObjectID(id, subid)] = info;
 }
 
-void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
+void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone, TreasurePlacer * tp)
 {
 	// FIXME: Wycina wszystkie obiekty poza pandorami i dwellami :?
 
@@ -1145,18 +1152,27 @@ void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
 		if (categoriesSet.count(category))
 		{
 			logGlobal->info("Removing object %s from possible objects", oi.templates.front()->stringID);
+			/* FIXME:
+			Removing object normal from possible objects
+			Removing object base from possible objects
+			Removing object default from possible objects
+			*/
 			return true;
 		}
 		return false;
 	});
 
-	vstd::erase_if(possibleObjects, [&zone](const ObjectInfo & object)
+	auto bannedObjects = zone.getBannedObjects();
+	auto bannedObjectsSet = std::set<CompoundMapObjectID>(bannedObjects.begin(), bannedObjects.end());
+	vstd::erase_if(possibleObjects, [&bannedObjectsSet](const ObjectInfo & object)
 	{
 		for (const auto & templ : object.templates)
 		{
 			CompoundMapObjectID key(templ->id, templ->subid);
-			if (vstd::contains(zone.getBannedObjects(), key))
+			if (bannedObjectsSet.count(key))
 			{
+				// FIXME: Stopped working, nothing is banned
+				logGlobal->info("Banning object %s from possible objects", templ->stringID);
 				return true;
 			}
 		}
@@ -1164,6 +1180,15 @@ void TreasurePlacer::ObjectPool::patchWithZoneConfig(const Zone & zone)
 	});
 
 	auto configuredObjects = zone.getConfiguredObjects();
+
+	// FIXME: Access TreasurePlacer from ObjectPool
+	for (auto & object : configuredObjects)
+	{
+		auto temp = object.templates.front();
+		tp->setBasicProperties(object, CompoundMapObjectID(temp->id, temp->subid));
+		addObject(object);
+		logGlobal->info("Added custom object of type %d.%d", temp->id, temp->subid);
+	}
 	// TODO: Overwrite or add to possibleObjects
 
 	// FIXME: Protect with mutex as well?

+ 2 - 1
lib/rmg/modificators/TreasurePlacer.h

@@ -34,6 +34,7 @@ public:
 	
 	void createTreasures(ObjectManager & manager);
 	void addObjectToRandomPool(const ObjectInfo& oi);
+	void setBasicProperties(ObjectInfo & oi, CompoundMapObjectID objid) const;
 
 	// TODO: Can be defaulted to addAllPossibleObjects, but then each object will need to be configured
 	void addCommonObjects();
@@ -69,7 +70,7 @@ protected:
 		void addObject(const ObjectInfo & info);
 		void updateObject(MapObjectID id, MapObjectSubID subid, ObjectInfo info);
 		std::vector<ObjectInfo> & getPossibleObjects();
-		void patchWithZoneConfig(const Zone & zone);
+		void patchWithZoneConfig(const Zone & zone, TreasurePlacer * tp);
 		void sortPossibleObjects();
 		void discardObjectsAboveValue(ui32 value);