Skip to content

Commit 7363930

Browse files
authored
Merge pull request #414 from Hoikas/phony_pfm_reorg
Reorganize PFM Stub Storage and Add the SDL Show/Hide Modifier.
2 parents 9dc7f68 + 0f0d6e1 commit 7363930

File tree

9 files changed

+299
-158
lines changed

9 files changed

+299
-158
lines changed

korman/exporter/convert.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -510,8 +510,12 @@ def _(temporary, parent):
510510

511511
@handle_temporary.register(bpy.types.NodeTree)
512512
def _(temporary, parent):
513-
self.exit_stack.enter_context(TemporaryObject(temporary, bpy.data.node_groups.remove))
514-
log_msg(f"'{parent.name}' generated NodeTree '{temporary.name}'")
513+
# NodeTrees are reuseable, so make sure we haven't already encountered it.
514+
if not temporary.name in self.want_node_trees:
515+
self.exit_stack.enter_context(TemporaryObject(temporary, bpy.data.node_groups.remove))
516+
log_msg(f"'{parent.name}' generated NodeTree '{temporary.name}'")
517+
else:
518+
log_msg(f"'{parent.name}' reused NodeTree '{temporary.name}'")
515519
if temporary.bl_idname == "PlasmaNodeTree":
516520
parent_so = self.mgr.find_create_object(plSceneObject, bl=parent)
517521
self.want_node_trees[temporary.name].add((parent, parent_so))
@@ -594,6 +598,10 @@ def age_name(self):
594598
else:
595599
return bpy.context.scene.world.plasma_age.age_name
596600

601+
@property
602+
def age_sdl(self) -> bool:
603+
return bpy.context.scene.world.plasma_age.age_sdl
604+
597605
@property
598606
def dat_only(self):
599607
return self._op.dat_only

korman/operators/op_ui.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,17 @@ class CollectionRemoveOperator(UIOperator, bpy.types.Operator):
7777
index_prop = StringProperty(name="Index Property",
7878
description="Name of the active element index property",
7979
options=set())
80+
manual_index = IntProperty(name="Manual Index",
81+
description="Manual integer index to remove",
82+
options=set())
8083

8184
def execute(self, context):
8285
props = getattr(context, self.context).path_resolve(self.group_path)
8386
collection = getattr(props, self.collection_prop)
84-
index = getattr(props, self.index_prop)
87+
if self.index_prop:
88+
index = getattr(props, self.index_prop)
89+
else:
90+
index = self.manual_index
8591
if len(collection) > index:
8692
collection.remove(index)
8793
setattr(props, self.index_prop, index - 1)

korman/plasma_api.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# This file is part of Korman.
2+
#
3+
# Korman is free software: you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation, either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# Korman is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with Korman. If not, see <http://www.gnu.org/licenses/>.
15+
16+
python_files = {
17+
"xAgeSDLBoolShowHide.py": (
18+
{ "id": 1, "type": "ptAttribString", "name": "sdlName" },
19+
{ "id": 2, "type": "ptAttribBoolean", "name": "showOnTrue" },
20+
# --- CWE Only Below ---
21+
{ "id": 3, "type": "ptAttribBoolean", "name": "defaultValue" },
22+
{ "id": 4, "type": "ptAttribBoolean", "name": "evalOnFirstUpdate "},
23+
),
24+
25+
"xAgeSDLIntShowHide.py": (
26+
{ "id": 1, "type": "ptAttribString", "name": "stringVarName" },
27+
{ "id": 2, "type": "ptAttribString", "name": "stringShowStates" },
28+
# --- CWE Only Below ---
29+
{ "id": 3, "type": "ptAttribInt", "name": "intDefault" },
30+
{ "id": 4, "type": "ptAttribBoolean", "name": "boolFirstUpdate "},
31+
),
32+
33+
# Provided by all variants of Uru and Myst V
34+
"xDialogToggle.py": (
35+
{ "id": 1, "type": "ptAttribActivator", "name": "Activate" },
36+
{ "id": 4, "type": "ptAttribString", "name": "Vignette" },
37+
),
38+
39+
# Provided by CWE or OfflineKI
40+
"xDynTextLoc.py": (
41+
{ "id": 1, "type": "ptAttribDynamicMap", "name": "dynTextMap", },
42+
{ "id": 2, "type": "ptAttribString", "name": "locPath" },
43+
{ "id": 3, "type": "ptAttribString", "name": "fontFace" },
44+
{ "id": 4, "type": "ptAttribInt", "name": "fontSize" },
45+
{ "id": 5, "type": "ptAttribFloat", "name": "fontColorR" },
46+
{ "id": 6, "type": "ptAttribFloat", "name": "fontColorG" },
47+
{ "id": 7, "type": "ptAttribFloat", "name": "fontColorB" },
48+
{ "id": 8, "type": "ptAttribFloat", "name": "fontColorA" },
49+
{ "id": 9, "type": "ptAttribInt", "name": "marginTop" },
50+
{ "id": 10, "type": "ptAttribInt", "name": "marginLeft" },
51+
{ "id": 11, "type": "ptAttribInt", "name": "marginBottom" },
52+
{ "id": 12, "type": "ptAttribInt", "name": "marginRight" },
53+
{ "id": 13, "type": "ptAttribInt", "name": "lineSpacing" },
54+
# Yes, it"s really a ptAttribDropDownList, but those are only for use in
55+
# artist generated node trees.
56+
{ "id": 14, "type": "ptAttribString", "name": "justify" },
57+
{ "id": 15, "type": "ptAttribFloat", "name": "clearColorR" },
58+
{ "id": 16, "type": "ptAttribFloat", "name": "clearColorG" },
59+
{ "id": 17, "type": "ptAttribFloat", "name": "clearColorB" },
60+
{ "id": 18, "type": "ptAttribFloat", "name": "clearColorA" },
61+
{ "id": 19, "type": "ptAttribBoolean", "name": "blockRGB" },
62+
),
63+
64+
# Provided by CWE and OfflineKI
65+
"xEntryCam.py": (
66+
{ "id": 1, "type": "ptAttribActivator", "name": "actRegionSensor" },
67+
{ "id": 2, "type": "ptAttribSceneobject", "name": "camera" },
68+
{ "id": 3, "type": "ptAttribBoolean", "name": "undoFirstPerson" },
69+
),
70+
71+
# Provided by CWE
72+
"xJournalBookGUIPopup.py": (
73+
{ "id": 1, "type": "ptAttribActivator", "name": "actClickableBook" },
74+
{ "id": 10, "type": "ptAttribBoolean", "name": "StartOpen" },
75+
{ "id": 11, "type": "ptAttribFloat", "name": "BookWidth" },
76+
{ "id": 12, "type": "ptAttribFloat", "name": "BookHeight" },
77+
{ "id": 13, "type": "ptAttribString", "name": "LocPath" },
78+
{ "id": 14, "type": "ptAttribString", "name": "GUIType" },
79+
),
80+
81+
# Provided by all variants of Uru and Myst V
82+
"xLinkingBookGUIPopup.py": (
83+
{ "id": 1, "type": "ptAttribActivator", "name": "actClickableBook" },
84+
{ "id": 2, "type": "ptAttribBehavior", "name": "SeekBehavior" },
85+
{ "id": 3, "type": "ptAttribResponder", "name": "respLinkResponder" },
86+
{ "id": 4, "type": "ptAttribString", "name": "TargetAge" },
87+
{ "id": 5, "type": "ptAttribActivator", "name": "actBookshelf" },
88+
{ "id": 6, "type": "ptAttribActivator", "name": "shareRegion" },
89+
{ "id": 7, "type": "ptAttribBehavior", "name": "shareBookSeek" },
90+
{ "id": 10, "type": "ptAttribBoolean", "name": "IsDRCStamped" },
91+
{ "id": 11, "type": "ptAttribBoolean", "name": "ForceThirdPerson" },
92+
),
93+
94+
# Supplied by the OfflineKI script:
95+
# https://gitlab.com/diafero/offline-ki/blob/master/offlineki/xSimpleJournal.py
96+
"xSimpleJournal.py": (
97+
{ "id": 1, "type": "ptAttribActivator", "name": "bookClickable" },
98+
{ "id": 2, "type": "ptAttribString", "name": "journalFileName" },
99+
{ "id": 3, "type": "ptAttribBoolean", "name": "isNotebook" },
100+
{ "id": 4, "type": "ptAttribFloat", "name": "BookWidth" },
101+
{ "id": 5, "type": "ptAttribFloat", "name": "BookHeight" },
102+
),
103+
104+
# Supplied by the OfflineKI script:
105+
# https://gitlab.com/diafero/offline-ki/blob/master/offlineki/xSimpleLinkingBook.py
106+
"xSimpleLinkingBook.py": (
107+
{ "id": 1, "type": "ptAttribActivator", "name": "bookClickable" },
108+
{ "id": 2, "type": "ptAttribString", "name": "destinationAge" },
109+
{ "id": 3, "type": "ptAttribString", "name": "spawnPoint" },
110+
{ "id": 4, "type": "ptAttribString", "name": "linkPanel" },
111+
{ "id": 5, "type": "ptAttribString", "name": "bookCover" },
112+
{ "id": 6, "type": "ptAttribString", "name": "stampTexture" },
113+
{ "id": 7, "type": "ptAttribFloat", "name": "stampX" },
114+
{ "id": 8, "type": "ptAttribFloat", "name": "stampY" },
115+
{ "id": 9, "type": "ptAttribFloat", "name": "bookWidth" },
116+
{ "id": 10, "type": "ptAttribFloat", "name": "BookHeight" },
117+
{ "id": 11, "type": "ptAttribBehavior", "name": "msbSeekBeforeUI" },
118+
{ "id": 12, "type": "ptAttribResponder", "name": "respOneShot" },
119+
),
120+
121+
# Provided by CWE or OfflineKI
122+
"xSitCam.py": (
123+
{ "id": 1, "type": "ptAttribActivator", "name": "sitAct" },
124+
{ "id": 2, "type": "ptAttribSceneobject", "name": "sitCam" },
125+
),
126+
127+
# Provided by all variants of Uru and Myst V
128+
"xTelescope.py": (
129+
{ "id": 1, "type": "ptAttribActivator", "name": "Activate" },
130+
{ "id": 2, "type": "ptAttribSceneobject", "name": "Camera" },
131+
{ "id": 3, "type": "ptAttribBehavior", "name": "Behavior" },
132+
{ "id": 4, "type": "ptAttribString", "name": "Vignette" },
133+
)
134+
}

korman/properties/modifiers/avatar.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,6 @@ def requires_actor(self):
7878
return True
7979

8080

81-
# Use xSitCam.py for when we want a camera to pop up
82-
sitting_pfm = {
83-
"filename": "xSitCam.py",
84-
"attribs": (
85-
{ 'id': 1, 'type': "ptAttribActivator", 'name': "sitAct" },
86-
{ 'id': 2, 'type': "ptAttribSceneobject", 'name': "sitCam" },
87-
)
88-
}
89-
90-
9181
sitting_approach_flags = [("kApproachFront", "Front", "Approach from the font"),
9282
("kApproachLeft", "Left", "Approach from the left"),
9383
("kApproachRight", "Right", "Approach from the right"),
@@ -140,7 +130,7 @@ def logicwiz(self, bo, tree):
140130
sittingmod.name = "SittingBeh"
141131
# xSitCam.py PythonFileMod
142132
if self.sitting_camera is not None:
143-
sittingpynode = self._create_python_file_node(tree, sitting_pfm["filename"], sitting_pfm["attribs"])
133+
sittingpynode = self._create_python_standard_file_node(tree, "xSitCam.py")
144134
sittingmod.link_output(sittingpynode, "satisfies", "sitAct")
145135

146136
# Camera Object

korman/properties/modifiers/base.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from ...nodes.node_python import *
2727

2828
from ... import helpers
29+
from ... import plasma_api
2930

3031
class PlasmaModifierProperties(bpy.types.PropertyGroup):
3132
@property
@@ -180,20 +181,24 @@ def requires_actor(self):
180181

181182
class PlasmaModifierLogicWiz:
182183
def convert_logic(self, bo, **kwargs):
183-
"""Creates, converts, and returns an unmanaged NodeTree for this logic wizard. If the wizard
184-
fails during conversion, the temporary tree is deleted for you. However, on success, you
185-
are responsible for removing the tree from Blender, if applicable."""
184+
"""Attempts to look up an already existing logic tree matching the name provided and returns
185+
it, if found. If not, creates, converts, and returns an unmanaged NodeTree for this wizard.
186+
If the wizard fails during conversion, the temporary tree is deleted for you. However, on
187+
success, you are responsible for removing the tree from Blender, if applicable."""
186188
name = kwargs.pop("name", self.key_name)
187189
assert not "tree" in kwargs
188-
tree = bpy.data.node_groups.new(name, "PlasmaNodeTree")
189-
kwargs["tree"] = tree
190-
try:
191-
self.logicwiz(bo, **kwargs)
192-
except:
193-
bpy.data.node_groups.remove(tree)
194-
raise
195-
else:
196-
return tree
190+
191+
node_groups = bpy.data.node_groups
192+
tree = node_groups.get(name)
193+
if tree is None:
194+
tree = node_groups.new(name, "PlasmaNodeTree")
195+
kwargs["tree"] = tree
196+
try:
197+
self.logicwiz(bo, **kwargs)
198+
except:
199+
bpy.data.node_groups.remove(tree)
200+
raise
201+
return tree
197202

198203
def _create_python_file_node(self, tree, filename: str, attributes: Dict[str, Any]) -> bpy.types.Node:
199204
pfm_node = tree.nodes.new("PlasmaPythonFileNode")
@@ -207,6 +212,10 @@ def _create_python_file_node(self, tree, filename: str, attributes: Dict[str, An
207212
pfm_node.update()
208213
return pfm_node
209214

215+
def _create_standard_python_file_node(self, tree, filename: str) -> bpy.types.Node:
216+
"""Create a Python File Node for a standard Plasma Python API file (e.g. xAgeSDLBoolShowHide.py)"""
217+
return self._create_python_file_node(tree, filename, plasma_api.python_files[filename])
218+
210219
def _create_python_attribute(self, pfm_node: PlasmaPythonFileNode, attribute_name: str, **kwargs):
211220
"""Creates and links a Python Attribute Node to the Python File Node given by `pfm_node`.
212221
For attribute nodes that require multiple values, the `value` may be set to None and

korman/properties/modifiers/gui.py

Lines changed: 5 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -35,33 +35,6 @@
3535
from ...exporter import Exporter
3636
from .game_gui import PlasmaGameGuiDialogModifier
3737

38-
39-
journal_pfms = {
40-
pvPots : {
41-
# Supplied by the OfflineKI script:
42-
# https://gitlab.com/diafero/offline-ki/blob/master/offlineki/xSimpleJournal.py
43-
"filename": "xSimpleJournal.py",
44-
"attribs": (
45-
{ 'id': 1, 'type': "ptAttribActivator", "name": "bookClickable" },
46-
{ 'id': 2, 'type': "ptAttribString", "name": "journalFileName" },
47-
{ 'id': 3, 'type': "ptAttribBoolean", "name": "isNotebook" },
48-
{ 'id': 4, 'type': "ptAttribFloat", "name": "BookWidth" },
49-
{ 'id': 5, 'type': "ptAttribFloat", "name": "BookHeight" },
50-
)
51-
},
52-
pvMoul : {
53-
"filename": "xJournalBookGUIPopup.py",
54-
"attribs": (
55-
{ 'id': 1, 'type': "ptAttribActivator", 'name': "actClickableBook" },
56-
{ 'id': 10, 'type': "ptAttribBoolean", 'name': "StartOpen" },
57-
{ 'id': 11, 'type': "ptAttribFloat", 'name': "BookWidth" },
58-
{ 'id': 12, 'type': "ptAttribFloat", 'name': "BookHeight" },
59-
{ 'id': 13, 'type': "ptAttribString", 'name': "LocPath" },
60-
{ 'id': 14, 'type': "ptAttribString", 'name': "GUIType" },
61-
)
62-
},
63-
}
64-
6538
# Do not change the numeric IDs. They allow the list to be rearranged.
6639
_languages = [("Dutch", "Nederlands", "Dutch", 0),
6740
("English", "English", "", 1),
@@ -246,11 +219,11 @@ def pre_export(self, exporter, bo):
246219

247220
def logicwiz(self, bo, tree, age_name, version):
248221
# Assign journal script based on target version
249-
journal_pfm = journal_pfms[version]
250-
journalnode = self._create_python_file_node(tree, journal_pfm["filename"], journal_pfm["attribs"])
251222
if version <= pvPots:
223+
journalnode = self._create_standard_python_file_node(tree, "xSimpleJournal.py")
252224
self._create_pots_nodes(bo, tree.nodes, journalnode, age_name)
253225
else:
226+
journalnode = self._create_standard_python_file_node(tree, "xJournalBookGUIPopup.py")
254227
self._create_moul_nodes(bo, tree.nodes, journalnode, age_name)
255228

256229
def _create_pots_nodes(self, clickable_object, nodes, journalnode, age_name):
@@ -324,43 +297,6 @@ def translations(self):
324297
return self.journal_translations
325298

326299

327-
linking_pfms = {
328-
pvPots : {
329-
# Supplied by the OfflineKI script:
330-
# https://gitlab.com/diafero/offline-ki/blob/master/offlineki/xSimpleLinkingBook.py
331-
"filename": "xSimpleLinkingBook.py",
332-
"attribs": (
333-
{ 'id': 1, 'type': "ptAttribActivator", "name": "bookClickable" },
334-
{ 'id': 2, 'type': "ptAttribString", "name": "destinationAge" },
335-
{ 'id': 3, 'type': "ptAttribString", "name": "spawnPoint" },
336-
{ 'id': 4, 'type': "ptAttribString", "name": "linkPanel" },
337-
{ 'id': 5, 'type': "ptAttribString", "name": "bookCover" },
338-
{ 'id': 6, 'type': "ptAttribString", "name": "stampTexture" },
339-
{ 'id': 7, 'type': "ptAttribFloat", "name": "stampX" },
340-
{ 'id': 8, 'type': "ptAttribFloat", "name": "stampY" },
341-
{ 'id': 9, 'type': "ptAttribFloat", "name": "bookWidth" },
342-
{ 'id': 10, 'type': "ptAttribFloat", "name": "BookHeight" },
343-
{ 'id': 11, 'type': "ptAttribBehavior", "name": "msbSeekBeforeUI" },
344-
{ 'id': 12, 'type': "ptAttribResponder", "name": "respOneShot" },
345-
)
346-
},
347-
pvMoul : {
348-
"filename": "xLinkingBookGUIPopup.py",
349-
"attribs": (
350-
{ 'id': 1, 'type': "ptAttribActivator", 'name': "actClickableBook" },
351-
{ 'id': 2, 'type': "ptAttribBehavior", 'name': "SeekBehavior" },
352-
{ 'id': 3, 'type': "ptAttribResponder", 'name': "respLinkResponder" },
353-
{ 'id': 4, 'type': "ptAttribString", 'name': "TargetAge" },
354-
{ 'id': 5, 'type': "ptAttribActivator", 'name': "actBookshelf" },
355-
{ 'id': 6, 'type': "ptAttribActivator", 'name': "shareRegion" },
356-
{ 'id': 7, 'type': "ptAttribBehavior", 'name': "shareBookSeek" },
357-
{ 'id': 10, 'type': "ptAttribBoolean", 'name': "IsDRCStamped" },
358-
{ 'id': 11, 'type': "ptAttribBoolean", 'name': "ForceThirdPerson" },
359-
)
360-
},
361-
}
362-
363-
364300
class PlasmaLinkingBookModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz):
365301
pl_id = "linkingbookmod"
366302

@@ -495,12 +431,11 @@ def harvest_actors(self):
495431
yield self.seek_point.name
496432

497433
def logicwiz(self, bo, tree, age_name, version):
498-
# Assign linking book script based on target version
499-
linking_pfm = linking_pfms[version]
500-
linkingnode = self._create_python_file_node(tree, linking_pfm["filename"], linking_pfm["attribs"])
501434
if version <= pvPots:
435+
linkingnode = self._create_standard_python_file_node(tree, "xSimpleLinkingBook.py")
502436
self._create_pots_nodes(bo, tree.nodes, linkingnode, age_name)
503437
else:
438+
linkingnode = self._create_standard_python_file_node(tree, "xLinkingBookGUIPopup.py")
504439
self._create_moul_nodes(bo, tree.nodes, linkingnode, age_name)
505440

506441
def _create_pots_nodes(self, clickable_object, nodes, linkingnode, age_name):
@@ -667,14 +602,6 @@ def sanity_check(self, exporter):
667602
raise ExportError("{}: Linking Book modifier requires a seek point!", self.id_data.name)
668603

669604

670-
dialog_toggle = {
671-
"filename": "xDialogToggle.py",
672-
"attribs": (
673-
{ 'id': 1, 'type': "ptAttribActivator", 'name': "Activate" },
674-
{ 'id': 4, 'type': "ptAttribString", 'name': "Vignette" },
675-
)
676-
}
677-
678605
class PlasmaNotePopupModifier(PlasmaModifierProperties, PlasmaModifierLogicWiz):
679606
pl_id = "note_popup"
680607

@@ -755,11 +682,7 @@ def logicwiz(self, bo, tree):
755682
nodes = tree.nodes
756683

757684
# xDialogToggle.py PythonFile Node
758-
dialog_node = self._create_python_file_node(
759-
tree,
760-
dialog_toggle["filename"],
761-
dialog_toggle["attribs"]
762-
)
685+
dialog_node = self._create_standard_python_file_node(tree, "xDialogToggle.py")
763686
self._create_python_attribute(dialog_node, "Vignette", value=self.gui_page)
764687

765688
# Clickable

0 commit comments

Comments
 (0)