419 lines
13 KiB
Plaintext
Executable File
419 lines
13 KiB
Plaintext
Executable File
struct RsFindScriptStruct
|
|
(
|
|
private
|
|
|
|
-- Hashtable which stores all menu item data.
|
|
--
|
|
-- key: Menu item button text.
|
|
-- value: Array - 1: maxscript filename, 2: the menu path
|
|
scriptsHash = undefined,
|
|
|
|
|
|
-- Hashtable which stores data parsed out of the macroScripts.
|
|
--
|
|
-- key: maxscript filename, including the extension.
|
|
-- value: The menu button text.
|
|
macroScriptsHash = undefined,
|
|
|
|
|
|
-- Parse the WW macroscript to find out what the button text is for each script file. In some cases, there is no script
|
|
-- being imported. Dealing with that happens in a different function.
|
|
fn processWWMacroScript mcr = (
|
|
local fstream = openFile mcr
|
|
|
|
if fstream != undefined do (
|
|
|
|
while not ( eof fstream ) do (
|
|
currentLine = readLine fstream
|
|
|
|
-- Find a macroscript block.
|
|
if ( matchPattern currentLine pattern:"macroscript *" ) then (
|
|
|
|
local buttonText = undefined
|
|
local scriptFilename = undefined
|
|
|
|
|
|
-- Find the button text
|
|
local foundButtonText = false
|
|
|
|
while ( not foundButtonText ) and ( not eof fstream ) do (
|
|
nextButtonTextLine = readLine fstream
|
|
|
|
if ( matchPattern ( toLower nextButtonTextLine ) pattern:"*buttontext:*" ) then (
|
|
|
|
-- First split by the colon
|
|
local rawButtonText = ( filterString nextButtonTextLine ":" )[ 2 ]
|
|
|
|
-- Pop quotations
|
|
buttonText = trimLeft rawButtonText "\""
|
|
buttonText = trimRight buttonText "\""
|
|
|
|
|
|
-- Find the maxscript file
|
|
local foundMaxscriptFile = false
|
|
|
|
while ( not foundMaxscriptFile ) and ( not eof fstream ) do (
|
|
nextOpenBracketLine = readLine fstream
|
|
|
|
if ( matchPattern ( toLower nextOpenBracketLine ) pattern:"*(*" ) then (
|
|
nextCodeLine = readLine fstream
|
|
|
|
-- In almost all cases, the very next line of the macroscript is calling filein on a script file.
|
|
if ( matchPattern ( toLower nextCodeLine ) pattern:"*filein (*" ) then (
|
|
local rawMSFilename = filterString nextCodeLine "/"
|
|
rawMSFilename = rawMSFilename[ rawMSFilename.count ]
|
|
|
|
local bracketIndex = findString rawMSFilename ")"
|
|
|
|
-- Gotta get rid of the trailing quote and bracket.
|
|
scriptFilename = toLower ( subString rawMSFilename 1 ( bracketIndex - 2 ) )
|
|
)
|
|
|
|
foundMaxscriptFile = true
|
|
)
|
|
)
|
|
|
|
foundButtonText = true
|
|
)
|
|
)
|
|
|
|
-- Add results of the current macroscript block to the hashtable.
|
|
|
|
if not macroScriptsHash.Contains buttonText then (
|
|
macroScriptsHash.Add buttonText scriptFilename
|
|
|
|
) else (
|
|
--print ( "RsFindScript: Item (" + buttonText + ") has already been added to the hashtable!" )
|
|
)
|
|
)
|
|
)
|
|
|
|
close fstream
|
|
)
|
|
),
|
|
|
|
|
|
-- Constructs a friendly path which reflects where the script lives in the WW menu system.
|
|
fn getWWMenuPath fileName = (
|
|
local pathToRemove = RsConfigGetWildwestDir() + "\\script\\max\\"
|
|
local rawMenuPath = substring fileName pathToRemove.count fileName.count
|
|
|
|
-- Rebuild the menu path to reflect how it looks in 3dsmax
|
|
local categories = filterString rawMenuPath "\\"
|
|
local msFilename = categories[ categories.count ]
|
|
|
|
-- Pop maxscript filename from the array, if the last item in the array is a maxscript. It could be a directory, in which case we want to keep.
|
|
if ( matchPattern msFilename pattern:"*.ms" ignoreCase:true ) then (
|
|
deleteItem categories categories.count
|
|
)
|
|
|
|
local fixedMenuPath = stringStream ""
|
|
|
|
for category in categories do (
|
|
|
|
-- Lower name and replace any underscores with a space.
|
|
local tempCategory = toLower ( substituteString category "_" " " )
|
|
|
|
-- Capitalize words.
|
|
local splitWords = filterString tempCategory " "
|
|
local properCategory = stringStream ""
|
|
|
|
for word in splitWords do (
|
|
word[ 1 ] = toUpper word[ 1 ]
|
|
|
|
format "% " word to:properCategory
|
|
)
|
|
|
|
-- Get rid of trailing white space.
|
|
properCategory = trimRight properCategory " "
|
|
|
|
format "%/" properCategory to:fixedMenuPath
|
|
)
|
|
|
|
fixedMenuPath = "RS Wildwest/" + ( trimRight fixedMenuPath "/" )
|
|
|
|
( fixedMenuPath as string )
|
|
),
|
|
|
|
|
|
fn parseWWConfigXml configXml = (
|
|
-- I'm just going to do raw file parsing atm. Will switch to a proper XML parser later.
|
|
|
|
fn getXmlAttributeValue xmlLine attribName = (
|
|
local attributeValue = undefined
|
|
local startQuoteIndex = findString xmlLine ( attribName + "='" )
|
|
|
|
if startQuoteIndex != undefined do (
|
|
local rawAttributeText = subString xmlLine ( startQuoteIndex + ( attribName + "='" ).count ) xmlLine.count
|
|
local endQuoteIndex = findString rawAttributeText "'"
|
|
local attributeValue = subString rawAttributeText 1 ( endQuoteIndex - 1 )
|
|
|
|
if attributeValue == "" then attributeValue = undefined
|
|
)
|
|
|
|
attributeValue
|
|
)
|
|
|
|
local excludedDirectories = #()
|
|
local excludedScripts = #()
|
|
local macroscriptAttributes = #()
|
|
|
|
local fstream = openFile configXml
|
|
|
|
if fstream != undefined do (
|
|
while not ( eof fstream ) do (
|
|
local currentLine = readLine fstream
|
|
|
|
-- Get excluded items.
|
|
/*
|
|
if ( matchPattern currentLine pattern:"*<excludeItems>*" ignoreCase:true ) do (
|
|
|
|
local foundEndExcludeItemsTag = false
|
|
|
|
while not foundEndExcludeItemsTag do (
|
|
local currentItemLine = readLine fstream
|
|
|
|
if ( matchPattern currentItemLine pattern:"*</excludeItems>*" ignoreCase:true ) do (
|
|
foundEndExcludeItemsTag = true
|
|
)
|
|
|
|
if not foundEndExcludeItemsTag do (
|
|
local tmp = ( filterString currentItemLine ">" )[ 2 ]
|
|
tmp = toLower ( filterString tmp "<" )[ 1 ]
|
|
|
|
local extension = subString tmp ( tmp.count - 2 ) tmp.count
|
|
|
|
-- We are excluding a directory.
|
|
if extension == "*.*" then (
|
|
local excludedDirectory = subString tmp 1 ( tmp.count - 3 )
|
|
append excludedDirectories excludedDirectory
|
|
|
|
-- We are excluding a maxscript.
|
|
) else if extension == ".ms" then (
|
|
print tmp
|
|
)
|
|
)
|
|
)
|
|
*/
|
|
|
|
if ( matchPattern currentLine pattern:"*<attributes>*" ignoreCase:true ) do (
|
|
local foundEndAttributesTag = false
|
|
|
|
while not foundEndAttributesTag do (
|
|
local attributesLine = readLine fstream
|
|
|
|
if ( matchPattern attributesLine pattern:"*</attributes>*" ignoreCase:true ) do (
|
|
foundEndAttributesTag = true
|
|
)
|
|
|
|
-- Parse attribute data.
|
|
if not foundEndAttributesTag do (
|
|
if ( matchPattern attributesLine pattern:"*<macroscript *" ignoreCase:true ) do (
|
|
|
|
-- Button Text
|
|
local buttonText = getXmlAttributeValue attributesLine "buttonText"
|
|
local maxScriptBody = getXmlAttributeValue attributesLine "maxscriptBody"
|
|
local maxScriptFile = toLower ( getXmlAttributeValue attributesLine "file" )
|
|
|
|
append macroscriptAttributes #( maxScriptFile, buttonText, maxScriptBody )
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
)
|
|
|
|
close fstream
|
|
)
|
|
|
|
#( excludedDirectories, excludedScripts, macroscriptAttributes )
|
|
),
|
|
|
|
|
|
-- This iterates over each directory for the project's WW directory and reconstructs
|
|
-- a path for each menu item that shows up in 3dsmax under RS Wildwest. The results
|
|
-- of this function are put into the scriptsHash hashtable.
|
|
fn recurseBuildWWMenuData dir = (
|
|
local directories = getDirectories ( dir + "*" )
|
|
|
|
for dir in directories do (
|
|
local files = getFiles ( dir + "*.ms" )
|
|
|
|
-- If a WW config file lives in this directory, parse and load it's data.
|
|
local wwConfigXml = getFiles ( dir + "wildwestconfig.xml" )
|
|
|
|
local excludedDirectories = #()
|
|
local excludedScripts = #()
|
|
local macroscriptAttributes = #()
|
|
|
|
if wwConfigXml.count > 0 do (
|
|
local data = parseWWConfigXml wwConfigXml[ 1 ]
|
|
|
|
excludedDirectories = data[ 1 ]
|
|
excludedScripts = data[ 2 ]
|
|
macroscriptAttributes = data[ 3 ]
|
|
)
|
|
|
|
-- Iterate over each file in the directory and create a hashtable entry if possible.
|
|
for file in files do (
|
|
local scriptFilename = toLower ( filenameFromPath file )
|
|
local menuPath = getWWMenuPath file
|
|
local buttonText = undefined
|
|
local maxScriptBody = undefined
|
|
|
|
local isOverridden = false
|
|
|
|
|
|
-- Get the button text.
|
|
local enum = macroScriptsHash.GetEnumerator()
|
|
|
|
while ( enum.MoveNext() ) do (
|
|
local macroButtonText = enum.Key
|
|
local macroScriptFilename = enum.Value
|
|
|
|
if macroScriptFilename != undefined do (
|
|
if ( matchPattern scriptFilename pattern:( "*" + macroScriptFilename + "*" ) ignoreCase:true ) do (
|
|
buttonText = macroButtonText
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
-- See if the current file has any specific overrides.
|
|
for macroscriptAttributeData in macroscriptAttributes while not isOverridden do (
|
|
local attributeScriptFilename = macroscriptAttributeData[ 1 ]
|
|
local attributeButtonText = macroscriptAttributeData[ 2 ]
|
|
local attributeMaxScriptBody = macroscriptAttributeData[ 3 ]
|
|
|
|
if ( matchPattern file pattern:( "*" + attributeScriptFilename + "*" ) ignoreCase:true ) then (
|
|
buttonText = attributeButtonText
|
|
maxScriptBody = attributeMaxScriptBody
|
|
|
|
isOverridden = true
|
|
)
|
|
)
|
|
|
|
|
|
if buttonText != undefined do (
|
|
if not ( scriptsHash.Contains buttonText ) then (
|
|
scriptsHash.Add buttonText #( toLower file, menuPath, maxScriptBody )
|
|
)
|
|
)
|
|
)
|
|
|
|
-- Attempt to include any macroscripts that did not have an associated script, but use maxscript code directly. Wooo boy.
|
|
local enum = macroScriptsHash.GetEnumerator()
|
|
|
|
while ( enum.MoveNext() ) do (
|
|
local buttonText = enum.Key
|
|
local maxScriptFilename = enum.Value
|
|
|
|
if maxScriptFilename == undefined do (
|
|
local found = false
|
|
|
|
for macroscriptAttributeData in macroscriptAttributes while not found do (
|
|
local attributeScriptFilename = macroscriptAttributeData[ 1 ]
|
|
local attributeButtonText = macroscriptAttributeData[ 2 ]
|
|
local attributeMaxScriptBody = macroscriptAttributeData[ 3 ]
|
|
|
|
if attributeMaxScriptBody != undefined do (
|
|
if attributeButtonText == buttonText do (
|
|
scriptsHash.Add buttonText #( ( toLower attributeScriptFilename ) , ( getWWMenuPath dir ), attributeMaxScriptBody )
|
|
found = true
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
recurseBuildWWMenuData dir
|
|
)
|
|
),
|
|
|
|
-- Entry point for constructing the necessary data for the search script system to work.
|
|
fn build = (
|
|
print "Building data necessary for 'Find R* Script'..."
|
|
|
|
-- Setup hashtables.
|
|
scriptsHash = dotNetObject "System.Collections.Hashtable"
|
|
macroScriptsHash = dotNetObject "System.Collections.Hashtable"
|
|
|
|
-- Fill in hashtables with necessary data.
|
|
processWWMacroScript ( RsConfigGetToolsDir() + "\\dcc\\current\\max2012\\ui\\macroscripts\\rswildwest.mcr" )
|
|
recurseBuildWWMenuData ( RsConfigGetWildwestDir() + "\\script\\max\\" )
|
|
),
|
|
|
|
|
|
public
|
|
|
|
-- Deletes the hashtables, which will cause them to get rebuilt the next time a search is performed.
|
|
fn flush = (
|
|
scriptsHash = undefined
|
|
macroScriptsHash = undefined
|
|
|
|
gc light:true
|
|
|
|
true
|
|
),
|
|
|
|
|
|
fn isBuilt = (
|
|
if scriptsHash != undefined and macroScriptsHash != undefined then (
|
|
return true
|
|
|
|
) else (
|
|
return false
|
|
)
|
|
),
|
|
|
|
|
|
fn search searchStr exactPhrase:false rebuild:false = (
|
|
if ( scriptsHash == undefined ) or ( macroScriptsHash == undefined ) or ( rebuild == true ) do build()
|
|
|
|
local results = #()
|
|
local searches = #()
|
|
|
|
-- Perform multiple searches from the single search string.
|
|
if ( matchPattern searchStr pattern:"*;*" ) then (
|
|
searches = filterString searchStr ";"
|
|
|
|
) else (
|
|
append searches searchStr
|
|
)
|
|
|
|
for search in searches do (
|
|
if not exactPhrase do (
|
|
|
|
-- Split up search string if there are spaces in it.
|
|
if ( matchPattern search pattern:"* *" ) then (
|
|
local rawSearchStr = filterString search " "
|
|
|
|
newSearchStr = stringStream "*"
|
|
|
|
for i in rawSearchStr do (
|
|
format "%*" i to:newSearchStr
|
|
)
|
|
|
|
search = "*" + newSearchStr as string
|
|
|
|
) else (
|
|
search = "*" + search + "*"
|
|
)
|
|
)
|
|
|
|
local enum = scriptsHash.GetEnumerator()
|
|
|
|
while ( enum.MoveNext() ) do (
|
|
if ( matchPattern ( enum.Key as string ) pattern:search ignoreCase:( not exactPhrase ) ) do (
|
|
|
|
-- What's in the array - 1: The menu item path, 2: Full path to the maxscript file on disk associated with the menu item, 3: MaxScript body
|
|
append results #( ( scriptsHash.Item[ enum.Key ][ 2 ] + "/" + enum.Key) as string, scriptsHash.Item[ enum.Key ][ 1 ], scriptsHash.Item[ enum.Key ][ 3 ] )
|
|
)
|
|
)
|
|
)
|
|
|
|
results
|
|
)
|
|
)
|
|
|
|
::RsFindScript = RsFindScriptStruct() |