Ticket #2951: template_subsets.diff
File template_subsets.diff, 36.5 KB (added by , 8 years ago) |
---|
-
new file inaries/data/mods/_test.sim/simulation/templates/special_filter/foundation.xml
From 2d06008d6b32499a28a547abd39946ff1b9fd83f Mon Sep 17 00:00:00 2001 From: leper <leper@wildfiregames.com> Date: Thu, 25 Feb 2016 15:47:31 +0100 Subject: [PATCH] Make special templates (foo|templatename) (apart from actor|) more moddable. Fixes #2951. This moves template additions to xml files. Permitted components are now done via filtered and merge. For adding new nodes while ignoring possible previous values use replace. Some explanation on how to use the new filter templates: * Previously permitted component types should be replaced by <Foo merge=""/>, which does not add the <Foo> node if it wasn't present. * To actually remove the other components the encompassing node should specify filtered="", which will remove all nodes which are present in the original, but not in the filter. * Additions that should be performed while ignoring a possible original node should specify replace="". * To add something to an existing node (or add that node if it does not exist) just use <Foo>...</Foo>. --- .../templates/special_filter/foundation.xml | 45 +++ .../templates/special_filter/construction.xml | 7 + .../simulation/templates/special_filter/corpse.xml | 31 ++ .../templates/special_filter/foundation.xml | 45 +++ .../simulation/templates/special_filter/mirage.xml | 21 ++ .../templates/special_filter/preview.xml | 29 ++ .../templates/special_filter/resource.xml | 29 ++ source/ps/TemplateLoader.cpp | 317 ++------------------- source/ps/TemplateLoader.h | 34 +-- source/simulation2/system/ParamNode.cpp | 27 +- source/simulation2/system/ParamNode.h | 40 ++- source/simulation2/tests/test_ParamNode.h | 18 +- 12 files changed, 320 insertions(+), 323 deletions(-) create mode 100644 binaries/data/mods/_test.sim/simulation/templates/special_filter/foundation.xml create mode 100644 binaries/data/mods/public/simulation/templates/special_filter/construction.xml create mode 100644 binaries/data/mods/public/simulation/templates/special_filter/corpse.xml create mode 100644 binaries/data/mods/public/simulation/templates/special_filter/foundation.xml create mode 100644 binaries/data/mods/public/simulation/templates/special_filter/mirage.xml create mode 100644 binaries/data/mods/public/simulation/templates/special_filter/preview.xml create mode 100644 binaries/data/mods/public/simulation/templates/special_filter/resource.xml diff --git a/binaries/data/mods/_test.sim/simulation/templates/special_filter/foundation.xml b/binaries/data/mods/_test.sim/simulation/templates/special_filter/foundation.xml new file mode 100644 index 0000000..e294934
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <Entity filtered=""> 3 <AIProxy merge=""/> 4 <Armour merge=""/> 5 <BuildRestrictions merge=""/> 6 <!-- Don't provide population bonuses yet (but still do take up population cost) --> 7 <Cost merge=""> 8 <PopulationBonus>0</PopulationBonus> 9 </Cost> 10 <Decay merge=""/> 11 <!-- Initialise health to 1 --> 12 <Health> 13 <Initial>1</Initial> 14 </Health> 15 <Fogging merge=""/> 16 <Footprint merge=""/> 17 <!-- Add the Foundation component, to deal with the construction process --> 18 <Foundation replace=""/> 19 <Health merge=""/> 20 <Identity merge=""/> 21 <!-- Foundations shouldn't initially block unit movement --> 22 <Obstruction merge=""> 23 <DisableBlockMovement>true</DisableBlockMovement> 24 <DisableBlockPathfinding>true</DisableBlockPathfinding> 25 </Obstruction> 26 <OverlayRenderer merge=""/> 27 <Ownership merge=""/> 28 <Position merge=""/> 29 <RallyPoint merge=""/> 30 <RallyPointRenderer merge=""/> 31 <Selectable merge=""/> 32 <Sound merge=""/> 33 <StatusBars merge=""/> 34 <Visibility merge=""/> 35 <!-- Foundations should be visible themselves in fog-of-war if their base template is, 36 but shouldn't have any vision range --> 37 <Vision merge=""> 38 <Range>0</Range> 39 <RevealShore merge="">false</RevealShore> 40 </Vision> 41 <!-- Switch the actor to foundation mode --> 42 <VisualActor> 43 <Foundation/> 44 </VisualActor> 45 </Entity> -
new file inaries/data/mods/public/simulation/templates/special_filter/construction.xml
diff --git a/binaries/data/mods/public/simulation/templates/special_filter/construction.xml b/binaries/data/mods/public/simulation/templates/special_filter/construction.xml new file mode 100644 index 0000000..c7f7da7
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <Entity filtered=""> 3 <Footprint merge=""/> 4 <Ownership merge=""/> 5 <Position merge=""/> 6 <VisualActor merge=""/> 7 </Entity> -
new file inaries/data/mods/public/simulation/templates/special_filter/corpse.xml
diff --git a/binaries/data/mods/public/simulation/templates/special_filter/corpse.xml b/binaries/data/mods/public/simulation/templates/special_filter/corpse.xml new file mode 100644 index 0000000..fe75d3f
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <Entity filtered=""> 3 <!-- We only want to include components which are necessary (for the visual previewing of an entity) 4 and safe (i.e. won't do anything that affects the synchronised simulation state), so additions 5 to this list should be carefully considered --> 6 <Attack merge=""/> <!-- Needed for the Actor Viewer --> 7 <BuildRestrictions merge=""/> 8 <!-- Corpses should include decay components and activate them --> 9 <Decay merge=""> 10 <Active>true</Active> 11 </Decay> 12 <Footprint merge=""/> 13 <Identity merge=""/> 14 <!-- Disable the Obstruction component (if there is one) so it doesn't affect pathfinding 15 (but can still be used for testing this entity for collisions against others) --> 16 <Obstruction merge=""> 17 <Active>false</Active> 18 </Obstruction> 19 <Ownership merge=""/> 20 <Position merge=""/> 21 <Sound merge=""/> <!-- Needed for the Actor Viewer --> 22 <UnitMotion merge=""/> <!-- Needed for the Actor Viewer --> 23 <!-- Corpses should remain visible in fog-of-war (for the owner only) --> 24 <Visibility> 25 <Corpse>true</Corpse> 26 </Visibility> 27 <!-- Corpses shouldn't display silhouettes (especially since they're often half underground) --> 28 <VisualActor merge=""> 29 <SilhouetteDisplay>false</SilhouetteDisplay> 30 </VisualActor> 31 </Entity> -
new file inaries/data/mods/public/simulation/templates/special_filter/foundation.xml
diff --git a/binaries/data/mods/public/simulation/templates/special_filter/foundation.xml b/binaries/data/mods/public/simulation/templates/special_filter/foundation.xml new file mode 100644 index 0000000..e294934
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <Entity filtered=""> 3 <AIProxy merge=""/> 4 <Armour merge=""/> 5 <BuildRestrictions merge=""/> 6 <!-- Don't provide population bonuses yet (but still do take up population cost) --> 7 <Cost merge=""> 8 <PopulationBonus>0</PopulationBonus> 9 </Cost> 10 <Decay merge=""/> 11 <!-- Initialise health to 1 --> 12 <Health> 13 <Initial>1</Initial> 14 </Health> 15 <Fogging merge=""/> 16 <Footprint merge=""/> 17 <!-- Add the Foundation component, to deal with the construction process --> 18 <Foundation replace=""/> 19 <Health merge=""/> 20 <Identity merge=""/> 21 <!-- Foundations shouldn't initially block unit movement --> 22 <Obstruction merge=""> 23 <DisableBlockMovement>true</DisableBlockMovement> 24 <DisableBlockPathfinding>true</DisableBlockPathfinding> 25 </Obstruction> 26 <OverlayRenderer merge=""/> 27 <Ownership merge=""/> 28 <Position merge=""/> 29 <RallyPoint merge=""/> 30 <RallyPointRenderer merge=""/> 31 <Selectable merge=""/> 32 <Sound merge=""/> 33 <StatusBars merge=""/> 34 <Visibility merge=""/> 35 <!-- Foundations should be visible themselves in fog-of-war if their base template is, 36 but shouldn't have any vision range --> 37 <Vision merge=""> 38 <Range>0</Range> 39 <RevealShore merge="">false</RevealShore> 40 </Vision> 41 <!-- Switch the actor to foundation mode --> 42 <VisualActor> 43 <Foundation/> 44 </VisualActor> 45 </Entity> -
new file inaries/data/mods/public/simulation/templates/special_filter/mirage.xml
diff --git a/binaries/data/mods/public/simulation/templates/special_filter/mirage.xml b/binaries/data/mods/public/simulation/templates/special_filter/mirage.xml new file mode 100644 index 0000000..565456d
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <Entity filtered=""> 3 <Footprint merge=""/> 4 <Identity filtered=""> 5 <Civ merge=""/> 6 <GenericName merge=""/> 7 <SpecificName merge=""/> 8 <Tooltip merge=""/> 9 <History merge=""/> 10 <Icon merge=""/> 11 </Identity> 12 <Minimap merge=""/> 13 <Mirage replace=""/> 14 <Ownership merge=""/> 15 <OverlayRenderer merge=""/> 16 <Position merge=""/> 17 <Selectable merge=""/> 18 <StatusBars merge=""/> 19 <Visibility merge=""/> 20 <VisualActor merge=""/> 21 </Entity> -
new file inaries/data/mods/public/simulation/templates/special_filter/preview.xml
diff --git a/binaries/data/mods/public/simulation/templates/special_filter/preview.xml b/binaries/data/mods/public/simulation/templates/special_filter/preview.xml new file mode 100644 index 0000000..9ae9cf9
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <Entity filtered=""> 3 <!-- We only want to include components which are necessary (for the visual previewing of an entity) 4 and safe (i.e. won't do anything that affects the synchronised simulation state), so additions 5 to this list should be carefully considered --> 6 <Attack merge=""/> <!-- Needed for the Actor Viewer --> 7 <BuildRestrictions merge=""/> 8 <Decay merge=""/> 9 <Footprint merge=""/> 10 <Identity merge=""/> 11 <!-- Disable the Obstruction component (if there is one) so it doesn't affect pathfinding 12 (but can still be used for testing this entity for collisions against others) --> 13 <Obstruction merge=""> 14 <Active>false</Active> 15 </Obstruction> 16 <Ownership merge=""/> 17 <Position merge=""/> 18 <Sound merge=""/> <!-- Needed for the Actor Viewer --> 19 <UnitMotion merge=""/> <!-- Needed for the Actor Viewer --> 20 <!-- Previews should always be visible in fog-of-war/etc --> 21 <Visibility> 22 <AlwaysVisible>true</AlwaysVisible> 23 <Preview>true</Preview> 24 </Visibility> 25 <!-- Previews should not cast shadows --> 26 <VisualActor merge=""> 27 <DisableShadows/> 28 </VisualActor> 29 </Entity> -
new file inaries/data/mods/public/simulation/templates/special_filter/resource.xml
diff --git a/binaries/data/mods/public/simulation/templates/special_filter/resource.xml b/binaries/data/mods/public/simulation/templates/special_filter/resource.xml new file mode 100644 index 0000000..ee62748
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <Entity filtered=""> 3 <AIProxy merge=""/> 4 <Footprint merge=""/> 5 <Identity merge=""/> 6 <Minimap merge=""/> 7 <!-- When dying, resources lose the unitMotion component, this causes them to have no clearance. 8 Since unit obstructions no longer have a radius, this makes them unreachable in some cases (see #3530). 9 Instead, create a static, unblocking (see #3530 for why) static obstruction. 10 TODO: this should probably be generalized as a parameter on entity death or something. 11 --> 12 <Obstruction replace=""> 13 <Active>true</Active> 14 <BlockMovement>false</BlockMovement> 15 <BlockPathfinding>false</BlockPathfinding> 16 <BlockFoundation>false</BlockFoundation> 17 <BlockConstruction>false</BlockConstruction> 18 <DisableBlockMovement>false</DisableBlockMovement> 19 <DisableBlockPathfinding>false</DisableBlockPathfinding> 20 <Static width="2.0" depth="2.0"/> 21 </Obstruction> 22 <OverlayRenderer merge=""/> 23 <Ownership merge=""/> 24 <Position merge=""/> 25 <ResourceSupply merge=""/> 26 <Selectable merge=""/> 27 <StatusBars merge=""/> 28 <VisualActor merge=""/> 29 </Entity> -
source/ps/TemplateLoader.cpp
diff --git a/source/ps/TemplateLoader.cpp b/source/ps/TemplateLoader.cpp index a9d067b..88701ac 100644
a b 1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … static const wchar_t ACTOR_ROOT[] = L"art/actors/"; 29 29 30 30 static CParamNode NULL_NODE(false); 31 31 32 33 32 bool CTemplateLoader::LoadTemplateFile(const std::string& templateName, int depth) 34 33 { 35 34 // If this file was already loaded, we don't need to do anything … … bool CTemplateLoader::LoadTemplateFile(const std::string& templateName, int dept 50 49 return true; 51 50 } 52 51 53 // Handle special case "preview|foo" 54 if (templateName.find("preview|") == 0) 52 // Handle special case "bar|foo" 53 size_t pos = templateName.find_first_of('|'); 54 if (pos != std::string::npos) 55 55 { 56 // Load the base entity template, if it wasn't already loaded 57 std::string baseName = templateName.substr(8); 56 std::string prefix = templateName.substr(0, pos); 57 std::string baseName = templateName.substr(pos+1); 58 58 59 if (!LoadTemplateFile(baseName, depth+1)) 59 60 { 60 61 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 61 62 return false; 62 63 } 63 // Copy a subset to the requested template64 CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], false);65 return true;66 }67 64 68 // Handle special case "corpse|foo" 69 if (templateName.find("corpse|") == 0) 70 { 71 // Load the base entity template, if it wasn't already loaded 72 std::string baseName = templateName.substr(7); 73 if (!LoadTemplateFile(baseName, depth+1)) 65 VfsPath path = VfsPath(TEMPLATE_ROOT) / L"special_filter" / wstring_from_utf8(prefix + ".xml"); 66 if (!VfsFileExists(path)) 74 67 { 75 LOGERROR(" Failed to load entity template '%s'", baseName.c_str());68 LOGERROR("Invalid subset '%s'", prefix.c_str()); 76 69 return false; 77 70 } 78 // Copy a subset to the requested template79 CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], true);80 return true;81 }82 71 83 // Handle special case "mirage|foo" 84 if (templateName.find("mirage|") == 0) 85 { 86 // Load the base entity template, if it wasn't already loaded 87 std::string baseName = templateName.substr(7); 88 if (!LoadTemplateFile(baseName, depth+1)) 89 { 90 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 91 return false; 92 } 93 // Copy a subset to the requested template 94 CopyMirageSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]); 95 return true; 96 } 72 CXeromyces xero; 73 PSRETURN ok = xero.Load(g_VFS, path); 74 if (ok != PSRETURN_OK) 75 return false; // (Xeromyces already logged an error with the full filename) 97 76 98 // Handle special case "foundation|foo" 99 if (templateName.find("foundation|") == 0) 100 { 101 // Load the base entity template, if it wasn't already loaded 102 std::string baseName = templateName.substr(11); 103 if (!LoadTemplateFile(baseName, depth+1)) 104 { 105 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 106 return false; 107 } 108 // Copy a subset to the requested template 109 CopyFoundationSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]); 110 return true; 111 } 112 113 // Handle special case "construction|foo" 114 if (templateName.find("construction|") == 0) 115 { 116 // Load the base entity template, if it wasn't already loaded 117 std::string baseName = templateName.substr(13); 118 if (!LoadTemplateFile(baseName, depth+1)) 119 { 120 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 121 return false; 122 } 123 // Copy a subset to the requested template 124 CopyConstructionSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]); 125 return true; 126 } 127 128 // Handle special case "resource|foo" 129 if (templateName.find("resource|") == 0) 130 { 131 // Load the base entity template, if it wasn't already loaded 132 std::string baseName = templateName.substr(9); 133 if (!LoadTemplateFile(baseName, depth+1)) 134 { 135 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 136 return false; 137 } 138 // Copy a subset to the requested template 139 CopyResourceSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]); 77 m_TemplateFileData[templateName] = m_TemplateFileData[baseName]; 78 CParamNode::LoadXML(m_TemplateFileData[templateName], xero, path.string().c_str()); 140 79 return true; 141 80 } 142 81 … … bool CTemplateLoader::TemplateExists(const std::string& templateName) const 215 154 216 155 std::vector<std::string> CTemplateLoader::FindPlaceableTemplates(const std::string& path, bool includeSubdirectories, ETemplatesType templatesType, ScriptInterface& scriptInterface) 217 156 { 157 if (templatesType != SIMULATION_TEMPLATES && templatesType != ACTOR_TEMPLATES && templatesType != ALL_TEMPLATES) 158 { 159 LOGERROR("Undefined template type (valid: all, simulation, actor)"); 160 return std::vector<std::string>(); 161 } 162 218 163 JSContext* cx = scriptInterface.GetContext(); 219 164 JSAutoRequest rq(cx); 220 165 … … std::vector<std::string> CTemplateLoader::FindPlaceableTemplates(const std::stri 222 167 Status ok; 223 168 VfsPath templatePath; 224 169 225 226 170 if (templatesType == SIMULATION_TEMPLATES || templatesType == ALL_TEMPLATES) 227 171 { 228 172 JS::RootedValue placeablesFilter(cx); … … std::vector<std::string> CTemplateLoader::FindPlaceableTemplates(const std::stri 289 233 WARN_IF_ERR(ok); 290 234 } 291 235 292 if (templatesType != SIMULATION_TEMPLATES && templatesType != ACTOR_TEMPLATES && templatesType != ALL_TEMPLATES)293 LOGERROR("Undefined template type (valid: all, simulation, actor)");294 295 236 return templates; 296 237 } 297 238 … … std::vector<std::string> CTemplateLoader::FindTemplates(const std::string& path, 299 240 { 300 241 std::vector<std::string> templates; 301 242 243 if (templatesType != SIMULATION_TEMPLATES && templatesType != ACTOR_TEMPLATES && templatesType != ALL_TEMPLATES) 244 { 245 LOGERROR("Undefined template type (valid: all, simulation, actor)"); 246 return templates; 247 } 248 302 249 Status ok; 303 250 VfsPath templatePath; 251 size_t flags = includeSubdirectories ? vfs::DIR_RECURSIVE : 0; 304 252 305 253 if (templatesType == SIMULATION_TEMPLATES || templatesType == ALL_TEMPLATES) 306 254 { 307 255 templatePath = VfsPath(TEMPLATE_ROOT) / path; 308 if (includeSubdirectories) 309 ok = vfs::ForEachFile(g_VFS, templatePath, AddToTemplates, (uintptr_t)&templates, L"*.xml", vfs::DIR_RECURSIVE); 310 else 311 ok = vfs::ForEachFile(g_VFS, templatePath, AddToTemplates, (uintptr_t)&templates, L"*.xml"); 256 ok = vfs::ForEachFile(g_VFS, templatePath, AddToTemplates, (uintptr_t)&templates, L"*.xml", flags); 312 257 WARN_IF_ERR(ok); 313 258 } 314 259 if (templatesType == ACTOR_TEMPLATES || templatesType == ALL_TEMPLATES) 315 260 { 316 261 templatePath = VfsPath(ACTOR_ROOT) / path; 317 if (includeSubdirectories) 318 ok = vfs::ForEachFile(g_VFS, templatePath, AddActorToTemplates, (uintptr_t)&templates, L"*.xml", vfs::DIR_RECURSIVE); 319 else 320 ok = vfs::ForEachFile(g_VFS, templatePath, AddActorToTemplates, (uintptr_t)&templates, L"*.xml"); 262 ok = vfs::ForEachFile(g_VFS, templatePath, AddActorToTemplates, (uintptr_t)&templates, L"*.xml", flags); 321 263 WARN_IF_ERR(ok); 322 264 } 323 265 324 if (templatesType != SIMULATION_TEMPLATES && templatesType != ACTOR_TEMPLATES && templatesType != ALL_TEMPLATES)325 LOGERROR("Undefined template type (valid: all, simulation, actor)");326 327 266 return templates; 328 267 } 329 268 … … void CTemplateLoader::ConstructTemplateActor(const std::string& actorName, CPara 367 306 368 307 CParamNode::LoadXMLString(out, xml.c_str(), actorNameW.c_str()); 369 308 } 370 371 void CTemplateLoader::CopyPreviewSubset(CParamNode& out, const CParamNode& in, bool corpse)372 {373 // We only want to include components which are necessary (for the visual previewing of an entity)374 // and safe (i.e. won't do anything that affects the synchronised simulation state), so additions375 // to this list should be carefully considered376 std::set<std::string> permittedComponentTypes;377 permittedComponentTypes.insert("Identity");378 permittedComponentTypes.insert("Ownership");379 permittedComponentTypes.insert("Position");380 permittedComponentTypes.insert("Visibility");381 permittedComponentTypes.insert("VisualActor");382 permittedComponentTypes.insert("Footprint");383 permittedComponentTypes.insert("Obstruction");384 permittedComponentTypes.insert("Decay");385 permittedComponentTypes.insert("BuildRestrictions");386 387 // Need these for the Actor Viewer:388 permittedComponentTypes.insert("Attack");389 permittedComponentTypes.insert("UnitMotion");390 permittedComponentTypes.insert("Sound");391 392 // (This set could be initialised once and reused, but it's not worth the effort)393 394 CParamNode::LoadXMLString(out, "<Entity/>");395 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);396 397 // Disable the Obstruction component (if there is one) so it doesn't affect pathfinding398 // (but can still be used for testing this entity for collisions against others)399 if (out.GetChild("Entity").GetChild("Obstruction").IsOk())400 CParamNode::LoadXMLString(out, "<Entity><Obstruction><Active>false</Active></Obstruction></Entity>");401 402 if (!corpse)403 {404 // Previews should not cast shadows405 if (out.GetChild("Entity").GetChild("VisualActor").IsOk())406 CParamNode::LoadXMLString(out, "<Entity><VisualActor><DisableShadows/></VisualActor></Entity>");407 408 // Previews should always be visible in fog-of-war/etc409 CParamNode::LoadXMLString(out, "<Entity><Visibility><AlwaysVisible>true</AlwaysVisible><Preview>true</Preview></Visibility></Entity>");410 }411 412 if (corpse)413 {414 // Corpses should include decay components and activate them415 if (out.GetChild("Entity").GetChild("Decay").IsOk())416 CParamNode::LoadXMLString(out, "<Entity><Decay><Active>true</Active></Decay></Entity>");417 418 // Corpses shouldn't display silhouettes (especially since they're often half underground)419 if (out.GetChild("Entity").GetChild("VisualActor").IsOk())420 CParamNode::LoadXMLString(out, "<Entity><VisualActor><SilhouetteDisplay>false</SilhouetteDisplay></VisualActor></Entity>");421 422 // Corpses should remain visible in fog-of-war (for the owner only)423 CParamNode::LoadXMLString(out, "<Entity><Visibility><Corpse>true</Corpse></Visibility></Entity>");424 }425 }426 427 void CTemplateLoader::CopyMirageSubset(CParamNode& out, const CParamNode& in)428 {429 // Currently used for mirage entities replacing real ones in fog-of-war430 431 std::set<std::string> permittedComponentTypes;432 permittedComponentTypes.insert("Footprint");433 permittedComponentTypes.insert("Minimap");434 permittedComponentTypes.insert("Ownership");435 permittedComponentTypes.insert("OverlayRenderer");436 permittedComponentTypes.insert("Position");437 permittedComponentTypes.insert("Selectable");438 permittedComponentTypes.insert("StatusBars");439 permittedComponentTypes.insert("Visibility");440 permittedComponentTypes.insert("VisualActor");441 442 CParamNode::LoadXMLString(out, "<Entity/>");443 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);444 445 // Select a subset of identity data. We don't want to have, for example, a CC mirage446 // that has also the CC class and then prevents construction of other CCs447 std::set<std::string> identitySubset;448 identitySubset.insert("Civ");449 identitySubset.insert("GenericName");450 identitySubset.insert("SpecificName");451 identitySubset.insert("Tooltip");452 identitySubset.insert("History");453 identitySubset.insert("Icon");454 CParamNode identity;455 CParamNode::LoadXMLString(identity, "<Identity/>");456 identity.CopyFilteredChildrenOfChild(in.GetChild("Entity"), "Identity", identitySubset);457 CParamNode::LoadXMLString(out, ("<Entity>"+utf8_from_wstring(identity.ToXML())+"</Entity>").c_str());458 459 // Set the entity as mirage entity460 CParamNode::LoadXMLString(out, "<Entity><Mirage/></Entity>");461 }462 463 void CTemplateLoader::CopyFoundationSubset(CParamNode& out, const CParamNode& in)464 {465 // TODO: this is all kind of yucky and hard-coded; it'd be nice to have a more generic466 // extensible scriptable way to define these subsets467 468 std::set<std::string> permittedComponentTypes;469 permittedComponentTypes.insert("Ownership");470 permittedComponentTypes.insert("Position");471 permittedComponentTypes.insert("VisualActor");472 permittedComponentTypes.insert("Identity");473 permittedComponentTypes.insert("BuildRestrictions");474 permittedComponentTypes.insert("Obstruction");475 permittedComponentTypes.insert("Selectable");476 permittedComponentTypes.insert("Footprint");477 permittedComponentTypes.insert("Fogging");478 permittedComponentTypes.insert("Armour");479 permittedComponentTypes.insert("Health");480 permittedComponentTypes.insert("StatusBars");481 permittedComponentTypes.insert("OverlayRenderer");482 permittedComponentTypes.insert("Decay");483 permittedComponentTypes.insert("Cost");484 permittedComponentTypes.insert("Sound");485 permittedComponentTypes.insert("Visibility");486 permittedComponentTypes.insert("Vision");487 permittedComponentTypes.insert("AIProxy");488 permittedComponentTypes.insert("RallyPoint");489 permittedComponentTypes.insert("RallyPointRenderer");490 491 CParamNode::LoadXMLString(out, "<Entity/>");492 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);493 494 // Switch the actor to foundation mode495 CParamNode::LoadXMLString(out, "<Entity><VisualActor><Foundation/></VisualActor></Entity>");496 497 // Add the Foundation component, to deal with the construction process498 CParamNode::LoadXMLString(out, "<Entity><Foundation/></Entity>");499 500 // Initialise health to 1501 CParamNode::LoadXMLString(out, "<Entity><Health><Initial>1</Initial></Health></Entity>");502 503 // Foundations shouldn't initially block unit movement504 if (out.GetChild("Entity").GetChild("Obstruction").IsOk())505 CParamNode::LoadXMLString(out, "<Entity><Obstruction><DisableBlockMovement>true</DisableBlockMovement><DisableBlockPathfinding>true</DisableBlockPathfinding></Obstruction></Entity>");506 507 // Don't provide population bonuses yet (but still do take up population cost)508 if (out.GetChild("Entity").GetChild("Cost").IsOk())509 CParamNode::LoadXMLString(out, "<Entity><Cost><PopulationBonus>0</PopulationBonus></Cost></Entity>");510 511 // Foundations should be visible themselves in fog-of-war if their base template is,512 // but shouldn't have any vision range513 if (out.GetChild("Entity").GetChild("Vision").IsOk())514 {515 CParamNode::LoadXMLString(out, "<Entity><Vision><Range>0</Range></Vision></Entity>");516 // Foundations should not have special vision capabilities either517 if (out.GetChild("Entity").GetChild("Vision").GetChild("RevealShore").IsOk())518 CParamNode::LoadXMLString(out, "<Entity><Vision><RevealShore>false</RevealShore></Vision></Entity>");519 }520 }521 522 void CTemplateLoader::CopyConstructionSubset(CParamNode& out, const CParamNode& in)523 {524 // Currently used for buildings rising during construction525 // Mostly serves to filter out components like Vision, UnitAI, etc.526 std::set<std::string> permittedComponentTypes;527 permittedComponentTypes.insert("Footprint");528 permittedComponentTypes.insert("Ownership");529 permittedComponentTypes.insert("Position");530 permittedComponentTypes.insert("VisualActor");531 532 CParamNode::LoadXMLString(out, "<Entity/>");533 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);534 }535 536 void CTemplateLoader::CopyResourceSubset(CParamNode& out, const CParamNode& in)537 {538 // Currently used for animals which die and leave a gatherable corpse.539 // Mostly serves to filter out components like Vision, UnitAI, etc.540 // Don't emit sound as our samples only apply to living animals.541 std::set<std::string> permittedComponentTypes;542 permittedComponentTypes.insert("Ownership");543 permittedComponentTypes.insert("Position");544 permittedComponentTypes.insert("VisualActor");545 permittedComponentTypes.insert("Identity");546 permittedComponentTypes.insert("Minimap");547 permittedComponentTypes.insert("ResourceSupply");548 permittedComponentTypes.insert("Selectable");549 permittedComponentTypes.insert("Footprint");550 permittedComponentTypes.insert("StatusBars");551 permittedComponentTypes.insert("OverlayRenderer");552 permittedComponentTypes.insert("AIProxy");553 554 CParamNode::LoadXMLString(out, "<Entity/>");555 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);556 557 // When dying, resources lose the unitMotion component558 // This causes them to have no clearance. Since unit obstructions no longer have a radius,559 // this makes them unreachable in some cases (see #3530).560 // Instead, create a static, unblocking (see #3530 for why) static obstruction.561 // TODO: this should probably be generalized as a parameter on entity death or something.562 CParamNode::LoadXMLString(out, "<Entity><Obstruction><Active>true</Active><BlockMovement>false</BlockMovement><BlockPathfinding>false</BlockPathfinding><BlockFoundation>false</BlockFoundation><BlockConstruction>false</BlockConstruction><DisableBlockMovement>false</DisableBlockMovement><DisableBlockPathfinding>false</DisableBlockPathfinding><Static width=\"2.0\" depth=\"2.0\"/></Obstruction></Entity>");563 } -
source/ps/TemplateLoader.h
diff --git a/source/ps/TemplateLoader.h b/source/ps/TemplateLoader.h index c34d303..d2a6514 100644
a b 1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … public: 48 48 CTemplateLoader() 49 49 { 50 50 } 51 51 52 52 /** 53 53 * Provides the file data for requested template. 54 54 */ … … private: 81 81 */ 82 82 void ConstructTemplateActor(const std::string& actorName, CParamNode& out); 83 83 84 /**85 * Copy the non-interactive components of an entity template (position, actor, etc) into86 * a new entity template87 */88 void CopyPreviewSubset(CParamNode& out, const CParamNode& in, bool corpse);89 90 /**91 * Copy the components of an entity template necessary for a fogged "mirage"92 * entity (position, actor) into a new entity template93 */94 void CopyMirageSubset(CParamNode& out, const CParamNode& in);95 96 /**97 * Copy the components of an entity template necessary for a construction foundation98 * (position, actor, armour, health, etc) into a new entity template99 */100 void CopyFoundationSubset(CParamNode& out, const CParamNode& in);101 102 /**103 * Copy the components of an entity template necessary for a non-foundation construction entity104 * into a new entity template105 */106 void CopyConstructionSubset(CParamNode& out, const CParamNode& in);107 108 /**109 * Copy the components of an entity template necessary for a gatherable resource110 * into a new entity template111 */112 void CopyResourceSubset(CParamNode& out, const CParamNode& in);113 114 84 /** 115 85 * Map from template name (XML filename or special |-separated string) to the most recently 116 86 * loaded non-broken template data. This includes files that will fail schema validation. -
source/simulation2/system/ParamNode.cpp
diff --git a/source/simulation2/system/ParamNode.cpp b/source/simulation2/system/ParamNode.cpp index 173117b..74ca203 100644
a b 1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const 76 76 // Look for special attributes 77 77 int at_disable = xmb.GetAttributeID("disable"); 78 78 int at_replace = xmb.GetAttributeID("replace"); 79 int at_filtered = xmb.GetAttributeID("filtered"); 80 int at_merge = xmb.GetAttributeID("merge"); 79 81 int at_op = xmb.GetAttributeID("op"); 80 82 int at_datatype = xmb.GetAttributeID("datatype"); 81 83 enum op { … … void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const 84 86 MUL 85 87 } op = INVALID; 86 88 bool replacing = false; 89 bool filtering = false; 87 90 { 88 91 XERO_ITER_ATTR(element, attr) 89 92 { … … void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const 97 100 m_Childs.erase(name); 98 101 replacing = true; 99 102 } 103 else if (attr.Name == at_filtered) 104 { 105 filtering = true; 106 } 107 else if (attr.Name == at_merge) 108 { 109 if (m_Childs.find(name) == m_Childs.end()) 110 return; 111 } 100 112 else if (attr.Name == at_op) 101 113 { 102 114 if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"add") … … void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const 150 162 } 151 163 } 152 164 165 // For the filtered case 166 ChildrenMap childs; 167 153 168 // Add this element as a child node 154 169 CParamNode& node = m_Childs[name]; 155 170 if (op != INVALID) … … void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const 175 190 XERO_ITER_EL(element, child) 176 191 { 177 192 node.ApplyLayer(xmb, child, sourceIdentifier); 193 if (filtering) 194 { 195 std::string childname = xmb.GetElementString(child.GetNodeName()); // TODO: is GetElementString inefficient? (especially if we call it twice) 196 childs[childname] = std::move(node.m_Childs[childname]); 197 } 178 198 } 179 199 200 if (filtering) 201 node.m_Childs.swap(childs); 202 180 203 // Add the element's attributes, prefixing names with "@" 181 204 XERO_ITER_ATTR(element, attr) 182 205 { 183 206 // Skip special attributes 184 if (attr.Name == at_replace || attr.Name == at_op )207 if (attr.Name == at_replace || attr.Name == at_op || attr.Name == at_merge || attr.Name == at_filtered) 185 208 continue; 186 209 // Add any others 187 210 std::string attrName = xmb.GetAttributeString(attr.Name); -
source/simulation2/system/ParamNode.h
diff --git a/source/simulation2/system/ParamNode.h b/source/simulation2/system/ParamNode.h index 4fc911f..9ce530e 100644
a b 1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … class XMBElement; 58 58 * <Example4 datatype="tokens"> 59 59 * one two three 60 60 * </Example4> 61 * <Example5> 62 * <E/> 63 * <F> 64 * <I>test</I> 65 * </F> 66 * <H> 67 * <J>example</J> 68 * </H> 69 * </Example5> 61 70 * </Entity> 62 71 * @endcode 63 72 * then a second like: … … class XMBElement; 75 84 * four <!-- add a token to the parent's set --> 76 85 * -two <!-- remove a token from the parent's set --> 77 86 * </Example4> 87 * <Example5 filtered=""> <!-- drop all children of this node that are not in this file --> 88 * <F merge=""> <!-- only add this element if it is also present in the parent --> 89 * <K>example</K> <!-- if F is present merge its children normally --> 90 * </F> 91 * <G merge=""/> <!-- keep the G element of the parent if it exists --> 92 * <H> 93 * <J>text</J> 94 * </H> 95 * </Example5> 78 96 * </Entity> 79 97 * @endcode 80 98 * is equivalent to loading a single file like: … … class XMBElement; 90 108 * <Example4> 91 109 * one three four 92 110 * </Example4> 111 * <Example5> 112 * <F> 113 * <I>test</I> 114 * <K>example</K> 115 * </F> 116 * <H> 117 * <J>text</J> 118 * </H> 119 * </Example5> 93 120 * </Entity> 94 121 * @endcode 95 122 * … … class XMBElement; 103 130 * "Example3": { 104 131 * "D": "new" 105 132 * }, 106 * "Example4": { "@datatype": "tokens", "_string": "one three four" } 133 * "Example4": { "@datatype": "tokens", "_string": "one three four" }, 134 * "Example5": { 135 * "F": { 136 * "I": "test", 137 * "K": "example" 138 * }, 139 * "H": { 140 * "J": "text" 141 * } 142 * } 107 143 * } 108 144 * } 109 145 * @endcode -
source/simulation2/tests/test_ParamNode.h
diff --git a/source/simulation2/tests/test_ParamNode.h b/source/simulation2/tests/test_ParamNode.h index 043554b..d329424 100644
a b 1 /* Copyright (C) 201 0Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … public: 135 135 TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a datatype=\"tokens\">Y X</a></test>"); 136 136 } 137 137 138 void test_overlay_filtered() 139 { 140 CParamNode node; 141 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a><b/></a> <c>toberemoved</c> <d><e/></d> </test>"), PSRETURN_OK); 142 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test filtered=\"\"> <a/> <d><f/></d> <g/> </test>"), PSRETURN_OK); 143 TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a><b></b></a><d><e></e><f></f></d><g></g></test>"); 144 } 145 146 void test_overlay_merge() 147 { 148 CParamNode node; 149 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a><b>foo</b><c>bar</c></a> <x><y><z>foo</z></y></x> </test>"), PSRETURN_OK); 150 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a merge=\"\"><b>test</b><d>baz</d></a> <i merge=\"\"><j>willnotbeincluded</j></i> <x merge=\"\"><y merge=\"\"><v>text</v></y><w>more text</w></x> </test>"), PSRETURN_OK); 151 TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a><b>test</b><c>bar</c><d>baz</d></a><x><w>more text</w><y><v>text</v><z>foo</z></y></x></test>"); 152 } 153 138 154 void test_types() 139 155 { 140 156 CParamNode node;