Advanced Tips

There is alot of information in the Maxscript help file but when it comes to dotNet it would be nice with some more info.

Creating a dictionary object in maxscript: Tip Found here

--this creates a dictionary that takes a string key and string value
mySuperDictionary = dotnetobject "System.Collections.Generic.Dictionary`2[System.String,System.String]" 

it = mySuperDictionary.GetEnumerator()
while it.MoveNext() do
 (
   format "Key: % Value: %\n" it.current.key it.current.value
 )

Here is an excellent guide on how to use enums in maxscript.

/*
Using DotNet Enums in MaxScript
With any custom class objects,
it's highly likely Enums will be used,
as they are a way of organizing custom
properties into easily recognizable names,
rather like structs in MXS have members
to describe elements so that you don't
have to resort to array elements with
confusing index numbers.

To use an enum in 3DSMax, you use a plus symbol
in between the class string and the enum type.
therefore, in the maxbutton class,
to get the enums used you would type the following
*/

(dotnetclass "LoneRobot.Controls.MaxButton+CustomIcons").NewDocument

(dotnetclass "LoneRobot.Controls.MaxButton+LayoutStyles").Top
(dotnetclass "LoneRobot.Controls.MaxButton+ColorPresets").MaxUIDark

--you would then use this to set the custom properties in the class.

 

This tip came from the AREA
When you run a script that’s doing a lot of work 3ds Max tends to show ‘Not Responding’ in the title bar and won’t print progress messages in the Listener either. Luckily there is the windows.processPostedMessages() function that can help!

Call the function just before you print the output to the listener:

for i=1 to 100 do
(
 s=timeStamp()

 -- put your code here

 e=timeStamp()
 windows.processPostedMessages()
 format "%s\n" ((e-s)/1000.0)
)

A brilliant tip from Klaas Nienhuis on how to use C# await inside maxscript. He also shows a clever method of adding c# code to maxscript by compiling it directly in memory

http://www.klaasnienhuis.nl/2016/07/asyncawait-in-maxscript/

(
	--Klaas Nienhuis, 2016
	clearListener()
	
	--this .net class sets up async downloads
	local strAssembly = \
"
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

namespace Downloader
{
    public class Download
    {
        public static async Task DownloadFileAsync(string remoteUrl, string localUrl)
        {
            using (HttpClient client = new HttpClient())
			{
				using (HttpResponseMessage responseMessage = await client.GetAsync(remoteUrl).ConfigureAwait(false))
				{
                    if (responseMessage.IsSuccessStatusCode)
                    {
						var byteArray = await responseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
						using (FileStream filestream = new FileStream(localUrl, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize:4096, useAsync:true))
						{
							await filestream.WriteAsync(byteArray, 0, byteArray.Length);
						}
					}
				}
			}
        }

        public static async Task DownloadMultipleFilesAsync(string[] remoteUrl, string[] localUrl)
        {
            List allTasks = new List();
            for (int n = 0; n < remoteUrl.Length; n++)
            {
                allTasks.Add(DownloadFileAsync(remoteUrl[n], localUrl[n]));
            }
            await Task.WhenAll(allTasks).ConfigureAwait(false);
        }
    }
}
"

	function fn_loadClass strAssembly =
	(
		/*
		Description
			Loads a .net class from a string
		Arguments
		Return
			compilerResults which can be instanciated
		*/

		local csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
		local compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
		compilerParams.ReferencedAssemblies.AddRange #("System.Net.Http.dll","System.dll", "System.Management.dll")
		compilerParams.GenerateInMemory = on
		local compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(strAssembly)
	)
		
	local compilerResults = fn_loadClass strAssembly
	
	local Download = compilerResults.CompiledAssembly.CreateInstance "Downloader.Download"

	--set up a folder to receive the downloaded files
	local  localFolder = (dotnetClass "system.IO.Path").Combine (pathConfig.removePathLeaf (getSourceFileName())) "output"
	makeDir localFolder
	
	local arrUrl = #()
	local arrFilePath = #()
	for n = 1 to 10 do
	(
		append arrUrl @"http://a.tile.openstreetmap.org/8/131/84.png"; --we'll download this file
		append arrFilePath ((dotnetClass "system.IO.Path").Combine localFolder (n as string + ".png"))
	)
	local theTask = Download.DownloadMultipleFilesAsync arrUrl arrFilePath
		
	--we need to wait for the async download task to finish, otherwise we might get in trouble with the rest of the script. If we don't
	--wait, we're counting on the files to be downloaded while they might not be there yet.
	theTask.Wait()
		
	local arrFile = getFiles (localFolder + @"\*.png")
	format "Downloaded % files\r\n" arrFile.count
)