577 lines
21 KiB
C++
577 lines
21 KiB
C++
|
#include "StarMaterialDatabase.hpp"
|
||
|
#include "StarJsonExtra.hpp"
|
||
|
#include "StarFormat.hpp"
|
||
|
#include "StarAssets.hpp"
|
||
|
#include "StarRoot.hpp"
|
||
|
#include "StarLogging.hpp"
|
||
|
#include "StarParticleDatabase.hpp"
|
||
|
|
||
|
namespace Star {
|
||
|
|
||
|
MaterialDatabase::MaterialDatabase() {
|
||
|
m_metaModIndex = {
|
||
|
{"metamod:none", NoModId},
|
||
|
{"metamod:biome", BiomeModId},
|
||
|
{"metamod:undergroundbiome", UndergroundBiomeModId}};
|
||
|
|
||
|
auto assets = Root::singleton().assets();
|
||
|
auto pdb = Root::singleton().particleDatabase();
|
||
|
|
||
|
setMetaMaterial(EmptyMaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:empty", EmptyMaterialId, CollisionKind::None, false});
|
||
|
setMetaMaterial(NullMaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:null", NullMaterialId, CollisionKind::Block, true});
|
||
|
setMetaMaterial(StructureMaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:structure", StructureMaterialId, CollisionKind::Block, true});
|
||
|
setMetaMaterial(BiomeMaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:biome", BiomeMaterialId, CollisionKind::Block, true});
|
||
|
setMetaMaterial(Biome1MaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:biome1", Biome1MaterialId, CollisionKind::Block, true});
|
||
|
setMetaMaterial(Biome2MaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:biome2", Biome2MaterialId, CollisionKind::Block, true});
|
||
|
setMetaMaterial(Biome3MaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:biome3", Biome3MaterialId, CollisionKind::Block, true});
|
||
|
setMetaMaterial(Biome4MaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:biome4", Biome4MaterialId, CollisionKind::Block, true});
|
||
|
setMetaMaterial(Biome5MaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:biome5", Biome5MaterialId, CollisionKind::Block, true});
|
||
|
setMetaMaterial(BoundaryMaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:boundary", BoundaryMaterialId, CollisionKind::Slippery, true});
|
||
|
setMetaMaterial(ObjectSolidMaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:objectsolid", ObjectSolidMaterialId, CollisionKind::Block, true});
|
||
|
setMetaMaterial(ObjectPlatformMaterialId, MaterialDatabase::MetaMaterialInfo{"metamaterial:objectplatform", ObjectPlatformMaterialId, CollisionKind::Platform, false});
|
||
|
|
||
|
auto metaMaterialConfig = assets->json("/metamaterials.config");
|
||
|
for (auto metaMaterial : metaMaterialConfig.iterateArray()) {
|
||
|
auto matName = "metamaterial:" + metaMaterial.getString("name");
|
||
|
if (isMaterialName(matName)) {
|
||
|
Logger::info("Metamaterial '%s' has duplicate material name!", matName);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
MaterialId matId = metaMaterial.getUInt("materialId");
|
||
|
if (isRealMaterial(matId) || matId >= FirstEngineMetaMaterialId) {
|
||
|
Logger::info("Material id %s for metamaterial '%s' does not fall within the valid range!", matId, matName);
|
||
|
continue;
|
||
|
} else if (containsMetaMaterial(matId)) {
|
||
|
Logger::info("Material id %s for metamaterial '%s' conflicts with another metamaterial id!", matId, matName);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
auto matCollisionKind = CollisionKindNames.getLeft(metaMaterial.getString("collisionKind"));
|
||
|
|
||
|
bool blocksLiquidFlow = metaMaterial.getBool("blocksLiquidFlow", isSolidColliding(matCollisionKind));
|
||
|
|
||
|
setMetaMaterial(matId, MaterialDatabase::MetaMaterialInfo{matName, matId, matCollisionKind, blocksLiquidFlow});
|
||
|
}
|
||
|
|
||
|
auto materials = assets->scanExtension("material");
|
||
|
auto mods = assets->scanExtension("matmod");
|
||
|
|
||
|
assets->queueJsons(materials);
|
||
|
assets->queueJsons(mods);
|
||
|
|
||
|
for (auto file : materials) {
|
||
|
try {
|
||
|
auto matConfig = assets->json(file);
|
||
|
|
||
|
MaterialInfo material;
|
||
|
|
||
|
auto materialId = matConfig.getInt("materialId");
|
||
|
material.id = materialId;
|
||
|
|
||
|
material.name = matConfig.getString("materialName");
|
||
|
material.path = file;
|
||
|
material.config = matConfig;
|
||
|
|
||
|
material.itemDrop = matConfig.getString("itemDrop", "");
|
||
|
|
||
|
JsonObject descriptions;
|
||
|
for (auto entry : matConfig.iterateObject())
|
||
|
if (entry.first.endsWith("Description"))
|
||
|
descriptions[entry.first] = entry.second;
|
||
|
descriptions["description"] = matConfig.getString("description", "");
|
||
|
descriptions["shortdescription"] = matConfig.getString("shortdescription", "");
|
||
|
material.descriptions = descriptions;
|
||
|
|
||
|
material.category = matConfig.getString("category");
|
||
|
|
||
|
material.particleColor = jsonToColor(matConfig.get("particleColor", JsonArray{0, 0, 0, 255}));
|
||
|
if (matConfig.contains("miningParticle"))
|
||
|
material.miningParticle = pdb->config(matConfig.getString("miningParticle"));
|
||
|
if (matConfig.contains("miningSounds"))
|
||
|
material.miningSounds = transform<StringList>(
|
||
|
jsonToStringList(matConfig.get("miningSounds")), bind(AssetPath::relativeTo, file, _1));
|
||
|
if (matConfig.contains("footstepSound"))
|
||
|
material.footstepSound = AssetPath::relativeTo(file, matConfig.getString("footstepSound"));
|
||
|
|
||
|
material.tillableMod = matConfig.getInt("tillableMod", NoModId);
|
||
|
material.soil = matConfig.getBool("soil", false);
|
||
|
material.falling = matConfig.getBool("falling", false);
|
||
|
material.cascading = matConfig.getBool("cascading", false);
|
||
|
|
||
|
if (matConfig.contains("renderTemplate")) {
|
||
|
auto renderTemplate = assets->fetchJson(matConfig.get("renderTemplate"), file);
|
||
|
auto renderParameters = matConfig.get("renderParameters");
|
||
|
material.materialRenderProfile = make_shared<MaterialRenderProfile>(parseMaterialRenderProfile(jsonMerge(renderTemplate, renderParameters), file));
|
||
|
}
|
||
|
|
||
|
material.damageParameters =
|
||
|
TileDamageParameters(assets->fetchJson(matConfig.get("damageTable", "/tiles/defaultDamage.config")),
|
||
|
matConfig.optFloat("health"),
|
||
|
matConfig.optUInt("requiredHarvestLevel"));
|
||
|
|
||
|
material.collisionKind = CollisionKindNames.getLeft(matConfig.getString("collisionKind", "block"));
|
||
|
material.foregroundOnly = matConfig.getBool("foregroundOnly", material.collisionKind != CollisionKind::Block);
|
||
|
material.supportsMods = matConfig.getBool("supportsMods", !(material.falling || material.cascading || material.collisionKind != CollisionKind::Block));
|
||
|
|
||
|
material.blocksLiquidFlow = matConfig.getBool("blocksLiquidFlow", isSolidColliding(material.collisionKind));
|
||
|
|
||
|
if (material.id != materialId || !isRealMaterial(material.id))
|
||
|
throw MaterialException(strf("Material id %s does not fall in the valid range\n", materialId));
|
||
|
|
||
|
if (containsMaterial(material.id))
|
||
|
throw MaterialException(strf("Duplicate material id %s found for material %s", material.id, material.name));
|
||
|
|
||
|
if (isMaterialName(material.name))
|
||
|
throw MaterialException(strf("Duplicate material name '%s' found", material.name));
|
||
|
|
||
|
setMaterial(material.id, material);
|
||
|
|
||
|
for (auto liquidInteraction : matConfig.getArray("liquidInteractions", {})) {
|
||
|
LiquidId liquidId = liquidInteraction.getUInt("liquidId");
|
||
|
LiquidMaterialInteraction interaction;
|
||
|
interaction.consumeLiquid = liquidInteraction.getFloat("consumeLiquid", 0.0f);
|
||
|
interaction.transformTo = liquidInteraction.getUInt("transformMaterialId", NullMaterialId);
|
||
|
interaction.topOnly = liquidInteraction.getBool("topOnly", false);
|
||
|
m_liquidMaterialInteractions[{liquidId, material.id}] = interaction;
|
||
|
}
|
||
|
} catch (StarException const& e) {
|
||
|
throw MaterialException(strf("Error loading material file %s", file), e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (auto file : mods) {
|
||
|
try {
|
||
|
auto modConfig = assets->json(file);
|
||
|
|
||
|
ModInfo mod;
|
||
|
|
||
|
auto modId = modConfig.getInt("modId");
|
||
|
mod.id = modId;
|
||
|
|
||
|
mod.name = modConfig.getString("modName");
|
||
|
mod.path = file;
|
||
|
mod.config = modConfig;
|
||
|
|
||
|
mod.itemDrop = modConfig.getString("itemDrop", "");
|
||
|
|
||
|
JsonObject descriptions;
|
||
|
for (auto entry : modConfig.iterateObject())
|
||
|
if (entry.first.endsWith("Description"))
|
||
|
descriptions[entry.first] = entry.second;
|
||
|
descriptions["description"] = modConfig.getString("description", "");
|
||
|
mod.descriptions = descriptions;
|
||
|
|
||
|
mod.particleColor = jsonToColor(modConfig.get("particleColor", JsonArray{0, 0, 0, 255}));
|
||
|
if (modConfig.contains("miningParticle"))
|
||
|
mod.miningParticle = pdb->config(modConfig.getString("miningParticle"));
|
||
|
if (modConfig.contains("miningSounds"))
|
||
|
mod.miningSounds = transform<StringList>(
|
||
|
jsonToStringList(modConfig.get("miningSounds")), bind(AssetPath::relativeTo, file, _1));
|
||
|
if (modConfig.contains("footstepSound"))
|
||
|
mod.footstepSound = AssetPath::relativeTo(file, modConfig.getString("footstepSound"));
|
||
|
|
||
|
mod.tilled = modConfig.getBool("tilled", false);
|
||
|
|
||
|
mod.breaksWithTile = modConfig.getBool("breaksWithTile", false);
|
||
|
|
||
|
if (modConfig.contains("renderTemplate")) {
|
||
|
auto renderTemplate = assets->fetchJson(modConfig.get("renderTemplate"));
|
||
|
auto renderParameters = modConfig.get("renderParameters");
|
||
|
mod.modRenderProfile = make_shared<MaterialRenderProfile>(parseMaterialRenderProfile(jsonMerge(renderTemplate, renderParameters), file));
|
||
|
}
|
||
|
|
||
|
mod.damageParameters =
|
||
|
TileDamageParameters(assets->fetchJson(modConfig.get("damageTable", "/tiles/defaultDamage.config")),
|
||
|
modConfig.optFloat("health"),
|
||
|
modConfig.optUInt("harvestLevel"));
|
||
|
|
||
|
if (modId != mod.id || !isRealMod(mod.id))
|
||
|
throw MaterialException(strf("Mod id %s does not fall in the valid range\n", mod.id));
|
||
|
|
||
|
if (containsMod(mod.id))
|
||
|
throw MaterialException(strf("Duplicate mod id %s found for mod %s", mod.id, mod.name));
|
||
|
|
||
|
if (m_modIndex.contains(mod.name) || m_metaModIndex.hasLeftValue(mod.name))
|
||
|
throw MaterialException(strf("Duplicate mod name '%s' found", mod.name));
|
||
|
|
||
|
setMod(mod.id, mod);
|
||
|
m_modIndex[mod.name] = mod.id;
|
||
|
|
||
|
for (auto liquidInteraction : modConfig.getArray("liquidInteractions", {})) {
|
||
|
LiquidId liquidId = liquidInteraction.getUInt("liquidId");
|
||
|
LiquidModInteraction interaction;
|
||
|
interaction.consumeLiquid = liquidInteraction.getFloat("consumeLiquid", 0.0f);
|
||
|
interaction.transformTo = liquidInteraction.getUInt("transformModId", NoModId);
|
||
|
interaction.topOnly = liquidInteraction.getBool("topOnly", false);
|
||
|
m_liquidModInteractions[{liquidId, mod.id}] = interaction;
|
||
|
}
|
||
|
} catch (StarException const& e) {
|
||
|
throw MaterialException(strf("Error loading mod file %s", file), e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_defaultFootstepSound = assets->json("/client.config:defaultFootstepSound").toString();
|
||
|
}
|
||
|
|
||
|
StringList MaterialDatabase::materialNames() const {
|
||
|
StringList names = m_materialIndex.keys();
|
||
|
names.appendAll(m_metaMaterialIndex.keys());
|
||
|
return names;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::isMetaMaterialName(String const& name) const {
|
||
|
return m_metaMaterialIndex.contains(name);
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::isMaterialName(String const& name) const {
|
||
|
return m_materialIndex.contains(name) || m_metaMaterialIndex.contains(name);
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::isValidMaterialId(MaterialId material) const {
|
||
|
if (isRealMaterial(material))
|
||
|
return containsMaterial(material);
|
||
|
else
|
||
|
return containsMetaMaterial(material);
|
||
|
}
|
||
|
|
||
|
MaterialId MaterialDatabase::materialId(String const& matName) const {
|
||
|
if (auto m = m_metaMaterialIndex.maybe(matName))
|
||
|
return *m;
|
||
|
else
|
||
|
return m_materialIndex.get(matName);
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::materialName(MaterialId materialId) const {
|
||
|
if (isRealMaterial(materialId))
|
||
|
return getMaterialInfo(materialId)->name;
|
||
|
else
|
||
|
return getMetaMaterialInfo(materialId)->name;
|
||
|
}
|
||
|
|
||
|
Maybe<String> MaterialDatabase::materialPath(MaterialId materialId) const {
|
||
|
if (isRealMaterial(materialId))
|
||
|
return getMaterialInfo(materialId)->path;
|
||
|
else
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
Maybe<Json> MaterialDatabase::materialConfig(MaterialId materialId) const {
|
||
|
if (isRealMaterial(materialId))
|
||
|
return getMaterialInfo(materialId)->config;
|
||
|
else
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::materialDescription(MaterialId materialNumber, String const& species) const {
|
||
|
auto material = m_materials[materialNumber];
|
||
|
return material->descriptions.getString(
|
||
|
strf("%sDescription", species), material->descriptions.getString("description"));
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::materialDescription(MaterialId materialNumber) const {
|
||
|
auto material = m_materials[materialNumber];
|
||
|
return material->descriptions.getString("description");
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::materialShortDescription(MaterialId materialNumber) const {
|
||
|
auto material = m_materials[materialNumber];
|
||
|
return material->descriptions.getString("shortdescription");
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::materialCategory(MaterialId materialNumber) const {
|
||
|
auto material = m_materials[materialNumber];
|
||
|
return material->category;
|
||
|
}
|
||
|
|
||
|
StringList MaterialDatabase::modNames() const {
|
||
|
StringList modNames = m_modIndex.keys();
|
||
|
modNames.appendAll(m_metaModIndex.leftValues());
|
||
|
return modNames;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::isModName(String const& name) const {
|
||
|
return m_modIndex.contains(name);
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::isValidModId(ModId mod) const {
|
||
|
if (isRealMod(mod))
|
||
|
return mod < m_mods.size() && (bool)m_mods[mod];
|
||
|
else
|
||
|
return m_metaModIndex.hasRightValue(mod);
|
||
|
}
|
||
|
|
||
|
ModId MaterialDatabase::modId(String const& modName) const {
|
||
|
if (auto m = m_metaModIndex.maybeRight(modName))
|
||
|
return *m;
|
||
|
else
|
||
|
return m_modIndex.get(modName);
|
||
|
}
|
||
|
|
||
|
String const& MaterialDatabase::modName(ModId mod) const {
|
||
|
if (isRealMod(mod))
|
||
|
return getModInfo(mod)->name;
|
||
|
else
|
||
|
return m_metaModIndex.getLeft(mod);
|
||
|
}
|
||
|
|
||
|
Maybe<String> MaterialDatabase::modPath(ModId mod) const {
|
||
|
if (isRealMod(mod))
|
||
|
return getModInfo(mod)->path;
|
||
|
else
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
Maybe<Json> MaterialDatabase::modConfig(ModId mod) const {
|
||
|
if (isRealMod(mod))
|
||
|
return getModInfo(mod)->config;
|
||
|
else
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::modDescription(ModId modId, String const& species) const {
|
||
|
auto mod = m_mods[modId];
|
||
|
return mod->descriptions.getString(strf("%sDescription", species), mod->descriptions.getString("description"));
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::modDescription(ModId modId) const {
|
||
|
auto mod = m_mods[modId];
|
||
|
return mod->descriptions.getString("description");
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::modShortDescription(ModId modId) const {
|
||
|
auto mod = m_mods[modId];
|
||
|
return mod->descriptions.getString("shortdescription");
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::defaultFootstepSound() const {
|
||
|
return m_defaultFootstepSound;
|
||
|
}
|
||
|
|
||
|
TileDamageParameters MaterialDatabase::materialDamageParameters(MaterialId materialId) const {
|
||
|
if (!isRealMaterial(materialId))
|
||
|
return {};
|
||
|
else
|
||
|
return getMaterialInfo(materialId)->damageParameters;
|
||
|
}
|
||
|
|
||
|
TileDamageParameters MaterialDatabase::modDamageParameters(ModId modId) const {
|
||
|
if (!isRealMod(modId))
|
||
|
return {};
|
||
|
else
|
||
|
return getModInfo(modId)->damageParameters;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::modBreaksWithTile(ModId modId) const {
|
||
|
if (!isRealMod(modId))
|
||
|
return {};
|
||
|
else
|
||
|
return getModInfo(modId)->breaksWithTile;
|
||
|
}
|
||
|
|
||
|
CollisionKind MaterialDatabase::materialCollisionKind(MaterialId materialId) const {
|
||
|
if (isRealMaterial(materialId))
|
||
|
return getMaterialInfo(materialId)->collisionKind;
|
||
|
else if (containsMetaMaterial(materialId))
|
||
|
return getMetaMaterialInfo(materialId)->collisionKind;
|
||
|
else
|
||
|
return CollisionKind::Block;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::canPlaceInLayer(MaterialId materialId, TileLayer layer) const {
|
||
|
return layer == TileLayer::Foreground || !getMaterialInfo(materialId)->foregroundOnly;
|
||
|
}
|
||
|
|
||
|
ItemDescriptor MaterialDatabase::materialItemDrop(MaterialId materialId) const {
|
||
|
if (isRealMaterial(materialId)) {
|
||
|
auto matInfo = getMaterialInfo(materialId);
|
||
|
if (!matInfo->itemDrop.empty())
|
||
|
return ItemDescriptor(matInfo->itemDrop, 1, JsonObject());
|
||
|
}
|
||
|
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
ItemDescriptor MaterialDatabase::modItemDrop(ModId modId) const {
|
||
|
if (isRealMod(modId)) {
|
||
|
auto modInfo = getModInfo(modId);
|
||
|
if (!modInfo->itemDrop.empty())
|
||
|
return ItemDescriptor(modInfo->itemDrop, 1);
|
||
|
}
|
||
|
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::isMultiColor(MaterialId materialId) const {
|
||
|
if (isRealMaterial(materialId)) {
|
||
|
auto const& matInfo = getMaterialInfo(materialId);
|
||
|
if (matInfo->materialRenderProfile)
|
||
|
return matInfo->materialRenderProfile->multiColor;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
ParticleConfigPtr MaterialDatabase::miningParticle(MaterialId materialId, ModId modId) const {
|
||
|
if (isRealMod(modId)) {
|
||
|
auto const& modInfo = getModInfo(modId);
|
||
|
if (modInfo->miningParticle)
|
||
|
return modInfo->miningParticle;
|
||
|
}
|
||
|
|
||
|
if (isRealMaterial(materialId)) {
|
||
|
auto const& matInfo = getMaterialInfo(materialId);
|
||
|
if (matInfo->miningParticle)
|
||
|
return matInfo->miningParticle;
|
||
|
}
|
||
|
|
||
|
return ParticleConfigPtr();
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::miningSound(MaterialId materialId, ModId modId) const {
|
||
|
if (isRealMod(modId)) {
|
||
|
auto const& modInfo = getModInfo(modId);
|
||
|
if (!modInfo->miningSounds.empty())
|
||
|
return Random::randValueFrom(modInfo->miningSounds);
|
||
|
}
|
||
|
|
||
|
if (isRealMaterial(materialId)) {
|
||
|
auto const& matInfo = getMaterialInfo(materialId);
|
||
|
if (!matInfo->miningSounds.empty())
|
||
|
return Random::randValueFrom(matInfo->miningSounds);
|
||
|
}
|
||
|
|
||
|
return String();
|
||
|
}
|
||
|
|
||
|
String MaterialDatabase::footstepSound(MaterialId materialId, ModId modId) const {
|
||
|
if (isRealMod(modId)) {
|
||
|
auto const& modInfo = getModInfo(modId);
|
||
|
if (!modInfo->footstepSound.empty())
|
||
|
return modInfo->footstepSound;
|
||
|
}
|
||
|
|
||
|
if (isRealMaterial(materialId)) {
|
||
|
auto const& matInfo = getMaterialInfo(materialId);
|
||
|
if (!matInfo->footstepSound.empty())
|
||
|
return matInfo->footstepSound;
|
||
|
}
|
||
|
|
||
|
return m_defaultFootstepSound;
|
||
|
}
|
||
|
|
||
|
Color MaterialDatabase::materialParticleColor(MaterialId materialId, MaterialHue hueShift) const {
|
||
|
auto color = getMaterialInfo(materialId)->particleColor;
|
||
|
color.setHue(pfmod(color.hue() + materialHueToDegrees(hueShift) / 360.0f, 1.0f));
|
||
|
return color;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::isTilledMod(ModId modId) const {
|
||
|
if (!isRealMod(modId))
|
||
|
return false;
|
||
|
return getModInfo(modId)->tilled;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::isSoil(MaterialId materialId) const {
|
||
|
if (!isRealMaterial(materialId))
|
||
|
return false;
|
||
|
return getMaterialInfo(materialId)->soil;
|
||
|
}
|
||
|
|
||
|
ModId MaterialDatabase::tilledModFor(MaterialId materialId) const {
|
||
|
if (!isRealMaterial(materialId))
|
||
|
return NoModId;
|
||
|
return getMaterialInfo(materialId)->tillableMod;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::isFallingMaterial(MaterialId materialId) const {
|
||
|
if (!isRealMaterial(materialId))
|
||
|
return false;
|
||
|
return getMaterialInfo(materialId)->falling;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::isCascadingFallingMaterial(MaterialId materialId) const {
|
||
|
if (!isRealMaterial(materialId))
|
||
|
return false;
|
||
|
return getMaterialInfo(materialId)->cascading;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::supportsMod(MaterialId materialId, ModId modId) const {
|
||
|
if (modId == NoModId)
|
||
|
return true;
|
||
|
if (!isRealMaterial(materialId))
|
||
|
return false;
|
||
|
if (!isRealMod(modId))
|
||
|
return false;
|
||
|
|
||
|
return getMaterialInfo(materialId)->supportsMods;
|
||
|
}
|
||
|
|
||
|
MaterialDatabase::MetaMaterialInfo::MetaMaterialInfo(String name, MaterialId id, CollisionKind collisionKind, bool blocksLiquidFlow)
|
||
|
: name(name), id(id), collisionKind(collisionKind), blocksLiquidFlow(blocksLiquidFlow) {}
|
||
|
|
||
|
MaterialDatabase::MaterialInfo::MaterialInfo() : id(NullMaterialId), tillableMod(NoModId), falling(), cascading() {}
|
||
|
|
||
|
MaterialDatabase::ModInfo::ModInfo() : id(NoModId), tilled(), breaksWithTile() {}
|
||
|
|
||
|
size_t MaterialDatabase::metaMaterialIndex(MaterialId materialId) const {
|
||
|
return materialId - FirstMetaMaterialId;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::containsMetaMaterial(MaterialId materialId) const {
|
||
|
auto i = metaMaterialIndex(materialId);
|
||
|
return m_metaMaterials.size() > i && m_metaMaterials[i];
|
||
|
}
|
||
|
|
||
|
void MaterialDatabase::setMetaMaterial(MaterialId materialId, MetaMaterialInfo info) {
|
||
|
auto i = metaMaterialIndex(materialId);
|
||
|
if (i >= m_metaMaterials.size())
|
||
|
m_metaMaterials.resize(i + 1);
|
||
|
m_metaMaterials[i] = make_shared<MetaMaterialInfo>(info);
|
||
|
m_metaMaterialIndex[info.name] = materialId;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::containsMaterial(MaterialId materialId) const {
|
||
|
return m_materials.size() > materialId && m_materials[materialId];
|
||
|
}
|
||
|
|
||
|
void MaterialDatabase::setMaterial(MaterialId materialId, MaterialInfo info) {
|
||
|
if (materialId >= m_materials.size())
|
||
|
m_materials.resize(materialId + 1);
|
||
|
m_materials[materialId] = make_shared<MaterialInfo>(info);
|
||
|
m_materialIndex[info.name] = materialId;
|
||
|
}
|
||
|
|
||
|
bool MaterialDatabase::containsMod(ModId modId) const {
|
||
|
return m_mods.size() > modId && m_mods[modId];
|
||
|
}
|
||
|
|
||
|
void MaterialDatabase::setMod(ModId modId, ModInfo info) {
|
||
|
if (modId >= m_mods.size())
|
||
|
m_mods.resize(modId + 1);
|
||
|
m_mods[modId] = make_shared<ModInfo>(info);
|
||
|
}
|
||
|
|
||
|
shared_ptr<MaterialDatabase::MetaMaterialInfo const> const& MaterialDatabase::getMetaMaterialInfo(MaterialId materialId) const {
|
||
|
if (!containsMetaMaterial(materialId))
|
||
|
throw MaterialException(strf("No such metamaterial id: %s\n", materialId));
|
||
|
else
|
||
|
return m_metaMaterials[metaMaterialIndex(materialId)];
|
||
|
}
|
||
|
|
||
|
shared_ptr<MaterialDatabase::MaterialInfo const> const& MaterialDatabase::getMaterialInfo(MaterialId materialId) const {
|
||
|
if (materialId >= m_materials.size() || !m_materials[materialId])
|
||
|
throw MaterialException(strf("No such material id: %s\n", materialId));
|
||
|
else
|
||
|
return m_materials[materialId];
|
||
|
}
|
||
|
|
||
|
shared_ptr<MaterialDatabase::ModInfo const> const& MaterialDatabase::getModInfo(ModId modId) const {
|
||
|
if (modId >= m_mods.size() || !m_mods[modId])
|
||
|
throw MaterialException(strf("No such modId id: %s\n", modId));
|
||
|
else
|
||
|
return m_mods[modId];
|
||
|
}
|
||
|
|
||
|
}
|