diff --git a/korman/exporter/convert.py b/korman/exporter/convert.py index 7e11520..149d3ac 100644 --- a/korman/exporter/convert.py +++ b/korman/exporter/convert.py @@ -24,6 +24,7 @@ from . import manager from . import mesh from . import physics from . import rtlight +from . import sumfile from . import utils class Exporter: @@ -41,11 +42,12 @@ class Exporter: start = time.process_time() # Step 0: Init export resmgr and stuff - self.mgr = manager.ExportManager(globals()[self._op.version]) + self.mgr = manager.ExportManager(self) self.mesh = mesh.MeshConverter(self) self.report = logger.ExportAnalysis() self.physics = physics.PhysicsConverter(self) self.light = rtlight.LightConverter(self) + self.sumfile = sumfile.SumFile() # Step 1: Gather a list of objects that we need to export # We should do this first so we can sanity check diff --git a/korman/exporter/manager.py b/korman/exporter/manager.py index fa7e10d..7e64eb1 100644 --- a/korman/exporter/manager.py +++ b/korman/exporter/manager.py @@ -16,6 +16,7 @@ import bpy import os.path from PyHSPlasma import * +import weakref from . import explosions @@ -43,9 +44,10 @@ _pool_types = ( class ExportManager: """Friendly resource-managing helper class.""" - def __init__(self, version): + def __init__(self, exporter): + self._exporter = weakref.ref(exporter) self.mgr = plResManager() - self.mgr.setVer(version) + self.mgr.setVer(globals()[exporter._op.version]) self._nodes = {} self._pages = {} @@ -238,31 +240,35 @@ class ExportManager: def save_age(self, path): relpath, ageFile = os.path.split(path) ageName = os.path.splitext(ageFile)[0] + sumfile = self._exporter().sumfile + sumfile.append(path) self.mgr.WriteAge(path, self._age_info) self._write_fni(relpath, ageName) self._write_pages(relpath, ageName) + if self.getVer() != pvMoul: + sumpath = os.path.join(relpath, "{}.sum".format(ageName)) + sumfile.write(sumpath, self.getVer()) + def _write_fni(self, path, ageName): if self.mgr.getVer() <= pvMoul: enc = plEncryptedStream.kEncXtea else: enc = plEncryptedStream.kEncAES fname = os.path.join(path, "{}.fni".format(ageName)) - stream = plEncryptedStream() - stream.open(fname, fmWrite, enc) - - # Write out some stuff - fni = bpy.context.scene.world.plasma_fni - stream.writeLine("Graphics.Renderer.SetClearColor {} {} {}".format(*fni.clear_color)) - if fni.fog_method != "none": - stream.writeLine("Graphics.Renderer.Fog.SetDefColor {} {} {}".format(*fni.fog_color)) - if fni.fog_method == "linear": - stream.writeLine("Graphics.Renderer.Fog.SetDefLinear {} {} {}".format(fni.fog_start, fni.fog_end, fni.fog_density)) - elif fni.fog_method == "exp2": - stream.writeLine("Graphics.Renderer.Fog.SetDefExp2 {} {}".format(fni.fog_end, fni.fog_density)) - stream.writeLine("Graphics.Renderer.SetYon {}".format(fni.yon)) - stream.close() + + with plEncryptedStream(self.mgr.getVer()).open(fname, fmWrite, enc) as stream: + fni = bpy.context.scene.world.plasma_fni + stream.writeLine("Graphics.Renderer.SetClearColor {} {} {}".format(*fni.clear_color)) + if fni.fog_method != "none": + stream.writeLine("Graphics.Renderer.Fog.SetDefColor {} {} {}".format(*fni.fog_color)) + if fni.fog_method == "linear": + stream.writeLine("Graphics.Renderer.Fog.SetDefLinear {} {} {}".format(fni.fog_start, fni.fog_end, fni.fog_density)) + elif fni.fog_method == "exp2": + stream.writeLine("Graphics.Renderer.Fog.SetDefExp2 {} {}".format(fni.fog_end, fni.fog_density)) + stream.writeLine("Graphics.Renderer.SetYon {}".format(fni.yon)) + self._exporter().sumfile.append(fname) def _write_pages(self, path, ageName): for loc in self._pages.values(): @@ -275,3 +281,4 @@ class ExportManager: chapter = "_" f = os.path.join(path, "{}{}{}.prp".format(ageName, chapter, page.page)) self.mgr.WritePage(f, page) + self._exporter().sumfile.append(f) diff --git a/korman/exporter/sumfile.py b/korman/exporter/sumfile.py new file mode 100644 index 0000000..7bdb013 --- /dev/null +++ b/korman/exporter/sumfile.py @@ -0,0 +1,74 @@ +# 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 hashlib +import os.path +from PyHSPlasma import * + +def _hashfile(filename, hasher, block=0xFFFF): + with open(filename, "rb") as handle: + h = hasher() + data = handle.read(block) + while data: + h.update(data) + data = handle.read(block) + return h.digest() + +class SumFile: + def __init__(self): + self._files = set() + + def append(self, filename): + self._files.add(filename) + + def _collect_files(self, version): + files = [] + for file in self._files: + filename = os.path.split(file)[1] + extension = os.path.splitext(filename)[1].lower() + if extension in {".age", ".csv", ".fni", ".loc", ".node", ".p2f", ".pfp", ".sub"}: + filename = os.path.join("dat", filename) + elif extension == ".prp" and version > pvPrime: + # ABM and UU don't want the directory for PRPs... Bug? + filename = os.path.join("dat", filename) + elif extension in {".pak", ".py"}: + filename = os.path.join("Python", filename) + elif extension in {".avi", ".bik", ".oggv", ".webm"}: + filename = os.path.join("avi", filename) + elif extension in {".ogg", ".opus", ".wav"}: + filename = os.path.join("sfx", filename) + elif extension == ".sdl": + filename = os.path.join("SDL", filename) + # else the filename has no directory prefix... oh well + + md5 = _hashfile(file, hashlib.md5) + timestamp = os.path.getmtime(file) + files.append((filename, md5, int(timestamp))) + return files + + + def write(self, sumpath, version): + """Writes a .sum file for Uru ABM, PotS, Myst 5, etc.""" + files = self._collect_files(version) + enc = plEncryptedStream.kEncAes if version >= pvEoa else plEncryptedStream.kEncXtea + + with plEncryptedStream(version).open(sumpath, fmWrite, enc) as stream: + stream.writeInt(len(files)) + stream.writeInt(0) + for file in files: + stream.writeSafeStr(file[0]) + stream.write(file[1]) + stream.writeInt(file[2]) + stream.writeInt(0)