Store scripted plugins and functions in a scene!

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

THREAD CLOSED
 
Thread Tools Search this Thread Display Modes
Old 05 May 2013   #1
Store scripted plugins and functions in a scene!

I am trying to write a complex scripted plugin and have been struggling with getting scope and transportability of the objects I am producing to be foolproof. I don't know if I have a perfect method here, but this seems to make a lot of sense.

A major advantage (other than scene storage) of this method is that the attribute acts as a function with a persistent variable. That is; you only need to update a single variable in order to run the function on the other variables.

Additionally, you can store the definition of your scripted plugins as a local, so that it gets initalised before it's required.

I doubt very much that no one else has come up with this method before, but I was pretty proud of myself for figuring it out so I thought I would share. The idea that I can now insert code into a scene, and keep it there until, well, my object is deleted, makes any subsequent work I make follow a pretty obvious trajectory.

If I'm doing it all wrong PLEASE tell me before I waste 5 months on a major tool project!

Tested in MAX 2013 only.


  persistent global PluginVariable
 cutter = attributes 
 		cutter--name
 		silentErrors:false
 			(
 				local CookieCut
 				local Senor_Window_Pane2
 				local thePlugin =
 					(
 						plugin helper PluginVariable
 						name:"ObjectName"
 						extends:Point
 						category:"Some Category"
 						invisible:false
 						version:1
 							(--plugin body
 							)
 						PluginVariable
 					)
 				parameters cutterParameters
 					(
 						nodeObj					type:#node
 						nodeTabCutters		type:#nodeTab		tabSizeVariable:true
 						on nodeTabCutters set void do if isValidObj nodeObj then CookieCut()
 					)
 				fn CookieCut =
 					(
 						ProBoolean.CreateBooleanObjects nodeObj nodeTabCutters 2 1 1
 						convertTo nodeObj Editable_Poly
 					)
 				fn doTo obj: cutters: =
 					(
 						if superClassOf obj == geometryClass then nodeObj = obj
 						if superClassOf cutters == geometryClass then nodeTabCutters[1] = cutters
 						else if classof cutters == array then nodeTabCutters = for cutterObj in cutters where superClassOf cutterObj == geometryClass collect cutterObj
 					)
 			)
 theCutterBox = Box length:10 width:10 height:10 pos:[0,0,0]
 CustAttributes.add theCutterBox cutter
 			
 boxToCut = Box length:10 width:10 height:10 pos:[10,10,10]
 boxToCutWith = Box length:10 width:10 height:10 pos:[15,15,15]
 
 theCutterBox.cutter.doTo obj:boxToCut cutters:boxToCutWith
 --superClassOf boxToCutWith
 theCutterBox.cutter.thePlugin()
  
__________________
http://blog.senorfreebie.com
My own self-interested promotion of technical ramblings and portfolio updates.
 
Old 05 May 2013   #2
There is also apparently a method to protect that node, using a double defined scripted plugin!


persistent global Master_Point
plugin helper Master_Point
name:"Master_Point"
classID:#(9000000,9000000)
extends:Point
replaceUI:true
category:"World Builder"
invisible:true
version:1
	(
		on detachedFromNode theNode do messagebox "HEY! Don't do that!"
	)
PlugIntoHelper = attributes 
		MasterStruct--name
		silentErrors:false
			(
				local Master_Point
				local thePlugin =
					(
						plugin helper Master_Point
						name:"Master_Point"
						classID:#(9000000,9000000)
						extends:Point
						replaceUI:true
						category:"World Builder"
						invisible:true
						version:2
							(
								on detachedFromNode theNode do messagebox "HEY! Don't do that!"
							)
						Master_Point
					)
				local myValue = true
			)
persistent global theGlobalHelper = Master_Point()
CustAttributes.add theGlobalHelper PlugIntoHelper
theGlobalHelper.MasterStruct.myValue = false
persistent global senorHouse = theGlobalHelper.MasterStruct
__________________
http://blog.senorfreebie.com
My own self-interested promotion of technical ramblings and portfolio updates.
 
Old 05 May 2013   #3
I don't get the point.

What happens in case of evolution of the tool ?

For example, you want to create a tool that would be able to batch-process your scripted nodes (already used in a hundred of scenes), but requiring some updates in the definition of your plugin ?
 
Old 05 May 2013   #4
I don't get the point.

What happens in case of evolution of the tool ?

For example, you want to create a tool that would be able to batch-process your scripted nodes (already used in a hundred of scenes), but requiring some updates in the definition of your plugin ?


It would be quite simple to handle that ... basically this would (and with the way I'm now writing my tool) function as a run once...

So; if you follow my logic here:

Load a scene, run the script once; have it install the tool into the scene permanently, so that it's transferable to computers that don't have the tools installed.

To update; run the new version of the script; existing plugin definitions are updated before the plugins are loaded, and they retain both their current attributes and parameters, while making room for new features. Any incidental redundancy can be handled in the definitions.
__________________
http://blog.senorfreebie.com
My own self-interested promotion of technical ramblings and portfolio updates.
 
Old 05 May 2013   #5
I don't know... Something makes me think you're dealing with dark forces here.

It's not that it wouldn't work, it's more about... how it's implemented.

What's most disturbing me is :

* In the last code you pasted there's double definitions (version 1 ? version 2 ?)
* A same variable name is used as global and local at the same time
* In a local variable (line 20), you declare something using a global variable name which has already been declared sooner

It's like a plugin-ception, in 38 lines I found the code not readable already.
How will this go when your plugin features grow up ? Will the code remain maintainable ?

Furthermore, it's listed everywhere (maxscript help, scripspot, and maybe here too) that using persistent global variables is a false good idea.

Let us admit it works, here are some questions I have in mind :

0 - If your plugin needs initializations (whatever xml, parsing directories, etc), when is it done ?
1 - What happens if global_helper is object B, and object A is needing the plugin definition, but loaded before ?
2 - What happens if your plugin has specific values set by scene, and you merge two max files (and thus the global_helper) ?
3 - What happens if you want to split your plugin into several files readability and maintainability ?

In fact, what's most disturbing me is this :

If your plug-in is going to process a lot of data, I don't know, for example managing game assets, e.g. reading xml data, reading image data, exporting scene status in I don't know what way (and so resulting in a lot of variables, functions), why would I want to store them in my scene ?

It would be like cooking a delicate meal, and when it's time to serve the dish, you put all the utensils you used at the same time on the plate.

Which makes me think of another scenario :

Let us admit you deploy your plugin version 0.1 into the infrastructure (e.g. 80 gfx artists, 40 render nodes in the renderfarm). People works on it using one week, producing more than 700 maxfiles created by layout, modeling, animating, and rendering team.

You discover a critical glitch (or you want to add an interesting upgrade, same issue). You have to update the plugin.

4 - Does that mean you have to open the 700+ files, run the script, and resave them ?
 
Old 05 May 2013   #6
TL;DR

Your concerns are valid, and I believe I can find solutions to all of them. I am not scripting with this structure, and actually, it feels very intuitive.

I don't know... Something makes me think you're dealing with dark forces here.


You're not wrong ... this really feels like I'm hacking max to do something it's not meant to do ... but I think the advantages are worth it.

It's not that it wouldn't work, it's more about... how it's implemented.

What's most disturbing me is :

* In the last code you pasted there's double definitions (version 1 ? version 2 ?)
* A same variable name is used as global and local at the same time
* In a local variable (line 20), you declare something using a global variable name which has already been declared sooner

It's like a plugin-ception, in 38 lines I found the code not readable already.



* The persistent global keeps the reference to the plugin
* The local variable is needed to initialise the stored attribute on scene load ... because the plugin is not yet defined.

How will this go when your plugin features grow up ? Will the code remain maintainable ?


I am working with this structure at home only at the moment; because I intend to release a large scale plugin later. When the features grow, I will write methods to transfer any data from version to version.

Furthermore, it's listed everywhere (maxscript help, scripspot, and maybe here too) that using persistent global variables is a false good idea.


I've discovered this previously... they have a bad tendency to forget themselves and to corrupt data. Actually; this is a massive problem if you want to try and store data in a scene this way. I am not using them in this manner. I am merely using them as references during scene load.

Let us admit it works, here are some questions I have in mind :

0 - If your plugin needs initializations (whatever xml, parsing directories, etc), when is it done ?
1 - What happens if global_helper is object B, and object A is needing the plugin definition, but loaded before ?


load order seems to be:

1. Attributes (including contained scripted plugins)
2. Objects

2 - What happens if your plugin has specific values set by scene, and you merge two max files (and thus the global_helper) ?


Values that may conflict will be contained in instances of scripted plugins, defined within the global helper ... in other words the second global helper will be irrelevant, unless I find a reason to store properties for the whole scene in it, which so far I have not. At that point, I could access that data and append it to the first helper on scene load by checking rootScene.world.children for the relevant classes.

3 - What happens if you want to split your plugin into several files readability and maintainability ?


This is a big problem actually;

Doing a filein as part of an attribute definition fails when you load the scene the second time because there is no actual file path to reference ... and well, you don't want to be loading external scripts anyway.

What I think would be the ultimate solution would be to develop this into a sort of compile and execute IDE... In fact, in this case you would not have any of this code there, except in some kind of pre structured source file.

In fact, what's most disturbing me is this :

If your plug-in is going to process a lot of data, I don't know, for example managing game assets, e.g. reading xml data, reading image data, exporting scene status in I don't know what way (and so resulting in a lot of variables, functions), why would I want to store them in my scene ?


Actually, the ability to store variables in the scene will help with this... You would only hold one variable at a time, but this would tell your code what step something is up to.

Imagine a baking tool that does a render of a series of objects in one scene, with dependencies:

You could store the objects to be baked in an array in the scene, with indexes to reference the job number. When a render node loads a job, it could resave with those indexes shifted due to a script that runs on load. That render node could be an online cloud based server... no need for software installation or external file access.

It would be like cooking a delicate meal, and when it's time to serve the dish, you put all the utensils you used at the same time on the plate.


Except that in this instance you can write script to choose which utensils you wanted in the first place, depending on whatever factors you choose.

Which makes me think of another scenario :

Let us admit you deploy your plugin version 0.1 into the infrastructure (e.g. 80 gfx artists, 40 render nodes in the renderfarm). People works on it using one week, producing more than 700 maxfiles created by layout, modeling, animating, and rendering team.

You discover a critical glitch (or you want to add an interesting upgrade, same issue). You have to update the plugin.

4 - Does that mean you have to open the 700+ files, run the script, and resave them ?


This is unlikely to be a scenario I will see during development, although I do have a studio with 10 artists & 60+ nodes to use as a guinea pig for testing.

I will be writing a network update function though which will work with SVN or UNC paths.

* If you want to upgrade, place the new script in a set location
* on load, attempt to re-define, with error handling
* if re-definition fails:
1. Give the artist a prompt to output a version of the failed scene state for debugging
2. Return to the non-updated version
3. Bar that update version for that scene, so auto updating doesn't occur again
__________________
http://blog.senorfreebie.com
My own self-interested promotion of technical ramblings and portfolio updates.
 
Old 05 May 2013   #7
What I think would be the ultimate solution would be to develop this into a sort of compile and execute IDE... In fact, in this case you would not have any of this code there, except in some kind of pre structured source file.

Oh, you mean doing it in another language than maxscript ? :]

All joking aside, this would result in a compiled DLL, you wouldn't be able to update anything until 3dsmax has stopped using it (that is to say closed), there'll also be a platform issue (32 or 64), and off-course a deployment issue.

Actually, the ability to store variables in the scene will help with this... You would only hold one variable at a time, but this would tell your code what step something is up to.

In fact it's not storing values that bothers me, it's storing the entire plugin definition in a maxfile.
I think I see what's your main objective, which is according to me concentrated in this sentence :

That render node could be an online cloud based server... no need for software installation or external file access.

And yeah, here I clearly see the point.

However, I believe that the main issue is that you're putting all the eggs in one basket.

Generally not a good idea.

You want to keep the data with the data, the process with the process, separated.

For example, I know you would never put in an xml file, the functions that helped to generate this xml (lol, this is quite a nonsense, I'm wondering what it would look like... but the idea is here).

The day you want to keep the workflow you established, but changing some piece of it (changing some parameters in the process, updating UI, changing scripting language, changing 3D package maybe, or anything else), it would be less painful (I didn't say painless).

Nevertheless, to contradict myself, it's also a bad idea to see too far away (my "what-if-questions"), I read this on Rob Galanakis' blog, maybe one of the best advice I received in my humble little experience. It does not prevent to have solid foundations though.

I will be writing a network update function though which will work with SVN or UNC paths.

* If you want to upgrade, place the new script in a set location
* on load, attempt to re-define, with error handling

What if the updated tool repo has changed ? The declared-into-max-plugins would risk being left alone.

In fact, aside from the "no-need-to-deploy-plugin" part, what are you trying to do ? If it's not a secret ?
 
Old 05 May 2013   #8
Oh, you mean doing it in another language than maxscript ? :]

All joking aside, this would result in a compiled DLL, you wouldn't be able to update anything until 3dsmax has stopped using it (that is to say closed), there'll also be a platform issue (32 or 64), and off-course a deployment issue.


Actually no; I was thinking of writing a compiler that basically read in files as strings, encapsulating them in the syntax you see above. Why? Well, I've got a compilation system at the moment, that allows me to view the structure of my object and sub-objects at the moment ... and that's great, but I have to work from one file and it's going to be thousands of lines by the end of all of this if I'm not careful.

In fact it's not storing values that bothers me, it's storing the entire plugin definition in a maxfile.
I think I see what's your main objective, which is according to me concentrated in this sentence :

Quote:
That render node could be an online cloud based server... no need for software installation or external file access.
And yeah, here I clearly see the point.

However, I believe that the main issue is that you're putting all the eggs in one basket.

Generally not a good idea.

You want to keep the data with the data, the process with the process, separated.

For example, I know you would never put in an xml file, the functions that helped to generate this xml (lol, this is quite a nonsense, I'm wondering what it would look like... but the idea is here).


Hrmm; I don't think that I am doing this. I am just defining a bunch of functions that can hold parameters permanently, which means they don't need to be updated so regularly. The scripted plugin definitions will be in there too, but the data will be attached to the nodes created by them... not to this master struct. That's just used to make the scene accessible in an artist friendly way.

What if the updated tool repo has changed ? The declared-into-max-plugins would risk being left alone.


I'm partially concerned about this. I think that the situation for most people will be that they will have the plugin installed on startup, since having to load a scene to access it is not helpful; which means simply running an update and actually having files to access for this, but I will try to provide people with a way to network update their artists, which they have to manually implement... I don't want to turn max into some hackers wet dream.

In fact, aside from the "no-need-to-deploy-plugin" part, what are you trying to do ? If it's not a secret ?


It's not really a secret, a lot of my colleagues know about it, but I only have very basic prototypes so far of what I'm trying to achieve overall and I'm not yet certain if it's in my interests to blather on about it publicly. I'll be sure to do that first on the TAO irc though.
__________________
http://blog.senorfreebie.com
My own self-interested promotion of technical ramblings and portfolio updates.
 
Old 05 May 2013   #9
Thread automatically closed

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.
 
Thread Closed share thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
CGSociety
Society of Digital Artists
www.cgsociety.org

Powered by vBulletin
Copyright 2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump
Miscellaneous

All times are GMT. The time now is 05:03 AM.


Powered by vBulletin
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.