diff --git a/korman/__init__.py b/korman/__init__.py
index f7b0df8..824cfd8 100644
--- a/korman/__init__.py
+++ b/korman/__init__.py
@@ -14,6 +14,7 @@
# along with Korman. If not, see .
import bpy
+from . import addon_prefs
from . import exporter, render
from . import properties, ui
from . import nodes
@@ -26,8 +27,7 @@ bl_info = {
"location": "File > Import-Export",
"description": "Exporter for Cyan Worlds' Plasma Engine",
"warning": "beta",
- "category": "System", # Eventually, we will hide some of the default
- # Blender panels (think materials)
+ "category": "System",
}
diff --git a/korman/addon_prefs.py b/korman/addon_prefs.py
new file mode 100644
index 0000000..94a3011
--- /dev/null
+++ b/korman/addon_prefs.py
@@ -0,0 +1,76 @@
+# 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 bpy.props import *
+
+game_versions = [("pvPrime", "Ages Beyond Myst (63.11)", "Targets the original Uru (Live) game"),
+ ("pvPots", "Path of the Shell (63.12)", "Targets the most recent offline expansion pack"),
+ ("pvMoul", "Myst Online: Uru Live (70)", "Targets the most recent online game")]
+
+class PlasmaGame(bpy.types.PropertyGroup):
+ name = StringProperty(name="Name",
+ description="Name of the Plasma Game",
+ options=set())
+ path = StringProperty(name="Path",
+ description="Path to this Plasma Game",
+ options=set())
+ version = EnumProperty(name="Version",
+ description="Plasma version of this game",
+ items=game_versions,
+ options=set())
+
+
+class KormanAddonPreferences(bpy.types.AddonPreferences):
+ bl_idname = __package__
+
+ games = CollectionProperty(type=PlasmaGame)
+ active_game_index = IntProperty(options={"SKIP_SAVE"})
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.label("Plasma Games:")
+ row = layout.row()
+ row.template_list("PlasmaGameListRW", "games", self, "games", self,
+ "active_game_index", rows=2)
+ col = row.column(align=True)
+ col.operator("world.plasma_game_add", icon="ZOOMIN", text="")
+ col.operator("world.plasma_game_remove", icon="ZOOMOUT", text="")
+ col.operator("world.plasma_game_convert", icon="IMPORT", text="")
+
+ # Game Properties
+ active_game_index = self.active_game_index
+ if bool(self.games) and active_game_index < len(self.games):
+ active_game = self.games[active_game_index]
+
+ layout.separator()
+ box = layout.box()
+
+ box.prop(active_game, "path", emboss=False)
+ box.prop(active_game, "version")
+ box.separator()
+
+ row = box.row(align=True)
+ op = row.operator("world.plasma_game_add", icon="FILE_FOLDER", text="Change Path")
+ op.filepath = active_game.path
+ op.game_index = active_game_index
+
+ @classmethod
+ def register(cls):
+ # Register the old-timey per-world Plasma Games for use in the conversion
+ # operator. What fun. I guess....
+ from .properties.prop_world import PlasmaGames
+ PlasmaGames.games = CollectionProperty(type=PlasmaGame)
diff --git a/korman/operators/op_export.py b/korman/operators/op_export.py
index 3a098f9..adec5bd 100644
--- a/korman/operators/op_export.py
+++ b/korman/operators/op_export.py
@@ -19,9 +19,10 @@ import cProfile
from pathlib import Path
import pstats
+from ..addon_prefs import game_versions
from .. import exporter
from ..helpers import UiHelper
-from ..properties.prop_world import PlasmaAge, game_versions
+from ..properties.prop_world import PlasmaAge
from ..korlib import ConsoleToggler
class ExportOperator(bpy.types.Operator):
diff --git a/korman/operators/op_ui.py b/korman/operators/op_ui.py
index 0f23da4..ffa3b17 100644
--- a/korman/operators/op_ui.py
+++ b/korman/operators/op_ui.py
@@ -13,6 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with Korman. If not, see .
+import addon_utils
import bpy
from bpy.props import *
@@ -87,3 +88,17 @@ class CollectionRemoveOperator(UIOperator, bpy.types.Operator):
return {"FINISHED"}
else:
return {"CANCELLED"}
+
+
+class OpenAddonPrefs(UIOperator, bpy.types.Operator):
+ bl_idname = "ui.korman_open_prefs"
+ bl_label = "Open Korman Preferences"
+ bl_description = "Opens the Korman User Preferences"
+
+ def execute(self, context):
+ bpy.ops.screen.userpref_show("INVOKE_DEFAULT")
+ context.user_preferences.active_section = "ADDONS"
+ context.window_manager.addon_filter = "System"
+ korman_addon = addon_utils.addons_fake_modules["korman"]
+ addon_utils.module_bl_info(korman_addon)["show_expanded"] = True
+ return {"FINISHED"}
diff --git a/korman/operators/op_world.py b/korman/operators/op_world.py
index 7affe66..866a580 100644
--- a/korman/operators/op_world.py
+++ b/korman/operators/op_world.py
@@ -32,38 +32,35 @@ class GameAddOperator(AgeOperator, bpy.types.Operator):
game_index = IntProperty(default=-1, options={"HIDDEN"})
def execute(self, context):
- w = context.world
- if w:
- # First, verify this is a valid Uru directory...
- path = Path(self.filepath)
-
- # Blendsucks likes to tack filenames onto our doggone directories...
- if not path.is_dir():
- path = path.parent
- if not ((path / "UruExplorer.exe").is_file() or (path / "plClient.exe").is_file()):
- self.report({"ERROR"}, "The selected directory is not a copy of URU.")
- return {"CANCELLED"}
+ prefs = context.user_preferences.addons["korman"].preferences
- # New game?
- games = w.plasma_games
- new_game = self.game_index == -1
- if new_game:
- games.active_game_index = len(games.games)
- game = games.games.add()
- else:
- game = games.games[self.game_index]
+ # First, verify this is a valid Uru directory...
+ path = Path(self.filepath)
- # Setup game...
- game.path = str(path)
- if (path / "cypython22.dll").is_file():
- game.version = "pvPots"
- else:
- game.version = "pvMoul"
- game.name = path.name
+ # Blendsucks likes to tack filenames onto our doggone directories...
+ if not path.is_dir():
+ path = path.parent
+ if not ((path / "UruExplorer.exe").is_file() or (path / "plClient.exe").is_file()):
+ self.report({"ERROR"}, "The selected directory is not a copy of URU.")
+ return {"CANCELLED"}
- return {"FINISHED"}
+ # New game?
+ new_game = self.game_index == -1
+ if new_game:
+ prefs.active_game_index = len(prefs.games)
+ game = prefs.games.add()
else:
- return {"CANCELLED"}
+ game = prefs.games[self.game_index]
+
+ # Setup game...
+ game.path = str(path)
+ if (path / "cypython22.dll").is_file():
+ game.version = "pvPots"
+ else:
+ game.version = "pvMoul"
+ game.name = path.name
+
+ return {"FINISHED"}
def invoke(self, context, event):
@@ -71,20 +68,53 @@ class GameAddOperator(AgeOperator, bpy.types.Operator):
return {"RUNNING_MODAL"}
+class GameConvertOperator(AgeOperator, bpy.types.Operator):
+ bl_idname = "world.plasma_game_convert"
+ bl_label = "This will save your User Preferences file!"
+ bl_description = "Load old per-file Plasma Games into your user preferences"
+
+ def draw(self, context):
+ self.layout.label("test")
+
+ def execute(self, context):
+ prefs = context.user_preferences.addons["korman"].preferences
+ w = context.scene.world
+
+ for old_game in w.plasma_games.games:
+ # don't add dupe games
+ match = next((i for i in prefs.games if i.path == old_game.path), None)
+ if match is not None:
+ continue
+
+ new_game = prefs.games.add()
+ new_game.name = old_game.name
+ new_game.path = old_game.path
+ new_game.version = old_game.version
+
+ w.plasma_games.games.clear()
+ bpy.ops.wm.save_userpref()
+ return {"FINISHED"}
+
+ def invoke(self, context, event):
+ return context.window_manager.invoke_confirm(self, event)
+
+ @classmethod
+ def poll(cls, context):
+ return super().poll(context) and bool(context.scene.world.plasma_games.games)
+
+
class GameRemoveOperator(AgeOperator, bpy.types.Operator):
bl_idname = "world.plasma_game_remove"
bl_label = "Remove Plasma Game"
def execute(self, context):
- w = context.world
- if w:
- games = w.plasma_games
- if games.active_game_index >= len(games.games):
- return {"CANCELLED"}
- games.games.remove(games.active_game_index)
- return {"FINISHED"}
- else:
+ prefs = context.user_preferences.addons["korman"].preferences
+
+ if prefs.active_game_index >= len(prefs.games):
return {"CANCELLED"}
+ prefs.games.remove(prefs.active_game_index)
+ prefs.active_game_index = max(prefs.active_game_index - 1, -1)
+ return {"FINISHED"}
class PageAddOperator(AgeOperator, bpy.types.Operator):
diff --git a/korman/properties/modifiers/gui.py b/korman/properties/modifiers/gui.py
index 257c3bb..62cecdf 100644
--- a/korman/properties/modifiers/gui.py
+++ b/korman/properties/modifiers/gui.py
@@ -20,8 +20,8 @@ import mathutils
from bpy.props import *
from PyHSPlasma import *
+from ...addon_prefs import game_versions
from .base import PlasmaModifierProperties, PlasmaModifierLogicWiz
-from .logic import game_versions
from ... import idprops
diff --git a/korman/properties/modifiers/logic.py b/korman/properties/modifiers/logic.py
index 2dea10e..261bc02 100644
--- a/korman/properties/modifiers/logic.py
+++ b/korman/properties/modifiers/logic.py
@@ -17,8 +17,8 @@ import bpy
from bpy.props import *
from PyHSPlasma import *
+from ...addon_prefs import game_versions
from .base import PlasmaModifierProperties
-from ..prop_world import game_versions
from ...exporter import ExportError
from ... import idprops
diff --git a/korman/properties/prop_world.py b/korman/properties/prop_world.py
index 9f32b43..1e159a5 100644
--- a/korman/properties/prop_world.py
+++ b/korman/properties/prop_world.py
@@ -17,9 +17,7 @@ import bpy
from bpy.props import *
from PyHSPlasma import *
-game_versions = [("pvPrime", "Ages Beyond Myst (63.11)", "Targets the original Uru (Live) game"),
- ("pvPots", "Path of the Shell (63.12)", "Targets the most recent offline expansion pack"),
- ("pvMoul", "Myst Online: Uru Live (70)", "Targets the most recent online game")]
+from ..addon_prefs import game_versions
class PlasmaFni(bpy.types.PropertyGroup):
bl_idname = "world.plasma_fni"
@@ -58,23 +56,9 @@ class PlasmaFni(bpy.types.PropertyGroup):
min=1)
-class PlasmaGame(bpy.types.PropertyGroup):
- name = StringProperty(name="Name",
- description="Name of the Plasma Game",
- options=set())
- path = StringProperty(name="Path",
- description="Path to this Plasma Game",
- options=set())
- version = EnumProperty(name="Version",
- description="Plasma version of this game",
- items=game_versions,
- options=set())
-
-
class PlasmaGames(bpy.types.PropertyGroup):
bl_idname = "world.plasma_games"
- games = CollectionProperty(type=PlasmaGame)
active_game_index = IntProperty(options={"HIDDEN"})
@property
diff --git a/korman/ui/ui_world.py b/korman/ui/ui_world.py
index c5580c4..543cc26 100644
--- a/korman/ui/ui_world.py
+++ b/korman/ui/ui_world.py
@@ -34,41 +34,39 @@ class PlasmaGamePanel(AgeButtonsPanel, bpy.types.Panel):
def draw(self, context):
layout = self.layout
+ prefs = context.user_preferences.addons["korman"].preferences
games = context.world.plasma_games
age = context.world.plasma_age
row = layout.row()
- row.template_list("PlasmaGameList", "games", games, "games", games,
+ # Remember: game storage moved to addon preferences!
+ row.template_list("PlasmaGameListRO", "games", prefs, "games", games,
"active_game_index", rows=2)
- col = row.column(align=True)
- col.operator("world.plasma_game_add", icon="ZOOMIN", text="")
- col.operator("world.plasma_game_remove", icon="ZOOMOUT", text="")
+ row.operator("ui.korman_open_prefs", icon="PREFERENCES", text="")
- # Game Properties
+ # Game Tools
active_game_index = games.active_game_index
- if active_game_index < len(games.games):
- active_game = games.games[active_game_index]
+ if active_game_index < len(prefs.games):
+ active_game = prefs.games[active_game_index]
+ else:
+ active_game = None
- layout.separator()
- box = layout.box()
+ layout.separator()
+ row = layout.row(align=True)
- box.prop(active_game, "path", emboss=False)
- box.prop(active_game, "version")
- box.separator()
-
- row = box.row(align=True)
- op = row.operator("world.plasma_game_add", icon="FILE_FOLDER", text="Change Path")
- op.filepath = active_game.path
- op.game_index = active_game_index
- row = row.row(align=True)
- row.operator_context = "EXEC_DEFAULT"
- row.enabled = bool(age.age_name.strip())
- op = row.operator("export.plasma_age", icon="EXPORT")
+ row.operator_context = "EXEC_DEFAULT"
+ row.enabled = bool(age.age_name.strip()) and active_game is not None
+ op = row.operator("export.plasma_age", icon="EXPORT")
+ if active_game is not None:
op.filepath = str((Path(active_game.path) / "dat" / age.age_name).with_suffix(".age"))
op.version = active_game.version
-class PlasmaGameList(bpy.types.UIList):
+class PlasmaGameListRO(bpy.types.UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_property, index=0, flt_flag=0):
+ layout.label(item.name, icon="BOOKMARKS")
+
+class PlasmaGameListRW(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_property, index=0, flt_flag=0):
layout.prop(item, "name", text="", emboss=False, icon="BOOKMARKS")