1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Move all OH3 objects and obstacle sets to a mod

This commit is contained in:
Tomasz Zieliński 2024-04-08 12:50:41 +02:00
parent 86cffb3a77
commit 3e3959d360
11 changed files with 1529 additions and 49 deletions

View File

@ -37,6 +37,7 @@ void CGameInfo::setFromLib()
terrainTypeHandler = VLC->terrainTypeHandler;
battleFieldHandler = VLC->battlefieldsHandler;
obstacleHandler = VLC->obstacleHandler;
//TODO: biomeHandler?
}
const ArtifactService * CGameInfo::artifacts() const

1320
config/biomes.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -67,6 +67,11 @@
"config/objects/witchHut.json"
],
"biomes" :
[
"config/biomes.json"
],
"artifacts" :
[
"config/artifacts.json"

31
config/schemas/biome.json Normal file
View File

@ -0,0 +1,31 @@
{
"type" : "object",
"$schema" : "http://json-schema.org/draft-04/schema",
"title" : "VCMI map obstacle set format",
"description" : "Description of map object set, used only as sub-schema of object",
"required" : ["biome", "templates"],
"additionalProperties" : true, // may have type-dependant properties
"properties" : {
"biome" : {
"type" : "object",
"properties": {
"objectType" : {
"type" : "string",
"enmum": ["mountain", "tree", "lake", "crater", "rock", "plant", "structure", "animal", "other"],
"description" : "Type of the obstacle set"
},
"terrain" : {
// TODO: Allow multiple terrains
"type" : "string",
"description" : "Terrain of the obstacle set"
}
}
},
"templates" : {
"type" : "array",
"items" : { "type" : "string" },
"description" : "Object templates of the obstacle set"
}
}
}

View File

@ -482,6 +482,7 @@ public:
OUTCROPPING = 136,
PINE_TREES = 137,
PLANT = 138,
RIVER_DELTA = 143,
ROCK = 147,
SAND_DUNE = 148,
SAND_PIT = 149,

View File

@ -108,7 +108,9 @@ std::vector<JsonNode> CObjectClassesHandler::loadLegacyData()
auto totalNumber = static_cast<size_t>(parser.readNumber()); // first line contains number of objects to read and nothing else
parser.endLine();
std::map<TerrainId, std::map<MapObjectID, std::map<MapObjectSubID, ObstacleSet>>> obstacleSets;
//std::map<TerrainId, std::map<MapObjectID, std::map<MapObjectSubID, ObstacleSet>>> obstacleSets;
// TODO: Create map defName -> tmpl
for (size_t i = 0; i < totalNumber; i++)
{
@ -120,44 +122,15 @@ std::vector<JsonNode> CObjectClassesHandler::loadLegacyData()
std::pair key(tmpl->id, tmpl->subid);
legacyTemplates.insert(std::make_pair(key, tmpl));
// Populate ObstacleSetHandler on our way
if (!tmpl->isVisitable())
{
// Create obstacle sets. Group by terrain for now
for (auto terrain : tmpl->getAllowedTerrains())
if (tmpl->id != Obj::RIVER_DELTA)
{
auto &obstacleMap = obstacleSets[terrain][tmpl->id];
auto it = obstacleMap.find(tmpl->subid);
if (it == obstacleMap.end())
{
// FIXME: This means this set will be available only on one terrain
auto type = VLC->biomeHandler->convertObstacleClass(tmpl->id);
auto newIt = obstacleMap.insert(std::make_pair(tmpl->subid, ObstacleSet(type, terrain)));
newIt.first->second.addObstacle(tmpl);
}
else
{
it->second.addObstacle(tmpl);
}
VLC->biomeHandler->addTemplate("core", tmpl->stringID, tmpl);
}
}
}
size_t count = 0;
for (auto terrain : obstacleSets)
{
for (auto obstacleType : terrain.second)
{
for (auto obstacleSet : obstacleType.second)
{
VLC->biomeHandler->addObstacleSet(obstacleSet.second);
count++;
}
}
}
logGlobal->info("Obstacle sets loaded: %d", count);
objects.resize(256);
std::vector<JsonNode> ret(dataSize);// create storage for 256 objects

View File

@ -64,10 +64,10 @@ void CObstacleConstructor::afterLoadFinalization()
// For now assume that all templates are from the same biome
for (auto terrain : terrains)
{
ObstacleSet os(obstacleType, terrain);
std::shared_ptr<ObstacleSet> os = std::make_shared<ObstacleSet>(obstacleType, terrain);
for (auto tmpl : templates)
{
os.addObstacle(tmpl);
os->addObstacle(tmpl);
}
VLC->biomeHandler->addObstacleSet(os);
logGlobal->info("Loaded obstacle set from mod %s, terrain: %s", getJsonKey(), terrain.encode(terrain.getNum()));

View File

@ -11,8 +11,16 @@
#include "StdInc.h"
#include "ObstacleSetHandler.h"
#include "../modding/IdentifierStorage.h"
VCMI_LIB_NAMESPACE_BEGIN
ObstacleSet::ObstacleSet():
type(INVALID),
terrain(TerrainId::NONE)
{
}
ObstacleSet::ObstacleSet(EObstacleType type, TerrainId terrain):
type(type),
terrain(terrain)
@ -51,11 +59,21 @@ TerrainId ObstacleSet::getTerrain() const
return terrain;
}
void ObstacleSet::setTerrain(TerrainId terrain)
{
this->terrain = terrain;
}
ObstacleSet::EObstacleType ObstacleSet::getType() const
{
return type;
}
void ObstacleSet::setType(EObstacleType type)
{
this->type = type;
}
std::vector<std::shared_ptr<const ObjectTemplate>> ObstacleSet::getObstacles() const
{
return obstacles;
@ -139,14 +157,128 @@ ObstacleSet::EObstacleType ObstacleSet::typeFromString(const std::string &str)
throw std::runtime_error("Invalid obstacle type: " + str);
}
std::string ObstacleSet::toString() const
{
static const std::map<EObstacleType, std::string> OBSTACLE_TYPE_STRINGS =
{
{MOUNTAINS, "mountain"},
{TREES, "tree"},
{LAKES, "lake"},
{CRATERS, "crater"},
{ROCKS, "rock"},
{PLANTS, "plant"},
{STRUCTURES, "structure"},
{ANIMALS, "animal"},
{OTHER, "other"}
};
return OBSTACLE_TYPE_STRINGS.at(type);
}
std::vector<ObstacleSet::EObstacleType> ObstacleSetFilter::getAllowedTypes() const
{
return allowedTypes;
}
void ObstacleSetHandler::addObstacleSet(const ObstacleSet &os)
std::vector<JsonNode> ObstacleSetHandler::loadLegacyData()
{
obstacleSets[os.getType()].push_back(os);
// TODO: Where to load objects.json?
return {};
}
void ObstacleSetHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto os = loadFromJson(scope, data, name, biomes.size());
if(os)
{
addObstacleSet(os);
}
else
{
logMod->error("Failed to load obstacle set: %s", name);
}
// TODO: Define some const array of object types ("biome" etc.)
VLC->identifiersHandler->registerObject(scope, "biome", name, biomes.back()->id);
}
void ObstacleSetHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
{
assert(objects.at(index) == nullptr); // ensure that this id was not loaded before
auto os = loadFromJson(scope, data, name, index);
if(os)
{
addObstacleSet(os);
}
else
{
logMod->error("Failed to load obstacle set: %s", name);
}
// TODO:
VLC->identifiersHandler->registerObject(scope, "biome", name, biomes.at(index)->id);
}
std::shared_ptr<ObstacleSet> ObstacleSetHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name, size_t index)
{
auto os = std::make_shared<ObstacleSet>();
// TODO: Register ObstacleSet by its name
auto biome = json["biome"].Struct();
os->setType(ObstacleSet::typeFromString(biome["objectType"].String()));
auto terrainName = biome["terrain"].String();
VLC->identifiers()->requestIdentifier(scope, "terrain", terrainName, [this, os](si32 id)
{
os->setTerrain(TerrainId(id));
});
auto templates = json["templates"].Vector();
for (const auto & node : templates)
{
// TODO: We need to store all the templates by their name
// TODO: We need to store all the templates by their id
logGlobal->info("Registering obstacle template: %s", node.String());
/*
FIXME:
Warning: identifier AVXplns0 is not in camelCase!
registered biome.templateSet1 as core:1701602145
*/
VLC->identifiers()->requestIdentifier(scope, "obstacleTemplate", node.String(), [this, os](si32 id)
{
logGlobal->info("Resolved obstacle id: %d", id);
os->addObstacle(obstacleTemplates[id]);
});
}
return os;
}
void ObstacleSetHandler::addTemplate(const std::string & scope, const std::string &name, std::shared_ptr<const ObjectTemplate> tmpl)
{
auto id = obstacleTemplates.size();
auto strippedName = name;
auto pos = strippedName.find(".def");
if(pos != std::string::npos)
strippedName.erase(pos, 4);
// TODO: Consider converting to lowercase?
// Save by name
VLC->identifiersHandler->registerObject(scope, "obstacleTemplate", strippedName, id);
// Index by id
obstacleTemplates[id] = tmpl;
}
void ObstacleSetHandler::addObstacleSet(std::shared_ptr<ObstacleSet> os)
{
// TODO: Allow to refer to existing obstacle set by its id (name)
obstacleSets[os->getType()].push_back(os);
biomes.push_back(os);
}
TObstacleTypes ObstacleSetHandler::getObstacles( const ObstacleSetFilter &filter) const
@ -160,7 +292,7 @@ TObstacleTypes ObstacleSetHandler::getObstacles( const ObstacleSetFilter &filter
{
for (const auto &os : it->second)
{
if (filter.filter(os))
if (filter.filter(*os))
{
result.push_back(os);
}

View File

@ -37,15 +37,22 @@ public:
ANIMALS, // Living, or bones
OTHER // Crystals, shipwrecks, barrels, etc.
};
ObstacleSet();
explicit ObstacleSet(EObstacleType type, TerrainId terrain);
void addObstacle(std::shared_ptr<const ObjectTemplate> obstacle);
std::vector<std::shared_ptr<const ObjectTemplate>> getObstacles() const;
EObstacleType getType() const;
void setType(EObstacleType type);
TerrainId getTerrain() const;
void setTerrain(TerrainId terrain);
static EObstacleType typeFromString(const std::string &str);
std::string toString() const;
si32 id;
private:
EObstacleType type;
@ -53,7 +60,7 @@ private:
std::vector<std::shared_ptr<const ObjectTemplate>> obstacles;
};
typedef std::vector<ObstacleSet> TObstacleTypes;
typedef std::vector<std::shared_ptr<ObstacleSet>> TObstacleTypes;
class DLL_LINKAGE ObstacleSetFilter
{
@ -80,22 +87,29 @@ public:
ObstacleSetHandler() = default;
~ObstacleSetHandler() = default;
// FIXME: Not needed at all
std::vector<JsonNode> loadLegacyData() override {return {};};
virtual void loadObject(std::string scope, std::string name, const JsonNode & data) override {};
virtual void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override {};
std::vector<JsonNode> loadLegacyData() override;
virtual void loadObject(std::string scope, std::string name, const JsonNode & data) override;
virtual void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
std::shared_ptr<ObstacleSet> loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name, size_t index);
ObstacleSet::EObstacleType convertObstacleClass(MapObjectID id);
// TODO: Populate obstacleSets with all the obstacle sets from the game data
void addTemplate(const std::string & scope, const std::string &name, std::shared_ptr<const ObjectTemplate> tmpl);
void addObstacleSet(const ObstacleSet &set);
void addObstacleSet(std::shared_ptr<ObstacleSet> set);
TObstacleTypes getObstacles(const ObstacleSetFilter &filter) const;
private:
std::map<ObstacleSet::EObstacleType, std::vector<ObstacleSet>> obstacleSets;
std::vector< std::shared_ptr<ObstacleSet> > biomes;
// TODO: Serialize?
std::map<si32, std::shared_ptr<const ObjectTemplate>> obstacleTemplates;
// FIXME: Store pointers?
std::map<ObstacleSet::EObstacleType, std::vector<std::shared_ptr<ObstacleSet>>> obstacleSets;
};
VCMI_LIB_NAMESPACE_END

View File

@ -58,7 +58,9 @@ bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
possibleObstacles.clear();
std::vector<ObstacleSet> obstacleSets;
// TODO: Move this logic to ObstacleSetHandler
std::vector<std::shared_ptr<ObstacleSet>> obstacleSets;
size_t selectedSets = 0;
const size_t MINIMUM_SETS = 6;
@ -103,7 +105,7 @@ bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
selectedSets++;
// TODO: Convert to string
logGlobal->info("Added large set of type %s", obstacleSets.back().getType());
logGlobal->info("Added large set of type %s", obstacleSets.back()->getType());
}
TObstacleTypes rockSets = VLC->biomeHandler->getObstacles(ObstacleSetFilter(ObstacleSet::EObstacleType::ROCKS, terrain));
@ -152,7 +154,7 @@ bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
smallObstacleSets.pop_back();
selectedSets++;
smallSets--;
logGlobal->info("Added small set of type %s", obstacleSets.back().getType());
logGlobal->info("Added small set of type %s", obstacleSets.back()->getType());
}
else if(otherSets.empty())
{
@ -183,7 +185,7 @@ bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
obstaclesBySize.clear();
for (const auto & os : obstacleSets)
{
for (const auto & temp : os.getObstacles())
for (const auto & temp : os->getObstacles())
{
if(temp->getBlockMapOffset().valid())
{

View File

@ -26,6 +26,7 @@
#include "../IHandlerBase.h"
#include "../Languages.h"
#include "../ObstacleHandler.h"
#include "../mapObjects/ObstacleSetHandler.h"
#include "../RiverHandler.h"
#include "../RoadHandler.h"
#include "../ScriptHandler.h"
@ -207,7 +208,7 @@ void CContentHandler::init()
handlers.insert(std::make_pair("rivers", ContentTypeHandler(VLC->riverTypeHandler.get(), "river")));
handlers.insert(std::make_pair("roads", ContentTypeHandler(VLC->roadTypeHandler.get(), "road")));
handlers.insert(std::make_pair("obstacles", ContentTypeHandler(VLC->obstacleHandler.get(), "obstacle")));
//TODO: any other types of moddables?
handlers.insert(std::make_pair("biomes", ContentTypeHandler(VLC->biomeHandler.get(), "biome")));
}
bool CContentHandler::preloadModData(const std::string & modName, JsonNode modConfig, bool validate)