Notifications
Clear all

[Closed] undefined global variables

hi there,

I have a script that works fine when run in the max editor but not when run from the command line with:

“C:/Program Files/Autodesk/3ds Max 2009/3dsmax.exe” -U MAXScript test.ms

The problem is some global variables are undefined when run from the command line:

global SERVER_NAME = "test-server"
  ...
  connectServer()
  

Produces error:

– Frame:
– SERVER_NAME: undefined
– Unable to convert: undefined to type: String

The error message says that SERVER_NAME is undefined in connectServer().
So, are global variables handled differently in maxscript run from the command line?

(Now, obviously the above example could be rewritten to avoid a global variable, but I have quite a few global ‘constants’ that I don’t want to pass around everywhere.)

thanks,
Richard

7 Replies
1 Reply
(@magicm)
Joined: 11 months ago

Posts: 0

Hard to say what the problem is without seeing more code, but I’m guessing it’s a scope issue. Where are you defining the global?
Also, I’d recommend using unique prefixes when defining globals, eg something like “CL_SERVER_NAME” (where I’ve just picked two letters from your username). This makes it less likely for your globals to clash with another script’s globals.

Martijn

or is there an alternative (more stable) way to use global constants?

hello,

I define the global variable within a function, but then it can’t be found by following functions:


 function connectBackburner = (
 	...
 	netManager.connect #manual CL_SERVER_NAME	
  	...
 )
 
 function main settings_file = (
 	-- read in settings from ini file	
 	...
 	global CL_SERVER_NAME = getINISetting settings_file "settings" "SERVER_NAME"
 	connectBackburner()
 	...
 )
 

I found the problem is global variables can only be accessed by code below where they are defined. So my code is now working with:


 function setGlobals settings_file = (
 	global CL_SERVER_NAME = getINISetting settings_file "settings" "SERVER_NAME"
 )
 
  function connectBackburner = (
  	netManager.connect #manual CL_SERVER_NAME
  )
  
  function main settings_file = (
 	-- read in settings from ini file	
  	setGlobals settings_file
 	connectBackburner()
 )
 

Is this documented somewhere?

Richard

1 Reply
(@magicm)
Joined: 11 months ago

Posts: 0

There’s a topic called Scope of Variables (or something similar) in the documentation that explains how scopes work.
It’s usually best to define your globals at the top to make sure it’s available to all other code in your script:

global CL_SERVER_NAME
 
function connectBackburner = (
    netManager.connect #manual CL_SERVER_NAME
)
  
function main settings_file = (
    -- read in settings from ini file	
    CL_SERVER_NAME = getINISetting settings_file "settings" "SERVER_NAME"
    connectBackburner()
)

Hope this helps,
Martijn

There’s a topic called Scope of Variables (or something similar) in the documentation that explains how scopes work.

I had read that section but didn’t find directly relevant information about ordering.

I am facing the same problem with functions now because I am being forced to order my functions so that the first used function is at the bottom and last used at the top. Otherwise I get an undefined function error.

Is there a way to declare a function before defining it, like “global CL_SERVER_NAME” achieves? Or should I be wrapping my functions in a class to avoid these order problems?

1 Reply
(@bobo)
Joined: 11 months ago

Posts: 0

That section is the MOST RELEVANT section ever for anything in the Help
Yes, you can predefine ANYTHING as global or local variable – user variables, functions, rollouts etc.

For example, if you have two functions that should “see” each other regardless of their order of definition, you can pre-declare their variable names:

(--start local scope
  local myFunction1, myFunction2 --pre-declare function names
  
  fn myFunction1 arg= --define function
  (
  myFunction2 (arg^2) --call the pre-declared function which is not defined yet
  )
  
  fn myFunction2 arg = --define the function - it will be stored in the existing variable
  (
  format "Result is %
" (arg)
  )
  
  myFunction1 5
  )--end local scope

In the above example, if you would not pre-declare myFunction2 before the definition of myFunction1, you would get a ‘call expected functions, got undefined’ type of error.

What the pre-declaration does is reserve a memory address for the variable myFunction2 and when the myFunction1 call to it comes, it just stores a pointer to that address in the evaluation tree. Since the variable points at a valid memory address albeit not holding a function yet, that is not a problem.

In the next couple of lines, the definition of myFunction2 comes along. Since a function is always stored in a variable, it goes looking for an existing variable called myFunction2 in the local scope and indeed finds an existing one. So the function just stores itself at that memory address and suddenly the call to it from myFunction1 becomes valid.

All this happens in the evaluation stage where the code is parsed into a tree structure but is not being run yet. In the actual execution step, the tree is populated with all the valid memory pointers and you get no errors…

You can do the same with global variables – you pre-declare them, then you can define functions that will be stored in these variables, thus becoming visible to ANY code anywhere in MAXScript. But if a script is loaded before that pre-declaration was performed, it won’t see them because when it tried to call the function by name, the variable was not in memory yet and it would have created a local variable with a value of undefined instead (any call to a variable or function that is not found in the local scope, in the higher scopes or the global scope will result in the creation of new local variable with the value of undefined)

It is allowed to declare the same global variable as often as you want – as long as you don’t assign anything to it, it will be ensured to exist from the point of view of any script. So if you are using some global functions, you can pre-declare them in ANY script that is going to use them, as long as their definitions will be set by some script (regardless of loading order) at some point of the Max startup process.

The best place to pre-declare and define global functions is script files in the \StdPlugs\StdScripts folder and any sub-folders of it.

local myfunction1, myfunction2

I didn’t know I could do that – thanks very much (again) Bobo!