Index: ps/trunk/binaries/data/mods/public/simulation/templates/mixins/builder.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/mixins/builder.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/mixins/builder.xml @@ -0,0 +1,37 @@ + + + + 1.0 + + structures/{civ}/civil_centre + structures/{civ}/crannog + structures/{civ}/military_colony + structures/{civ}/house + structures/{civ}/apartment + structures/{civ}/storehouse + structures/{civ}/farmstead + structures/{civ}/field + structures/{civ}/corral + structures/{civ}/dock + structures/{civ}/barracks + structures/{civ}/stable + structures/{civ}/elephant_stable + structures/{civ}/arsenal + structures/{civ}/forge + structures/{civ}/temple + structures/{civ}/market + structures/{civ}/outpost + structures/{civ}/sentry_tower + structures/{civ}/defense_tower + structures/{civ}/fortress + structures/wallset_palisade + structures/{civ}/wallset_siege + structures/{civ}/wallset_stone + structures/{civ}/theater + structures/{civ}/wonder + + + + Builder + + Index: ps/trunk/binaries/data/mods/public/simulation/templates/mixins/hoplite.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/mixins/hoplite.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/mixins/hoplite.xml @@ -0,0 +1,8 @@ + + + + + special/formations/phalanx + + + Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_champion_infantry_spearman_hoplite.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_champion_infantry_spearman_hoplite.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_champion_infantry_spearman_hoplite.xml @@ -1,8 +0,0 @@ - - - - - special/formations/phalanx - - - Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_spearman_hoplite.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_spearman_hoplite.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_spearman_hoplite.xml @@ -1,8 +0,0 @@ - - - - - special/formations/phalanx - - - Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml @@ -1,5 +1,5 @@ - + Capture @@ -16,37 +16,6 @@ 2 - - 1.0 - - structures/{civ}/civil_centre - structures/{civ}/crannog - structures/{civ}/military_colony - structures/{civ}/house - structures/{civ}/apartment - structures/{civ}/storehouse - structures/{civ}/farmstead - structures/{civ}/field - structures/{civ}/corral - structures/{civ}/dock - structures/{civ}/barracks - structures/{civ}/stable - structures/{civ}/elephant_stable - structures/{civ}/arsenal - structures/{civ}/forge - structures/{civ}/temple - structures/{civ}/market - structures/{civ}/outpost - structures/{civ}/sentry_tower - structures/{civ}/defense_tower - structures/{civ}/fortress - structures/wallset_palisade - structures/{civ}/wallset_siege - structures/{civ}/wallset_stone - structures/{civ}/theater - structures/{civ}/wonder - - 12 @@ -62,7 +31,7 @@ Infantry Human CitizenSoldier - Citizen Builder Worker Soldier Infantry + Citizen Worker Soldier Infantry Basic Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_infantry_melee_spearman_hoplite.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_infantry_melee_spearman_hoplite.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_infantry_melee_spearman_hoplite.xml @@ -1,8 +0,0 @@ - - - - - special/formations/phalanx - - - Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml @@ -1,5 +1,5 @@ - + Dagger @@ -18,37 +18,6 @@ 2 - - 1.0 - - structures/{civ}/civil_centre - structures/{civ}/crannog - structures/{civ}/military_colony - structures/{civ}/house - structures/{civ}/apartment - structures/{civ}/storehouse - structures/{civ}/farmstead - structures/{civ}/field - structures/{civ}/corral - structures/{civ}/dock - structures/{civ}/barracks - structures/{civ}/stable - structures/{civ}/elephant_stable - structures/{civ}/arsenal - structures/{civ}/forge - structures/{civ}/temple - structures/{civ}/market - structures/{civ}/outpost - structures/{civ}/sentry_tower - structures/{civ}/defense_tower - structures/{civ}/fortress - structures/wallset_palisade - structures/{civ}/wallset_siege - structures/{civ}/wallset_stone - structures/{civ}/theater - structures/{civ}/wonder - - 9 @@ -63,7 +32,7 @@ Female Citizen template_unit_support_female_citizen FemaleCitizen - Citizen Builder Worker + Citizen Worker Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml @@ -1,35 +1,7 @@ - + 0.5 - - structures/{civ}/civil_centre - structures/{civ}/crannog - structures/{civ}/military_colony - structures/{civ}/house - structures/{civ}/apartment - structures/{civ}/storehouse - structures/{civ}/farmstead - structures/{civ}/field - structures/{civ}/corral - structures/{civ}/dock - structures/{civ}/barracks - structures/{civ}/stable - structures/{civ}/elephant_stable - structures/{civ}/arsenal - structures/{civ}/forge - structures/{civ}/temple - structures/{civ}/market - structures/{civ}/outpost - structures/{civ}/sentry_tower - structures/{civ}/defense_tower - structures/{civ}/fortress - structures/wallset_palisade - structures/{civ}/wallset_siege - structures/{civ}/wallset_stone - structures/{civ}/theater - structures/{civ}/wonder - 0 @@ -46,7 +18,7 @@ Slave template_unit_support_slave Gatherer with a finite life span. Bonused at mining and lumbering. - Builder Worker Slave + Worker Slave 10 Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/champion_infantry.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/champion_infantry.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/champion_infantry.xml @@ -1,5 +1,5 @@ - + athen greek Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/hero_pericles.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/hero_pericles.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/hero_pericles.xml @@ -1,5 +1,5 @@ - + units/heroes/athen_hero_pericles_1 units/heroes/athen_hero_pericles_2 Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/infantry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/infantry_spearman_b.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/infantry_spearman_b.xml @@ -1,5 +1,5 @@ - + structures/athen/gymnasium Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/champion_infantry.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/champion_infantry.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/champion_infantry.xml @@ -1,5 +1,5 @@ - + cart Sacred Band Infantry Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_spearman_b.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_spearman_b.xml @@ -1,5 +1,5 @@ - + structures/cart/super_dock Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/champion_infantry_spearman.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/champion_infantry_spearman.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/champion_infantry_spearman.xml @@ -1,5 +1,5 @@ - + mace greek Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/kardakes_hoplite.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/kardakes_hoplite.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/kardakes_hoplite.xml @@ -1,5 +1,5 @@ - + pers Mercenary Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_spearman_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_spearman_merc_b.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_spearman_merc_b.xml @@ -1,5 +1,5 @@ - + structures/ptol/lighthouse Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/samnite_spearman.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/samnite_spearman.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/samnite_spearman.xml @@ -1,5 +1,5 @@ - + Mercenary Samnite Spearman Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_spearman_b.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_spearman_b.xml @@ -1,5 +1,5 @@ - + sele greek Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/champion_infantry_spear.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/champion_infantry_spear.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/champion_infantry_spear.xml @@ -1,5 +1,5 @@ - + spart greek Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/hero_agis.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/hero_agis.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/hero_agis.xml @@ -1,5 +1,5 @@ - + spart greek Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/hero_leonidas.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/hero_leonidas.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/hero_leonidas.xml @@ -1,5 +1,5 @@ - + units/heroes/spart_hero_leonidas Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/infantry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/infantry_spearman_b.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/infantry_spearman_b.xml @@ -1,5 +1,5 @@ - + structures/spart/syssiton Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/thebes_sacred_band_hoplitai.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/thebes_sacred_band_hoplitai.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/thebes_sacred_band_hoplitai.xml @@ -1,5 +1,5 @@ - + greek Theban Sacred Band Hoplite Index: ps/trunk/source/ps/TemplateLoader.h =================================================================== --- ps/trunk/source/ps/TemplateLoader.h +++ ps/trunk/source/ps/TemplateLoader.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,6 +20,9 @@ #include "simulation2/system/ParamNode.h" +#include +#include + enum ETemplatesType { ALL_TEMPLATES, @@ -69,14 +72,16 @@ * (Re)loads the given template, regardless of whether it exists already, * and saves into m_TemplateFileData. Also loads any parents that are not yet * loaded. Returns false on error. - * @param templateName XML filename to load (not a |-separated string) + * @param templateName - XML filename to load (may be a |-separated string) + * @param compositing - whether this template is an intermediary layer in a |-separated string. + * @param depth - the current recursion depth. */ - bool LoadTemplateFile(const std::string& templateName, int depth); + bool LoadTemplateFile(CParamNode& node, std::string_view templateName, bool compositing, int depth); /** * Constructs a standard static-decorative-object template for the given actor */ - void ConstructTemplateActor(const std::string& actorName, CParamNode& out); + void ConstructTemplateActor(std::string_view actorName, CParamNode& out); /** * Map from template name (XML filename or special |-separated string) to the most recently @@ -84,7 +89,7 @@ * (Failed loads won't remove existing entries under the same name, so we behave more nicely * when hotloading broken files) */ - std::map m_TemplateFileData; + std::unordered_map m_TemplateFileData; }; #endif // INCLUDED_TEMPLATELOADER Index: ps/trunk/source/ps/TemplateLoader.cpp =================================================================== --- ps/trunk/source/ps/TemplateLoader.cpp +++ ps/trunk/source/ps/TemplateLoader.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,91 +29,58 @@ static CParamNode NULL_NODE(false); -bool CTemplateLoader::LoadTemplateFile(const std::string& templateName, int depth) +bool CTemplateLoader::LoadTemplateFile(CParamNode& node, std::string_view templateName, bool compositing, int depth) { - // If this file was already loaded, we don't need to do anything - if (m_TemplateFileData.find(templateName) != m_TemplateFileData.end()) + // Handle special case "actor|foo", which does not load 'foo' at all, just uses the name. + if (templateName.compare(0, 6, "actor|") == 0) + { + ConstructTemplateActor(templateName.substr(6), node); return true; - + } // Handle infinite loops more gracefully than running out of stack space and crashing if (depth > 100) { - LOGERROR("Probable infinite inheritance loop in entity template '%s'", templateName.c_str()); + LOGERROR("Probable infinite inheritance loop in entity template '%s'", std::string(templateName)); return false; } - // Handle special case "actor|foo" - if (templateName.find("actor|") == 0) - { - ConstructTemplateActor(templateName.substr(6), m_TemplateFileData[templateName]); - return true; - } - - // Handle special case "bar|foo" size_t pos = templateName.find_first_of('|'); if (pos != std::string::npos) { - std::string prefix = templateName.substr(0, pos); - std::string baseName = templateName.substr(pos+1); - - if (!LoadTemplateFile(baseName, depth+1)) - { - LOGERROR("Failed to load entity template '%s'", baseName.c_str()); + // 'foo|bar' pattern: 'bar' is treated as the parent of 'foo'. + if (!LoadTemplateFile(node, templateName.substr(pos + 1), false, depth + 1)) return false; - } - - VfsPath path = VfsPath(TEMPLATE_ROOT) / L"special" / L"filter" / wstring_from_utf8(prefix + ".xml"); - if (!VfsFileExists(path)) - { - LOGERROR("Invalid subset '%s'", prefix.c_str()); + if (!LoadTemplateFile(node, templateName.substr(0, pos), true, depth + 1)) return false; - } - - CXeromyces xero; - PSRETURN ok = xero.Load(g_VFS, path); - if (ok != PSRETURN_OK) - return false; // (Xeromyces already logged an error with the full filename) - - m_TemplateFileData[templateName] = m_TemplateFileData[baseName]; - CParamNode::LoadXML(m_TemplateFileData[templateName], xero, path.string().c_str()); return true; } - // Normal case: templateName is an XML file: + // Load the data we need to apply on the node. This data may contain special modifiers, + // such as filters, merges, multiplying the parent values, etc. Applying it to paramnode is destructive. + // Find the XML file to load - by default, this assumes the files reside in 'special/filter'. + // If not found there, it will be searched for in 'mixins/', then from the root. + // The reason for this order is that filters are used at runtime, mixins at load time. + std::wstring wtempName = wstring_from_utf8(std::string(templateName) + ".xml"); + VfsPath path = VfsPath(TEMPLATE_ROOT) / L"special" / L"filter" / wtempName; + if (!VfsFileExists(path)) + path = VfsPath(TEMPLATE_ROOT) / L"mixins" / wtempName; + if (!VfsFileExists(path)) + path = VfsPath(TEMPLATE_ROOT) / wtempName; - VfsPath path = VfsPath(TEMPLATE_ROOT) / wstring_from_utf8(templateName + ".xml"); CXeromyces xero; PSRETURN ok = xero.Load(g_VFS, path); if (ok != PSRETURN_OK) return false; // (Xeromyces already logged an error with the full filename) + // If the layer defines an explicit parent, we must load that and apply it before ourselves. int attr_parent = xero.GetAttributeID("parent"); CStr parentName = xero.GetRoot().GetAttributes().GetNamedItem(attr_parent); - if (!parentName.empty()) - { - // To prevent needless complexity in template design, we don't allow |-separated strings as parents - if (parentName.find('|') != parentName.npos) - { - LOGERROR("Invalid parent '%s' in entity template '%s'", parentName.c_str(), templateName.c_str()); - return false; - } - - // Ensure the parent is loaded - if (!LoadTemplateFile(parentName, depth+1)) - { - LOGERROR("Failed to load parent '%s' of entity template '%s'", parentName.c_str(), templateName.c_str()); - return false; - } - - CParamNode& parentData = m_TemplateFileData[parentName]; - - // Initialise this template with its parent - m_TemplateFileData[templateName] = parentData; - } - - // Load the new file into the template data (overriding parent values) - CParamNode::LoadXML(m_TemplateFileData[templateName], xero, wstring_from_utf8(templateName).c_str()); + if (!parentName.empty() && !LoadTemplateFile(node, parentName, compositing, depth + 1)) + return false; + // Load the new file into the template data (overriding parent values). + // TODO: error handling. + CParamNode::LoadXML(node, xero); return true; } @@ -124,13 +91,14 @@ // Strip the .xml extension VfsPath pathstem = pathname.ChangeExtension(L""); // Strip the root from the path - std::wstring name = pathstem.string().substr(ARRAY_SIZE(TEMPLATE_ROOT)-1); + std::wstring_view name = pathstem.string().substr(ARRAY_SIZE(TEMPLATE_ROOT)-1); // We want to ignore template_*.xml templates, since they should never be built in the editor if (name.substr(0, 9) == L"template_") return INFO::OK; - if (name.substr(0, 8) == L"special/") + // Also ignore some subfolders. + if (name.substr(0, 8) == L"special/" || name.substr(0, 7) == L"mixins/") return INFO::OK; templates.push_back(std::string(name.begin(), name.end())); @@ -178,33 +146,35 @@ const CParamNode& CTemplateLoader::GetTemplateFileData(const std::string& templateName) { - // Load the template if necessary - if (!LoadTemplateFile(templateName, 0)) + if (std::unordered_map::const_iterator it = m_TemplateFileData.find(templateName); it != m_TemplateFileData.end()) + return it->second; + + CParamNode ret; + if (!LoadTemplateFile(ret, templateName, false, 0)) { LOGERROR("Failed to load entity template '%s'", templateName.c_str()); return NULL_NODE; } - - return m_TemplateFileData[templateName]; + return m_TemplateFileData.insert_or_assign(templateName, ret).first->second; } -void CTemplateLoader::ConstructTemplateActor(const std::string& actorName, CParamNode& out) +void CTemplateLoader::ConstructTemplateActor(std::string_view actorName, CParamNode& out) { // Copy the actor template out = GetTemplateFileData("special/actor"); // Initialize the actor's name and make it an Atlas selectable entity. - std::wstring actorNameW = wstring_from_utf8(actorName); - std::string name = utf8_from_wstring(CParamNode::EscapeXMLString(actorNameW)); - std::string xml = "" - "" + name + "" - // Arbitrary-sized Footprint definition to make actors' selection outlines show up in Atlas. - "1.0" - "" - "" - "128x128/ellipse.png128x128/ellipse_mask.png" - "" - ""; - - CParamNode::LoadXMLString(out, xml.c_str(), actorNameW.c_str()); + std::string source(actorName); + std::wstring actorNameW = wstring_from_utf8(source); + source = "" + "" + source + "" + // Arbitrary-sized Footprint definition to make actors' selection outlines show up in Atlas. + "1.0" + "" + "" + "128x128/ellipse.png128x128/ellipse_mask.png" + "" + ""; + // We'll assume that actorName is valid XML, otherwise this will fail and report the error anyways. + CParamNode::LoadXMLString(out, source.c_str(), actorNameW.c_str()); } Index: ps/trunk/source/tools/entity/Entity.pm =================================================================== --- ps/trunk/source/tools/entity/Entity.pm +++ ps/trunk/source/tools/entity/Entity.pm @@ -12,7 +12,13 @@ sub get_filename { my ($vfspath, $mod) = @_; - my $fn = "$vfsroot/$mod/simulation/templates/$vfspath.xml"; + my $fn = "$vfsroot/$mod/simulation/templates/special/filter/$vfspath.xml"; + if (not -e $fn) { + $fn = "$vfsroot/$mod/simulation/templates/mixins/$vfspath.xml"; + } + if (not -e $fn) { + $fn = "$vfsroot/$mod/simulation/templates/$vfspath.xml"; + } return $fn; } @@ -136,16 +142,28 @@ sub load_inherited { - my ($vfspath, $mods) = @_; + my ($vfspath, $mods, $base) = @_; + if ($vfspath =~ /\|/) { + my @paths = split(/\|/, $vfspath, 2); + $base = load_inherited($paths[1], $mods, $base); + $base = load_inherited($paths[0], $mods, $base); + return $base + } my $main_mod = get_main_mod($vfspath, $mods); my $layer = load_xml($vfspath, get_file($vfspath, $main_mod)); if ($layer->{Entity}{'@parent'}) { - my $parent = load_inherited($layer->{Entity}{'@parent'}{' content'}, $mods); + my $parent = load_inherited($layer->{Entity}{'@parent'}{' content'}, $mods, $base); apply_layer($parent->{Entity}, $layer->{Entity}); return $parent; } else { - return $layer; + if (not $base) { + return $layer; + } + else { + apply_layer($base->{Entity}, $layer->{Entity}); + return $base + } } } Index: ps/trunk/source/tools/entity/checkrefs.pl =================================================================== --- ps/trunk/source/tools/entity/checkrefs.pl +++ ps/trunk/source/tools/entity/checkrefs.pl @@ -130,7 +130,14 @@ push @files, $path; my $ent = Entity::load_inherited($f, "$mod_list_string"); - push @deps, [ $path, "simulation/templates/" . $ent->{Entity}{'@parent'}{' content'} . ".xml" ] if $ent->{Entity}{'@parent'}; + if ($ent->{Entity}{'@parent'}) + { + my @parents = split(/\|/, $ent->{Entity}{'@parent'}{' content'}); + for my $parentPath (@parents) + { + push @deps, [ $path, "simulation/templates/" . $parentPath . ".xml" ]; + } + } if ($f !~ /^template_/) { @@ -638,6 +645,11 @@ for my $f (sort keys %revdeps) { + if ($f =~ /simulation\/templates\//) + { + next if exists $files{$f =~ s/templates\//templates\/special\/filter\//r}; + next if exists $files{$f =~ s/templates\//templates\/mixins\//r}; + } next if exists $files{$f}; warn "Missing file '$f' referenced by: " . (join ', ', map "'$_'", map vfs_to_relative_to_mods($_), sort @{$revdeps{$f}}) . "\n";