Ticket #2951: 2951_template_subsets_v2_without_committed_cleanup.diff
File 2951_template_subsets_v2_without_committed_cleanup.diff, 39.8 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/simulation/templates/special_filter/construction.xml
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> -
binaries/data/mods/public/simulation/templates/special_filter/corpse.xml
Property changes on: binaries/data/mods/public/simulation/templates/special_filter/construction.xml ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
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> -
binaries/data/mods/public/simulation/templates/special_filter/foundation.xml
Property changes on: binaries/data/mods/public/simulation/templates/special_filter/corpse.xml ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
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> -
binaries/data/mods/public/simulation/templates/special_filter/mirage.xml
Property changes on: binaries/data/mods/public/simulation/templates/special_filter/foundation.xml ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
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> -
binaries/data/mods/public/simulation/templates/special_filter/preview.xml
Property changes on: binaries/data/mods/public/simulation/templates/special_filter/mirage.xml ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
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> -
binaries/data/mods/public/simulation/templates/special_filter/resource.xml
Property changes on: binaries/data/mods/public/simulation/templates/special_filter/preview.xml ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
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
Property changes on: binaries/data/mods/public/simulation/templates/special_filter/resource.xml ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
bool CTemplateLoader::LoadTemplateFile(c 47 47 { 48 48 ConstructTemplateActor(templateName.substr(6), m_TemplateFileData[templateName]); 49 49 return true; 50 50 } 51 51 52 // Handle special case "preview|foo" 53 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) 54 55 { 55 // Load the base entity template, if it wasn't already loaded 56 std::string baseName = templateName.substr(8); 57 if (!LoadTemplateFile(baseName, depth+1)) 58 { 59 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 60 return false; 61 } 62 // Copy a subset to the requested template 63 CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], false); 64 return true; 65 } 56 std::string prefix = templateName.substr(0, pos); 57 std::string baseName = templateName.substr(pos+1); 66 58 67 // Handle special case "corpse|foo"68 if (templateName.find("corpse|") == 0)69 {70 // Load the base entity template, if it wasn't already loaded71 std::string baseName = templateName.substr(7);72 59 if (!LoadTemplateFile(baseName, depth+1)) 73 60 { 74 61 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 75 62 return false; 76 63 } 77 // Copy a subset to the requested template78 CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], true);79 return true;80 }81 64 82 // Handle special case "mirage|foo" 83 if (templateName.find("mirage|") == 0) 84 { 85 // Load the base entity template, if it wasn't already loaded 86 std::string baseName = templateName.substr(7); 87 if (!LoadTemplateFile(baseName, depth+1)) 65 VfsPath path = VfsPath(TEMPLATE_ROOT) / L"special_filter" / wstring_from_utf8(prefix + ".xml"); 66 if (!VfsFileExists(path)) 88 67 { 89 LOGERROR(" Failed to load entity template '%s'", baseName.c_str());68 LOGERROR("Invalid subset '%s'", prefix.c_str()); 90 69 return false; 91 70 } 92 // Copy a subset to the requested template93 CopyMirageSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]);94 return true;95 }96 71 97 // Handle special case "foundation|foo" 98 if (templateName.find("foundation|") == 0) 99 { 100 // Load the base entity template, if it wasn't already loaded 101 std::string baseName = templateName.substr(11); 102 if (!LoadTemplateFile(baseName, depth+1)) 103 { 104 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 105 return false; 106 } 107 // Copy a subset to the requested template 108 CopyFoundationSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]); 109 return true; 110 } 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) 111 76 112 // Handle special case "construction|foo" 113 if (templateName.find("construction|") == 0) 114 { 115 // Load the base entity template, if it wasn't already loaded 116 std::string baseName = templateName.substr(13); 117 if (!LoadTemplateFile(baseName, depth+1)) 118 { 119 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 120 return false; 121 } 122 // Copy a subset to the requested template 123 CopyConstructionSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]); 124 return true; 125 } 126 127 // Handle special case "resource|foo" 128 if (templateName.find("resource|") == 0) 129 { 130 // Load the base entity template, if it wasn't already loaded 131 std::string baseName = templateName.substr(9); 132 if (!LoadTemplateFile(baseName, depth+1)) 133 { 134 LOGERROR("Failed to load entity template '%s'", baseName.c_str()); 135 return false; 136 } 137 // Copy a subset to the requested template 138 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()); 139 79 return true; 140 80 } 141 81 142 82 // Normal case: templateName is an XML file: 143 83 … … void CTemplateLoader::ConstructTemplateA 354 294 "</Selectable>" 355 295 "</Entity>"; 356 296 357 297 CParamNode::LoadXMLString(out, xml.c_str(), actorNameW.c_str()); 358 298 } 359 360 void CTemplateLoader::CopyPreviewSubset(CParamNode& out, const CParamNode& in, bool corpse)361 {362 // We only want to include components which are necessary (for the visual previewing of an entity)363 // and safe (i.e. won't do anything that affects the synchronised simulation state), so additions364 // to this list should be carefully considered365 std::set<std::string> permittedComponentTypes;366 permittedComponentTypes.insert("Identity");367 permittedComponentTypes.insert("Ownership");368 permittedComponentTypes.insert("Position");369 permittedComponentTypes.insert("Visibility");370 permittedComponentTypes.insert("VisualActor");371 permittedComponentTypes.insert("Footprint");372 permittedComponentTypes.insert("Obstruction");373 permittedComponentTypes.insert("Decay");374 permittedComponentTypes.insert("BuildRestrictions");375 376 // Need these for the Actor Viewer:377 permittedComponentTypes.insert("Attack");378 permittedComponentTypes.insert("UnitMotion");379 permittedComponentTypes.insert("Sound");380 381 // (This set could be initialised once and reused, but it's not worth the effort)382 383 CParamNode::LoadXMLString(out, "<Entity/>");384 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);385 386 // Disable the Obstruction component (if there is one) so it doesn't affect pathfinding387 // (but can still be used for testing this entity for collisions against others)388 if (out.GetChild("Entity").GetChild("Obstruction").IsOk())389 CParamNode::LoadXMLString(out, "<Entity><Obstruction><Active>false</Active></Obstruction></Entity>");390 391 if (!corpse)392 {393 // Previews should not cast shadows394 if (out.GetChild("Entity").GetChild("VisualActor").IsOk())395 CParamNode::LoadXMLString(out, "<Entity><VisualActor><DisableShadows/></VisualActor></Entity>");396 397 // Previews should always be visible in fog-of-war/etc398 CParamNode::LoadXMLString(out, "<Entity><Visibility><AlwaysVisible>true</AlwaysVisible><Preview>true</Preview></Visibility></Entity>");399 }400 401 if (corpse)402 {403 // Corpses should include decay components and activate them404 if (out.GetChild("Entity").GetChild("Decay").IsOk())405 CParamNode::LoadXMLString(out, "<Entity><Decay><Active>true</Active></Decay></Entity>");406 407 // Corpses shouldn't display silhouettes (especially since they're often half underground)408 if (out.GetChild("Entity").GetChild("VisualActor").IsOk())409 CParamNode::LoadXMLString(out, "<Entity><VisualActor><SilhouetteDisplay>false</SilhouetteDisplay></VisualActor></Entity>");410 411 // Corpses should remain visible in fog-of-war (for the owner only)412 CParamNode::LoadXMLString(out, "<Entity><Visibility><Corpse>true</Corpse></Visibility></Entity>");413 }414 }415 416 void CTemplateLoader::CopyMirageSubset(CParamNode& out, const CParamNode& in)417 {418 // Currently used for mirage entities replacing real ones in fog-of-war419 420 std::set<std::string> permittedComponentTypes;421 permittedComponentTypes.insert("Footprint");422 permittedComponentTypes.insert("Minimap");423 permittedComponentTypes.insert("Obstruction");424 permittedComponentTypes.insert("Ownership");425 permittedComponentTypes.insert("OverlayRenderer");426 permittedComponentTypes.insert("Position");427 permittedComponentTypes.insert("Selectable");428 permittedComponentTypes.insert("StatusBars");429 permittedComponentTypes.insert("Visibility");430 permittedComponentTypes.insert("VisualActor");431 432 CParamNode::LoadXMLString(out, "<Entity/>");433 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);434 435 // Select a subset of identity data. We don't want to have, for example, a CC mirage436 // that has also the CC class and then prevents construction of other CCs437 std::set<std::string> identitySubset;438 identitySubset.insert("Civ");439 identitySubset.insert("GenericName");440 identitySubset.insert("SpecificName");441 identitySubset.insert("Tooltip");442 identitySubset.insert("History");443 identitySubset.insert("Icon");444 CParamNode identity;445 CParamNode::LoadXMLString(identity, "<Identity/>");446 identity.CopyFilteredChildrenOfChild(in.GetChild("Entity"), "Identity", identitySubset);447 CParamNode::LoadXMLString(out, ("<Entity>"+utf8_from_wstring(identity.ToXML())+"</Entity>").c_str());448 449 // Mirages obstruction shouldn't block anything450 if (out.GetChild("Entity").GetChild("Obstruction").IsOk())451 CParamNode::LoadXMLString(out, "<Entity><Obstruction><BlockMovement>false</BlockMovement><BlockPathfinding>false</BlockPathfinding><BlockFoundation>false</BlockFoundation><BlockConstruction>false</BlockConstruction></Obstruction></Entity>");452 453 // Set the entity as mirage entity454 CParamNode::LoadXMLString(out, "<Entity><Mirage/></Entity>");455 }456 457 void CTemplateLoader::CopyFoundationSubset(CParamNode& out, const CParamNode& in)458 {459 // TODO: this is all kind of yucky and hard-coded; it'd be nice to have a more generic460 // extensible scriptable way to define these subsets461 462 std::set<std::string> permittedComponentTypes;463 permittedComponentTypes.insert("Ownership");464 permittedComponentTypes.insert("Position");465 permittedComponentTypes.insert("VisualActor");466 permittedComponentTypes.insert("Identity");467 permittedComponentTypes.insert("BuildRestrictions");468 permittedComponentTypes.insert("Obstruction");469 permittedComponentTypes.insert("Selectable");470 permittedComponentTypes.insert("Footprint");471 permittedComponentTypes.insert("Fogging");472 permittedComponentTypes.insert("Armour");473 permittedComponentTypes.insert("Health");474 permittedComponentTypes.insert("Market");475 permittedComponentTypes.insert("StatusBars");476 permittedComponentTypes.insert("OverlayRenderer");477 permittedComponentTypes.insert("Decay");478 permittedComponentTypes.insert("Cost");479 permittedComponentTypes.insert("Sound");480 permittedComponentTypes.insert("Visibility");481 permittedComponentTypes.insert("Vision");482 permittedComponentTypes.insert("AIProxy");483 permittedComponentTypes.insert("RallyPoint");484 permittedComponentTypes.insert("RallyPointRenderer");485 486 CParamNode::LoadXMLString(out, "<Entity/>");487 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);488 489 // Switch the actor to foundation mode490 CParamNode::LoadXMLString(out, "<Entity><VisualActor><Foundation/></VisualActor></Entity>");491 492 // Add the Foundation component, to deal with the construction process493 CParamNode::LoadXMLString(out, "<Entity><Foundation/></Entity>");494 495 // Initialise health to 1496 CParamNode::LoadXMLString(out, "<Entity><Health><Initial>1</Initial></Health></Entity>");497 498 // Foundations shouldn't initially block unit movement499 if (out.GetChild("Entity").GetChild("Obstruction").IsOk())500 CParamNode::LoadXMLString(out, "<Entity><Obstruction><DisableBlockMovement>true</DisableBlockMovement><DisableBlockPathfinding>true</DisableBlockPathfinding></Obstruction></Entity>");501 502 // Don't provide population bonuses yet (but still do take up population cost)503 if (out.GetChild("Entity").GetChild("Cost").IsOk())504 CParamNode::LoadXMLString(out, "<Entity><Cost><PopulationBonus>0</PopulationBonus></Cost></Entity>");505 506 // Foundations should be visible themselves in fog-of-war if their base template is,507 // but shouldn't have any vision range508 if (out.GetChild("Entity").GetChild("Vision").IsOk())509 {510 CParamNode::LoadXMLString(out, "<Entity><Vision><Range>0</Range></Vision></Entity>");511 // Foundations should not have special vision capabilities either512 if (out.GetChild("Entity").GetChild("Vision").GetChild("RevealShore").IsOk())513 CParamNode::LoadXMLString(out, "<Entity><Vision><RevealShore>false</RevealShore></Vision></Entity>");514 }515 }516 517 void CTemplateLoader::CopyConstructionSubset(CParamNode& out, const CParamNode& in)518 {519 // Currently used for buildings rising during construction520 // Mostly serves to filter out components like Vision, UnitAI, etc.521 std::set<std::string> permittedComponentTypes;522 permittedComponentTypes.insert("Footprint");523 permittedComponentTypes.insert("Ownership");524 permittedComponentTypes.insert("Position");525 permittedComponentTypes.insert("VisualActor");526 527 CParamNode::LoadXMLString(out, "<Entity/>");528 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);529 }530 531 void CTemplateLoader::CopyResourceSubset(CParamNode& out, const CParamNode& in)532 {533 // Currently used for animals which die and leave a gatherable corpse.534 // Mostly serves to filter out components like Vision, UnitAI, etc.535 // Don't emit sound as our samples only apply to living animals.536 std::set<std::string> permittedComponentTypes;537 permittedComponentTypes.insert("Ownership");538 permittedComponentTypes.insert("Position");539 permittedComponentTypes.insert("VisualActor");540 permittedComponentTypes.insert("Identity");541 permittedComponentTypes.insert("Minimap");542 permittedComponentTypes.insert("ResourceSupply");543 permittedComponentTypes.insert("Selectable");544 permittedComponentTypes.insert("Footprint");545 permittedComponentTypes.insert("StatusBars");546 permittedComponentTypes.insert("OverlayRenderer");547 permittedComponentTypes.insert("AIProxy");548 549 CParamNode::LoadXMLString(out, "<Entity/>");550 out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);551 552 // When dying, resources lose the unitMotion component553 // This causes them to have no clearance. Since unit obstructions no longer have a radius,554 // this makes them unreachable in some cases (see #3530).555 // Instead, create a static, unblocking (see #3530 for why) static obstruction.556 // TODO: this should probably be generalized as a parameter on entity death or something.557 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>");558 } -
source/ps/TemplateLoader.h
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 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … class CTemplateLoader 46 46 { 47 47 public: 48 48 CTemplateLoader() 49 49 { 50 50 } 51 51 52 52 /** 53 53 * Provides the file data for requested template. 54 54 */ 55 55 const CParamNode& GetTemplateFileData(const std::string& templateName); 56 56 … … private: 79 79 /** 80 80 * Constructs a standard static-decorative-object template for the given actor 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. 117 87 * (Failed loads won't remove existing entries under the same name, so we behave more nicely 118 88 * when hotloading broken files) -
source/simulation2/components/tests/test_scripts.h
public: 57 57 } 58 58 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)); 69 66 for (const VfsPath& path : paths) 70 67 { -
source/simulation2/system/ParamNode.cpp
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 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … void CParamNode::ApplyLayer(const XMBFil 74 74 bool hasSetValue = false; 75 75 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 { 82 84 INVALID, 83 85 ADD, 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 { 90 94 if (attr.Name == at_disable) 91 95 { … … void CParamNode::ApplyLayer(const XMBFil 95 99 else if (attr.Name == at_replace) 96 100 { 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") 103 117 op = ADD; 104 118 else if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"mul") … … void CParamNode::ApplyLayer(const XMBFil 166 180 node.m_Value = (oldval.Multiply(mod)).ToString().FromUTF8(); 167 181 break; 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); 188 214 node.m_Childs["@" + attrName].m_Value = attr.Value.FromUTF8(); 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); 210 221 if (it == m_Childs.end()) 211 222 return g_NullNode; -
source/simulation2/system/ParamNode.h
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 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … class XMBElement; 56 56 * <C/> 57 57 * </Example3> 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: 64 73 * @code 65 74 * <Entity> … … class XMBElement; 73 82 * </Example3> 74 83 * <Example4 datatype="tokens"> <!-- treat as space-separated lists of tokens to merge --> 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: 81 99 * @code 82 100 * <Entity> … … class XMBElement; 88 106 * <D>new</D> 89 107 * </Example3> 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 * 96 123 * Parameter nodes can be translated to JavaScript objects. The previous example will become the object: 97 124 * @code … … class XMBElement; 101 128 * "D": "new" 102 129 * }, 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 110 146 * (Note the special @c _string for the hopefully-rare cases where a node contains both child nodes and text.) 111 147 */ … … public: 144 180 * the data getting loaded. Used for output to log messages if an error occurs. 145 181 */ 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; 160 188 // (Children are returned as const in order to allow future optimisations, where we assume 161 189 // a node is always modified explicitly and not indirectly via its children, e.g. to cache jsvals) -
source/simulation2/tests/test_CmpTemplateManager.h
29 29 #include "graphics/Terrain.h" 30 30 #include "ps/Filesystem.h" 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: 37 39 void setUp() 38 40 { 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 45 51 void tearDown() 46 52 { … … public: 115 121 116 122 const CParamNode* actor = tempMan->LoadTemplate(ent2, "actor|example1", -1); 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() 126 146 { 127 147 CSimContext context; -
source/simulation2/tests/test_ParamNode.h
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 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … public: 133 133 CParamNode node; 134 134 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a datatype='tokens'> Y - X </a></test>"), PSRETURN_OK); 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; 141 299 TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test><n>+010.75</n><t>true</t></test>"), PSRETURN_OK); 142 300 TS_ASSERT(node.GetChild("test").IsOk());