Skip to content

Commit 81596a2

Browse files
committed
fix score merging
it sucked before but now it doesnt
1 parent d6cc747 commit 81596a2

File tree

1 file changed

+54
-18
lines changed

1 file changed

+54
-18
lines changed

Diff for: XMLMerger/merge_xml.py

+54-18
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@
6565
# Each modern Etterna XML usually has up to 6 sections (in a single giant <Stats> section)
6666
# These sections are always in this order:
6767
# GeneralData, Favorites, Permamirror, Playlists, ScoreGoals, PlayerScores
68-
# We want to merge the XMLs to produce a super XML of both while hopefully staying consistent
69-
# in terms of keeping certain TopScore values with scores. That'll be the hardest part.
68+
# We want to merge the XMLs to produce a super XML of both. The client can sanitize the scores
69+
# as long as they are placed in the correct location, as TopScore and the SSRs are recalculated on startup.
7070

7171
def findSection(xml, sectionName):
7272
''' Find a section of the XML by name. Return None if no section exists.'''
@@ -77,6 +77,10 @@ def findSection(xml, sectionName):
7777

7878
# GeneralData. This contains literally general data and info about the profile.
7979
# I'm expecting this to be already filled out so I won't mess with it.
80+
e_generaldata = findSection(e, "GeneralData")
81+
if e_generaldata is None:
82+
print("The first XML is missing general data so I quit.")
83+
exit()
8084

8185
# Favorites. This contains a list of chartkeys as tag endings, simply enough.
8286
# We can merge this.
@@ -211,47 +215,79 @@ def findSection(xml, sectionName):
211215
# This is the largest and most important piece of information.
212216
# Merging this is very tough.
213217
# Consider: Each score is organized by Chart Key. Beyond that, it is organized by lists of scores at a rate.
214-
# Each score has a TopScore status. This status is likely to change (and should be recalculated by the game anyways)
215-
# Due to astronomical amounts of laziness, I have chosen to just cram the elements all into one pile.
216-
# (and also filter out duplicates in the process)
217-
all_scores = {}
218+
219+
all_scores = {} # by chartkey
218220
e_score_section = findSection(e, "PlayerScores")
219221
e2_score_section = findSection(e2, "PlayerScores")
220222

223+
all_score_keys = set() # by scorekey
221224
if e_score_section is not None:
222225
print("Main xml score size", len(e_score_section))
223226
for chart in list(e_score_section):
224227
key = chart.attrib["Key"]
225228
if key not in all_scores:
226-
all_scores[key] = chart
229+
all_scores[key] = {}
230+
for scoresat in list(chart):
231+
all_scores[key][scoresat.attrib["Rate"]] = scoresat
232+
for score in list(scoresat):
233+
all_score_keys.add(score.attrib["Key"])
227234
else:
228235
for scoresat in list(chart):
229-
all_scores[key].append(scoresat)
236+
rate = scoresat.attrib["Rate"]
237+
if rate in all_scores[key]:
238+
for score in list(scoresat):
239+
if score.attrib["Key"] in all_score_keys:
240+
continue
241+
all_score_keys.add(score.attrib["Key"])
242+
ggg = xml.etree.ElementTree.SubElement(all_scores[key][rate], "Score", attrib={"Key": score.attrib["Key"]})
243+
ggg.extend(score)
244+
else:
245+
all_scores[key][scoresat.attrib["Rate"]] = scoresat
246+
for score in list(scoresat):
247+
all_score_keys.add(score.attrib["Key"])
248+
230249

231250
if e2_score_section is not None:
232251
print("Second xml score size", len(e2_score_section))
233252
for chart in list(e2_score_section):
234253
key = chart.attrib["Key"]
235254
if key not in all_scores:
236-
all_scores[key] = chart
255+
all_scores[key] = {}
256+
for scoresat in list(chart):
257+
all_scores[key][scoresat.attrib["Rate"]] = scoresat
258+
for score in list(scoresat):
259+
all_score_keys.add(score.attrib["Key"])
237260
else:
238261
for scoresat in list(chart):
239-
all_scores[key].append(scoresat)
262+
rate = scoresat.attrib["Rate"]
263+
if rate in all_scores[key]:
264+
for score in list(scoresat):
265+
if score.attrib["Key"] in all_score_keys:
266+
continue
267+
all_score_keys.add(score.attrib["Key"])
268+
ggg = xml.etree.ElementTree.SubElement(all_scores[key][rate], "Score", attrib={"Key": score.attrib["Key"]})
269+
ggg.extend(score)
270+
else:
271+
all_scores[key][scoresat.attrib["Rate"]] = scoresat
272+
for score in list(scoresat):
273+
all_score_keys.add(score.attrib["Key"])
240274
e3_score_section = None
241275
if len(all_scores) > 0:
242276
e3_score_section = xml.etree.ElementTree.Element("PlayerScores")
243-
for chart_element in all_scores.values():
244-
e3_score_section.append(chart_element)
245-
print("Final xml score size", len(e3_score_section))
246-
277+
for chartkey, scoresat in all_scores.items():
278+
cnode = xml.etree.ElementTree.SubElement(e3_score_section, "Chart")
279+
cnode.attrib["Key"] = chartkey
280+
for rate, scores in scoresat.items():
281+
satnode = xml.etree.ElementTree.SubElement(cnode, "ScoresAt")
282+
satnode.attrib["Rate"] = rate
283+
for s in list(scores):
284+
snode = xml.etree.ElementTree.SubElement(satnode, "Score", attrib={"Key": s.attrib["Key"]})
285+
snode.extend(s)
286+
print("Final xml score size", len(e3_score_section))
247287

248288

249289
# Outputting the xml.
250290
root = xml.etree.ElementTree.Element("Stats")
251-
e_generaldata = findSection(e, "GeneralData")
252-
if e_generaldata is None:
253-
print("The first XML is missing general data so I quit.")
254-
exit()
255291

256292
root.append(e_generaldata)
257293
if favorites_Element is not None:

0 commit comments

Comments
 (0)