I’m working in my spare time on several maxscript I’d like to integrate in our pipeline (we’re a small studio, but you know… ).
I used to code during university years, before turning to full time art and now I’m trying to remember how to do stuff properly.
My plan is to save useful functions in specific structs stored into separated ms files. I’m basically pretending to do object oriented programming and writing classes. (Well,sort of…)
Up to now the ms files end with the declaration of a global struct and they are evaluated at startup: this means that every other script I use doesn’t need to include them: I can directly use any struct and its functions.
So I don’t need to manually add stuff and there is only 1 instance for each class…
But they’re all global, and I know that is not the most elegant thing.
So I’m here looking for some good programming hint: is this a nice solution or could be better to define only structs (aka classes) and then include them only where needed, creating a specific instance for each script?
I already know quite well game engines and shaders and basic coding, but I’m working hard on this stuff (and learning python too): I want to become better tech artist and in time improve the studio pipeline
Thanks for any suggestion!
Totally get what you’re trying to do and why. I think when I was doing some of that, I would declare my “includes” as fileIn at the top of the scripts that used them so I’d at least make it look like python imports.
But I’m also working on a project right now where that’s not the case and all the functional code just assumes everything evaluated and loaded correctly. I don’t think it’s strictly necessary to go the extra step you’re proposing.
@Adam_Pletcher might have some more thoughts on the topic, though.
@ Volition we hit an odd bug on Max startup that would only present very randomly and was tied to executing startup scripts to put global structs in memory. It was more tightly related to the PyWin32 Python module, which was being called from a startup struct file.
I got around it, and made our code a bit more optimized, by creating a MaxScript method similar to Python’s import( ) method. This method is global and created in a script that runs from the stdscripts folder so it is evaluated before any other startup MaxScripts.
( global mxs_import _imported_modules = #( ) fn mxs_import module_filename = ( module_filepath = undefined path_parts = filterString module_filename "\\" if path_parts.count > 1 then ( module_filepath = module_filename module_filename = path_parts[ path_parts.count ] ) if findItem _imported_modules module_filename == 0 then ( append _imported_modules module_filename if module_filepath != undefined then ( fileIn ( module_filepath ) ) ) ) )
Now at the top of various tools files we declare the libraries we need like:
What Jeff said. We used to put all our “library” .ms files in the stdscripts folder then just rely on those structs being defined for every other script. Eventually we hit some weird situations that didn’t work, as Jeff mentioned, and switched over to explicit fileIns.
Regardless, having shared MaxScript library code is totally a valid/useful thing.
I’m glad read that my idea is not completely silly!
Thanks for all your feedbacks.
Despite having global declared structs doesn’t seem to be a huge problem, it’s quite clear that sooner or later a switch to explicit fileIns were better.
I’ve never stumbled into the bug mentioned by Jeff but I’d like avoid the risk…
I like the method to include other scripts… I could try something similar.
Including structs then should be better to put the declaration of an instance directly its ms file…something like:
fn myStuff =()
myInstance = myStruct()
or create it in the script including the struct?
(*yes…I’m a new-line-when-bracket guy )
I apologize for what probably seems to be a bunch of trivial questions, but I’m still in the phase I need to clarify ideas (and remove layers and layers of dust from my ancient coding knowledge )
No need to apologize! The forums are here for just this type of interaction. At Volition we do the instantiation in the struct definition file like you wrote. That way the instance is also global, which will help prevent against multiple instances of the struct under different names and taking up memory with identical information.
If you need more immediate answers to questions, or just want to hang out and chat, join the TA Slack tech-artists.slack.org.
I’ve tried something similar one time, but with a try-catch block (if trying to access the struct instance throws an error, I instantiate it).
If I correctly understand you have a global array of module names to keep track of already imported stuff.
I don’t fully get last part: how it can import scripts if (like in your following examples) the module_filename were composed only by the .ms file name? The IF statement on path_parts.count is false, so module_filepath stays undefined… and then no fileIn.
Or am I wrong?
Got it! So global, pre-instantiated structs + conditional include is the way (well… one good way)
I already am on Slack… I just don’t like it too much as tool