Changeset View
Changeset View
Standalone View
Standalone View
source/tools/entity/scriptlib/__init__.py
from collections import Counter | from collections import Counter | ||||
from decimal import Decimal | from decimal import Decimal | ||||
from re import split | from re import split | ||||
from sys import stderr | |||||
from xml.etree import ElementTree | from xml.etree import ElementTree | ||||
from os.path import exists | from os.path import exists | ||||
class SimulTemplateEntity: | class SimulTemplateEntity: | ||||
def __init__(self, vfs_root, logger): | def __init__(self, vfs_root, logger): | ||||
self.vfs_root = vfs_root | self.vfs_root = vfs_root | ||||
self.logger = logger | self.logger = logger | ||||
def get_file(self, base_path, vfs_path, mod): | def get_file(self, base_path, vfs_path, mod): | ||||
default_path = self.vfs_root / mod / base_path | default_path = self.vfs_root / mod / base_path | ||||
file = (default_path/ "special" / "filter" / vfs_path).with_suffix('.xml') | file = (default_path / "special" / "filter" / vfs_path).with_suffix('.xml') | ||||
if not exists(file): | if not exists(file): | ||||
file = (default_path / "mixins" / vfs_path).with_suffix('.xml') | file = (default_path / "mixins" / vfs_path).with_suffix('.xml') | ||||
if not exists(file): | if not exists(file): | ||||
file = (default_path / vfs_path).with_suffix('.xml') | file = (default_path / vfs_path).with_suffix('.xml') | ||||
return file | return file | ||||
def get_main_mod(self, base_path, vfs_path, mods): | def get_main_mod(self, base_path, vfs_path, mods): | ||||
for mod in mods: | for mod in mods: | ||||
Show All 19 Lines | def apply_layer(self, base_tag, tag): | ||||
for token in tokens: | for token in tokens: | ||||
if token.startswith('-'): | if token.startswith('-'): | ||||
token_to_remove = token[1:] | token_to_remove = token[1:] | ||||
if token_to_remove in final_tokens: | if token_to_remove in final_tokens: | ||||
final_tokens.remove(token_to_remove) | final_tokens.remove(token_to_remove) | ||||
elif token not in final_tokens: | elif token not in final_tokens: | ||||
final_tokens.append(token) | final_tokens.append(token) | ||||
base_tag.text = ' '.join(final_tokens) | base_tag.text = ' '.join(final_tokens) | ||||
base_tag.set("datatype", "tokens") | |||||
elif tag.get('op'): | elif tag.get('op'): | ||||
op = tag.get('op') | op = tag.get('op') | ||||
op1 = Decimal(base_tag.text or '0') | op1 = Decimal(base_tag.text or '0') | ||||
op2 = Decimal(tag.text or '0') | op2 = Decimal(tag.text or '0') | ||||
# Try converting to integers if possible, to pass validation. | |||||
if op == 'add': | if op == 'add': | ||||
base_tag.text = str(op1 + op2) | base_tag.text = str(int(op1 + op2) if int(op1 + op2) == op1 + op2 else op1 + op2) | ||||
elif op == 'mul': | elif op == 'mul': | ||||
base_tag.text = str(op1 * op2) | base_tag.text = str(int(op1 * op2) if int(op1 * op2) == op1 * op2 else op1 * op2) | ||||
elif op == 'mul_round': | elif op == 'mul_round': | ||||
base_tag.text = str(round(op1 * op2)) | base_tag.text = str(round(op1 * op2)) | ||||
else: | else: | ||||
raise ValueError(f"Invalid operator '{op}'") | raise ValueError(f"Invalid operator '{op}'") | ||||
else: | else: | ||||
base_tag.text = tag.text | base_tag.text = tag.text | ||||
for prop in tag.attrib: | |||||
if prop not in ('disable', 'replace', 'parent', 'merge'): | |||||
base_tag.set(prop, tag.get(prop)) | |||||
for child in tag: | for child in tag: | ||||
base_child = base_tag.find(child.tag) | base_child = base_tag.find(child.tag) | ||||
if 'disable' in child.attrib: | if 'disable' in child.attrib: | ||||
if base_child is not None: | if base_child is not None: | ||||
base_tag.remove(base_child) | base_tag.remove(base_child) | ||||
else: | elif ('merge' not in child.attrib) or (base_child is not None): | ||||
if 'replace' in child.attrib and base_child is not None: | if 'replace' in child.attrib and base_child is not None: | ||||
base_tag.remove(base_child) | base_tag.remove(base_child) | ||||
base_child = None | |||||
if base_child is None: | if base_child is None: | ||||
base_child = ElementTree.Element(child.tag) | base_child = ElementTree.Element(child.tag) | ||||
base_tag.append(base_child) | base_tag.append(base_child) | ||||
self.apply_layer(base_child, child) | self.apply_layer(base_child, child) | ||||
if 'replace' in base_child.attrib: | if 'replace' in base_child.attrib: | ||||
del base_child.attrib['replace'] | del base_child.attrib['replace'] | ||||
def load_inherited(self, base_path, vfs_path, mods, base = None): | def load_inherited(self, base_path, vfs_path, mods): | ||||
entity = self._load_inherited(base_path, vfs_path, mods) | |||||
entity[:] = sorted(entity[:], key=lambda x: x.tag) | |||||
return entity | |||||
def _load_inherited(self, base_path, vfs_path, mods, base=None): | |||||
""" | """ | ||||
vfs_path should be relative to base_path in a mod | vfs_path should be relative to base_path in a mod | ||||
""" | """ | ||||
if '|' in vfs_path: | if '|' in vfs_path: | ||||
paths = vfs_path.split("|", 2) | paths = vfs_path.split("|", 1) | ||||
base = self.load_inherited(base_path, paths[1], mods, base); | base = self._load_inherited(base_path, paths[1], mods, base) | ||||
base = self.load_inherited(base_path, paths[0], mods, base); | base = self._load_inherited(base_path, paths[0], mods, base) | ||||
return base | return base | ||||
main_mod = self.get_main_mod(base_path, vfs_path, mods) | main_mod = self.get_main_mod(base_path, vfs_path, mods) | ||||
fp = self.get_file(base_path, vfs_path, main_mod) | fp = self.get_file(base_path, vfs_path, main_mod) | ||||
layer = ElementTree.parse(fp).getroot() | layer = ElementTree.parse(fp).getroot() | ||||
for el in layer.iter(): | for el in layer.iter(): | ||||
children = [x.tag for x in el] | children = [x.tag for x in el] | ||||
duplicates = [x for x, c in Counter(children).items() if c > 1] | duplicates = [x for x, c in Counter(children).items() if c > 1] | ||||
if duplicates: | if duplicates: | ||||
for dup in duplicates: | for dup in duplicates: | ||||
self.logger.warning(f"Duplicate child node '{dup}' in tag {el.tag} of {fp}") | self.logger.warning(f"Duplicate child node '{dup}' in tag {el.tag} of {fp}") | ||||
if layer.get('parent'): | if layer.get('parent'): | ||||
parent = self.load_inherited(base_path, layer.get('parent'), mods) | parent = self._load_inherited(base_path, layer.get('parent'), mods, base) | ||||
self.apply_layer(parent, layer) | self.apply_layer(parent, layer) | ||||
return parent | return parent | ||||
else: | else: | ||||
if not base: | if not base: | ||||
return layer | return layer | ||||
else: | else: | ||||
self.apply_layer(base, layer) | self.apply_layer(base, layer) | ||||
return base | return base | ||||
Show All 20 Lines |
Wildfire Games · Phabricator