/*########### Creature Metadata Setup Description: --Used for creating creature metadata files for driving things like wrinkle maps and hair scaling History: --Kevin Ala-Pantti - January, 2014 --Created Wiki: --https://devstar.rockstargames.com/wiki/index.php/Ped_Creature_Metadata ###########*/ try(destroyDialog RSCreatureMetadata)catch() -- This line loads the custom header filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms") filein (RsConfigGetWildWestDir() + "script/3dsMax/_common_functions/FN_RSTA_xml.ms") --Load the xml assemply dotNet.loadAssembly "system.xml" ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- global RSCreatureMetadata /*------------------------------------------------------------------------------------------------------------------------- RsTa_hashDriverName Hashes the name string of an object and removes the trailing L -------------------------------------------------------------------------------------------------------------------------*/ fn RsTa_hashDriverName driver= ( local driverNameHash = substring driver 5 driver.count driverNameHash = ((athash16u driverNameHash) as string) driverNameHash = substring driverNameHash 1 (driverNameHash.count-1) ) /*------------------------------------------------------------------------------------------------------------------------- RsTa_clearSection Deletes a section of an xml -------------------------------------------------------------------------------------------------------------------------*/ fn RsTa_clearSection savePath sectionToClear= ( -- Load the XML to edit local xmlDoc = dotNetObject "system.xml.xmlDocument" xmlDoc.load savePath -- Get the root element local docEle = xmlDoc.documentElement local childToRemove = undefined -- If the root element exists and is named properly try find the desired section if docEle!=undefined and docEle.name=="CCreatureMetaData" then ( for i = 0 to docEle.childNodes.count-1 do ( if docEle.ChildNodes.itemOf[i].name == sectionToClear then ( childToRemove = docEle.ChildNodes.itemOf[i] ) ) -- If the child was found then delete that section if childToRemove != undefined then docEle.RemoveChild childToRemove ) xmlDoc.save (savePath) ) /*------------------------------------------------------------------------------------------------------------------------- RsTa_findXMLSection Finds if a section of an xml exists; returns that section if it is found -------------------------------------------------------------------------------------------------------------------------*/ fn RsTa_findXMLSection savePath sectionToFind= ( -- Load the XML to edit local xmlDoc = dotNetObject "system.xml.xmlDocument" xmlDoc.load savePath -- Get the root element local docEle = xmlDoc.documentElement local found = undefined -- If the root element exists and is named properly try find the desired section if docEle!=undefined and docEle.name=="CCreatureMetaData" then ( for i = 0 to docEle.childNodes.count-1 do ( if docEle.ChildNodes.itemOf[i].name == sectionToFind then found = docEle.ChildNodes.itemOf[i] ) ) -- Return the found section, or undefined if it doesn't exist found ) /*------------------------------------------------------------------------------------------------------------------------- RsTa_createXMLSectionNode Fills in the "Item"s of an XML section -------------------------------------------------------------------------------------------------------------------------*/ fn RsTa_createXMLSectionNode root nodeTypes nodeAttrTypes nodeAttrValues nodeInnerText= ( -- Create a new Item under the current section local item = rsta_xml.makeNode "Item" root -- Create the contents of the item for i = 1 to nodeTypes.count do ( rsta_xml.makeNode nodeTypes[i] item attr:nodeAttrTypes[i] value:nodeAttrValues[i] innerText:nodeInnerText[i] ) ) /*------------------------------------------------------------------------------------------------------------------------- RsTa_writeXMLSection Write a new section of the XML under the topmost root; converts passed values to proper attribute and innertext values -------------------------------------------------------------------------------------------------------------------------*/ fn RsTa_writeXMLSection savePath root metaType compType varHash driverList numVariations= ( local typeRoot = undefined for i = 0 to root.childNodes.count-1 do ( if root.ChildNodes.itemOf[i].name == metaType then typeRoot = root.ChildNodes.itemOf[i] ) if metaType == "shaderVariableComponents" then ( -- If the root for this type of metadata doesn't exist then make it if typeRoot == undefined then typeRoot = rsta_xml.makeNode metaType root -- The contents of the items to put under the root local nodeTypes = #("pedcompID", "maskID", "shaderVariableHashString", "tracks", "ids", "components") local nodeAttrTypes = #("value","value",undefined,"content","content","content") for i = 1 to driverList.count do ( local nodeAttrValues = #(((compType-1) as string), driverList[i][1], "", "char_array", "short_array", "char_array") local driverNameHash = RsTa_hashDriverName driverList[i] local nodeInnerText = #(undefined, undefined, varHash, "23", driverNameHash, driverList[i][3]) RsTa_createXMLSectionNode typeRoot nodeTypes nodeAttrTypes nodeAttrValues nodeInnerText ) ) if metaType == "pedPropExpressions" then ( if typeRoot == undefined then typeRoot = rsta_xml.makeNode metaType root local nodeTypes = #("pedPropID", "pedPropVarIndex", "pedPropExpressionIndex", "tracks", "ids", "types", "components") local nodeAttrTypes = #("value","value","value","content","content","content","content") for i = 1 to driverList.count do ( for vars = -1 to numVariations do ( local exprSlot = 0 if vars == -1 then exprSlot = "-1" else exprSlot = driverList[i][3] local nodeAttrValues = #(((compType-1) as string), (vars as string), exprSlot, "char_array", "short_array", "char_array", "char_array") local driverNameHash = RsTa_hashDriverName driverList[i] local axis = "" case driverList[i][1] of ( "X": axis = "0" "Y": axis = "1" "Z": axis = "2" ) local nodeInnerText = #(undefined, undefined, undefined, "33", driverNameHash, "2", axis) RsTa_createXMLSectionNode typeRoot nodeTypes nodeAttrTypes nodeAttrValues nodeInnerText ) ) ) if metaType == "pedCompExpressions" then ( if typeRoot == undefined then typeRoot = rsta_xml.makeNode metaType root local nodeTypes = #("pedcompID", "pedCompVarIndex", "pedCompExpressionIndex", "tracks", "ids", "types", "components") local nodeAttrTypes = #("value","value","value","content","content","content","content") for i = 1 to driverList.count do ( for vars = 0 to numVariations do ( local exprSlot = 0 if vars == -1 then exprSlot = "-1" else exprSlot = driverList[i][3] local nodeAttrValues = #(((compType-1) as string), (vars as string), exprSlot, "char_array", "short_array", "char_array", "char_array") local driverNameHash = RsTa_hashDriverName driverList[i] local axis = "" case driverList[i][1] of ( "X": axis = "0" "Y": axis = "1" "Z": axis = "2" ) local nodeInnerText = #(undefined, undefined, undefined, "33", driverNameHash, "2", axis) RsTa_createXMLSectionNode typeRoot nodeTypes nodeAttrTypes nodeAttrValues nodeInnerText ) ) ) ) /*------------------------------------------------------------------------------------------------------------------------- RsTa_appendXMLSection Add on a new section after the last child of the XML root -------------------------------------------------------------------------------------------------------------------------*/ fn RsTa_appendXMLSection savePath metaType compType varHash driverList numVariations= ( local xmlDoc = dotNetObject "system.xml.xmlDocument" xmlDoc.load savePath local root = xmlDoc.documentElement RsTa_writeXMLSection savePath root metaType compType varHash driverList numVariations xmlDoc.save (savePath) ) /*------------------------------------------------------------------------------------------------------------------------- RsTa_newXML Create a whole new XML -------------------------------------------------------------------------------------------------------------------------*/ fn RsTa_newXML savePath metaType compType varHash driverList numVariations= ( -- make a new XML local xmlDoc = dotNetObject "system.xml.xmlDocument" xmlDoc.AppendChild (xmlDoc.CreateXmlDeclaration "1.0" "utf-8" "") -- the top most root local root = xmlDoc.createElement "CCreatureMetaData" xmlDoc.appendChild root RsTa_writeXMLSection savePath root metaType compType varHash driverList numVariations xmlDoc.save (savePath) ) /*------------------------------------------------------------------------------------------------------------------------- RsTa_writeXML Ensures file exists; checks Add / Overwrite state and begins the proper type of XML writing -------------------------------------------------------------------------------------------------------------------------*/ fn RsTa_writeXML savePath metaType compType varHash driverList numVariations updateState = ( if doesFileExist savePath == false then ( -- file doesn't exist so make a new XML RsTa_newXML savePath metaType compType varHash driverList numVariations ) else if updateState == 3 then ( -- overwrite full file RsTa_newXML savePath metaType compType varHash driverList numVariations ) else if doesFileExist savePath == true then ( if updateState == 1 then ( -- add section RsTa_appendXMLSection savePath metaType compType varHash driverList numVariations ) if updateState == 2 then ( -- overwrite section local typeRoot = RsTa_findXMLSection savePath metaType if typeRoot == undefined then RsTa_appendXMLSection savePath metaType compType varHash driverList numVariations else ( RsTa_clearSection savePath metaType RsTa_appendXMLSection savePath metaType compType varHash driverList numVariations ) ) ) ) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- /*------------------------------------------------------------------------------------------------------------------------- SHADERVARIABLECOMPONENTS ROLLOUT -------------------------------------------------------------------------------------------------------------------------*/ rollout RSCreatureMetadata_Shaders "Shader Variable Components" ( local compTypes = #("Head", "Berd", "Hair", "Uppr", "Lowr", "Hand", "Feet", "Teef", "Accs", "Task", "Decl", "Jbib") local hashStrings = #("WrinkleWeights") local overwrites = #("Add To Section","Overwrite Section", "Overwrite All") local savePath = undefined dropdownlist ddl_compType "Component Type:" items:compTypes dropdownlist ddl_hashString "Variable Hash String:" items:hashStrings button btn_populateDrivers "Populate List With Selected Drivers" width:(RSCreatureMetadata_Shaders.width-26) height:30 listbox lbx_Drivers "Drivers" align:#left width:(RSCreatureMetadata_Shaders.width-130) spinner spn_maskID "Mask ID" range:[0,5,0] type:#integer fieldWidth:20 offset:[0, -110] enabled:false spinner spn_rgbaChannel "RGBA Channel" range:[0,3,0] type:#integer fieldWidth:20 offset:[0,25] enabled:false button btn_chooseDirectory "Save As..." width:(RSCreatureMetadata_Shaders.width-26) enabled:false offset:[0,80] height:40 button btn_writeXML "Write XML" width:(RSCreatureMetadata_Shaders.width-26) enabled:false height:40 group "Options" ( radiobuttons rbtn_updateOverwrite "Add / Overwrite" labels:overwrites align:#center ) on btn_populateDrivers pressed do ( local sel = getCurrentSelection() if (sel.count > 0) then ( spn_maskID.enabled = true spn_rgbaChannel.enabled = true btn_chooseDirectory.enabled = true local selNames = for x in sel collect x.name for i = 1 to selNames.count do selNames[i] = ("0 0 " + selNames[i]) lbx_Drivers.items = selNames ) ) on spn_maskID changed ID do ( local tempStr = lbx_Drivers.selected tempStr[1] = (ID as string) lbx_Drivers.selected = tempStr ) on spn_rgbaChannel changed chan do ( local tempStr = lbx_Drivers.selected tempStr[3] = (chan as string) lbx_Drivers.selected = tempStr ) on lbx_Drivers selected item do ( local itemStr = lbx_Drivers.items[item] local maskID = (itemStr[1] as integer) local rgbaChan = (itemStr[3] as integer) spn_maskID.value = maskID spn_rgbaChannel.value = rgbaChan ) on btn_chooseDirectory pressed do ( savePath = getSaveFileName caption:"Save CreatureMetadata XML" filename:"" types:"Metadata(*.meta)|*.meta|" if (savePath != undefined) then ( RSCreatureMetadata.savePath = savePath btn_writeXML.enabled = true ) ) on btn_writeXML pressed do ( local metaType = "shaderVariableComponents" local compType = ddl_compType.selection local varHash = ddl_hashString.selected local driverList = lbx_Drivers.items local numVariations = 0 local updateState = rbtn_updateOverwrite.state RsTa_writeXML savePath metaType compType varHash driverList numVariations updateState ) on rbtn_updateOverwrite changed state do ( RSCreatureMetadata.addOverwriteState = state ) on RSCreatureMetadata_Shaders open do ( if RSCreatureMetadata == undefined then rbtn_updateOverwrite.state = 1 else rbtn_updateOverwrite.state = RSCreatureMetadata.addOverwriteState if RSCreatureMetadata != undefined then ( if RSCreatureMetadata.savePath != undefined then ( savePath = RSCreatureMetadata.savePath btn_writeXML.enabled = true ) ) ) ) ------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------- /*------------------------------------------------------------------------------------------------------------------------- PEDPROPEXPRESSIONS ROLLOUT -------------------------------------------------------------------------------------------------------------------------*/ rollout RSCreatureMetadata_Props "Ped Prop Expressions" ( local compTypes = #("P_Head", "P_Eyes") local axes = #("X","Y","Z") local overwrites = #("Add To Section","Overwrite Section", "Overwrite All") local savePath = undefined dropdownlist ddl_compType "Component Type:" items:compTypes button btn_populateDrivers "Populate List With Selected Drivers" width:(RSCreatureMetadata_Shaders.width-26) height:30 listbox lbx_Drivers "Drivers" align:#left width:(RSCreatureMetadata_Shaders.width-130) radiobuttons rbtn_drivenAxis "Driven By Axis" labels:axes align:#right offset:[0,-140] enabled:false spinner spn_expressionChannel "Expr. Index" range:[0,4,0] type:#integer fieldWidth:20 enabled:false offset:[0,25] spinner spn_numVariations "# Variations" range:[0,30,0] type:#integer fieldWidth:20 enabled:false offset:[0,25] button btn_chooseDirectory "Save As..." width:(RSCreatureMetadata_Shaders.width-26) enabled:false offset:[0,45] height:40 button btn_writeXML "Write XML" width:(RSCreatureMetadata_Shaders.width-26) enabled:false height:40 group "Options" ( radiobuttons rbtn_updateOverwrite "Add / Overwrite" labels:overwrites align:#center ) on btn_populateDrivers pressed do ( local sel = getCurrentSelection() if (sel.count > 0) then ( rbtn_drivenAxis.enabled = true spn_expressionChannel.enabled = true spn_numVariations.enabled = true btn_chooseDirectory.enabled = true local selNames = for x in sel collect x.name for i = 1 to selNames.count do selNames[i] = ("X 0 " + selNames[i]) lbx_Drivers.items = selNames ) ) on rbtn_drivenAxis changed axis do ( local tempStr = lbx_Drivers.selected tempStr[1] = (axes[axis] as string) lbx_Drivers.selected = tempStr ) on spn_expressionChannel changed chan do ( local tempStr = lbx_Drivers.selected tempStr[3] = (chan as string) lbx_Drivers.selected = tempStr ) on lbx_Drivers selected item do ( local itemStr = lbx_Drivers.items[item] local axis = itemStr[1] local exprChan = (itemStr[3] as integer) local axisNum = findItem axes axis rbtn_drivenAxis.state = axisNum spn_expressionChannel.value = exprChan ) on btn_chooseDirectory pressed do ( savePath = getSaveFileName caption:"Save CreatureMetadata XML" filename:"" types:"Metadata(*.meta)|*.meta|" if (savePath != undefined) then ( RSCreatureMetadata.savePath = savePath btn_writeXML.enabled = true ) ) on btn_writeXML pressed do ( local metaType = "pedPropExpressions" local compType = ddl_compType.selection local varHash = "" local driverList = lbx_Drivers.items local numVariations = spn_numVariations.value local updateState = rbtn_updateOverwrite.state RsTa_writeXML savePath metaType compType varHash driverList numVariations updateState ) on rbtn_updateOverwrite changed state do ( RSCreatureMetadata.addOverwriteState = state ) on RSCreatureMetadata_Props open do ( if RSCreatureMetadata == undefined then rbtn_updateOverwrite.state = 1 else rbtn_updateOverwrite.state = RSCreatureMetadata.addOverwriteState if RSCreatureMetadata != undefined then ( if RSCreatureMetadata.savePath != undefined then ( savePath = RSCreatureMetadata.savePath btn_writeXML.enabled = true ) ) ) ) ------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------- /*------------------------------------------------------------------------------------------------------------------------- PEDCOMPEXPRESSIONS ROLLOUT -------------------------------------------------------------------------------------------------------------------------*/ rollout RSCreatureMetadata_Components "Ped Component Expressions" ( local compTypes = #("Head", "Berd", "Hair", "Uppr", "Lowr", "Hand", "Feet", "Teef", "Accs", "Task", "Decl", "Jbib") local axes = #("X","Y","Z") local overwrites = #("Add To Section","Overwrite Section", "Overwrite All") local savePath = undefined dropdownlist ddl_compType "Component Type:" items:compTypes button btn_populateDrivers "Populate List With Selected Drivers" width:(RSCreatureMetadata_Shaders.width-26) height:30 listbox lbx_Drivers "Drivers" align:#left width:(RSCreatureMetadata_Shaders.width-130) radiobuttons rbtn_drivenAxis "Driven By Axis" labels:axes align:#right offset:[0,-140] enabled:false spinner spn_expressionChannel "Expr. Index" range:[0,4,0] type:#integer fieldWidth:20 enabled:false offset:[0,25] spinner spn_numVariations "# Variations" range:[0,30,0] type:#integer fieldWidth:20 enabled:false offset:[0,25] button btn_chooseDirectory "Save As..." width:(RSCreatureMetadata_Shaders.width-26) enabled:false offset:[0,45] height:40 button btn_writeXML "Write XML" width:(RSCreatureMetadata_Shaders.width-26) enabled:false height:40 group "Options" ( radiobuttons rbtn_updateOverwrite "Add / Overwrite" labels:overwrites align:#center ) on btn_populateDrivers pressed do ( local sel = getCurrentSelection() if (sel.count > 0) then ( rbtn_drivenAxis.enabled = true spn_expressionChannel.enabled = true spn_numVariations.enabled = true btn_chooseDirectory.enabled = true local selNames = for x in sel collect x.name for i = 1 to selNames.count do selNames[i] = ("X 0 " + selNames[i]) lbx_Drivers.items = selNames ) ) on rbtn_drivenAxis changed axis do ( local tempStr = lbx_Drivers.selected tempStr[1] = (axes[axis] as string) lbx_Drivers.selected = tempStr ) on spn_expressionChannel changed chan do ( local tempStr = lbx_Drivers.selected tempStr[3] = (chan as string) lbx_Drivers.selected = tempStr ) on lbx_Drivers selected item do ( local itemStr = lbx_Drivers.items[item] local axis = itemStr[1] local exprChan = (itemStr[3] as integer) local axisNum = findItem axes axis rbtn_drivenAxis.state = axisNum spn_expressionChannel.value = exprChan ) on btn_chooseDirectory pressed do ( savePath = getSaveFileName caption:"Save CreatureMetadata XML" filename:"" types:"Metadata(*.meta)|*.meta|" if (savePath != undefined) then ( RSCreatureMetadata.savePath = savePath btn_writeXML.enabled = true ) ) on btn_writeXML pressed do ( local metaType = "pedCompExpressions" local compType = ddl_compType.selection local varHash = "" local driverList = lbx_Drivers.items local numVariations = spn_numVariations.value local updateState = rbtn_updateOverwrite.state RsTa_writeXML savePath metaType compType varHash driverList numVariations updateState ) on rbtn_updateOverwrite changed state do ( RSCreatureMetadata.addOverwriteState = state ) on RSCreatureMetadata_Components open do ( if RSCreatureMetadata == undefined then rbtn_updateOverwrite.state = 1 else rbtn_updateOverwrite.state = RSCreatureMetadata.addOverwriteState if RSCreatureMetadata != undefined then ( if RSCreatureMetadata.savePath != undefined then ( savePath = RSCreatureMetadata.savePath btn_writeXML.enabled = true ) ) ) ) ------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------- /*------------------------------------------------------------------------------------------------------------------------- MAIN ROLLOUT -------------------------------------------------------------------------------------------------------------------------*/ rollout RSCreatureMetadata "R* Creature Metadata Editor" width:400 ( dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:(RSCreatureMetadata.width) local banner = makeRsBanner dn_Panel:rsBannerPanel wiki:"Ped_Creature_Metadata" filename:(getThisScriptFilename()) dotNetControl dn_tabs "System.Windows.Forms.TabControl" height:20 width:(RSCreatureMetadata.width) align:#center pos:[-1, (RsBannerPanel.height + 2)] subRollout theSubRollout height:750 align:#center width:(RSCreatureMetadata.width) pos:[0, dn_tabs.pos.y + dn_tabs.height] local lastClickNum local maxAutoHeight = 900 local keepWidth local savePath = undefined local addOverwriteState = 1 local tabRollouts = #( dataPair name:"Shaders" rollouts:#(RSCreatureMetadata_Shaders), dataPair name:"Props" rollouts:#(RSCreatureMetadata_Props), dataPair name:"Components" rollouts:#(RSCreatureMetadata_Components) ) fn setSubrollSize = ( theSubRollout.height = (RSCreatureMetadata.height - theSubRollout.pos.y) ) fn showTab clickNum = ( if (lastClickNum != clickNum) do --do not update if the same tab clicked twice ( lastClickNum = clickNum for subRoll in theSubRollout.rollouts do ( removeSubRollout theSubRollout subroll ) local setHeight = theSubRollout.pos.y + 6 for subRoll in tabRollouts[clickNum].rollouts do ( addSubRollout theSubRollout subRoll setHeight += (subRoll.height + 24) ) if (setHeight > maxAutoHeight) do ( setHeight = maxAutoHeight ) RSCreatureMetadata.height = setHeight setSubrollSize() ) ) on dn_tabs Selected itm do ( local clickNum = (itm.TabPageIndex + 1) showTab clickNum RsSettingWrite "RsCharSeamSnapper" "lastTab" tabRollouts[clickNum].name ) on RSCreatureMetadata resized newSize do ( if (newSize.x != keepWidth) and (keepWidth != undefined) do ( RSCreatureMetadata.width = keepWidth ) setSubrollSize() ) on RSCreatureMetadata open do ( banner.setup() keepWidth = RSCreatureMetadata.width local savedTabName = RsSettingsReadString "RSCreatureMetadata" "lastTab" undefined local savedTabNum = 1 for tabNum = 1 to tabRollouts.count do ( local tabName = tabRollouts[tabNum].name dn_tabs.TabPages.add tabName if (tabName == savedTabName) do ( savedTabNum = tabNum ) ) dn_tabs.SelectedIndex = (savedTabNum - 1) showTab savedTabNum ) ) ------------------------------------------------------------------------------------------------------------------------- createDialog RSCreatureMetadata 400 400 style:#(#style_resizing,#style_titlebar, #style_toolwindow, #style_sysmenu)