Files
gtav-src/tools_ng/wildwest/script/3dsMax/Evaluation/find_script.ms
T
2025-09-29 00:52:08 +02:00

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()