Ticket #2951: 2951_template_subsets_v2_without_committed_cleanup.diff

File 2951_template_subsets_v2_without_committed_cleanup.diff, 39.8 KB (added by elexis, 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  
    4747    {
    4848        ConstructTemplateActor(templateName.substr(6), m_TemplateFileData[templateName]);
    4949        return true;
    5050    }
    5151
    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)
    5455    {
    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);
    6658
    67     // Handle special case "corpse|foo"
    68     if (templateName.find("corpse|") == 0)
    69     {
    70         // Load the base entity template, if it wasn't already loaded
    71         std::string baseName = templateName.substr(7);
    7259        if (!LoadTemplateFile(baseName, depth+1))
    7360        {
    7461            LOGERROR("Failed to load entity template '%s'", baseName.c_str());
    7562            return false;
    7663        }
    77         // Copy a subset to the requested template
    78         CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], true);
    79         return true;
    80     }
    8164
    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))
    8867        {
    89             LOGERROR("Failed to load entity template '%s'", baseName.c_str());
     68            LOGERROR("Invalid subset '%s'", prefix.c_str());
    9069            return false;
    9170        }
    92         // Copy a subset to the requested template
    93         CopyMirageSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]);
    94         return true;
    95     }
    9671
    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)
    11176
    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());
    13979        return true;
    14080    }
    14181
    14282    // Normal case: templateName is an XML file:
    14383
    void CTemplateLoader::ConstructTemplateA  
    354294                          "</Selectable>"
    355295                      "</Entity>";
    356296
    357297    CParamNode::LoadXMLString(out, xml.c_str(), actorNameW.c_str());
    358298}
    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 additions
    364     // to this list should be carefully considered
    365     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 pathfinding
    387     // (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 shadows
    394         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/etc
    398         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 them
    404         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-war
    419 
    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 mirage
    436     // that has also the CC class and then prevents construction of other CCs
    437     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 anything
    450     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 entity
    454     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 generic
    460     // extensible scriptable way to define these subsets
    461 
    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 mode
    490     CParamNode::LoadXMLString(out, "<Entity><VisualActor><Foundation/></VisualActor></Entity>");
    491 
    492     // Add the Foundation component, to deal with the construction process
    493     CParamNode::LoadXMLString(out, "<Entity><Foundation/></Entity>");
    494 
    495     // Initialise health to 1
    496     CParamNode::LoadXMLString(out, "<Entity><Health><Initial>1</Initial></Health></Entity>");
    497 
    498     // Foundations shouldn't initially block unit movement
    499     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 range
    508     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 either
    512         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 construction
    520     // 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 component
    553     // 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) 2015 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    55 * it under the terms of the GNU General Public License as published by
    66 * the Free Software Foundation, either version 2 of the License, or
    class CTemplateLoader  
    4646{
    4747public:
    4848    CTemplateLoader()
    4949    {
    5050    }
    51    
     51
    5252    /**
    5353     * Provides the file data for requested template.
    5454     */
    5555    const CParamNode& GetTemplateFileData(const std::string& templateName);
    5656
    private:  
    7979    /**
    8080     * Constructs a standard static-decorative-object template for the given actor
    8181     */
    8282    void ConstructTemplateActor(const std::string& actorName, CParamNode& out);
    8383
    84     /**
    85      * Copy the non-interactive components of an entity template (position, actor, etc) into
    86      * a new entity template
    87      */
    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 template
    93      */
    94     void CopyMirageSubset(CParamNode& out, const CParamNode& in);
    95 
    96     /**
    97      * Copy the components of an entity template necessary for a construction foundation
    98      * (position, actor, armour, health, etc) into a new entity template
    99      */
    100     void CopyFoundationSubset(CParamNode& out, const CParamNode& in);
    101 
    102     /**
    103      * Copy the components of an entity template necessary for a non-foundation construction entity
    104      * into a new entity template
    105      */
    106     void CopyConstructionSubset(CParamNode& out, const CParamNode& in);
    107 
    108     /**
    109      * Copy the components of an entity template necessary for a gatherable resource
    110      * into a new entity template
    111      */
    112     void CopyResourceSubset(CParamNode& out, const CParamNode& in);
    113 
    11484    /**
    11585     * Map from template name (XML filename or special |-separated string) to the most recently
    11686     * loaded non-broken template data. This includes files that will fail schema validation.
    11787     * (Failed loads won't remove existing entries under the same name, so we behave more nicely
    11888     * when hotloading broken files)
  • source/simulation2/components/tests/test_scripts.h

    public:  
    5757    }
    5858
    5959    void test_scripts()
    6060    {
    6161        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");
    6462            return;
    65         }
    6663
    6764        VfsPaths paths;
    6865        TS_ASSERT_OK(vfs::GetPathnames(g_VFS, L"simulation/components/tests/", L"test_*.js", paths));
    6966        for (const VfsPath& path : paths)
    7067        {
  • source/simulation2/system/ParamNode.cpp

     
    1 /* Copyright (C) 2015 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    55 * it under the terms of the GNU General Public License as published by
    66 * the Free Software Foundation, either version 2 of the License, or
    void CParamNode::ApplyLayer(const XMBFil  
    7474    bool hasSetValue = false;
    7575
    7676    // Look for special attributes
    7777    int at_disable = xmb.GetAttributeID("disable");
    7878    int at_replace = xmb.GetAttributeID("replace");
     79    int at_filtered = xmb.GetAttributeID("filtered");
     80    int at_merge = xmb.GetAttributeID("merge");
    7981    int at_op = xmb.GetAttributeID("op");
    8082    int at_datatype = xmb.GetAttributeID("datatype");
    8183    enum op {
    8284        INVALID,
    8385        ADD,
    8486        MUL
    8587    } op = INVALID;
    8688    bool replacing = false;
     89    bool filtering = false;
     90    bool merging = false;
    8791    {
    8892        XERO_ITER_ATTR(element, attr)
    8993        {
    9094            if (attr.Name == at_disable)
    9195            {
    void CParamNode::ApplyLayer(const XMBFil  
    9599            else if (attr.Name == at_replace)
    96100            {
    97101                m_Childs.erase(name);
    98102                replacing = true;
    99103            }
     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            }
    100114            else if (attr.Name == at_op)
    101115            {
    102116                if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"add")
    103117                    op = ADD;
    104118                else if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"mul")
    void CParamNode::ApplyLayer(const XMBFil  
    166180            node.m_Value = (oldval.Multiply(mod)).ToString().FromUTF8();
    167181            break;
    168182        }
    169183        hasSetValue = true;
    170184    }
    171     if (!hasSetValue)
     185    if (!hasSetValue && !merging)
    172186        node.m_Value = value;
    173187
     188    // For the filtered case
     189    ChildrenMap childs;
     190
    174191    // Recurse through the element's children
    175192    XERO_ITER_EL(element, child)
    176193    {
    177194        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        }
    178201    }
    179202
     203    if (filtering)
     204        node.m_Childs.swap(childs);
     205
    180206    // Add the element's attributes, prefixing names with "@"
    181207    XERO_ITER_ATTR(element, attr)
    182208    {
    183209        // 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)
    185211            continue;
    186212        // Add any others
    187213        std::string attrName = xmb.GetAttributeString(attr.Name);
    188214        node.m_Childs["@" + attrName].m_Value = attr.Value.FromUTF8();
    189215    }
    190216}
    191217
    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; // error
    200 
    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 
    207218const CParamNode& CParamNode::GetChild(const char* name) const
    208219{
    209220    ChildrenMap::const_iterator it = m_Childs.find(name);
    210221    if (it == m_Childs.end())
    211222        return g_NullNode;
  • source/simulation2/system/ParamNode.h

     
    1 /* Copyright (C) 2015 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    55 * it under the terms of the GNU General Public License as published by
    66 * the Free Software Foundation, either version 2 of the License, or
    class XMBElement;  
    5656 *     <C/>
    5757 *   </Example3>
    5858 *   <Example4 datatype="tokens">
    5959 *     one two three
    6060 *   </Example4>
     61 *   <Example5>
     62 *     <E/>
     63 *     <F>
     64 *       <I>test</I>
     65 *     </F>
     66 *     <H>
     67 *       <J>example</J>
     68 *     </H>
     69 *   </Example5>
    6170 * </Entity>
    6271 * @endcode
    6372 * then a second like:
    6473 * @code
    6574 * <Entity>
    class XMBElement;  
    7382 *   </Example3>
    7483 *   <Example4 datatype="tokens">  <!-- treat as space-separated lists of tokens to merge -->
    7584 *     four             <!-- add a token to the parent's set -->
    7685 *     -two             <!-- remove a token from the parent's set -->
    7786 *   </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>
    7896 * </Entity>
    7997 * @endcode
    8098 * is equivalent to loading a single file like:
    8199 * @code
    82100 * <Entity>
    class XMBElement;  
    88106 *     <D>new</D>
    89107 *   </Example3>
    90108 *   <Example4>
    91109 *     one three four
    92110 *   </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>
    93120 * </Entity>
    94121 * @endcode
    95122 *
    96123 * Parameter nodes can be translated to JavaScript objects. The previous example will become the object:
    97124 * @code
    class XMBElement;  
    101128 *       "D": "new"
    102129 *     },
    103130 *     "Example3": {
    104131 *       "D": "new"
    105132 *     },
    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 *     }
    107143 *   }
    108144 * }
    109145 * @endcode
    110146 * (Note the special @c _string for the hopefully-rare cases where a node contains both child nodes and text.)
    111147 */
    public:  
    144180     *        the data getting loaded. Used for output to log messages if an error occurs.
    145181     */
    146182    static PSRETURN LoadXMLString(CParamNode& ret, const char* xml, const wchar_t* sourceIdentifier = NULL);
    147183
    148184    /**
    149      * Finds the childs named @a name from @a src and from @a this, and copies the source child's children
    150      * 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     /**
    157185     * Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none.
    158186     */
    159187    const CParamNode& GetChild(const char* name) const;
    160188    // (Children are returned as const in order to allow future optimisations, where we assume
    161189    // a node is always modified explicitly and not indirectly via its children, e.g. to cache jsvals)
  • source/simulation2/tests/test_CmpTemplateManager.h

     
    2929#include "graphics/Terrain.h"
    3030#include "ps/Filesystem.h"
    3131#include "ps/CLogger.h"
    3232#include "ps/XML/Xeromyces.h"
    3333
     34static const char SPECIAL_FILTER[] = "simulation/templates/special_filter/";
     35
    3436class TestCmpTemplateManager : public CxxTest::TestSuite
    3537{
    3638public:
    3739    void setUp()
    3840    {
    3941        g_VFS = CreateVfs(20 * MiB);
    4042        TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"_test.sim", VFS_MOUNT_MUST_EXIST));
    4143        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
    4248        CXeromyces::Startup();
    4349    }
    4450
    4551    void tearDown()
    4652    {
    public:  
    115121
    116122        const CParamNode* actor = tempMan->LoadTemplate(ent2, "actor|example1", -1);
    117123        ScriptInterface::ToJSVal(cx, &val, &actor->GetChild("VisualActor"));
    118124        TS_ASSERT_STR_EQUALS(man.GetScriptInterface().ToString(&val), "({Actor:\"example1\", ActorOnly:(void 0), SilhouetteDisplay:\"false\", SilhouetteOccluder:\"false\", VisibleInAtlasOnly:\"false\"})");
    119125
    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        }
    123143    }
    124144
    125145    void test_LoadTemplate_errors()
    126146    {
    127147        CSimContext context;
  • source/simulation2/tests/test_ParamNode.h

     
    1 /* Copyright (C) 2010 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    55 * it under the terms of the GNU General Public License as published by
    66 * the Free Software Foundation, either version 2 of the License, or
    public:  
    133133        CParamNode node;
    134134        TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a datatype='tokens'>  Y  -  X </a></test>"), PSRETURN_OK);
    135135        TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a datatype=\"tokens\">Y X</a></test>");
    136136    }
    137137
     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
    138296    void test_types()
    139297    {
    140298        CParamNode node;
    141299        TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test><n>+010.75</n><t>true</t></test>"), PSRETURN_OK);
    142300        TS_ASSERT(node.GetChild("test").IsOk());