Ticket #2951: 2951_template_subsets_v2.diff
File 2951_template_subsets_v2.diff, 39.8 KB (added by , 8 years ago) |
---|
-
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..c1e20b5
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <Entity filtered=""> 3 <!-- 4 We only want to include components which are necessary (for the visual previewing of an entity) 5 and safe (i.e. won't do anything that affects the synchronised simulation state), so additions 6 to this list should be carefully considered. 7 The Attack, Sound and UnitMotion components are needed for the Actor Viewer. 8 --> 9 <Attack merge=""/> 10 <BuildRestrictions merge=""/> 11 <!-- Corpses should include decay components and activate them --> 12 <Decay merge=""> 13 <Active>true</Active> 14 </Decay> 15 <Footprint merge=""/> 16 <Identity merge=""/> 17 <!-- Disable the Obstruction component (if there is one) so it doesn't affect pathfinding 18 (but can still be used for testing this entity for collisions against others) --> 19 <Obstruction merge=""> 20 <Active>false</Active> 21 </Obstruction> 22 <Ownership merge=""/> 23 <Position merge=""/> 24 <Sound merge=""/> 25 <UnitMotion merge=""/> 26 <!-- Corpses should remain visible in fog-of-war (for the owner only) --> 27 <Visibility> 28 <Corpse>true</Corpse> 29 </Visibility> 30 <!-- Corpses shouldn't display silhouettes (especially since they're often half underground) --> 31 <VisualActor merge=""> 32 <SilhouetteDisplay>false</SilhouetteDisplay> 33 </VisualActor> 34 </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..99b0e87
- + 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 <Fogging merge=""/> 12 <Footprint merge=""/> 13 <!-- Add the Foundation component, to deal with the construction process --> 14 <Foundation replace=""/> 15 <Health> 16 <Initial>1</Initial> 17 </Health> 18 <Identity merge=""/> 19 <Market merge=""/> 20 <!-- Foundations shouldn't initially block unit movement --> 21 <Obstruction merge=""> 22 <DisableBlockMovement>true</DisableBlockMovement> 23 <DisableBlockPathfinding>true</DisableBlockPathfinding> 24 </Obstruction> 25 <OverlayRenderer merge=""/> 26 <Ownership merge=""/> 27 <Position merge=""/> 28 <RallyPoint merge=""/> 29 <RallyPointRenderer merge=""/> 30 <Selectable merge=""/> 31 <Sound merge=""/> 32 <StatusBars merge=""/> 33 <Visibility merge=""/> 34 <!-- Foundations should be visible themselves in fog-of-war if their base template is, 35 but shouldn't have any vision range --> 36 <Vision merge=""> 37 <Range>0</Range> 38 <RevealShore>false</RevealShore> 39 </Vision> 40 <!-- Switch the actor to foundation mode --> 41 <VisualActor> 42 <Foundation/> 43 </VisualActor> 44 </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..8f86013
- + 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 <Obstruction merge=""> 15 <BlockMovement>false</BlockMovement> 16 <BlockPathfinding>false</BlockPathfinding> 17 <BlockFoundation>false</BlockFoundation> 18 <BlockConstruction>false</BlockConstruction> 19 </Obstruction> 20 <Ownership merge=""/> 21 <OverlayRenderer merge=""/> 22 <Position merge=""/> 23 <Selectable merge=""/> 24 <StatusBars merge=""/> 25 <Visibility merge=""/> 26 <VisualActor merge=""/> 27 </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..0be3e4c
- + 1 <?xml version="1.0" encoding="utf-8"?> 2 <Entity filtered=""> 3 <!-- 4 We only want to include components which are necessary (for the visual previewing of an entity) 5 and safe (i.e. won't do anything that affects the synchronised simulation state), so additions 6 to this list should be carefully considered. 7 The Attack, Sound and UnitMotion components are needed for the Actor Viewer. 8 --> 9 <Attack merge=""/> 10 <BuildRestrictions merge=""/> 11 <Decay merge=""/> 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=""/> 22 <UnitMotion merge=""/> 23 <!-- Previews should always be visible in fog-of-war/etc --> 24 <Visibility> 25 <AlwaysVisible>true</AlwaysVisible> 26 <Preview>true</Preview> 27 </Visibility> 28 <!-- Previews should not cast shadows --> 29 <VisualActor merge=""> 30 <DisableShadows/> 31 </VisualActor> 32 </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 b9f7606..38edbe1 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); 58 if (!LoadTemplateFile(baseName, depth+1)) 59 { 60 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 61 return false; 62 } 63 // Copy a subset to the requested template 64 CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], false); 65 return true; 66 } 56 std::string prefix = templateName.substr(0, pos); 57 std::string baseName = templateName.substr(pos+1); 67 58 68 // Handle special case "corpse|foo"69 if (templateName.find("corpse|") == 0)70 {71 // Load the base entity template, if it wasn't already loaded72 std::string baseName = templateName.substr(7);73 59 if (!LoadTemplateFile(baseName, depth+1)) 74 60 { 75 61 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 76 62 return false; 77 63 } 78 // Copy a subset to the requested template79 CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], true);80 return true;81 }82 64 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)) 65 VfsPath path = VfsPath(TEMPLATE_ROOT) / L"special_filter" / wstring_from_utf8(prefix + ".xml"); 66 if (!VfsFileExists(path)) 89 67 { 90 LOGERROR(" Failed to load entity template '%s'", baseName.c_str());68 LOGERROR("Invalid subset '%s'", prefix.c_str()); 91 69 return false; 92 70 } 93 // Copy a subset to the requested template94 CopyMirageSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]);95 return true;96 }97 71 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 } 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) 112 76 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 221 166 std::vector<std::string> templates; 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 259 203 std::wstring fileFilter; 260 204 scriptInterface.GetProperty(val, "directory", directoryPath); 261 205 scriptInterface.GetProperty(val, "file", fileFilter); 262 206 263 207 VfsPaths filenames; 264 208 if (vfs::GetPathnames(g_VFS, templatePath / (directoryPath + "/"), fileFilter.c_str(), filenames) != INFO::OK) 265 209 continue; 266 210 267 211 for (const VfsPath& filename : filenames) 268 212 { 269 213 // Strip the .xml extension … … std::vector<std::string> CTemplateLoader::FindPlaceableTemplates(const std::stri 273 217 274 218 templates.emplace_back(name.begin(), name.end()); 275 219 } 276 220 277 221 } 278 279 222 } 280 223 } 281 224 … … std::vector<std::string> CTemplateLoader::FindPlaceableTemplates(const std::stri 289 232 WARN_IF_ERR(ok); 290 233 } 291 234 292 if (templatesType != SIMULATION_TEMPLATES && templatesType != ACTOR_TEMPLATES && templatesType != ALL_TEMPLATES)293 LOGERROR("Undefined template type (valid: all, simulation, actor)");294 295 235 return templates; 296 236 } 297 237 … … std::vector<std::string> CTemplateLoader::FindTemplates(const std::string& path, 299 239 { 300 240 std::vector<std::string> templates; 301 241 302 Status ok; 303 VfsPath templatePath; 304 305 if (templatesType == SIMULATION_TEMPLATES || templatesType == ALL_TEMPLATES) 306 { 307 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"); 312 WARN_IF_ERR(ok); 313 } 314 if (templatesType == ACTOR_TEMPLATES || templatesType == ALL_TEMPLATES) 242 if (templatesType != SIMULATION_TEMPLATES && templatesType != ACTOR_TEMPLATES && templatesType != ALL_TEMPLATES) 315 243 { 316 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"); 321 WARN_IF_ERR(ok); 244 LOGERROR("Undefined template type (valid: all, simulation, actor)"); 245 return templates; 322 246 } 323 247 324 if (templatesType != SIMULATION_TEMPLATES && templatesType != ACTOR_TEMPLATES && templatesType != ALL_TEMPLATES) 325 LOGERROR("Undefined template type (valid: all, simulation, actor)"); 248 size_t flags = includeSubdirectories ? vfs::DIR_RECURSIVE : 0; 249 250 if (templatesType == SIMULATION_TEMPLATES || templatesType == ALL_TEMPLATES) 251 WARN_IF_ERR(vfs::ForEachFile(g_VFS, VfsPath(TEMPLATE_ROOT) / path, AddToTemplates, (uintptr_t)&templates, L"*.xml", flags)); 252 253 if (templatesType == ACTOR_TEMPLATES || templatesType == ALL_TEMPLATES) 254 WARN_IF_ERR(vfs::ForEachFile(g_VFS, VfsPath(ACTOR_ROOT) / path, AddActorToTemplates, (uintptr_t)&templates, L"*.xml", flags)); 326 255 327 256 return templates; 328 257 } … … void CTemplateLoader::ConstructTemplateActor(const std::string& actorName, CPara 367 296 368 297 CParamNode::LoadXMLString(out, xml.c_str(), actorNameW.c_str()); 369 298 } 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("Obstruction");435 permittedComponentTypes.insert("Ownership");436 permittedComponentTypes.insert("OverlayRenderer");437 permittedComponentTypes.insert("Position");438 permittedComponentTypes.insert("Selectable");439 permittedComponentTypes.insert("StatusBars");440 permittedComponentTypes.insert("Visibility");441 permittedComponentTypes.insert("VisualActor");442 443 CParamNode::LoadXMLString(out, "<Entity/>");444 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);445 446 // Select a subset of identity data. We don't want to have, for example, a CC mirage447 // that has also the CC class and then prevents construction of other CCs448 std::set<std::string> identitySubset;449 identitySubset.insert("Civ");450 identitySubset.insert("GenericName");451 identitySubset.insert("SpecificName");452 identitySubset.insert("Tooltip");453 identitySubset.insert("History");454 identitySubset.insert("Icon");455 CParamNode identity;456 CParamNode::LoadXMLString(identity, "<Identity/>");457 identity.CopyFilteredChildrenOfChild(in.GetChild("Entity"), "Identity", identitySubset);458 CParamNode::LoadXMLString(out, ("<Entity>"+utf8_from_wstring(identity.ToXML())+"</Entity>").c_str());459 460 // Mirages obstruction shouldn't block anything461 if (out.GetChild("Entity").GetChild("Obstruction").IsOk())462 CParamNode::LoadXMLString(out, "<Entity><Obstruction><BlockMovement>false</BlockMovement><BlockPathfinding>false</BlockPathfinding><BlockFoundation>false</BlockFoundation><BlockConstruction>false</BlockConstruction></Obstruction></Entity>");463 464 // Set the entity as mirage entity465 CParamNode::LoadXMLString(out, "<Entity><Mirage/></Entity>");466 }467 468 void CTemplateLoader::CopyFoundationSubset(CParamNode& out, const CParamNode& in)469 {470 // TODO: this is all kind of yucky and hard-coded; it'd be nice to have a more generic471 // extensible scriptable way to define these subsets472 473 std::set<std::string> permittedComponentTypes;474 permittedComponentTypes.insert("Ownership");475 permittedComponentTypes.insert("Position");476 permittedComponentTypes.insert("VisualActor");477 permittedComponentTypes.insert("Identity");478 permittedComponentTypes.insert("BuildRestrictions");479 permittedComponentTypes.insert("Obstruction");480 permittedComponentTypes.insert("Selectable");481 permittedComponentTypes.insert("Footprint");482 permittedComponentTypes.insert("Fogging");483 permittedComponentTypes.insert("Armour");484 permittedComponentTypes.insert("Health");485 permittedComponentTypes.insert("Market");486 permittedComponentTypes.insert("StatusBars");487 permittedComponentTypes.insert("OverlayRenderer");488 permittedComponentTypes.insert("Decay");489 permittedComponentTypes.insert("Cost");490 permittedComponentTypes.insert("Sound");491 permittedComponentTypes.insert("Visibility");492 permittedComponentTypes.insert("Vision");493 permittedComponentTypes.insert("AIProxy");494 permittedComponentTypes.insert("RallyPoint");495 permittedComponentTypes.insert("RallyPointRenderer");496 497 CParamNode::LoadXMLString(out, "<Entity/>");498 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);499 500 // Switch the actor to foundation mode501 CParamNode::LoadXMLString(out, "<Entity><VisualActor><Foundation/></VisualActor></Entity>");502 503 // Add the Foundation component, to deal with the construction process504 CParamNode::LoadXMLString(out, "<Entity><Foundation/></Entity>");505 506 // Initialise health to 1507 CParamNode::LoadXMLString(out, "<Entity><Health><Initial>1</Initial></Health></Entity>");508 509 // Foundations shouldn't initially block unit movement510 if (out.GetChild("Entity").GetChild("Obstruction").IsOk())511 CParamNode::LoadXMLString(out, "<Entity><Obstruction><DisableBlockMovement>true</DisableBlockMovement><DisableBlockPathfinding>true</DisableBlockPathfinding></Obstruction></Entity>");512 513 // Don't provide population bonuses yet (but still do take up population cost)514 if (out.GetChild("Entity").GetChild("Cost").IsOk())515 CParamNode::LoadXMLString(out, "<Entity><Cost><PopulationBonus>0</PopulationBonus></Cost></Entity>");516 517 // Foundations should be visible themselves in fog-of-war if their base template is,518 // but shouldn't have any vision range519 if (out.GetChild("Entity").GetChild("Vision").IsOk())520 {521 CParamNode::LoadXMLString(out, "<Entity><Vision><Range>0</Range></Vision></Entity>");522 // Foundations should not have special vision capabilities either523 if (out.GetChild("Entity").GetChild("Vision").GetChild("RevealShore").IsOk())524 CParamNode::LoadXMLString(out, "<Entity><Vision><RevealShore>false</RevealShore></Vision></Entity>");525 }526 }527 528 void CTemplateLoader::CopyConstructionSubset(CParamNode& out, const CParamNode& in)529 {530 // Currently used for buildings rising during construction531 // Mostly serves to filter out components like Vision, UnitAI, etc.532 std::set<std::string> permittedComponentTypes;533 permittedComponentTypes.insert("Footprint");534 permittedComponentTypes.insert("Ownership");535 permittedComponentTypes.insert("Position");536 permittedComponentTypes.insert("VisualActor");537 538 CParamNode::LoadXMLString(out, "<Entity/>");539 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);540 }541 542 void CTemplateLoader::CopyResourceSubset(CParamNode& out, const CParamNode& in)543 {544 // Currently used for animals which die and leave a gatherable corpse.545 // Mostly serves to filter out components like Vision, UnitAI, etc.546 // Don't emit sound as our samples only apply to living animals.547 std::set<std::string> permittedComponentTypes;548 permittedComponentTypes.insert("Ownership");549 permittedComponentTypes.insert("Position");550 permittedComponentTypes.insert("VisualActor");551 permittedComponentTypes.insert("Identity");552 permittedComponentTypes.insert("Minimap");553 permittedComponentTypes.insert("ResourceSupply");554 permittedComponentTypes.insert("Selectable");555 permittedComponentTypes.insert("Footprint");556 permittedComponentTypes.insert("StatusBars");557 permittedComponentTypes.insert("OverlayRenderer");558 permittedComponentTypes.insert("AIProxy");559 560 CParamNode::LoadXMLString(out, "<Entity/>");561 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);562 563 // When dying, resources lose the unitMotion component564 // This causes them to have no clearance. Since unit obstructions no longer have a radius,565 // this makes them unreachable in some cases (see #3530).566 // Instead, create a static, unblocking (see #3530 for why) static obstruction.567 // TODO: this should probably be generalized as a parameter on entity death or something.568 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>");569 } -
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/components/tests/test_scripts.h
diff --git a/source/simulation2/components/tests/test_scripts.h b/source/simulation2/components/tests/test_scripts.h index 5cf8c2a..29014b4 100644
a b public: 59 59 void test_scripts() 60 60 { 61 61 if (!VfsFileExists(L"simulation/components/tests/setup.js")) 62 {63 debug_printf("WARNING: Skipping component scripts tests (can't find binaries/data/mods/public/simulation/components/tests/setup.js)\n");64 62 return; 65 }66 63 67 64 VfsPaths paths; 68 65 TS_ASSERT_OK(vfs::GetPathnames(g_VFS, L"simulation/components/tests/", L"test_*.js", paths)); -
source/simulation2/system/ParamNode.cpp
diff --git a/source/simulation2/system/ParamNode.cpp b/source/simulation2/system/ParamNode.cpp index 173117b..89ba11d 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; 90 bool merging = false; 87 91 { 88 92 XERO_ITER_ATTR(element, attr) 89 93 { … … void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const 97 101 m_Childs.erase(name); 98 102 replacing = true; 99 103 } 104 else if (attr.Name == at_filtered) 105 { 106 filtering = true; 107 } 108 else if (attr.Name == at_merge) 109 { 110 if (m_Childs.find(name) == m_Childs.end()) 111 return; 112 merging = true; 113 } 100 114 else if (attr.Name == at_op) 101 115 { 102 116 if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"add") … … void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const 168 182 } 169 183 hasSetValue = true; 170 184 } 171 if (!hasSetValue )185 if (!hasSetValue && !merging) 172 186 node.m_Value = value; 173 187 188 // For the filtered case 189 ChildrenMap childs; 190 174 191 // Recurse through the element's children 175 192 XERO_ITER_EL(element, child) 176 193 { 177 194 node.ApplyLayer(xmb, child, sourceIdentifier); 195 if (filtering) 196 { 197 std::string childname = xmb.GetElementString(child.GetNodeName()); 198 if (node.m_Childs.find(childname) != node.m_Childs.end()) 199 childs[childname] = std::move(node.m_Childs[childname]); 200 } 178 201 } 179 202 203 if (filtering) 204 node.m_Childs.swap(childs); 205 180 206 // Add the element's attributes, prefixing names with "@" 181 207 XERO_ITER_ATTR(element, attr) 182 208 { 183 209 // Skip special attributes 184 if (attr.Name == at_replace || attr.Name == at_op )210 if (attr.Name == at_replace || attr.Name == at_op || attr.Name == at_merge || attr.Name == at_filtered) 185 211 continue; 186 212 // Add any others 187 213 std::string attrName = xmb.GetAttributeString(attr.Name); … … void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const 189 215 } 190 216 } 191 217 192 void CParamNode::CopyFilteredChildrenOfChild(const CParamNode& src, const char* name, const std::set<std::string>& permitted)193 {194 ResetScriptVal();195 196 ChildrenMap::iterator dstChild = m_Childs.find(name);197 ChildrenMap::const_iterator srcChild = src.m_Childs.find(name);198 if (dstChild == m_Childs.end() || srcChild == src.m_Childs.end())199 return; // error200 201 ChildrenMap::const_iterator it = srcChild->second.m_Childs.begin();202 for (; it != srcChild->second.m_Childs.end(); ++it)203 if (permitted.count(it->first))204 dstChild->second.m_Childs[it->first] = it->second;205 }206 207 218 const CParamNode& CParamNode::GetChild(const char* name) const 208 219 { 209 220 ChildrenMap::const_iterator it = m_Childs.find(name); -
source/simulation2/system/ParamNode.h
diff --git a/source/simulation2/system/ParamNode.h b/source/simulation2/system/ParamNode.h index 4fc911f..0b18e5e 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 … … public: 146 182 static PSRETURN LoadXMLString(CParamNode& ret, const char* xml, const wchar_t* sourceIdentifier = NULL); 147 183 148 184 /** 149 * Finds the childs named @a name from @a src and from @a this, and copies the source child's children150 * which are in the @a permitted set into this node's child.151 * Intended for use as a filtered clone of XML files.152 * @a this and @a src must have childs named @a name.153 */154 void CopyFilteredChildrenOfChild(const CParamNode& src, const char* name, const std::set<std::string>& permitted);155 156 /**157 185 * Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none. 158 186 */ 159 187 const CParamNode& GetChild(const char* name) const; -
source/simulation2/tests/test_CmpTemplateManager.h
diff --git a/source/simulation2/tests/test_CmpTemplateManager.h b/source/simulation2/tests/test_CmpTemplateManager.h index 8103254..0fdc180 100644
a b 31 31 #include "ps/CLogger.h" 32 32 #include "ps/XML/Xeromyces.h" 33 33 34 static const char SPECIAL_FILTER[] = "simulation/templates/special_filter/"; 35 34 36 class TestCmpTemplateManager : public CxxTest::TestSuite 35 37 { 36 38 public: … … public: 39 41 g_VFS = CreateVfs(20 * MiB); 40 42 TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"_test.sim", VFS_MOUNT_MUST_EXIST)); 41 43 TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache")); 44 45 // If the public mod exists, test the special_filter templates too 46 g_VFS->Mount(SPECIAL_FILTER, DataDir() / "mods" / "public" / SPECIAL_FILTER); 47 42 48 CXeromyces::Startup(); 43 49 } 44 50 … … public: 117 123 ScriptInterface::ToJSVal(cx, &val, &actor->GetChild("VisualActor")); 118 124 TS_ASSERT_STR_EQUALS(man.GetScriptInterface().ToString(&val), "({Actor:\"example1\", ActorOnly:(void 0), SilhouetteDisplay:\"false\", SilhouetteOccluder:\"false\", VisibleInAtlasOnly:\"false\"})"); 119 125 120 const CParamNode* foundation = tempMan->LoadTemplate(ent2, "foundation|actor|example1", -1); 121 ScriptInterface::ToJSVal(cx, &val, &foundation->GetChild("VisualActor")); 122 TS_ASSERT_STR_EQUALS(man.GetScriptInterface().ToString(&val), "({Actor:\"example1\", ActorOnly:(void 0), Foundation:(void 0), SilhouetteDisplay:\"false\", SilhouetteOccluder:\"false\", VisibleInAtlasOnly:\"false\"})"); 126 if (VfsDirectoryExists(SPECIAL_FILTER)) 127 { 128 const CParamNode* foundation = tempMan->LoadTemplate(ent2, "foundation|actor|example1", -1); 129 ScriptInterface::ToJSVal(cx, &val, &foundation->GetChild("VisualActor")); 130 131 TS_ASSERT_STR_EQUALS( 132 man.GetScriptInterface().ToString(&val), 133 "({" 134 "Actor:\"example1\", " 135 "ActorOnly:(void 0), " 136 "Foundation:(void 0), " 137 "SilhouetteDisplay:\"false\", " 138 "SilhouetteOccluder:\"false\", " 139 "VisibleInAtlasOnly:\"false\"" 140 "})" 141 ); 142 } 123 143 } 124 144 125 145 void test_LoadTemplate_errors() -
source/simulation2/tests/test_ParamNode.h
diff --git a/source/simulation2/tests/test_ParamNode.h b/source/simulation2/tests/test_ParamNode.h index 043554b..83e11b9 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, 142 "<test>" 143 "<a>" 144 "<b/>" 145 "</a>" 146 "<c>toberemoved</c>" 147 "<d>" 148 "<e/>" 149 "</d>" 150 "</test>"), PSRETURN_OK); 151 152 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, 153 "<test filtered=\"\">" 154 "<a/>" 155 "<d>" 156 "<f/>" 157 "</d>" 158 "<g/>" 159 "</test>"), PSRETURN_OK); 160 161 TS_ASSERT_WSTR_EQUALS(node.ToXML(), 162 L"<test>" 163 "<a>" 164 "<b></b>" 165 "</a>" 166 "<d>" 167 "<e></e>" 168 "<f></f>" 169 "</d>" 170 "<g></g>" 171 "</test>"); 172 } 173 174 void test_overlay_filtered_and_merge() 175 { 176 CParamNode node; 177 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, 178 "<test>" 179 "<a>" 180 "<b>b</b>" 181 "<c>c</c>" 182 "<d>d</d>" 183 "<e>e</e>" 184 "</a>" 185 "<f/>" 186 "</test>"), PSRETURN_OK); 187 188 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, 189 "<test filtered=\"\">" 190 "<a filtered=\"\">" 191 "<b merge=\"\"/>" 192 "<c>c2</c>" 193 "<d/>" 194 "</a>" 195 "</test>"), PSRETURN_OK); 196 197 TS_ASSERT_WSTR_EQUALS(node.ToXML(), 198 L"<test>" 199 "<a>" 200 "<b>b</b>" 201 "<c>c2</c>" 202 "<d></d>" 203 "</a>" 204 "</test>"); 205 } 206 207 void test_overlay_merge() 208 { 209 CParamNode node; 210 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, 211 "<test>" 212 "<a>" 213 "<b>foo</b>" 214 "<c>bar</c>" 215 "</a>" 216 "<x>" 217 "<y>" 218 "<z>foo</z>" 219 "</y>" 220 "</x>" 221 "</test>"), PSRETURN_OK); 222 223 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, 224 "<test>" 225 "<a merge=\"\">" 226 "<b>test</b>" 227 "<d>baz</d>" 228 "</a>" 229 "<i merge=\"\">" 230 "<j>willnotbeincluded</j>" 231 "</i>" 232 "<x merge=\"\">" 233 "<y merge=\"\">" 234 "<v>text</v>" 235 "</y>" 236 "<w>more text</w>" 237 "</x>" 238 "</test>"), PSRETURN_OK); 239 240 TS_ASSERT_WSTR_EQUALS(node.ToXML(), 241 L"<test>" 242 "<a>" 243 "<b>test</b>" 244 "<c>bar</c>" 245 "<d>baz</d>" 246 "</a>" 247 "<x>" 248 "<w>more text</w>" 249 "<y>" 250 "<v>text</v>" 251 "<z>foo</z>" 252 "</y>" 253 "</x>" 254 "</test>"); 255 } 256 257 void test_overlay_filtered_merge() 258 { 259 CParamNode node; 260 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, 261 "<test>" 262 "<a>" 263 "<b/>" 264 "</a>" 265 "<c>" 266 "<x/>" 267 "</c>" 268 "<Health>" 269 "<Max>1200</Max>" 270 "</Health>" 271 "</test>"), PSRETURN_OK); 272 273 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, 274 "<test filtered=\"\">" 275 "<c merge=\"\"/>" 276 "<d>bar</d>" 277 "<e merge=\"\"/>" 278 "<Health>" 279 "<Initial>1</Initial>" 280 "</Health>" 281 "</test>"), PSRETURN_OK); 282 283 TS_ASSERT_WSTR_EQUALS(node.ToXML(), 284 L"<test>" 285 "<Health>" 286 "<Initial>1</Initial>" 287 "<Max>1200</Max>" 288 "</Health>" 289 "<c>" 290 "<x></x>" 291 "</c>" 292 "<d>bar</d>" 293 "</test>"); 294 } 295 138 296 void test_types() 139 297 { 140 298 CParamNode node;