Just a simple, and painful to use calculator for the game Factorio written in Python
Révision | 462d2d0e4160c79b389278dde46bd2e215989fd7 (tree) |
---|---|
l'heure | 2018-02-03 03:37:30 |
Auteur | Eric Hopper <hopper@omni...> |
Commiter | Eric Hopper |
Added code to read and parse XML database.
@@ -5,7 +5,11 @@ | ||
5 | 5 | import sys |
6 | 6 | from collections import namedtuple |
7 | 7 | import re |
8 | +from xml.etree import ElementTree | |
8 | 9 | |
10 | +def _checkXMLHasNoText(xmlel): | |
11 | + return ((xmlel.text is None) or (xmlel.text.strip() == '')) \ | |
12 | + and ((xmlel.tail is None) or (xmlel.tail.strip() == '')) | |
9 | 13 | |
10 | 14 | class ProductionItem: |
11 | 15 | __slots__ = ('_name', '_time', '_ingredients', '_produced', '__weakref__') |
@@ -17,7 +21,6 @@ | ||
17 | 21 | self._time = time |
18 | 22 | def lookup_ingredients(ingredients): |
19 | 23 | for ct, item in ingredients: |
20 | - print(f"Lookup up ({ct}, {item!s})", file=sys.stderr) | |
21 | 24 | if not isinstance(item, ProductionItem): |
22 | 25 | item = item_db[item] |
23 | 26 | print(f"Wasn't already an item, found {item!s}", |
@@ -113,6 +116,67 @@ | ||
113 | 116 | yield from self._itemAsXML(item, item_idmap) |
114 | 117 | yield '</factorio_calc_item_db>\n' |
115 | 118 | |
119 | + @staticmethod | |
120 | + def createFromXML(infile): | |
121 | + newdb = ItemSet() | |
122 | + ET = ElementTree | |
123 | + parser = ET.XMLParser() | |
124 | + block = infile.read(4 * 1024 * 1024) | |
125 | + while len(block) > 0: | |
126 | + parser.feed(block) | |
127 | + block = infile.read(4 * 1024 * 1024) | |
128 | + block = None | |
129 | + tree = parser.close() | |
130 | + parser = None | |
131 | + if tree.tag != 'factorio_calc_item_db': | |
132 | + raise ValueError("Not an XML item database.") | |
133 | + if tree.attrib.get('version', '1.0') != '1.0': | |
134 | + raise ValueError(f"Do not know how to handle version " | |
135 | + f"{tree.attrib['version']}.") | |
136 | + if not _checkXMLHasNoText(tree): | |
137 | + raise ValueError("Invalid XML database.") | |
138 | + item_idmap = {} | |
139 | + for itemel in tree.getchildren(): | |
140 | + itemid, item = ItemSet.itemFromXML(item_idmap, itemel) | |
141 | + item_idmap[itemid] = item | |
142 | + newdb.add(item) | |
143 | + return newdb | |
144 | + | |
145 | + @staticmethod | |
146 | + def itemFromXML(item_idmap, itemel): | |
147 | + if itemel.tag != 'item': | |
148 | + raise ValueError(f"Got element '{itemel.tag}', expecting 'item'.") | |
149 | + itemid = itemel.attrib['id'] | |
150 | + if not _checkXMLHasNoText(itemel): | |
151 | + raise ValueError(f"Invalid item {itemid}") | |
152 | + if itemid in item_idmap: | |
153 | + raise ValueError(f"Item {itemid} defined twice.") | |
154 | + name = itemel.attrib['name'] | |
155 | + time = itemel.attrib.get('time', None) | |
156 | + produced = itemel.attrib.get('produced', None) | |
157 | + if (produced is None) != (time is None): | |
158 | + raise ValueError(f"Invalid item '{itemid}'.") | |
159 | + if time is not None: | |
160 | + time = _F(time) | |
161 | + produced = int(produced) | |
162 | + ingredients = [] | |
163 | + for ingredientel in itemel.getchildren(): | |
164 | + if ingredientel.tag != 'ingredient': | |
165 | + raise ValueError(f"Item {itemid} has {ingredientel.tag}") | |
166 | + ingid = ingredientel.attrib['idref'] | |
167 | + if not _checkXMLHasNoText(ingredientel): | |
168 | + raise ValueError(f"Invalid ingredient '{ingid}' in '{itemid}'") | |
169 | + ingcount = int(ingredientel.attrib['count']) | |
170 | + if ingid not in item_idmap: | |
171 | + raise ValueError(f"Item '{itemid}' mentions ingredient " | |
172 | + f"'{ingid}' before it's defined.") | |
173 | + ingredients.append((ingcount, item_idmap[ingid])) | |
174 | + if (len(ingredients) > 0) and (time is None): | |
175 | + raise ValueError(f"Item '{itemid}' has ingredients but " | |
176 | + "no production time.") | |
177 | + return (itemid, | |
178 | + ProductionItem(name, time, tuple(ingredients), produced)) | |
179 | + | |
116 | 180 | _mod_dir = _osp.dirname(__file__) |
117 | 181 | db_fname = _osp.join(_mod_dir, 'item-db.pickle') |
118 | 182 |