Maxscript: function not recognised by callbacks.addScript

Maxscript: function not recognised by callbacks.addScript

Anonymous
Not applicable
2,999 Views
4 Replies
Message 1 of 5

Maxscript: function not recognised by callbacks.addScript

Anonymous
Not applicable

I'm trying to get a layerchange to trigger events and i had it working earlier but now when i rewrote the callback i get  -- Type error: Call needs function or class, got: undefined

It works when i run the code in the listener but not when run as .ms, so i'm guessing it has to do with the function not set up correctly ?.

 

Code:

 

MacroScript NewTest
Category: "ScriptTests"
(

      fn RunThis =
      (
      print "problem solved!"
      )--end fn

     fn disable_event = (callbacks.removescripts #nodeLayerChanged id:#TestID)
     fn enable_event = (callbacks.addScript #nodeLayerChanged "RunThis()" id:#TestID)
     disable_event()
     enable_event()

)--end script

 

Thanks in advance

0 Likes
Accepted solutions (1)
3,000 Views
4 Replies
Replies (4)
Message 2 of 5

michaelsonbritt
Advocate
Advocate
Accepted solution

This looks like a scoping problem.  Try defining the RunThis() function as global per the script below.  Notice that global is used before the RunThis function is defined, so that when defined it's setting the global value instead of creating a new local.

 

When the callback triggers, it's running in the global scope at that time.  It tries to execute the function RunThis(), but there is no such function because that was a local variable inside the MacroScript definition of NewTest.  You could explicitly make the RunThis() global.  Or, maybe a better approach more generally, you could create a startup script which defines a struct containing all your various utility functions as members.  Then your MacroScripts can access them as "myGlobalStruct.myFunction()" without creating too much global namespace pollution.

 

Cheers,

Michaelson Britt

 

macroScript NewTest
Category: "ScriptTests"
(
	global RunThis
	fn RunThis =
	(
	print "problem solved!"
	)--end fn

	fn disable_event = (callbacks.removescripts #nodeLayerChanged id:#TestID)
	fn enable_event = (callbacks.addScript #nodeLayerChanged "RunThis()" id:#TestID)
	disable_event()
	enable_event()

)--end script
0 Likes
Message 3 of 5

Anonymous
Not applicable

Great help!

I was suspecting this was the issue but for some reason i didn't think you could make functions global this easy .

I've heard many talk about a struct startup-file and i will be looking into this, but is there a way to not have to put it into the startupfolder?.

I work on multiple workstations and like to have all the scripts i use in one folder in the cloud to easy be able to update them .

I've looked into filein and include and filein looked most promising. Most of all i would like to find a tutorial about how to organise complex scripts and good practice but no luck so far.

 

0 Likes
Message 4 of 5

michaelsonbritt
Advocate
Advocate

Generally, scripts are executed at startup when located in one of these folders. Notice the choice of either install root, or your local app data.

  • C:\Program Files\Autodesk\3ds Max 2019\stdplugs\stdscripts
  • C:\Program Files\Autodesk\3ds Max 2019\scripts\Startup
  • C:\Users\ (username) \AppData\Local\Autodesk\3dsMax\2019 - 64bit\ENU\scripts\startup

There are various tricks and other options, but those are the basics.


If you do not want a script running at startup, then you can define the struct whenever your script is run, and skip past the initialization later, if the script is run a second time. See below for an example.


And yes! I would like to (eventually) write a tutorial going into more depth.


Cheers,

Michaelson Britt

 

global myScope

-- Define the scope when first used (it's initially undefined)
if myScope==undefined do
(
	-- Define the struct's type (this doesn't create data yet)
	-- Notice both data and methods here, and methods can use "this" value
	-- Notice data members can have default values here
	struct MyScopeStruct (
		fn myFunc param =
		(
			messagebox ("Hello, "+param+" My data is "+(this.myData as string))
		),
		myData = 1
	)

	-- Create an instance of the struct
	-- Notice member data can optionally be set
	myScope = MyScopeStruct myData:2

	-- Test it out, set member data and call methods
	myScope.myData = 3
	myScope.myFunc "world!"
)

 

0 Likes
Message 5 of 5

Anonymous
Not applicable

Got structs to work,thanks.

What wasn't clear in maxscript help was that functions and vars inside structs is separated with comma(,).

Secondly, why are you using a var (myScope) to point to the struct instead of calling and making MyScopeStruct global directly?.

After solving my initial problem i changed the functions to something else then a simple text print. constructors crash max to desktop without warning, se example:

 

macroScript NewTest
Category: "TestScripts"
(

global RunThis
fn RunThis =
(
sphere()
)--end fn

 


fn disable_event = (callbacks.removescripts #nodeLayerChanged id:#TestID)
fn enable_event = (callbacks.addScript #nodeLayerChanged "(RunThis())" id:#TestID)

disable_event()
enable_event()

)--end script

 

Only thing working is manipulation and string prints.

I've created a new topic in the forum here : https://forums.autodesk.com/t5/3ds-max-programming/maxscript-callbacks-addscript-nodelayerchanged-fn... as i think this a new separate problem

0 Likes