Browse Source

Merge pull request #130 from Hoikas/journal-loc

Fix #129
pull/152/head v0.08
Adam Johnson 6 years ago committed by GitHub
parent
commit
95dd0341f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      korman/exporter/__init__.py
  2. 3
      korman/exporter/convert.py
  3. 201
      korman/exporter/locman.py
  4. 48
      korman/operators/op_export.py
  5. 153
      korman/properties/modifiers/gui.py
  6. 46
      korman/ui/modifiers/gui.py
  7. 82
      korman/ui/ui_world.py

1
korman/exporter/__init__.py

@ -18,5 +18,6 @@ from PyHSPlasma import *
from .convert import *
from .explosions import *
from .locman import *
from .python import *
from . import utils

3
korman/exporter/convert.py

@ -24,6 +24,7 @@ from . import camera
from . import explosions
from . import etlight
from . import image
from . import locman
from . import logger
from . import manager
from . import mesh
@ -52,6 +53,7 @@ class Exporter:
self.output = outfile.OutputFiles(self, self._op.filepath)
self.camera = camera.CameraConverter(self)
self.image = image.ImageCache(self)
self.locman = locman.LocalizationConverter(self)
# Step 0.8: Init the progress mgr
self.mesh.add_progress_presteps(self.report)
@ -368,6 +370,7 @@ class Exporter:
# If something bad happens in the final flush, it would be a shame to
# simply toss away the potentially freshly regenerated texture cache.
try:
self.locman.save()
self.mgr.save_age()
self.output.save()
finally:

201
korman/exporter/locman.py

@ -0,0 +1,201 @@
# 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 <http://www.gnu.org/licenses/>.
import bpy
from contextlib import contextmanager
from .explosions import NonfatalExportError
from .. import korlib
from . import logger
from pathlib import Path
from PyHSPlasma import *
import weakref
from xml.sax.saxutils import escape as xml_escape
_SP_LANGUAGES = {"English", "French", "German", "Italian", "Spanish"}
class LocalizationConverter:
def __init__(self, exporter=None, **kwargs):
if exporter is not None:
self._exporter = weakref.ref(exporter)
self._age_name = exporter.age_name
self._report = exporter.report
self._version = exporter.mgr.getVer()
else:
self._exporter = None
self._age_name = kwargs.get("age_name")
self._path = kwargs.get("path")
self._version = kwargs.get("version")
self._journals = {}
self._strings = {}
def add_journal(self, name, language, text_id, indent=0):
if text_id.is_modified:
self._report.warn("Journal '{}' translation for '{}' is modified on the disk but not reloaded in Blender.",
name, language, indent=indent)
journal = self._journals.setdefault(name, {})
journal[language] = text_id.as_string()
def add_string(self, set_name, element_name, language, value):
trans_set = self._strings.setdefault(set_name, {})
trans_element = trans_set.setdefault(element_name, {})
trans_element[language] = value
@contextmanager
def _generate_file(self, filename, **kwargs):
if self._exporter is not None:
with self._exporter().output.generate_dat_file(filename, **kwargs) as handle:
yield handle
else:
dirname = kwargs.get("dirname", "dat")
filepath = str(Path(self._path) / dirname / filename)
handle = open(filepath, "wb")
try:
yield handle
except:
raise
finally:
handle.close()
def _generate_journal_texts(self):
age_name = self._age_name
def write_journal_file(language, file_name, contents):
try:
with self._generate_file(dirname="ageresources", filename=file_name) as stream:
stream.write(contents.encode("windows-1252"))
except UnicodeEncodeError:
self._report.error("Translation '{}': Contents contains characters that cannot be used in this version of Plasma",
language, indent=2)
return False
else:
return True
for journal_name, translations in self._journals.items():
self._report.msg("Copying Journal '{}'", journal_name, indent=1)
for language_name, value in translations.items():
if language_name not in _SP_LANGUAGES:
self._report.warn("Translation '{}' will not be used because it is not supported in this version of Plasma.",
language_name, indent=2)
continue
suffix = "_{}".format(language_name.lower()) if language_name != "English" else ""
file_name = "{}--{}{}.txt".format(age_name, journal_name, suffix)
write_journal_file(language_name, file_name, value)
# Ensure that default (read: "English") journal is available
if "English" not in translations:
language_name, value = next(((language_name, value) for language_name, value in translations.items()
if language_name in _SP_LANGUAGES), (None, None))
if language_name is not None:
file_name = "{}--{}.txt".format(age_name, journal_name)
# If you manage to screw up this badly... Well, I am very sorry.
if write_journal_file(language_name, file_name, value):
self._report.warn("No 'English' translation available, so '{}' will be used as the default",
language_name, indent=2)
else:
self._report.port("No 'English' nor any other suitable default translation available", indent=2)
def _generate_loc_file(self):
# Only generate this junk if needed
if not self._strings and not self._journals:
return
def write_line(value, *args, **kwargs):
# tabs suck, then you die...
whitespace = " " * kwargs.pop("indent", 0)
if args or kwargs:
value = value.format(*args, **kwargs)
line = "".join((whitespace, value, "\n"))
stream.write(line.encode("utf-16_le"))
age_name = self._age_name
enc = plEncryptedStream.kEncAes if self._version == pvEoa else None
file_name = "{}.loc".format(age_name)
with self._generate_file(file_name, enc=enc) as stream:
# UTF-16 little endian byte order mark
stream.write(b"\xFF\xFE")
write_line("<?xml version=\"1.0\" encoding=\"utf-16\"?>")
write_line("<localizations>")
write_line("<age name=\"{}\">", age_name, indent=1)
# Arbitrary strings defined by something like a GUI or a node tree
for set_name, elements in self._strings.items():
write_line("<set name=\"{}\">", set_name, indent=2)
for element_name, translations in elements.items():
write_line("<element name=\"{}\">", element_name, indent=3)
for language_name, value in translations.items():
write_line("<translation language=\"{language}\">{translation}</translation>",
language=language_name, translation=xml_escape(value), indent=4)
write_line("</element>", indent=3)
write_line("</set>", indent=2)
# Journals
if self._journals:
write_line("<set name=\"Journals\">", indent=2)
for journal_name, translations in self._journals.items():
write_line("<element name=\"{}\">", journal_name, indent=3)
for language_name, value in translations.items():
write_line("<translation language=\"{language}\">{translation}</translation>",
language=language_name, translation=xml_escape(value), indent=4)
write_line("</element>", indent=3)
write_line("</set>", indent=2)
# Verbose XML junk...
# <Deledrius> You call it verbose. I call it unambiguously complete.
write_line("</age>", indent=1)
write_line("</localizations>")
def run(self):
age_props = bpy.context.scene.world.plasma_age
loc_path = str(Path(self._path) / "dat" / "{}.loc".format(self._age_name))
log = logger.ExportVerboseLogger if age_props.verbose else logger.ExportProgressLogger
with korlib.ConsoleToggler(age_props.show_console), log(loc_path) as self._report:
self._report.progress_add_step("Harvesting Journals")
self._report.progress_add_step("Generating Localization")
self._report.progress_start("Exporting Localization Data")
self._run_harvest_journals()
self._run_generate()
# DONE
self._report.progress_end()
self._report.raise_errors()
def _run_harvest_journals(self):
objects = bpy.context.scene.objects
self._report.progress_advance()
self._report.progress_range = len(objects)
inc_progress = self._report.progress_increment
for i in objects:
journal = i.plasma_modifiers.journalbookmod
if journal.enabled:
translations = [j for j in journal.journal_translations if j.text_id is not None]
if not translations:
self._report.error("Journal '{}': No content translations available. The journal will not be exported.",
i.name, indent=2)
for j in translations:
self.add_journal(journal.key_name, j.language, j.text_id, indent=1)
inc_progress()
def _run_generate(self):
self._report.progress_advance()
self.save()
def save(self):
if self._version > pvPots:
self._generate_loc_file()
else:
self._generate_journal_texts()

48
korman/operators/op_export.py

@ -218,6 +218,54 @@ class PlasmaAgeExportOperator(ExportOperator, bpy.types.Operator):
setattr(PlasmaAge, name, prop(**age_options))
class PlasmaLocalizationExportOperator(ExportOperator, bpy.types.Operator):
bl_idname = "export.plasma_loc"
bl_label = "Export Localization"
bl_description = "Export Age Localization Data"
filepath = StringProperty(subtype="DIR_PATH")
filter_glob = StringProperty(default="*.pak", options={'HIDDEN'})
version = EnumProperty(name="Version",
description="Plasma version to export this age for",
items=game_versions,
default="pvPots",
options=set())
def execute(self, context):
path = Path(self.filepath)
if not self.filepath:
self.report({"ERROR"}, "No file specified")
return {"CANCELLED"}
else:
if not path.exists:
try:
path.mkdir(parents=True)
except OSError:
self.report({"ERROR"}, "Failed to create export directory")
return {"CANCELLED"}
# Age names cannot be python keywords
age_name = context.scene.world.plasma_age.age_name
if korlib.is_python_keyword(age_name):
self.report({"ERROR"}, "The Age name conflicts with the Python keyword '{}'".format(age_name))
return {"CANCELLED"}
# Bonus Fun: Implement Profile-mode here (later...)
e = exporter.LocalizationConverter(age_name=age_name, path=self.filepath,
version=globals()[self.version])
try:
e.run()
except exporter.ExportError as error:
self.report({"ERROR"}, str(error))
return {"CANCELLED"}
except exporter.NonfatalExportError as error:
self.report({"WARNING"}, str(error))
return {"FINISHED"}
else:
return {"FINISHED"}
class PlasmaPythonExportOperator(ExportOperator, bpy.types.Operator):
bl_idname = "export.plasma_pak"
bl_label = "Package Scripts"

153
korman/properties/modifiers/gui.py

@ -21,19 +21,11 @@ from bpy.props import *
from PyHSPlasma import *
from ...addon_prefs import game_versions
from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz
from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz, PlasmaModifierUpgradable
from ... import idprops
journal_pfms = {
pvPrime : {
"filename": "xJournalBookGUIPopup.py",
"attribs": (
{ 'id': 1, 'type': "ptAttribActivator", "name": "actClickableBook" },
{ 'id': 3, 'type': "ptAttribString", "name": "JournalName" },
{ 'id': 10, 'type': "ptAttribBoolean", 'name': "StartOpen" },
)
},
pvPots : {
# Supplied by the OfflineKI script:
# https://gitlab.com/diafero/offline-ki/blob/master/offlineki/xSimpleJournal.py
@ -59,6 +51,26 @@ journal_pfms = {
},
}
# Do not change the numeric IDs. They allow the list to be rearranged.
_languages = [("Dutch", "Nederlands", "Dutch", 0),
("English", "English", "", 1),
("Finnish", "Suomi", "Finnish", 2),
("French", "Français", "French", 3),
("German", "Deutsch", "German", 4),
("Hungarian", "Magyar", "Hungarian", 5),
("Italian", "Italiano ", "Italian", 6),
# Blender 2.79b can't render 日本語 by default
("Japanese", "Nihongo", "Japanese", 7),
("Norwegian", "Norsk", "Norwegian", 8),
("Polish", "Polski", "Polish", 9),
("Romanian", "Română", "Romanian", 10),
("Russian", "Pyccĸий", "Russian", 11),
("Spanish", "Español", "Spanish", 12),
("Swedish", "Svenska", "Swedish", 13)]
languages = sorted(_languages, key=lambda x: x[1])
_DEFAULT_LANGUAGE_NAME = "English"
_DEFAULT_LANGUAGE_ID = 1
class ImageLibraryItem(bpy.types.PropertyGroup):
image = bpy.props.PointerProperty(name="Image Item",
@ -91,6 +103,22 @@ class PlasmaImageLibraryModifier(PlasmaModifierProperties):
exporter.mesh.material.export_prepared_image(owner=ilmod, image=item.image, allowed_formats={"JPG", "PNG"}, extension="hsm")
class PlasmaJournalTranslation(bpy.types.PropertyGroup):
def _poll_nonpytext(self, value):
return not value.name.endswith(".py")
language = EnumProperty(name="Language",
description="Language of this translation",
items=languages,
default=_DEFAULT_LANGUAGE_NAME,
options=set())
text_id = PointerProperty(name="Journal Contents",
description="Text data block containing the journal's contents for this language",
type=bpy.types.Text,
poll=_poll_nonpytext,
options=set())
class PlasmaJournalBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz):
pl_id = "journalbookmod"
@ -122,28 +150,69 @@ class PlasmaJournalBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
description="Height scale",
default=100, min=0, max=100,
subtype="PERCENTAGE")
book_source_locpath = StringProperty(name="Book Source LocPath",
description="LocPath for book's text (MO:UL)",
default="Global.Journals.Empty")
book_source_filename = StringProperty(name="Book Source Filename",
description="Filename for book's text (Uru:CC)",
default="")
book_source_name = StringProperty(name="Book Source Name",
description="Name of xJournalBookDefs.py entry for book's text (Uru:ABM)",
default="Dummy")
clickable_region = PointerProperty(name="Region",
description="Region inside which the avatar must stand to be able to open the journal (optional)",
type=bpy.types.Object,
poll=idprops.poll_mesh_objects)
def _get_translation(self):
# Ensure there is always a default (read: English) translation available.
default_idx, default = next(((idx, translation) for idx, translation in enumerate(self.journal_translations)
if translation.language == _DEFAULT_LANGUAGE_NAME), (None, None))
if default is None:
default_idx = len(self.journal_translations)
default = self.journal_translations.add()
default.language = _DEFAULT_LANGUAGE_NAME
if self.active_translation_index < len(self.journal_translations):
language = self.journal_translations[self.active_translation_index].language
else:
self.active_translation_index = default_idx
language = default.language
# Due to the fact that we are using IDs to keep the data from becoming insane on new
# additions, we must return the integer id...
return next((idx for key, _, _, idx in languages if key == language))
def _set_translation(self, value):
# We were given an int here, must change to a string
language_name = next((key for key, _, _, i in languages if i == value))
idx = next((idx for idx, translation in enumerate(self.journal_translations)
if translation.language == language_name), None)
if idx is None:
self.active_translation_index = len(self.journal_translations)
translation = self.journal_translations.add()
translation.language = language_name
else:
self.active_translation_index = idx
journal_translations = CollectionProperty(name="Journal Translations",
type=PlasmaJournalTranslation,
options=set())
active_translation_index = IntProperty(options={"HIDDEN"})
active_translation = EnumProperty(name="Language",
description="Language of this translation",
items=languages,
get=_get_translation, set=_set_translation,
options=set())
def export(self, exporter, bo, so):
our_versions = [globals()[j] for j in self.versions]
our_versions = (globals()[j] for j in self.versions)
version = exporter.mgr.getVer()
if version not in our_versions:
# We aren't needed here
exporter.report.port("Object '{}' has a JournalMod not enabled for export to the selected engine. Skipping.".format(bo.name, version), indent=2)
exporter.report.port("Object '{}' has a JournalMod not enabled for export to the selected engine. Skipping.",
bo.name, version, indent=2)
return
# Export the Journal translation contents
translations = [i for i in self.journal_translations if i.text_id is not None]
if not translations:
exporter.report.error("Journal '{}': No content translations available. The journal will not be exported.",
bo.name, indent=2)
return
for i in translations:
exporter.locman.add_journal(self.key_name, i.language, i.text_id, indent=2)
if self.clickable_region is None:
# Create a region for the clickable's condition
rgn_mesh = bpy.data.meshes.new("{}_Journal_ClkRgn".format(self.key_name))
@ -163,14 +232,14 @@ class PlasmaJournalBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
self.temp_rgn = self.clickable_region
# Generate the logic nodes
with self.generate_logic(bo, version=version) as tree:
with self.generate_logic(bo, age_name=exporter.age_name, version=version) as tree:
tree.export(exporter, bo, so)
# Get rid of our temporary clickable region
if self.clickable_region is None:
bpy.context.scene.objects.unlink(self.temp_rgn)
def logicwiz(self, bo, tree, version):
def logicwiz(self, bo, tree, age_name, version):
nodes = tree.nodes
# Assign journal script based on target version
@ -188,36 +257,12 @@ class PlasmaJournalBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
new_attr.attribute_name = attr["name"]
journalnode.update()
if version == pvPrime:
self.create_prime_nodes(bo, nodes, journalnode)
elif version == pvPots:
self.create_pots_nodes(bo, nodes, journalnode)
elif version == pvMoul:
self.create_moul_nodes(bo, nodes, journalnode)
def create_prime_nodes(self, clickable_object, nodes, journalnode):
clickable_region = nodes.new("PlasmaClickableRegionNode")
clickable_region.region_object = self.temp_rgn
facing_object = nodes.new("PlasmaFacingTargetNode")
facing_object.directional = False
facing_object.tolerance = math.degrees(-1)
clickable = nodes.new("PlasmaClickableNode")
clickable.link_input(clickable_region, "satisfies", "region")
clickable.link_input(facing_object, "satisfies", "facing")
clickable.link_output(journalnode, "satisfies", "actClickableBook")
clickable.clickable_object = clickable_object
start_open = nodes.new("PlasmaAttribBoolNode")
start_open.link_output(journalnode, "pfm", "StartOpen")
start_open.value = self.start_state == "OPEN"
journal_name = nodes.new("PlasmaAttribStringNode")
journal_name.link_output(journalnode, "pfm", "JournalName")
journal_name.value = self.book_source_name
if version <= pvPots:
self._create_pots_nodes(bo, nodes, journalnode, age_name)
else:
self._create_moul_nodes(bo, nodes, journalnode, age_name)
def create_pots_nodes(self, clickable_object, nodes, journalnode):
def _create_pots_nodes(self, clickable_object, nodes, journalnode, age_name):
clickable_region = nodes.new("PlasmaClickableRegionNode")
clickable_region.region_object = self.temp_rgn
@ -233,7 +278,7 @@ class PlasmaJournalBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
srcfile = nodes.new("PlasmaAttribStringNode")
srcfile.link_output(journalnode, "pfm", "journalFileName")
srcfile.value = self.book_source_filename
srcfile.value = self.key_name
guitype = nodes.new("PlasmaAttribBoolNode")
guitype.link_output(journalnode, "pfm", "isNotebook")
@ -247,7 +292,7 @@ class PlasmaJournalBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
height.link_output(journalnode, "pfm", "BookHeight")
height.value_float = self.book_scale_h / 100.0
def create_moul_nodes(self, clickable_object, nodes, journalnode):
def _create_moul_nodes(self, clickable_object, nodes, journalnode, age_name):
clickable_region = nodes.new("PlasmaClickableRegionNode")
clickable_region.region_object = self.temp_rgn
@ -275,7 +320,7 @@ class PlasmaJournalBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz
locpath = nodes.new("PlasmaAttribStringNode")
locpath.link_output(journalnode, "pfm", "LocPath")
locpath.value = self.book_source_locpath
locpath.value = "{}.Journals.{}".format(age_name, self.key_name)
guitype = nodes.new("PlasmaAttribStringNode")
guitype.link_output(journalnode, "pfm", "GUIType")

46
korman/ui/modifiers/gui.py

@ -36,22 +36,34 @@ def imagelibmod(modifier, layout, context):
def journalbookmod(modifier, layout, context):
layout.prop_menu_enum(modifier, "versions")
layout.separator()
if not {"pvPrime", "pvMoul"}.isdisjoint(modifier.versions):
layout.prop(modifier, "start_state")
split = layout.split()
main_col = split.column()
if not {"pvPots", "pvMoul"}.isdisjoint(modifier.versions):
layout.prop(modifier, "book_type")
row = layout.row(align=True)
row.label("Book Scaling:")
row.prop(modifier, "book_scale_w", text="Width", slider=True)
row.prop(modifier, "book_scale_h", text="Height", slider=True)
if "pvPrime" in modifier.versions:
layout.prop(modifier, "book_source_name", text="Name")
if "pvPots" in modifier.versions:
layout.prop(modifier, "book_source_filename", text="Filename")
if "pvMoul" in modifier.versions:
layout.prop(modifier, "book_source_locpath", text="LocPath")
layout.prop(modifier, "clickable_region")
main_col.label("Display Settings:")
col = main_col.column()
col.active = "pvMoul" in modifier.versions
col.prop(modifier, "start_state", text="")
main_col.prop(modifier, "book_type", text="")
main_col.separator()
main_col.label("Book Scaling:")
col = main_col.column(align=True)
col.prop(modifier, "book_scale_w", text="Width", slider=True)
col.prop(modifier, "book_scale_h", text="Height", slider=True)
main_col = split.column()
main_col.label("Content Translations:")
main_col.prop(modifier, "active_translation", text="")
# This should never fail...
try:
translation = modifier.journal_translations[modifier.active_translation_index]
except Exception as e:
main_col.label(text="Error (see console)", icon="ERROR")
print(e)
else:
main_col.prop(translation, "text_id", text="")
main_col.separator()
main_col.label("Clickable Region:")
main_col.prop(modifier, "clickable_region", text="")

82
korman/ui/ui_world.py

@ -29,7 +29,59 @@ class AgeButtonsPanel:
return context.world and context.scene.render.engine == "PLASMA_GAME"
class PlasmaGamePanel(AgeButtonsPanel, bpy.types.Panel):
class PlasmaGameHelper:
@property
def active_game(self):
games = bpy.context.world.plasma_games
prefs = bpy.context.user_preferences.addons["korman"].preferences
active_game_index = games.active_game_index
if active_game_index < len(prefs.games):
return prefs.games[active_game_index]
else:
return None
def format_path(self, dirname="dat", ext=".age"):
active_game = self.active_game
if active_game is None:
return ""
age_name = bpy.context.world.plasma_age.age_name
return str((Path(active_game.path) / dirname / age_name).with_suffix(ext))
@property
def legal_game(self):
if self.active_game is not None:
return bool(bpy.context.world.plasma_age.age_name.strip())
class PlasmaGameExportMenu(PlasmaGameHelper, bpy.types.Menu):
bl_label = "Plasma Export Menu"
def draw(self, context):
layout = self.layout
age_name = context.world.plasma_age.age_name
active_game = self.active_game
legal_game = self.legal_game
# Localization
row = layout.row()
row.operator_context = "EXEC_DEFAULT"
row.enabled = legal_game
op = row.operator("export.plasma_loc", icon="FILE_SCRIPT")
if active_game is not None:
op.filepath = active_game.path
op.version = active_game.version
# Python
row = layout.row()
row.operator_context = "EXEC_DEFAULT"
row.enabled = legal_game and active_game.version != "pvMoul"
op = row.operator("export.plasma_pak", icon="FILE_SCRIPT")
op.filepath = self.format_path("Python", ".pak")
if active_game is not None:
op.version = active_game.version
class PlasmaGamePanel(AgeButtonsPanel, PlasmaGameHelper, bpy.types.Panel):
bl_label = "Plasma Games"
def draw(self, context):
@ -37,6 +89,8 @@ class PlasmaGamePanel(AgeButtonsPanel, bpy.types.Panel):
prefs = context.user_preferences.addons["korman"].preferences
games = context.world.plasma_games
age = context.world.plasma_age
active_game = self.active_game
legal_game = self.legal_game
row = layout.row()
# Remember: game storage moved to addon preferences!
@ -44,39 +98,31 @@ class PlasmaGamePanel(AgeButtonsPanel, bpy.types.Panel):
"active_game_index", rows=2)
row.operator("ui.korman_open_prefs", icon="PREFERENCES", text="")
# Game Tools
active_game_index = games.active_game_index
if active_game_index < len(prefs.games):
active_game = prefs.games[active_game_index]
else:
active_game = None
layout.separator()
row = layout.row(align=True)
legal_game = bool(age.age_name.strip()) and active_game is not None
# Export Age
row.operator_context = "EXEC_DEFAULT"
row.enabled = legal_game
op = row.operator("export.plasma_age", icon="EXPORT")
if active_game is not None:
op.dat_only = False
op.filepath = str((Path(active_game.path) / "dat" / age.age_name).with_suffix(".age"))
op.filepath = self.format_path()
op.version = active_game.version
# Package Age
row = row.row(align=True)
row.enabled = legal_game
row.operator_context = "INVOKE_DEFAULT"
op = row.operator("export.plasma_age", icon="PACKAGE", text="Package Age")
op.dat_only = False
op.filepath = "{}.zip".format(age.age_name)
if active_game is not None:
op.dat_only = False
op.filepath = "{}.zip".format(age.age_name)
op.version = active_game.version
# Special Menu
row = row.row(align=True)
row.operator_context = "EXEC_DEFAULT"
row.enabled = legal_game and active_game.version != "pvMoul"
op = row.operator("export.plasma_pak", icon="FILE_SCRIPT")
if active_game is not None:
op.filepath = str((Path(active_game.path) / "Python" / age.age_name).with_suffix(".pak"))
op.version = active_game.version
row.menu("PlasmaGameExportMenu", icon='DOWNARROW_HLT', text="")
class PlasmaGameListRO(bpy.types.UIList):

Loading…
Cancel
Save