Skip to content

Instantly share code, notes, and snippets.

@nekiro
Last active October 17, 2023 21:44
Show Gist options
  • Save nekiro/d4b74302bc85010e68eda07e55e62d33 to your computer and use it in GitHub Desktop.
Save nekiro/d4b74302bc85010e68eda07e55e62d33 to your computer and use it in GitHub Desktop.
Item name to item id converter script
import sys
sys.modules["_elementtree"] = None
import xml.etree.ElementTree as ET
import os
from pathlib import Path
items = {}
# stolen from https://stackoverflow.com/a/36430270
class LineNumberingParser(ET.XMLParser):
def _start(self, *args, **kwargs):
# Here we assume the default XML parser which is expat
# and copy its element position attributes into output Elements
element = super(self.__class__, self)._start(*args, **kwargs)
element._start_line_number = self.parser.CurrentLineNumber
element._start_column_number = self.parser.CurrentColumnNumber
element._start_byte_index = self.parser.CurrentByteIndex
return element
def _end(self, *args, **kwargs):
element = super(self.__class__, self)._end(*args, **kwargs)
element._end_line_number = self.parser.CurrentLineNumber
element._end_column_number = self.parser.CurrentColumnNumber
element._end_byte_index = self.parser.CurrentByteIndex
return element
def convertMonster(path, name, outPath):
path = os.path.join(path, name)
if not os.path.exists(path):
print("Couldn't find xml file at path {}", path)
return
print("Converting {}".format(name))
root = ET.parse(path, parser=LineNumberingParser(target=ET.TreeBuilder(insert_comments=True))).getroot()
loot = root.find("loot")
if loot is None:
return
commentsLines = {}
for child in loot:
item_name = child.attrib.get("name")
id = child.attrib.get("id")
if item_name is None or id is not None:
continue
child.attrib.pop("name")
id = items.get(item_name.lower())
if id is None:
continue
# trickery to add new attribute as the first attribute, google didn't tell me how to do this in etree :(
copy = list(child.attrib.items())
copy.insert(0, ("id", id))
child.attrib = dict(copy)
# store to add item name comments
commentsLines[child._start_line_number - 1] = item_name # dont ask me why it counts lines wrong, but - 1 fixes it, probably declaration?
outFile = os.path.join(outPath, name)
# save to file
ET.ElementTree(root).write(os.path.join(outPath, name), encoding='utf-8', xml_declaration=True)
# add comments with item name
with open(outFile, "r") as f:
lines = f.readlines()
lines.append("\n")
for key, value in commentsLines.items():
lines[key] = "{} <!-- {} -->\n".format(lines[key].rstrip("\n"), value)
with open(outFile, "w") as f:
f.writelines(lines)
def convertMonsters(path):
path = Path(path).resolve()
if not os.path.exists(path):
exit("Unable to resolve monsters directory, aborting...")
print("Resolved monsters path {}".format(path))
outPath = os.path.join(Path(input("Out directory path (if out not present will create one)")).resolve(), "out")
# ensure out directory is present
if not os.path.exists(outPath):
os.makedirs(outPath)
print("Resolved output path {}".format(outPath))
# convert
for file in os.listdir(path):
if file.endswith(".xml"):
convertMonster(path, file, outPath)
def readItems(path):
path = os.path.join(Path(path).resolve(), "items.xml")
if not os.path.exists(path):
exit('Unable to find items.xml in given path, aborting...')
print("Resolved items path {}".format(path))
root = ET.parse(path).getroot()
for elem in root:
name = elem.attrib.get("name")
id = elem.attrib.get("id")
if name is None or id is None:
continue
items[name.lower()] = id
if __name__ == "__main__":
# read items first
readItems(input("Path to items directory: "))
# monsters
convertMonsters(input("Path to monster directory: "))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment