Index: binaries/data/mods/public/simulation/templates/special/generic/builder_entities.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/templates/special/generic/builder_entities.xml
@@ -0,0 +1,29 @@
+
+
+ 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
+
Index: binaries/data/mods/public/simulation/templates/template_unit_infantry.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_infantry.xml
+++ binaries/data/mods/public/simulation/templates/template_unit_infantry.xml
@@ -18,34 +18,7 @@
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
Index: binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml
+++ binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml
@@ -20,34 +20,7 @@
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
Index: binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml
+++ binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml
@@ -2,34 +2,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
Index: source/gui/ObjectTypes/CMiniMap.cpp
===================================================================
--- source/gui/ObjectTypes/CMiniMap.cpp
+++ source/gui/ObjectTypes/CMiniMap.cpp
@@ -744,7 +744,7 @@
float CMiniMap::GetShallowPassageHeight()
{
float shallowPassageHeight = 0.0f;
- CParamNode externalParamNode;
+ CParamNode externalParamNode(nullptr);
CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder");
const CParamNode pathingSettings = externalParamNode.GetChild("Pathfinder").GetChild("PassabilityClasses");
if (pathingSettings.GetChild("default").IsOk() && pathingSettings.GetChild("default").GetChild("MaxWaterDepth").IsOk())
Index: source/gui/Scripting/ScriptFunctions.cpp
===================================================================
--- source/gui/Scripting/ScriptFunctions.cpp
+++ source/gui/Scripting/ScriptFunctions.cpp
@@ -34,6 +34,7 @@
#include "ps/scripting/JSInterface_Mod.h"
#include "ps/scripting/JSInterface_ModIo.h"
#include "ps/scripting/JSInterface_SavedGame.h"
+#include "ps/scripting/JSInterface_TemplateLoader.h"
#include "ps/scripting/JSInterface_UserReport.h"
#include "ps/scripting/JSInterface_VFS.h"
#include "ps/scripting/JSInterface_VisualReplay.h"
@@ -70,6 +71,7 @@
JSI_SavedGame::RegisterScriptFunctions(rq);
JSI_Simulation::RegisterScriptFunctions(rq);
JSI_Sound::RegisterScriptFunctions(rq);
+ JSI_TemplateLoader::RegisterScriptFunctions(rq);
JSI_UserReport::RegisterScriptFunctions(rq);
JSI_VFS::RegisterScriptFunctions_GUI(rq);
JSI_VisualReplay::RegisterScriptFunctions(rq);
Index: source/ps/TemplateLoader.h
===================================================================
--- source/ps/TemplateLoader.h
+++ 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
@@ -43,6 +43,7 @@
*/
class CTemplateLoader
{
+ friend class CParamNode;
public:
CTemplateLoader()
{
@@ -65,6 +66,8 @@
std::vector FindTemplates(const std::string& path, bool includeSubdirectories, ETemplatesType templatesType) const;
private:
+ CParamNode& GetData(const std::string& templateName);
+
/**
* (Re)loads the given template, regardless of whether it exists already,
* and saves into m_TemplateFileData. Also loads any parents that are not yet
Index: source/ps/TemplateLoader.cpp
===================================================================
--- source/ps/TemplateLoader.cpp
+++ 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
@@ -27,7 +27,7 @@
static const wchar_t TEMPLATE_ROOT[] = L"simulation/templates/";
static const wchar_t ACTOR_ROOT[] = L"art/actors/";
-static CParamNode NULL_NODE(false);
+static CParamNode NULL_NODE(nullptr, false);
bool CTemplateLoader::LoadTemplateFile(const std::string& templateName, int depth)
{
@@ -45,7 +45,7 @@
// Handle special case "actor|foo"
if (templateName.find("actor|") == 0)
{
- ConstructTemplateActor(templateName.substr(6), m_TemplateFileData[templateName]);
+ ConstructTemplateActor(templateName.substr(6), m_TemplateFileData.try_emplace(templateName, this).first->second);
return true;
}
@@ -74,8 +74,8 @@
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());
+ m_TemplateFileData.insert_or_assign(templateName, m_TemplateFileData.at(baseName));
+ CParamNode::LoadXML(m_TemplateFileData.at(templateName), xero, path.string().c_str());
return true;
}
@@ -87,32 +87,8 @@
if (ok != PSRETURN_OK)
return false; // (Xeromyces already logged an error with the full filename)
- 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());
+ CParamNode::LoadXML(m_TemplateFileData.try_emplace(templateName, this).first->second, xero, wstring_from_utf8(templateName).c_str());
return true;
}
@@ -185,7 +161,19 @@
return NULL_NODE;
}
- return m_TemplateFileData[templateName];
+ return m_TemplateFileData.at(templateName);
+}
+
+CParamNode& CTemplateLoader::GetData(const std::string& templateName)
+{
+ // Load the template if necessary
+ if (!LoadTemplateFile(templateName, 0))
+ {
+ LOGERROR("Failed to load entity template '%s'", templateName.c_str());
+ return NULL_NODE;
+ }
+
+ return m_TemplateFileData.at(templateName);
}
void CTemplateLoader::ConstructTemplateActor(const std::string& actorName, CParamNode& out)
Index: source/simulation2/components/CCmpAIManager.cpp
===================================================================
--- source/simulation2/components/CCmpAIManager.cpp
+++ source/simulation2/components/CCmpAIManager.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
@@ -330,7 +330,7 @@
CParamNode GetTemplate(const std::string& name)
{
if (!m_TemplateLoader.TemplateExists(name))
- return CParamNode(false);
+ return CParamNode(&m_TemplateLoader, false);
return m_TemplateLoader.GetTemplateFileData(name).GetChild("Entity");
}
Index: source/simulation2/components/CCmpPathfinder.cpp
===================================================================
--- source/simulation2/components/CCmpPathfinder.cpp
+++ source/simulation2/components/CCmpPathfinder.cpp
@@ -67,7 +67,7 @@
// Since this is used as a system component (not loaded from an entity template),
// we can't use the real paramNode (it won't get handled properly when deserializing),
// so load the data from a special XML file.
- CParamNode externalParamNode;
+ CParamNode externalParamNode(nullptr);
CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder");
// Previously all move commands during a turn were
Index: source/simulation2/components/CCmpTerritoryManager.cpp
===================================================================
--- source/simulation2/components/CCmpTerritoryManager.cpp
+++ source/simulation2/components/CCmpTerritoryManager.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
@@ -138,7 +138,7 @@
// Register Relax NG validator
CXeromyces::AddValidator(g_VFS, "territorymanager", "simulation/data/territorymanager.rng");
- CParamNode externalParamNode;
+ CParamNode externalParamNode(nullptr);
CParamNode::LoadXML(externalParamNode, L"simulation/data/territorymanager.xml", "territorymanager");
int impassableCost = externalParamNode.GetChild("TerritoryManager").GetChild("ImpassableCost").ToInt();
Index: source/simulation2/system/ComponentManager.cpp
===================================================================
--- source/simulation2/system/ComponentManager.cpp
+++ source/simulation2/system/ComponentManager.cpp
@@ -665,7 +665,7 @@
void CComponentManager::AddSystemComponents(bool skipScriptedComponents, bool skipAI)
{
- CParamNode noParam;
+ CParamNode noParam(nullptr);
AddComponent(m_SystemEntity, CID_TemplateManager, noParam);
AddComponent(m_SystemEntity, CID_CinemaManager, noParam);
AddComponent(m_SystemEntity, CID_CommandQueue, noParam);
Index: source/simulation2/system/ComponentManagerSerialization.cpp
===================================================================
--- source/simulation2/system/ComponentManagerSerialization.cpp
+++ source/simulation2/system/ComponentManagerSerialization.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
@@ -313,7 +313,7 @@
deserializer.NumberU32_Unbounded("num system component types", numSystemComponentTypes);
ICmpTemplateManager* templateManager = NULL;
- CParamNode noParam;
+ CParamNode noParam(nullptr);
for (size_t i = 0; i < numSystemComponentTypes; ++i)
{
Index: source/simulation2/system/ParamNode.h
===================================================================
--- source/simulation2/system/ParamNode.h
+++ source/simulation2/system/ParamNode.h
@@ -32,6 +32,8 @@
class ScriptRequest;
+class CTemplateLoader;
+
/**
* An entity initialisation parameter node.
* Each node has a text value, plus a number of named child nodes (in a tree structure).
@@ -155,7 +157,7 @@
/**
* Constructs a new, empty node.
*/
- CParamNode(bool isOk = true);
+ CParamNode(CTemplateLoader* templateLoader, bool isOk = true);
/**
* Loads the XML data specified by @a file into the node @a ret.
@@ -274,6 +276,7 @@
* the data getting applied. Used for output to log messages if an error occurs.
*/
void ApplyLayer(const XMBFile& xmb, const XMBElement& element, const wchar_t* sourceIdentifier = NULL);
+ void ApplyLayer(const CParamNode& node);
void ResetScriptVal();
@@ -283,6 +286,8 @@
ChildrenMap m_Childs;
bool m_IsOk;
+ CTemplateLoader* m_TemplateLoader;
+
/**
* Caches the ToJSVal script representation of this node.
*/
Index: source/simulation2/system/ParamNode.cpp
===================================================================
--- source/simulation2/system/ParamNode.cpp
+++ source/simulation2/system/ParamNode.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
@@ -23,6 +23,7 @@
#include "ps/CLogger.h"
#include "ps/CStr.h"
#include "ps/Filesystem.h"
+#include "ps/TemplateLoader.h"
#include "ps/XML/Xeromyces.h"
#include "scriptinterface/ScriptInterface.h"
@@ -31,10 +32,10 @@
#include
#include // this isn't in string.hpp in old Boosts
-static CParamNode g_NullNode(false);
+static CParamNode g_NullNode(nullptr, false);
-CParamNode::CParamNode(bool isOk) :
- m_IsOk(isOk)
+CParamNode::CParamNode(CTemplateLoader* templateLoader, bool isOk) :
+ m_TemplateLoader(templateLoader), m_IsOk(isOk)
{
}
@@ -75,6 +76,7 @@
bool hasSetValue = false;
// Look for special attributes
+ int at_parent = xmb.GetAttributeID("parent");
int at_disable = xmb.GetAttributeID("disable");
int at_replace = xmb.GetAttributeID("replace");
int at_filtered = xmb.GetAttributeID("filtered");
@@ -93,6 +95,10 @@
{
XERO_ITER_ATTR(element, attr)
{
+ if (attr.Name == at_parent)
+ {
+ ApplyLayer(m_TemplateLoader->GetTemplateFileData(attr.Value));
+ }
if (attr.Name == at_disable)
{
m_Childs.erase(name);
@@ -131,7 +137,7 @@
{
if (attr.Name == at_datatype && std::wstring(attr.Value.begin(), attr.Value.end()) == L"tokens")
{
- CParamNode& node = m_Childs[name];
+ CParamNode& node = m_Childs.try_emplace(name, m_TemplateLoader).first->second;
// Split into tokens
std::vector oldTokens;
@@ -169,7 +175,7 @@
}
// Add this element as a child node
- CParamNode& node = m_Childs[name];
+ CParamNode& node = m_Childs.try_emplace(name, m_TemplateLoader).first->second;
if (op != INVALID)
{
// TODO: Support parsing of data types other than fixed; log warnings in other cases
@@ -211,7 +217,7 @@
{
std::string childname = xmb.GetElementString(child.GetNodeName());
if (node.m_Childs.find(childname) != node.m_Childs.end())
- childs[childname] = std::move(node.m_Childs[childname]);
+ childs.try_emplace(childname, std::move(node.m_Childs.at(childname)));
}
}
@@ -222,14 +228,23 @@
XERO_ITER_ATTR(element, attr)
{
// Skip special attributes
- if (attr.Name == at_replace || attr.Name == at_op || attr.Name == at_merge || attr.Name == at_filtered)
+ if (attr.Name == at_parent || attr.Name == at_replace || attr.Name == at_op || attr.Name == at_merge || attr.Name == at_filtered)
continue;
// Add any others
std::string attrName = xmb.GetAttributeString(attr.Name);
- node.m_Childs["@" + attrName].m_Value = attr.Value.FromUTF8();
+ node.m_Childs.try_emplace("@" + attrName, m_TemplateLoader).first->second.m_Value = attr.Value.FromUTF8();
}
}
+void CParamNode::ApplyLayer(const CParamNode& node)
+{
+ ResetScriptVal();
+
+ m_Value = node.m_Value;
+ for (const std::pair& child : node.m_Childs)
+ m_Childs.insert_or_assign(child.first, child.second);
+}
+
const CParamNode& CParamNode::GetChild(const char* name) const
{
ChildrenMap::const_iterator it = m_Childs.find(name);