[Maxscript] Issues with Macroscript Toolbar buttons and fileIn/Include commands

I am building a series of tools along with a browser tool that scans my directories and builds a dynamic list based upon tools found within. I have built them inside structs to allow similar naming conventions to make them easy to understand and to prevent accidental overlap with multiple tools running.

The scripts on their own work fine when launched from the script editor, but upon making a macroscript button to launch to main browser tool, the whole project falls apart.

I’ve made macroscript launch buttons before. I have other tools already on my toolbar, but those tools’ ms files are in the plugin folder, so they are being launched as Max starts, and the button just executes a .run() command to open and close the dialog. Those toolbuttons look like this:

macroScript morphtoollauncher
	category:"Dstinct Tools"
	buttonText:"Morph Tool"
	toolTip:"Launch/Close Morph Tool."
(
	on execute do
	(
		mirrorVert.run()
	)	
)

The launcher I’m trying to make for the browser looks like this:

macroScript fxassetbrowserlauncher
	category:"Dstinct Tools"
	buttonText:"FX Browser"
	toolTip:"Launch/Close Material FX Browser."
(
	
	
	on execute do
	(
		::fileIn @"C:\Users\Dstinct\Desktop\FXTD\devFXTDT\FXAssetBrowser\fxAssetBrowser.ms"
		fxAssetBrowser.run()
	)	
)

When I click on the button, I get the error message: “–Unknown property: ‘run’ in undefined”. The macroscript then opens up in the editor window with the line it’s stuck on highlighted. If I evaluate the whole script that just opens, I get the notification “26001 OK” to show that it’s been added. If I then click the macrobutton, the tool opens, but clicking it again should close the tool because of the way the .run() script is written. What’s strange is that the fileIn commands executed by the _run and _open buttons work fine. I was also able to get the browser to open by only putting a fileIn command in the macrobutton that calls an external ms file that has the fileIn and .run() command that I originally had in the macrobutton launcher, but the _asPub button fails on launch. Even stranger, doing it this way, the _asPub button errors out and the Editor window opens. I close the window and browser tool, then repress the macrobutton to launch the tool, and then the _asPub button works.

The related part of the toolcode looks like this:

try(destroyDialog fxAssetBrowser._assetBrowserR)catch()

struct fxAssetBrowser
(
	_assetBrowserR = undefined,
	
	LibPath = @"C:\Users\Dstinct\Desktop\FXTD\devFXTDT\FXToolsLibrary\",
	_assetItems = getdirectories @"C:\Users\Dstinct\Desktop\FXTD\devFXTDT\FXToolsLibrary\*",
	
	_assetItemsUI = #(),
	
	fn uiSort = 
	(
		for i = 1 to _assetItems.count do
		(
			_assetItemsUI[i]=(filterstring _assetItems[i] @"\")[8]
		)
	),

	fn UI = 
	(
		rollout _assetBrowserR "FX Browser" width:125
		(
			local btWid=_assetBrowserR.width-6
			listbox _assetList "Asset List" items:_assetItemsUI width:btWid align:#center
			button _run "Run Tool" width:btWid align:#center
			button _open "Open / Close Dialog" width:btWid align:#center
			button _asPub "Open Asset Publisher" width:btWid align:#center
			button _explLib "Open Asset Library" width:btWid align:#center
			button _reset "Reload Browser" width:btWid align:#center
				
			on _run pressed do
			(
				FXAssetDir = fxAssetBrowser._assetItems[_assetList.selection]
				FXAssetMarkerFile = "FXS_Asset_"+fxAssetBrowser._AssetItemsUI[_assetList.selection]+"_Marker.ms"
				::filein (FXAssetDir + FXAssetMarkerFile)
				try
				(
					FXAssetRunFile = "FXS_Asset_"+fxAssetBrowser._AssetItemsUI[_assetList.selection]+"_Run.ms"
					::filein (FXAssetDir + FXAssetRunFile)
				)
				catch()
			)
			
			on _open pressed do
			(
				try(FXAssetDir = fxAssetBrowser._assetItems[_assetList.selection]
				FXAssetRunFile = "FXS_Asset_"+fxAssetBrowser._AssetItemsUI[_assetList.selection]+"_Run.ms"
				::filein (FXAssetDir + FXAssetRunFile))
				catch(messageBox "This tool does not have a Dialog Window." title:"Error")					
			)
			
			on _explLib pressed do
			(
				shelllaunch fxAssetBrowser.LibPath ""
			)
			
			on _asPub pressed do
			(
				::filein "C:\Users\Dstinct\Desktop\FXTD\devFXTDT\FXAssetPublisher\assetPublisher.ms"
				fxAssetPub.run()
			)
						
			
			on _reset pressed do
			(
				fxAssetBrowser.run()
				::filein @"C:\Users\Dstinct\Desktop\FXTD\devFXTDT\FXAssetBrowser\fxAssetBrowser.ms"
				fxAssetBrowser.run()	
			)
			
			on _assetBrowserR close do
			(
				fxAssetBrowser._assetBrowserR=undefined
			)			
		)
	),
	
	fn run = 
	(
		if _assetBrowserR==undefined then
		(
			_assetBrowserR=ui()
			fxAssetBrowser.uiSort()
			viewportScreenPos = mouse.screenpos - mouse.pos
			createDialog _assetBrowserR pos:[(viewportScreenPos[1]+10),(viewportScreenPos[2]+30)] style:#(#style_toolwindow,#style_sysmenu)
		)
		else
		(
			destroyDialog _assetBrowserR
			fxAssetBrowser._assetBrowserR=undefined
		)
	)
)

fxAssetBrowser=fxAssetBrowser()

Executing this script on its own followed by the run function allows everything to work perfectly fine. It just won’t launch from the macroscript launcher. I’ve tried all kinds of variations of fileIn and Include, but nothing seems to work. While troubleshooting, I placed the ms file in the plugin folder like my other plugins. Upon doing so, the dialog opens as it should. The problem is that the button for the asset publisher, which also uses a fileIn command, doesn’t work, giving me the same error as the browser: “–Unknown property: ‘run’ in undefined”.

I’m a mid-level coder, so maybe I’m missing something really simple, but it appears that for, whatever reason, the macroscripts do not like the fileIn command, at least if it’s directly followed by a hardcoded directory as opposed to an assembled string. Is there a better way to implement these tools? Or is there a specific way you have to code the fileIn command for it to work within a macroscript?

Thanks for any help. I’m really stuck here.

Josh

First thought would be to rename your fxAssetBrowser struct to something different than the variable you use when you instantiate it.

Second thought would be to declare your instance in the global scope so that other scripts can access it.

+1 to declaring the instance global
I have moved to doing this for all my struct based tools.
It allows for a lot more accessibility form both within (dialog in the struct) and without
because they are structs they have a ‘namespace’ so global conflicts are less risky


Global myToolInstance

struct myToolStruct 
(
	--tool struct code
)

myToolInstance=myToolStruct()

I ended up getting it to work by forming my macro this way:

macroScript fxassetbrowserlauncher
	category:"Dstinct Tools"
	buttonText:"FX Browser"
	toolTip:"Launch/Close Material FX Browser."
(
	fileIn @"C:\Users\Dstinct\Desktop\FXTD\devFXTDT\FXAssetBrowser\fxAssetBrowser.ms"
	
	on execute do
	(
		::fxAssetBrowser.run()
	)	
)

I had to move the file in out of the executable because it wouldn’t allow me to close the tool by hitting the button when it was inside. By using the colons, I believe that it is being told to look for fxAssetBrowser as a global variable instead of just inside the macro it is being executed inside of.

Is this good coding, or a hack job to get it to work?