Add A25 to A26 scripts
This commit is contained in:
parent
0af8f6b051
commit
675591324c
0
.normalized_ao_public
Normal file
0
.normalized_ao_public
Normal file
68
A25ToA26.py
Normal file
68
A25ToA26.py
Normal file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from A25_A26.ElevationBonusFixer import ElevationBonusFixer
|
||||
from A25_A26.PlayerXMLFixer import PlayerXMLFixer
|
||||
from A25_A26.SessionIconPathFixer import SessionIconPathFixer
|
||||
from A25_A26.FixNewPlayerParent import FixNewPlayerParent
|
||||
from A25_A26.FormationFixer import FormationFixer
|
||||
from A25_A26.PlayerXMLFormationFixer import PlayerXMLFormationFixer
|
||||
from A25_A26.P256 import TemplateFixer, ModifiersFixer
|
||||
from A25_A26.P259 import convert_recursively
|
||||
from A25_A26.P261 import TemplateFixer as TemplateFixerP261, SedLike
|
||||
from A25_A26.FancyGrassRemover import FancyGrassRemover
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser(description='A25 to A26 converter.')
|
||||
parser.add_argument('-r', '--root', action='store', dest='root', default=os.path.dirname(os.path.realpath(__file__)))
|
||||
parser.add_argument('-m', '--mod', action='store', dest='mod', default='public')
|
||||
parser.add_argument('-v', '--verbose', action='store_true', default=False, help="Be verbose.")
|
||||
args = parser.parse_args()
|
||||
script_dir = args.root
|
||||
mod_name = args.mod
|
||||
path = Path(script_dir) / mod_name
|
||||
print(f"Running in {path}")
|
||||
print("Running P256...")
|
||||
template_fixer = TemplateFixer(path)
|
||||
template_fixer.run()
|
||||
modifier_fixer = ModifiersFixer(path)
|
||||
modifier_fixer.run()
|
||||
if not os.path.exists('.normalized_ao_' + mod_name) and os.path.isdir(path):
|
||||
print("Running P259...")
|
||||
convert_recursively(path)
|
||||
(Path('.normalized_ao_' + mod_name)).touch()
|
||||
else:
|
||||
print("Skipping P259...")
|
||||
print("Fixing r26074...")
|
||||
elevationFixer = ElevationBonusFixer(path, args.verbose)
|
||||
elevationFixer.run()
|
||||
print("Running P261...")
|
||||
template_fixer = TemplateFixerP261(path)
|
||||
template_fixer.run()
|
||||
print("Running FancyGrassRemover...")
|
||||
remover = FancyGrassRemover(path, args.verbose)
|
||||
remover.run()
|
||||
print("Fixing r26298...")
|
||||
fixer = PlayerXMLFixer(path, args.verbose)
|
||||
fixer.run()
|
||||
print("Fixing r26299...")
|
||||
fixer = PlayerXMLFormationFixer(path, args.verbose)
|
||||
fixer.run()
|
||||
print("Fixing r26317...")
|
||||
fixer = SessionIconPathFixer(path, args.verbose)
|
||||
fixer.run()
|
||||
print("Fixing r26458 ...")
|
||||
fixer = FixNewPlayerParent(path, args.verbose)
|
||||
fixer.run()
|
||||
print("Fixing r26476...")
|
||||
fixer = FormationFixer(path, args.verbose)
|
||||
fixer.run()
|
||||
|
54
A25_A26/ElevationBonusFixer.py
Normal file
54
A25_A26/ElevationBonusFixer.py
Normal file
@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from utils.fixers.BaseFixer import BaseFixer
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import os
|
||||
|
||||
class ElevationBonusFixer(BaseFixer):
|
||||
def __init__(self, vfs_root, verbose=False):
|
||||
BaseFixer.__init__(self, vfs_root, verbose, __name__)
|
||||
self.add_files(os.path.join('simulation', 'templates'), tuple(".xml"))
|
||||
|
||||
def fixEffectDelay(self, root):
|
||||
cmpAttack = root.find('Attack')
|
||||
changed = False
|
||||
|
||||
if cmpAttack is not None:
|
||||
for attack_type in cmpAttack:
|
||||
delay = attack_type.find('Delay')
|
||||
if delay is not None:
|
||||
delay.tag = 'EffectDelay'
|
||||
changed = True
|
||||
|
||||
return changed
|
||||
|
||||
def fixElevationBonus(self, root):
|
||||
cmpAttack = root.find('Attack')
|
||||
changed = False
|
||||
|
||||
if cmpAttack is not None:
|
||||
for attack_type in cmpAttack:
|
||||
bonus = attack_type.find('ElevationBonus')
|
||||
if bonus is not None:
|
||||
ET.SubElement(bonus, 'X').text = '0'
|
||||
ET.SubElement(bonus, 'Y').text = bonus.text
|
||||
ET.SubElement(bonus, 'Z').text = '0'
|
||||
bonus.tag = 'Origin'
|
||||
bonus.text = ''
|
||||
changed = True
|
||||
|
||||
return changed
|
||||
|
||||
def run(self):
|
||||
for file in self.files:
|
||||
tree = ET.parse(file)
|
||||
root = tree.getroot()
|
||||
if self.fixElevationBonus(root) or self.fixEffectDelay(root):
|
||||
self.logger.info(f'Saving {file}')
|
||||
self.save_xml_file(tree, root, file)
|
43
A25_A26/FancyGrassRemover.py
Normal file
43
A25_A26/FancyGrassRemover.py
Normal file
@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from utils.fixers.BaseFixer import BaseFixer
|
||||
from utils.PMPMap import PmpMap
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
class FancyGrassRemover(BaseFixer):
|
||||
def __init__(self, vfs_root, verbose=False):
|
||||
BaseFixer.__init__(self, vfs_root, verbose, __name__)
|
||||
self.vfs_root = Path(vfs_root)
|
||||
self.verbose = verbose
|
||||
self.add_files(os.path.join("maps"), tuple(".pmp"))
|
||||
|
||||
def run(self):
|
||||
for filePath in self.files:
|
||||
with open(filePath, "r+b") as f1:
|
||||
pmpMap = PmpMap(f1)
|
||||
hasChanged = False
|
||||
if (self.verbose):
|
||||
self.logger.info(f'Parsing {filePath}')
|
||||
for textureIndex in range(0, len(pmpMap.textures)):
|
||||
texture = pmpMap.textures[textureIndex]
|
||||
if '_fancy' in texture:
|
||||
pmpMap.header.data_size -= len(texture)
|
||||
if (self.verbose):
|
||||
self.logger.info(f'Replacing {texture} by {texture.replace("_fancy", "")}')
|
||||
pmpMap.textures[textureIndex] = texture.replace('_fancy', '')
|
||||
pmpMap.header.data_size += len(texture)
|
||||
hasChanged = True
|
||||
if hasChanged:
|
||||
self.logger.info(f"Patching {filePath}...")
|
||||
f1.seek(0)
|
||||
pmpMap.write_to_stream(f1)
|
||||
else:
|
||||
f1.close()
|
||||
|
23
A25_A26/FixNewPlayerParent.py
Normal file
23
A25_A26/FixNewPlayerParent.py
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from utils.fixers.BaseFixer import BaseFixer
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import os
|
||||
|
||||
class FixNewPlayerParent(BaseFixer):
|
||||
def __init__(self, vfs_root, verbose=False):
|
||||
BaseFixer.__init__(self, vfs_root, verbose, __name__)
|
||||
self.add_files(os.path.join('simulation', 'templates', 'special', 'players'), tuple(".xml"))
|
||||
|
||||
def run(self):
|
||||
for file in self.files:
|
||||
tree = ET.parse(file)
|
||||
root = tree.getroot()
|
||||
root.set('parent', "template_player")
|
||||
self.save_xml_file(tree, root, file)
|
40
A25_A26/FormationFixer.py
Normal file
40
A25_A26/FormationFixer.py
Normal file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from utils.fixers.BaseFixer import BaseFixer
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import os
|
||||
|
||||
class FormationFixer(BaseFixer):
|
||||
def __init__(self, vfs_root, verbose=False):
|
||||
BaseFixer.__init__(self, vfs_root, verbose, __name__)
|
||||
self.add_files(os.path.join('simulation', 'templates'), tuple(".xml"))
|
||||
|
||||
def run(self):
|
||||
for file in self.files:
|
||||
tree = ET.parse(file)
|
||||
root = tree.getroot()
|
||||
cmp_formation = root.find('Formation')
|
||||
if cmp_formation is None:
|
||||
continue
|
||||
|
||||
cmp_identity = self.create_tag_if_not_exist(root, 'Identity')
|
||||
formation_icon_tag = cmp_formation.find('Icon')
|
||||
if formation_icon_tag is not None:
|
||||
icon_tag = self.create_tag_if_not_exist(cmp_identity, 'Icon')
|
||||
icon_tag.text = formation_icon_tag.text
|
||||
|
||||
cmp_formation.remove(formation_icon_tag)
|
||||
|
||||
formation_name_tag = cmp_formation.find('FormationName')
|
||||
if formation_name_tag is not None:
|
||||
generic_name_tag = self.create_tag_if_not_exist(cmp_identity, 'GenericName')
|
||||
generic_name_tag.text = formation_name_tag.text
|
||||
cmp_formation.remove(formation_name_tag)
|
||||
|
||||
self.save_xml_file(tree, root, file)
|
113
A25_A26/P256.py
Normal file
113
A25_A26/P256.py
Normal file
@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Freagarach
|
||||
|
||||
import fileinput
|
||||
import glob
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
class SedLike:
|
||||
def sed(path, changes):
|
||||
for line in fileinput.input(path, inplace=True, encoding='utf-8'):
|
||||
for change in changes:
|
||||
line = line.replace(change[0], change[1])
|
||||
print(line, end="")
|
||||
|
||||
class TemplateFixer:
|
||||
def __init__(self, vfs_root):
|
||||
self.template_folder = os.path.join(vfs_root, 'simulation', 'templates')
|
||||
|
||||
def fix_template(self, template_path):
|
||||
tree = ET.parse(template_path)
|
||||
root = tree.getroot()
|
||||
production_queue = root.find('ProductionQueue')
|
||||
if production_queue == None:
|
||||
return False
|
||||
|
||||
technologies = production_queue.find('Technologies')
|
||||
tech_cost_multiplier = production_queue.find('TechCostMultiplier')
|
||||
if technologies != None or tech_cost_multiplier != None:
|
||||
researcher = ET.Element('Researcher')
|
||||
if (technologies != None):
|
||||
researcher.append(technologies)
|
||||
production_queue.remove(technologies)
|
||||
if (tech_cost_multiplier != None):
|
||||
researcher.append(tech_cost_multiplier)
|
||||
production_queue.remove(tech_cost_multiplier)
|
||||
researcher[:] = sorted(researcher, key=lambda x: x.tag)
|
||||
root.append(researcher)
|
||||
|
||||
entities = production_queue.find('Entities')
|
||||
batch_time_modifier = production_queue.find('BatchTimeModifier')
|
||||
if entities != None or batch_time_modifier != None:
|
||||
trainer = ET.Element('Trainer')
|
||||
if (entities != None):
|
||||
trainer.append(entities)
|
||||
production_queue.remove(entities)
|
||||
if (batch_time_modifier != None):
|
||||
trainer.append(batch_time_modifier)
|
||||
production_queue.remove(batch_time_modifier)
|
||||
trainer[:] = sorted(trainer, key=lambda x: x.tag)
|
||||
root.append(trainer)
|
||||
|
||||
if production_queue.get('disable') != None:
|
||||
for element in ["Researcher", "Trainer"]:
|
||||
existing_element = root.find(element)
|
||||
if existing_element is None:
|
||||
functionality = ET.Element(element)
|
||||
functionality.set('disable', "")
|
||||
root.append(functionality)
|
||||
else:
|
||||
existing_element.set('disable', "")
|
||||
else:
|
||||
root.remove(production_queue)
|
||||
|
||||
root[:] = sorted(root, key=lambda x: x.tag)
|
||||
ET.indent(tree)
|
||||
|
||||
tree.write(template_path, xml_declaration=True, encoding='utf-8')
|
||||
return True
|
||||
|
||||
def fix_style(self, template_path):
|
||||
self.changes = [
|
||||
[' />', '/>'],
|
||||
["version='1.0'", 'version="1.0"'],
|
||||
["'utf-8'", '"utf-8"']
|
||||
]
|
||||
SedLike.sed(template_path, self.changes)
|
||||
with open(template_path, 'a' , encoding='utf-8') as file:
|
||||
file.write('\n')
|
||||
|
||||
def run(self):
|
||||
for template in glob.iglob(self.template_folder + '/**/*.xml', recursive=True):
|
||||
if self.fix_template(template):
|
||||
print(template)
|
||||
self.fix_style(template)
|
||||
|
||||
|
||||
class ModifiersFixer:
|
||||
def __init__(self, vfs_root):
|
||||
self.data_folder = os.path.join(vfs_root, 'simulation', 'data')
|
||||
self.changes = [
|
||||
["ProductionQueue/Batch", "Trainer/Batch"],
|
||||
["ProductionQueue/Ent", "Trainer/Ent"],
|
||||
["ProductionQueue/Train", "Trainer/Train"],
|
||||
["ProductionQueue/Tech", "Researcher/Tech"],
|
||||
]
|
||||
|
||||
def run(self):
|
||||
for modification in glob.iglob(self.data_folder + '/**/*.json', recursive=True):
|
||||
SedLike.sed(modification, self.changes)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
template_fixer = TemplateFixer(script_dir)
|
||||
template_fixer.run()
|
||||
|
||||
modifier_fixer = ModifiersFixer(script_dir)
|
||||
modifier_fixer.run()
|
52
A25_A26/P259.py
Normal file
52
A25_A26/P259.py
Normal file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Vladislav Belov
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
def convert_ao(path):
|
||||
if 'ao' not in path.lower():
|
||||
return
|
||||
print(path)
|
||||
|
||||
image = Image.open(path)
|
||||
image_out = Image.new('L', image.size)
|
||||
for y in range(image.size[1]):
|
||||
for x in range(image.size[0]):
|
||||
if image.mode in ['1', 'L', 'P']:
|
||||
ao = float(image.getpixel((x, y))) / 255.0
|
||||
else:
|
||||
ao = float(image.getpixel((x, y))[0]) / 255.0
|
||||
ao = 0.3 + ao * 2.0 * 0.7 # Might be adjusted for a particular mod.
|
||||
gray = int(ao * 255)
|
||||
if gray < 0:
|
||||
gray = 0
|
||||
elif gray > 255:
|
||||
gray = 255
|
||||
image_out.putpixel((x, y), (gray))
|
||||
image_out.save(path)
|
||||
|
||||
def convert_recursively(path):
|
||||
for file_name in os.listdir(path):
|
||||
file_path = os.path.join(path, file_name)
|
||||
if os.path.isfile(file_path):
|
||||
name, ext = os.path.splitext(file_name)
|
||||
if ext.lower() in ['.png']:
|
||||
convert_ao(file_path)
|
||||
elif os.path.isdir(file_path):
|
||||
convert_recursively(file_path)
|
||||
|
||||
if __name__ == '__main__':
|
||||
paths = sys.argv[1:]
|
||||
for path in paths:
|
||||
if os.path.isfile(path):
|
||||
convert_ao(path)
|
||||
elif os.path.isdir(path):
|
||||
convert_recursively(path)
|
||||
|
70
A25_A26/P261.py
Normal file
70
A25_A26/P261.py
Normal file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Freagarach
|
||||
|
||||
import fileinput
|
||||
import glob
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
class SedLike:
|
||||
def sed(path, changes):
|
||||
for line in fileinput.input(path, inplace=True, encoding='utf-8'):
|
||||
for change in changes:
|
||||
line = line.replace(change[0], change[1])
|
||||
print(line, end="")
|
||||
|
||||
class TemplateFixer:
|
||||
def __init__(self, vfs_root):
|
||||
self.template_folder = os.path.join(vfs_root, 'simulation', 'templates')
|
||||
|
||||
def fix_template(self, template_path):
|
||||
tree = ET.parse(template_path)
|
||||
root = tree.getroot()
|
||||
cmp_identity = root.find('Identity')
|
||||
if cmp_identity == None:
|
||||
return False
|
||||
|
||||
formations = cmp_identity.find('Formations')
|
||||
if formations == None:
|
||||
return False
|
||||
|
||||
cmp_unitai = root.find('UnitAI')
|
||||
if cmp_unitai == None:
|
||||
cmp_unitai = ET.Element('UnitAI')
|
||||
root.append(cmp_unitai)
|
||||
cmp_unitai.append(formations)
|
||||
cmp_identity.remove(formations)
|
||||
|
||||
if cmp_identity.__len__() == 0:
|
||||
root.remove(cmp_identity)
|
||||
|
||||
root[:] = sorted(root, key=lambda x: x.tag)
|
||||
ET.indent(tree)
|
||||
|
||||
tree.write(template_path, xml_declaration=True, encoding='utf-8')
|
||||
return True
|
||||
|
||||
def fix_style(self, template_path):
|
||||
self.changes = [
|
||||
[' />', '/>'],
|
||||
["version='1.0'", 'version="1.0"'],
|
||||
["'utf-8'", '"utf-8"']
|
||||
]
|
||||
SedLike.sed(template_path, self.changes)
|
||||
with open(template_path, 'a', encoding='utf-8') as file:
|
||||
file.write('\n')
|
||||
|
||||
def run(self):
|
||||
for template in glob.iglob(self.template_folder + '/**/*.xml', recursive=True):
|
||||
if self.fix_template(template):
|
||||
print(template)
|
||||
self.fix_style(template)
|
||||
|
||||
if __name__ == '__main__':
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
template_fixer = TemplateFixer(script_dir)
|
||||
template_fixer.run()
|
91
A25_A26/PlayerXMLFixer.py
Normal file
91
A25_A26/PlayerXMLFixer.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from utils.fixers.BaseFixer import BaseFixer
|
||||
|
||||
from pathlib import Path
|
||||
import os
|
||||
import json
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
class PlayerXMLFixer(BaseFixer):
|
||||
|
||||
def __init__(self, vfs_root, verbose=False, name=__name__):
|
||||
BaseFixer.__init__(self, vfs_root, verbose, name)
|
||||
self.add_files(os.path.join('simulation', 'templates', 'special', 'player'), tuple(".xml"))
|
||||
|
||||
def list_civs(self):
|
||||
|
||||
civs = []
|
||||
for root, _, files in os.walk(str(self.vfs_root)):
|
||||
for name in files:
|
||||
file_path = os.path.join(root, name)
|
||||
if os.path.isfile(file_path) and os.path.join('simulation', 'data', 'civs') in file_path and '.json' in name:
|
||||
civs.append({"Path" : file_path , "Code" : name.split('.')[0]})
|
||||
|
||||
return civs
|
||||
|
||||
def create_player_file(self):
|
||||
root = ET.Element("Entity ")
|
||||
root.set('parent', "special/player")
|
||||
return root
|
||||
|
||||
def run(self):
|
||||
for civ in self.list_civs():
|
||||
tree = None
|
||||
root = None
|
||||
xml_file = None
|
||||
for file in self.files:
|
||||
if civ["Code"] in file:
|
||||
xml_file = file
|
||||
break
|
||||
|
||||
if xml_file is not None:
|
||||
tree = ET.parse(xml_file)
|
||||
root = tree.getroot()
|
||||
root.set('parent', "special/player")
|
||||
else:
|
||||
root = self.create_player_file()
|
||||
tree = ET.ElementTree(root)
|
||||
|
||||
|
||||
data = None
|
||||
with open(civ["Path"], 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
cmp_identity = self.create_tag_if_not_exist(root, 'Identity')
|
||||
|
||||
if "History" in data.keys() and data["History"] is not None:
|
||||
history_tag = self.create_tag_if_not_exist(cmp_identity, 'History')
|
||||
history_tag.text = data["History"]
|
||||
del data["History"]
|
||||
|
||||
if "Code" in data.keys():
|
||||
civ_tag = self.create_tag_if_not_exist(cmp_identity, 'Civ')
|
||||
civ_tag.text = data["Code"]
|
||||
|
||||
if "Name" in data.keys():
|
||||
generic_name_tag = self.create_tag_if_not_exist(cmp_identity, 'GenericName')
|
||||
generic_name_tag.text = data["Name"]
|
||||
del data["Name"]
|
||||
|
||||
if "Emblem" in data.keys():
|
||||
icon_tag = self.create_tag_if_not_exist(cmp_identity, 'Icon')
|
||||
icon_tag.text = data["Emblem"]
|
||||
del data["Emblem"]
|
||||
|
||||
outputFolder = Path(self.vfs_root) / 'simulation' / 'templates' / 'special' / 'players'
|
||||
os.makedirs(outputFolder, exist_ok=True)
|
||||
outputFile = outputFolder / (civ["Code"] + '.xml')
|
||||
outputFile.touch()
|
||||
self.save_xml_file(tree, root, outputFile)
|
||||
with open(civ["Path"], 'w', encoding='utf-8') as outfile:
|
||||
json.dump(data, outfile, indent='\t')
|
||||
|
||||
oldPlayerFolder = Path(self.vfs_root) / 'simulation' / 'templates' / 'special' / 'player'
|
||||
if oldPlayerFolder.exists():
|
||||
shutil.rmtree(oldPlayerFolder)
|
60
A25_A26/PlayerXMLFormationFixer.py
Normal file
60
A25_A26/PlayerXMLFormationFixer.py
Normal file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from .PlayerXMLFixer import PlayerXMLFixer
|
||||
|
||||
from pathlib import Path
|
||||
import xml.etree.ElementTree as ET
|
||||
import json
|
||||
import os
|
||||
|
||||
class PlayerXMLFormationFixer(PlayerXMLFixer):
|
||||
|
||||
def __init__(self, vfs_root, verbose=False):
|
||||
super(PlayerXMLFixer, self).__init__(vfs_root, verbose, __name__)
|
||||
self.add_files(os.path.join('simulation', 'templates', 'special', 'players'), tuple(".xml"))
|
||||
|
||||
def run(self):
|
||||
for civ in self.list_civs():
|
||||
tree = None
|
||||
root = None
|
||||
xml_file = None
|
||||
for file in self.files:
|
||||
if civ["Code"] in file:
|
||||
xml_file = file
|
||||
break
|
||||
|
||||
if xml_file is not None:
|
||||
tree = ET.parse(xml_file)
|
||||
root = tree.getroot()
|
||||
root.set('parent', "special/player")
|
||||
else:
|
||||
root = self.create_player_file()
|
||||
tree = ET.ElementTree(root)
|
||||
|
||||
|
||||
data = None
|
||||
with open(civ["Path"], 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
|
||||
|
||||
cmp_player = self.create_tag_if_not_exist(root, 'Player')
|
||||
if "Formations" in data.keys() and data["Formations"] is not None:
|
||||
formations_tag = self.create_tag_if_not_exist(cmp_player, 'Formations')
|
||||
formations_tag.text = " ".join(data["Formations"])
|
||||
|
||||
del data["Formations"]
|
||||
|
||||
|
||||
outputFolder = Path(self.vfs_root) / 'simulation' / 'templates' / 'special' / 'players'
|
||||
os.makedirs(outputFolder, exist_ok=True)
|
||||
outputFile = outputFolder / (civ["Code"] + '.xml')
|
||||
outputFile.touch()
|
||||
self.save_xml_file(tree, root, outputFile)
|
||||
with open(civ["Path"], 'w', encoding='utf-8') as outfile:
|
||||
json.dump(data, outfile, indent='\t', ensure_ascii=False)
|
35
A25_A26/SessionIconPathFixer.py
Normal file
35
A25_A26/SessionIconPathFixer.py
Normal file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from utils.fixers.BaseFixer import BaseFixer
|
||||
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
class SessionIconPathFixer(BaseFixer):
|
||||
|
||||
def __init__(self, vfs_root, verbose=False):
|
||||
BaseFixer.__init__(self, vfs_root, verbose, __name__)
|
||||
self.add_files(os.path.join('simulation', 'templates', 'special', 'players'), tuple(".xml"))
|
||||
|
||||
def run(self):
|
||||
for file in self.files:
|
||||
|
||||
tree = ET.parse(file)
|
||||
root = tree.getroot()
|
||||
|
||||
cmp_identity = root.find('Identity')
|
||||
if cmp_identity is None:
|
||||
continue
|
||||
|
||||
icon_tag = cmp_identity.find('Icon')
|
||||
if icon_tag is None:
|
||||
continue
|
||||
|
||||
icon_tag.text = str(icon_tag.text).replace("session/portraits/", "")
|
||||
self.save_xml_file(tree, root, file)
|
||||
self.fix_style(file)
|
95
utils/PMPMap.py
Normal file
95
utils/PMPMap.py
Normal file
@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from io import BufferedReader, BufferedWriter
|
||||
|
||||
class PmpHeader():
|
||||
def __init__(self, stream : BufferedReader):
|
||||
self.magic = int.from_bytes(stream.read(4), byteorder='little')
|
||||
self.version = int.from_bytes(stream.read(4), byteorder='little')
|
||||
self.data_size = int.from_bytes(stream.read(4), byteorder='little')
|
||||
self.map_size = int.from_bytes(stream.read(4), byteorder='little')
|
||||
|
||||
def write_to_stream(self, stream : BufferedWriter):
|
||||
stream.write(self.magic.to_bytes(4, 'little'))
|
||||
stream.write(self.version.to_bytes(4, 'little'))
|
||||
stream.write(self.data_size.to_bytes(4, 'little'))
|
||||
stream.write(self.map_size.to_bytes(4, 'little'))
|
||||
|
||||
class PmpHeightMap(list):
|
||||
def __init__(self, stream : BufferedReader, width : int, height : int):
|
||||
self.capacity = (width * 16 + 1) * (height * 16 + 1)
|
||||
for _ in range (0, self.capacity):
|
||||
self.append(int.from_bytes(stream.read(2), byteorder='little'))
|
||||
|
||||
def write_to_stream(self, stream : BufferedWriter):
|
||||
for height_data in self:
|
||||
stream.write(height_data.to_bytes(2, byteorder='little'))
|
||||
|
||||
class PmpTextures(list):
|
||||
def __init__(self, stream : BufferedReader):
|
||||
self.capacity = int.from_bytes(stream.read(4), byteorder='little')
|
||||
for _ in range (0, self.capacity):
|
||||
length = int.from_bytes(stream.read(4), byteorder='little')
|
||||
self.append(stream.read(length).decode())
|
||||
|
||||
def write_to_stream(self, stream : BufferedWriter):
|
||||
stream.write((len(self)).to_bytes(4, byteorder='little'))
|
||||
for texture in self:
|
||||
stream.write(len(texture).to_bytes(4, byteorder='little'))
|
||||
stream.write(texture.encode())
|
||||
|
||||
class PmpTiles(list):
|
||||
def __init__(self, stream : BufferedReader, capacity : int):
|
||||
for _ in range(0, capacity):
|
||||
self.append(PmpTile(stream))
|
||||
|
||||
def write_to_stream(self, stream : BufferedWriter):
|
||||
for tile in self:
|
||||
tile.write_to_stream(stream)
|
||||
|
||||
class PmpTile():
|
||||
def __init__(self, stream : BufferedReader):
|
||||
self.texture1 = int.from_bytes(stream.read(2), byteorder='little')
|
||||
self.texture2 = int.from_bytes(stream.read(2), byteorder='little')
|
||||
self.priority = int.from_bytes(stream.read(4), byteorder='little')
|
||||
|
||||
def write_to_stream(self, stream : BufferedWriter):
|
||||
stream.write(self.texture1.to_bytes(2, byteorder='little'))
|
||||
stream.write(self.texture2.to_bytes(2, byteorder='little'))
|
||||
stream.write(self.priority.to_bytes(4, byteorder='little'))
|
||||
|
||||
class PmpPatch():
|
||||
def __init__(self, stream : BufferedReader):
|
||||
self.TILE_SIZE = 16 * 16
|
||||
self.tiles = PmpTiles(stream, self.TILE_SIZE)
|
||||
def write_to_stream(self, stream : BufferedWriter):
|
||||
self.tiles.write_to_stream(stream)
|
||||
|
||||
class PmpPatches(list):
|
||||
def __init__(self, stream, width, height):
|
||||
self.capacity = width * height
|
||||
for _ in range (0, self.capacity):
|
||||
self.append(PmpPatch(stream))
|
||||
def write_to_stream(self, stream : BufferedWriter):
|
||||
for patch in self:
|
||||
patch.write_to_stream(stream)
|
||||
|
||||
class PmpMap():
|
||||
def __init__(self, stream : BufferedReader):
|
||||
self.header = PmpHeader(stream)
|
||||
self.heightMap = PmpHeightMap(stream, self.header.map_size, self.header.map_size)
|
||||
self.textures = PmpTextures(stream)
|
||||
self.patches = PmpPatches(stream, self.header.map_size, self.header.map_size)
|
||||
|
||||
def write_to_stream(self, stream : BufferedWriter):
|
||||
self.header.write_to_stream(stream)
|
||||
self.heightMap.write_to_stream(stream)
|
||||
self.textures.write_to_stream(stream)
|
||||
self.patches.write_to_stream(stream)
|
||||
|
||||
|
97
utils/fixers/BaseFixer.py
Normal file
97
utils/fixers/BaseFixer.py
Normal file
@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from ..logger_utils.InterceptableLogger import InterceptableLogger
|
||||
|
||||
from pathlib import Path
|
||||
import fileinput
|
||||
import os
|
||||
|
||||
class BaseFixer():
|
||||
def __init__(self, vfs_root, verbose=False, name=__name__):
|
||||
self.vfs_root = Path(vfs_root)
|
||||
self.verbose = verbose
|
||||
self.files = []
|
||||
self.logger = InterceptableLogger(name)
|
||||
|
||||
def fix_style(self, xml_path):
|
||||
changes = [
|
||||
[' />', '/>'],
|
||||
["version='1.0'", 'version="1.0"'],
|
||||
["'utf-8'", '"utf-8"']
|
||||
]
|
||||
for line in fileinput.input(xml_path, inplace=True):
|
||||
for change in changes:
|
||||
line = line.replace(change[0], change[1])
|
||||
print(line, end="")
|
||||
|
||||
with open(xml_path, 'a', encoding='utf-8') as file:
|
||||
file.write('\n')
|
||||
|
||||
def indent(self, elem, level=0, more_sibs=False):
|
||||
i = "\n"
|
||||
if level:
|
||||
i += (level-1) * ' '
|
||||
num_kids = len(elem)
|
||||
if num_kids:
|
||||
if not elem.text or not elem.text.strip():
|
||||
elem.text = i + " "
|
||||
if level:
|
||||
elem.text += ' '
|
||||
count = 0
|
||||
for kid in elem:
|
||||
self.indent(kid, level+1, count < num_kids - 1)
|
||||
count += 1
|
||||
if not elem.tail or not elem.tail.strip():
|
||||
elem.tail = i
|
||||
if more_sibs:
|
||||
elem.tail += ' '
|
||||
else:
|
||||
if level and (not elem.tail or not elem.tail.strip()):
|
||||
elem.tail = i
|
||||
if more_sibs:
|
||||
elem.tail += ' '
|
||||
def sort(self, root):
|
||||
# sort the first layer
|
||||
root[:] = sorted(root, key=lambda child: (child.tag,child.get('name')))
|
||||
|
||||
# sort the second layer
|
||||
for c in root:
|
||||
c[:] = sorted(c, key=lambda child: (child.tag,child.get('name')))
|
||||
for cp in c:
|
||||
cp[:] = sorted(cp, key=lambda child: (child.tag,child.get('name')))
|
||||
for scp in cp:
|
||||
scp[:] = sorted(scp, key=lambda child: (child.tag,child.get('name')))
|
||||
|
||||
def save_xml_file(self, tree, root, xml_file, sort=True):
|
||||
if sort:
|
||||
self.sort(root)
|
||||
self.indent(root)
|
||||
tree.write(xml_file, xml_declaration=True, encoding='utf-8')
|
||||
self.fix_style(xml_file)
|
||||
|
||||
def create_tag_if_not_exist(self, parent, name):
|
||||
tag = parent.find(name)
|
||||
if tag is None:
|
||||
tag = ET.SubElement(parent, name)
|
||||
return tag
|
||||
|
||||
def add_files(self, path, extensions : tuple[str]):
|
||||
self.files = []
|
||||
if os.path.isfile(str(self.vfs_root)):
|
||||
self.files.append(self.vfs_root)
|
||||
elif os.path.isdir(str(self.vfs_root)):
|
||||
for root, _, files in os.walk(str(self.vfs_root)):
|
||||
for name in files:
|
||||
file_path = os.path.join(root, name)
|
||||
if os.path.isfile(file_path) and path in file_path and name.endswith(extensions):
|
||||
self.files.append(file_path)
|
||||
if self.verbose:
|
||||
if len(self.files) > 0:
|
||||
self.logger.info(f"Found {len(self.files)} file(s).")
|
||||
else:
|
||||
self.logger.info(f"No files were found.")
|
35
utils/logger_utils/InterceptableLogger.py
Normal file
35
utils/logger_utils/InterceptableLogger.py
Normal file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from .SingleLevelFilter import SingleLevelFilter
|
||||
|
||||
from logging import getLogger, StreamHandler, INFO, WARNING, Formatter
|
||||
from sys import stdout, stderr
|
||||
|
||||
class InterceptableLogger():
|
||||
def __init__(self, logger_name : str):
|
||||
self.logger = getLogger(logger_name)
|
||||
self.logger.setLevel(INFO)
|
||||
ch = StreamHandler(stdout)
|
||||
ch.setLevel(INFO)
|
||||
ch.setFormatter(Formatter('%(levelname)s - %(message)s'))
|
||||
f1 = SingleLevelFilter(INFO, False)
|
||||
ch.addFilter(f1)
|
||||
self.logger.addHandler(ch)
|
||||
errorch = StreamHandler(stderr)
|
||||
errorch.setLevel(WARNING)
|
||||
errorch.setFormatter(Formatter('%(levelname)s - %(message)s'))
|
||||
self.logger.addHandler(errorch)
|
||||
|
||||
def info(self, message):
|
||||
self.logger.info(message)
|
||||
|
||||
def warn(self, message):
|
||||
self.logger.warn(message)
|
||||
|
||||
def error(self, message):
|
||||
self.logger.error(message)
|
19
utils/logger_utils/SingleLevelFilter.py
Normal file
19
utils/logger_utils/SingleLevelFilter.py
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- mode: python-mode; python-indent-offset: 4; -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
# SPDX-FileCopyrightText: © 2023 Wildfire Games
|
||||
# SPDX-FileCopyrightText: © 2023 Stanislas Daniel Claude Dolcini
|
||||
|
||||
from logging import Filter
|
||||
|
||||
class SingleLevelFilter(Filter):
|
||||
def __init__(self, passlevel, reject):
|
||||
self.passlevel = passlevel
|
||||
self.reject = reject
|
||||
|
||||
def filter(self, record):
|
||||
if self.reject:
|
||||
return (record.levelno != self.passlevel)
|
||||
else:
|
||||
return (record.levelno == self.passlevel)
|
Loading…
Reference in New Issue
Block a user