[Closed] Persistent when construct
Hi there,
i’m creating a camera Rig via maxscript.
I wanna release it when it’s done (for free) but i’m still running into some problems.
It involves several nodes that get linked and some wiring and controller stuff. In the end everything gets packed into an assembly that holds custom attributes. One of the attributes is a ddlist to select the display style. The options are: Show always, show when selected, show never.
Once the rig is created i have a when construct to show or hide the rig on selection.
my code:
fn FunctionForChangedSelection myassembly =
(
TheMasterNode = myassembly
TheDisplayValue = (TheMasterNode.DisplayStyleValue)
if TheMasterNode.isselected then hideme = false else hideme = true
case TheDisplayValue of
(
1:(TheMasterNode.CrossNode.ishidden = false; TheMasterNode.LeftRightNode.ishidden = false; TheMasterNode.UpDownNode.ishidden = false)
2:(TheMasterNode.CrossNode.ishidden = hideme; TheMasterNode.LeftRightNode.ishidden = hideme; TheMasterNode.UpDownNode.ishidden = hideme)
3:(TheMasterNode.CrossNode.ishidden = true; TheMasterNode.LeftRightNode.ishidden = true; TheMasterNode.UpDownNode.ishidden = true)
)
)
when select myassembly changes id:#CamRigChangeHandler do FunctionForChangedSelection myassembly
This code works totally fine if i keep working in the scene, but upon saving and loading the changehandler/callback doesn’t work anymore. Obviously because it doesn’t get saved with the scene.
Now my question is, how can i manage to have my when-construct persistent or is there a better way to do it? maybe the general callbacks? or can i put some selection handling to my custom attributes?
Regards, Lukas
Don’t use persistent callbacks. Instead, register the when construct every time you open the scene, in the CA’s load or postload event.
Hi, thank you for the advice.
However, i’m a bit confused.
Could you give me a simple example?
I couldn’t make it work and it seems like the load event in the maxscript help doesn’t give much…
Here you go. I ended up doing it using the paramater setter, not the postload, which would also work but is unnecessary.
myDef = attributes "WhenExample" attribID:#(0x11223344, 0xDEADBEEF) version:1
(
local whenHandler
fn callbackFn obj =
(
format "% selection changed
" obj
)
parameters main
(
myNode type:#node
on myNode set val do --this will also be executed during load
(
if (whenHandler != undefined) do
(
--clean up an exisiting handler
deleteChangeHandler whenHandler
)
if (isValidNode val) do
(
whenHandler = when select val changes id:#whenExample obj do callbackFn obj
)
)
)
)
--usage example
delete objects
t = teapot()
s = sphere()
custAttributes.add t myDef
t.myNode = s
Thank you very much again!
I’m getting closer now. Although now i think i have a problem with self-referencing. Afaik i can’t set myNode to the node hgolding the CA’s right?
I tried setting it with (refs.dependentNodes ((refs.dependents this)[1]))[1], but it also throws me an error.
--- selection handling
myNode type:#node
on myNode set val do --this will also be executed during load
(
val = (refs.dependentNodes ((refs.dependents this)[1]))[1]
if (whenHandler != undefined) do
(
--clean up an exisiting handler
deleteChangeHandler whenHandler
)
if (isValidNode val) then
(
whenHandler = when select val changes id:#whenExample obj do callbackFn obj
)
else print "invalid node"
print "whenHandler registered"
)
--- end selection handling
Right. You can’t directly reference a node in a custom attribute which is applied on that node. That results in a dependency loop.
Workarounds:
- Use a weak reference (NodeTransformMonitor).
- Don’t use any reference. Get the node just when registering the callback. See below:
myDef = attributes "WhenExample" attribID:#(0x11223344, 0xDEADBEEF) version:1
(
local whenHandler
fn callbackFn obj =
(
format "% selection changed
" obj
)
fn GetOwningNode =
(
local owner = custAttributes.getOwner this
if not isValidNode owner do
(
owner = refs.dependentNodes owner firstOnly:on
)
owner
)
parameters main
(
--whatever
)
fn registerChangeHandler =
(
if (whenHandler != undefined) do
(
deleteChangeHandler whenHandler
)
local node = GetOwningNode()
if (isValidNode node) do
(
whenHandler = when select node changes id:#whenExample obj do callbackFn obj
)
)
on postLoad do
(
registerChangeHandler()
)
)
--usage example
delete objects
t = teapot()
custAttributes.add t myDef
--after adding to a node, register manually. We don't want to do it on create, because there won't be a node yet.
t.registerChangeHandler()
everything ok except the situation where you delete this object and try to undo deletion.
postload handler doesn’t work in this case and ‘when’ handler will be lost.
Thank you, i got it working now with the laste example!
The drawback with the delete & undo is not good,
although not too much of an issue for me.
Thanks again!
for my tasks delete/undo/redo usually is the important thing. there is no easy solution (at least i couldn’t find it) via using CA and when construct.
so i use NodeEventCallback setup during CA definition.
Well, now I’m curious if u would like to show simple example how you put it in place