From 838c57f3a17b1befc246b577bd1b174ce3823c2a Mon Sep 17 00:00:00 2001
From: leper <leper@wildfiregames.com>
Date: Mon, 11 Apr 2016 03:45:15 +0200
Subject: [PATCH] Fix some issues.
* Do not specify Health twice for foundations.
* Change merging behaviour slightly to fix the Identity case.
Previously using merge="" would overwrite the value of that tag with the new value,
this would lead to all elements below Identity having empty/undef values, causing
the GUI to complain about the specific name not being defined.
* Only keep elements that are actually defined in the parent if we are filtering. (merge fix #2)
* Remove unused function.
* Add tests for some of the above issues.
TODO: Check if some of the tests are (partially) duplicated, and possibly fix the tags of the last test.
---
.../templates/special_filter/foundation.xml | 9 ++++-----
source/simulation2/system/ParamNode.cpp | 22 +++++-----------------
source/simulation2/system/ParamNode.h | 8 --------
source/simulation2/tests/test_ParamNode.h | 13 +++++++++++++
4 files changed, 22 insertions(+), 30 deletions(-)
diff --git a/binaries/data/mods/public/simulation/templates/special_filter/foundation.xml b/binaries/data/mods/public/simulation/templates/special_filter/foundation.xml
index e294934..633ccdc 100644
a
|
b
|
|
8 | 8 | <PopulationBonus>0</PopulationBonus> |
9 | 9 | </Cost> |
10 | 10 | <Decay merge=""/> |
11 | | <!-- Initialise health to 1 --> |
12 | | <Health> |
13 | | <Initial>1</Initial> |
14 | | </Health> |
15 | 11 | <Fogging merge=""/> |
16 | 12 | <Footprint merge=""/> |
17 | 13 | <!-- Add the Foundation component, to deal with the construction process --> |
18 | 14 | <Foundation replace=""/> |
19 | | <Health merge=""/> |
| 15 | <!-- Initialise health to 1 --> |
| 16 | <Health> |
| 17 | <Initial>1</Initial> |
| 18 | </Health> |
20 | 19 | <Identity merge=""/> |
21 | 20 | <!-- Foundations shouldn't initially block unit movement --> |
22 | 21 | <Obstruction merge=""> |
diff --git a/source/simulation2/system/ParamNode.cpp b/source/simulation2/system/ParamNode.cpp
index 74ca203..e41df76 100644
a
|
b
|
void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
|
87 | 87 | } op = INVALID; |
88 | 88 | bool replacing = false; |
89 | 89 | bool filtering = false; |
| 90 | bool merging = false; |
90 | 91 | { |
91 | 92 | XERO_ITER_ATTR(element, attr) |
92 | 93 | { |
… |
… |
void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
|
108 | 109 | { |
109 | 110 | if (m_Childs.find(name) == m_Childs.end()) |
110 | 111 | return; |
| 112 | merging = true; |
111 | 113 | } |
112 | 114 | else if (attr.Name == at_op) |
113 | 115 | { |
… |
… |
void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
|
183 | 185 | } |
184 | 186 | hasSetValue = true; |
185 | 187 | } |
186 | | if (!hasSetValue) |
| 188 | if (!hasSetValue && !merging) |
187 | 189 | node.m_Value = value; |
188 | 190 | |
189 | 191 | // Recurse through the element's children |
… |
… |
void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
|
193 | 195 | if (filtering) |
194 | 196 | { |
195 | 197 | std::string childname = xmb.GetElementString(child.GetNodeName()); // TODO: is GetElementString inefficient? (especially if we call it twice) |
196 | | childs[childname] = std::move(node.m_Childs[childname]); |
| 198 | if (node.m_Childs.find(childname) != node.m_Childs.end()) |
| 199 | childs[childname] = std::move(node.m_Childs[childname]); |
197 | 200 | } |
198 | 201 | } |
199 | 202 | |
… |
… |
void CParamNode::ApplyLayer(const XMBFile& xmb, const XMBElement& element, const
|
212 | 215 | } |
213 | 216 | } |
214 | 217 | |
215 | | void CParamNode::CopyFilteredChildrenOfChild(const CParamNode& src, const char* name, const std::set<std::string>& permitted) |
216 | | { |
217 | | ResetScriptVal(); |
218 | | |
219 | | ChildrenMap::iterator dstChild = m_Childs.find(name); |
220 | | ChildrenMap::const_iterator srcChild = src.m_Childs.find(name); |
221 | | if (dstChild == m_Childs.end() || srcChild == src.m_Childs.end()) |
222 | | return; // error |
223 | | |
224 | | ChildrenMap::const_iterator it = srcChild->second.m_Childs.begin(); |
225 | | for (; it != srcChild->second.m_Childs.end(); ++it) |
226 | | if (permitted.count(it->first)) |
227 | | dstChild->second.m_Childs[it->first] = it->second; |
228 | | } |
229 | | |
230 | 218 | const CParamNode& CParamNode::GetChild(const char* name) const |
231 | 219 | { |
232 | 220 | ChildrenMap::const_iterator it = m_Childs.find(name); |
diff --git a/source/simulation2/system/ParamNode.h b/source/simulation2/system/ParamNode.h
index 9ce530e..0b18e5e 100644
a
|
b
|
public:
|
182 | 182 | static PSRETURN LoadXMLString(CParamNode& ret, const char* xml, const wchar_t* sourceIdentifier = NULL); |
183 | 183 | |
184 | 184 | /** |
185 | | * Finds the childs named @a name from @a src and from @a this, and copies the source child's children |
186 | | * which are in the @a permitted set into this node's child. |
187 | | * Intended for use as a filtered clone of XML files. |
188 | | * @a this and @a src must have childs named @a name. |
189 | | */ |
190 | | void CopyFilteredChildrenOfChild(const CParamNode& src, const char* name, const std::set<std::string>& permitted); |
191 | | |
192 | | /** |
193 | 185 | * Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none. |
194 | 186 | */ |
195 | 187 | const CParamNode& GetChild(const char* name) const; |
diff --git a/source/simulation2/tests/test_ParamNode.h b/source/simulation2/tests/test_ParamNode.h
index d329424..fc9a1ed 100644
a
|
b
|
public:
|
141 | 141 | TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a><b/></a> <c>toberemoved</c> <d><e/></d> </test>"), PSRETURN_OK); |
142 | 142 | TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test filtered=\"\"> <a/> <d><f/></d> <g/> </test>"), PSRETURN_OK); |
143 | 143 | TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a><b></b></a><d><e></e><f></f></d><g></g></test>"); |
| 144 | |
| 145 | CParamNode node2; |
| 146 | TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node2, "<test> <a><b>b</b><c>c</c><d>d</d><e>e</e></a> <f/> </test>"), PSRETURN_OK); |
| 147 | TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node2, "<test filtered=\"\"> <a filtered=\"\"><b merge=\"\"/><c>c2</c><d/></a> </test>"), PSRETURN_OK); |
| 148 | TS_ASSERT_WSTR_EQUALS(node2.ToXML(), L"<test><a><b>b</b><c>c2</c><d></d></a></test>"); |
144 | 149 | } |
145 | 150 | |
146 | 151 | void test_overlay_merge() |
… |
… |
public:
|
151 | 156 | TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><a><b>test</b><c>bar</c><d>baz</d></a><x><w>more text</w><y><v>text</v><z>foo</z></y></x></test>"); |
152 | 157 | } |
153 | 158 | |
| 159 | void test_overlay_filtered_merge() |
| 160 | { |
| 161 | CParamNode node; |
| 162 | TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test> <a><b/></a> <c><x/></c> <Health><Max>1200</Max></Health> </test>"), PSRETURN_OK); |
| 163 | TS_ASSERT_EQUALS(CParamNode::LoadXMLString(node, "<test filtered=\"\"> <c merge=\"\"/> <d>bar</d> <e merge=\"\"/> <Health><Initial>1</Initial></Health> </test>"), PSRETURN_OK); |
| 164 | TS_ASSERT_WSTR_EQUALS(node.ToXML(), L"<test><Health><Initial>1</Initial><Max>1200</Max></Health><c><x></x></c><d>bar</d></test>"); |
| 165 | } |
| 166 | |
154 | 167 | void test_types() |
155 | 168 | { |
156 | 169 | CParamNode node; |