# This file is part of Korman. # # Korman is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Korman is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Korman. If not, see . import bpy from pathlib import Path from PyHSPlasma import * from .explosions import ExportError from . import logger from .. import korlib from ..plasma_magic import plasma_python_glue, very_very_special_python class PythonPackageExporter: def __init__(self, filepath, version): self._filepath = filepath self._modules = {} self._pfms = {} self._version = version def _compyle(self, report): report.progress_advance() report.progress_range = len(self._modules) + len(self._pfms) inc_progress = report.progress_increment age = bpy.context.scene.world.plasma_age Text = bpy.types.Text if self._version <= pvPots: py_version = (2, 2) else: py_version = (2, 3) py_code = [] for filename, source in self._pfms.items(): if isinstance(source, Text): if not source.plasma_text.package and age.python_method != "all": inc_progress() continue code = source.as_string() else: code = source code = "{}\n\n{}\n".format(code, plasma_python_glue) success, result = korlib.compyle(filename, code, py_version, report, indent=1) if not success: raise ExportError("Failed to compyle '{}':\n{}".format(filename, result)) py_code.append((filename, result)) inc_progress() for filename, source in self._modules.items(): if isinstance(source, Text): if not source.plasma_text.package and age.python_method != "all": inc_progress() continue code = source.as_string() else: code = source # no glue needed here, ma! success, result = korlib.compyle(filename, code, py_version, report, indent=1) if not success: raise ExportError("Failed to compyle '{}':\n{}".format(filename, result)) py_code.append((filename, result)) inc_progress() # man that was ugly... return py_code def _ensure_age_sdl_hook(self, report): age_props = bpy.context.scene.world.plasma_age if age_props.age_sdl: fixed_agename = korlib.replace_python2_identifier(age_props.age_name) py_filename = "{}.py".format(fixed_agename) age_py = self._modules.get(py_filename) if age_py is not None: del self._modules[py_filename] if age_py.plasma_text.package or age.python_method == "all": self._pfms[py_filename] = age_py else: report.warn("AgeSDL Python Script provided, but not requested for packing... Using default Python.", indent=1) self._pfms[py_filename] = very_very_special_python.format(age_name=fixed_agename) else: report.msg("Packing default AgeSDL Python", indent=1) very_very_special_python.format(age_name=age_props.age_name) self._pfms[py_filename] = very_very_special_python.format(age_name=fixed_agename) def _harvest_pfms(self, report): objects = bpy.context.scene.objects report.progress_advance() report.progress_range = len(objects) inc_progress = report.progress_increment for i in objects: logic = i.plasma_modifiers.advanced_logic if i.plasma_object.enabled and logic.enabled: for j in logic.logic_groups: tree_versions = (globals()[version] for version in j.version) if self._version in tree_versions: self._harvest_tree(j.node_tree) inc_progress() def _harvest_modules(self, report): texts = bpy.data.texts report.progress_advance() report.progress_range = len(texts) inc_progress = report.progress_increment for i in texts: if i.name.endswith(".py") and i.name not in self._pfms: self._modules.setdefault(i.name, i) inc_progress() def _harvest_tree(self, tree): # Search the node tree for any python file nodes. Any that we find are PFMs for i in tree.nodes: if i.bl_idname == "PlasmaPythonFileNode": if i.filename and i.text_id: self._pfms.setdefault(i.filename, i.text_id) def run(self): """Runs a stripped-down version of the Exporter that only handles Python files""" age_props = bpy.context.scene.world.plasma_age log = logger.ExportVerboseLogger if age_props.verbose else logger.ExportProgressLogger with korlib.ConsoleToggler(age_props.show_console), log(self._filepath) as report: report.progress_add_step("Harvesting Plasma PythonFileMods") report.progress_add_step("Harvesting Helper Python Modules") report.progress_add_step("Compyling Python Code") report.progress_add_step("Packing Compyled Code") report.progress_start("PACKING PYTHON") # Harvest the Python code self._harvest_pfms(report) self._harvest_modules(report) self._ensure_age_sdl_hook(report) # Compyle and package the Python self._package_python(report) # DONE report.progress_end() report.raise_errors() def _package_python(self, report): py_code = self._compyle(report) if not py_code: report.error("No Python files were packaged.") self._write_python_pak(py_code, report) def _write_python_pak(self, py_code, report): report.progress_advance() if self._version == pvEoa: enc = plEncryptedStream.kEncAes elif self._version == pvMoul: enc = None else: enc = plEncryptedStream.kEncXtea if enc is None: stream = hsFileStream(self._version).open(self._filepath, fmCreate) else: stream = plEncryptedStream(self._version).open(self._filepath, fmCreate, enc) try: korlib.package_python(stream, py_code) finally: stream.close()