Index: binaries/data/mods/data_validator/gui/data_validator.js
===================================================================
--- /dev/null
+++ binaries/data/mods/data_validator/gui/data_validator.js
@@ -0,0 +1,76 @@
+var templates = Engine.ListDirectoryFiles("simulation/templates", "*.xml", true);
+var technologies = Engine.ListDirectoryFiles("simulation/data/technologies", "*.json", true)
+ .map(tech => tech.replace("simulation/data/technologies/", "").replace(".json", ""));
+var ressourcesCodes = new Resources().resourceCodes;
+
+let civs = loadCivFiles();
+var civCodes = [];
+for (let civ in civs)
+ civCodes.push(civs[civ].Code);
+
+function validate_techs()
+{
+ var foundTechs = {};
+ // Hardcode a few techs as being seen despite them not being in templates.
+ foundTechs.phase_town = 1;
+ foundTechs.phase_village = 1;
+ foundTechs.phase_city = 1;
+ foundTechs.advanced_unit_bonus = 1;
+ foundTechs.elite_unit_bonus = 1;
+
+ let tokensFormat = /([^ ]+( |$))+/;
+
+ for (let templateName of templates)
+ {
+ if (templateName.indexOf("special/filter") !== -1)
+ continue;
+
+ let template;
+ let techs = [];
+ try {
+ template = Engine.GetTemplate(templateName.replace("simulation/templates/", "").replace(".xml",""));
+ if (!template.ProductionQueue || !template.ProductionQueue.Technologies ||
+ !template.ProductionQueue.Technologies._string)
+ continue;
+ if (!template.ProductionQueue.Technologies._string.match(tokensFormat))
+ warn("Technology tokens of " + templateName + " are not following the proper format: " + template.ProductionQueue.Technologies._string);
+ techs = template.ProductionQueue.Technologies._string.split(" ");
+ } catch(error) {
+ warn("Error parsing " + templateName + ":\n" + error);
+ continue;
+ }
+ for (let tech of techs)
+ {
+ if (tech.startsWith("phase_") && template.Identity.Civ !== "athen")
+ tech = tech.replace("{civ}", "generic");
+ else if (tech.indexOf('{civ}') !== -1)
+ tech = tech.replace('{civ}', template.Identity.Civ);
+
+ let index = technologies.indexOf(tech);
+ if (index === -1)
+ warn("unknown tech " + tech + " referenced by template " + templateName);
+ else
+ {
+ if (!(tech in foundTechs))
+ foundTechs[tech] = 0;
+ ++foundTechs[tech];
+ }
+ }
+ }
+
+ for (let tech of technologies)
+ {
+ let techData = Engine.ReadJSONFile("simulation/data/technologies/" + tech + ".json");
+ if (techData.autoResearch)
+ foundTechs[tech] = 1;
+ if (foundTechs[tech] && techData.top)
+ foundTechs[techData.top] = 1;
+ if (foundTechs[tech] && techData.bottom)
+ foundTechs[techData.bottom] = 1;
+ }
+
+ for (let tech of technologies)
+ if (!(tech in foundTechs))
+ warn("Technology " + tech + " not found in any template.");
+}
+validate_techs();
Index: binaries/data/mods/data_validator/gui/data_validator.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/data_validator/gui/data_validator.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
Index: binaries/data/mods/data_validator/gui/page_pregame.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/data_validator/gui/page_pregame.xml
@@ -0,0 +1,8 @@
+
+
+ common/modern/setup.xml
+ common/modern/styles.xml
+ common/modern/sprites.xml
+
+ data_validator.xml
+
Index: binaries/data/mods/data_validator/mod.json
===================================================================
--- /dev/null
+++ binaries/data/mods/data_validator/mod.json
@@ -0,0 +1,8 @@
+{
+ "name": "data_validator",
+ "version": "0.1",
+ "label": "Data validator",
+ "url": "https://play0ad.com",
+ "description": "Automatically validate files.",
+ "dependencies": []
+}