filein "pipeline/export/models/RsObjectFlags.ms" filein "rockstar/util/anim.ms" try gRsStatedAnimTool.Deinit() catch() global gStatedAnimFoundTXDs = #() global allowedStateClasses = #("Gta Object", "RS IMAP Group") global allowedAnimStateClasses = #("Gta Object") fn StatedAnimAddNewTxd thename = ( if undefined!=thename and 0==findItem gStatedAnimFoundTXDs thename then append gStatedAnimFoundTXDs thename ) struct sRsStatedAnim ( animGroup = "DEFAULT", objectArray = #(), looped = false, compression = "Stated_Anim_Default", txdIdx = getattrindex "Gta Object" "TXD", loopIdx = getattrindex "Gta Object" "looped", idxDontAddIPL = getattrindex "Gta Object" "Dont Add To IPL", IsFixedIdx = getattrindex "Gta Object" "Is Fixed", HasAnimIdx = getattrindex "Gta Object" "Has Anim", fn Reset = ( animGroup = "DEFAULT" objectArray = #() looped = false gStatedAnimFoundTXDs = #() ), fn getAnimationStates = ( for o in objectArray where ( (not isDeleted o) and (0!=finditem allowedStateClasses (Getattrclass o)) and ("Animation"==(getAttr o (getattrindex (getattrclass o) "animState"))) ) collect o ), fn GetObjAnimationRangeRec obj &range = ( local maxLength = 0 local skel = rexGetSkinRootBone obj if undefined!=skel then ( -- print ("using skeleton for animation length calculation"+skel as string) obj = skel ) RsGetControllerKeyRangeRec obj.controller &range for c in obj.children do ( GetObjAnimationRangeRec c &range ) --print ("animation length:"+maxLength as string) return maxLength ), fn getAnimationRange = ( local range = sNegInterval start:9999f end:0f for o in getAnimationStates() do ( GetObjAnimationRangeRec o &range ) return range ), fn getChildren obj outVal:#() = ( append outVal obj for c in obj.children where IsValidNode c do (getChildren c outVal:outVal) return outVal ), fn selectObject num = ( if 0==num or undefined==objectArray[num] then return false clearSelection() select (getChildren objectArray[num]) ), fn sortObjList v1 v2 = ( local stateIdxV1 = getattrindex (getattrclass v1) "animState" local stateIdxV2 = getattrindex (getattrclass v2) "animState" case of ( (getAttr v1 stateIdxV1 == "Start"):-1 (getAttr v2 stateIdxV2 == "Start"):1 (getAttr v1 stateIdxV1 == "End"):1 (getAttr v2 stateIdxV2 == "End"):-1 default: ( case of ( (undefined!=v1.modifiers[#skin]):-1 (undefined!=v2.modifiers[#skin]):1 default:striCmp v1.name v2.name ) ) ) ), fn addObject newObj loading:false = ( while undefined!=newObj.parent do newObj = newobj.parent if ((findItem objectArray newObj) != 0) do ( return false ) if 0==findItem allowedStateClasses (getattrclass newobj) then ( return false ) local groupIdx = getattrindex (getattrclass newObj) "groupName" if loading then ( if (animGroup == undefined) do ( animGroup = (getAttr newObj groupIdx) ) ) else ( local isStartEnd = true setAttr newObj groupIdx animGroup local stateIdx = getattrindex (getattrclass newObj) "animState" case of ( (matchPattern newObj.name pattern:"*_START*"): ( setAttr newObj stateIdx "Start" ) (matchPattern newObj.name pattern:"*_END*"): ( setAttr newObj stateIdx "End" ) default: ( setAttr newObj stateIdx "Animation" isStartEnd = false ) ) if 0!=findItem allowedAnimStateClasses (getattrclass newobj) then ( setattr newObj idxDontAddIPL true -- Set start/end animation-roots to "Is Fixed": setAttr newObj IsFixedIdx isStartEnd -- Set other anim-roots to "Has Anim" setAttr newObj HasAnimIdx (not isStartEnd) ) ) append objectArray newObj qsort objectArray sortObjList local insertIdx = findItem objectArray newObj if 0!=findItem allowedAnimStateClasses (getattrclass newobj) then StatedAnimAddNewTxd (getattr newobj txdIdx) return newobj ), fn setLooped state = ( looped = state for obj in objectArray do ( setAttr obj loopIdx state ) ), fn resetAttributes objs = ( if classof objs!=array then objs = #(objs) for obj in objs do ( if 0!=findItem allowedStateClasses (getattrclass obj) then ( local groupIdx = getattrindex (getattrclass obj) "groupName" local stateIdx = getattrindex (getattrclass obj) "animState" setAttr obj groupIdx "DEFAULT" setAttr obj stateIdx "None" if 0!=findItem allowedAnimStateClasses (getattrclass newobj) then ( setAttr obj IsFixedIdx false setAttr obj HasAnimIdx false ) ) else ( gRsUlog.LogError ("Object "+obj as string+" is not a valid statedAnim state. Please select Meshes or IMAP groups only to reset their related attributes.") context:obj ) ) gRsUlog.Validate() ), -- If objNum is -1, all objects are reset fn deleteObject objNum = ( if (objNum == 0) or (objNum > objectArray.count) then ( return false ) else ( local objs = if (objNum == -1) then objectArray else #(objectArray[objNum]) -- Unset anim-flags: resetAttributes objs if (objNum == -1) then ( format "Clearing StatedAnim data for animgroup: %\n" (animGroup as string) Reset() ) else ( format "Clearing StatedAnim data for object: %, %\n" objectArray[objNum].name objNum deleteItem objectArray objNum ) return true ) ) ) struct sRsStatedAnimTool ( txdIdx = getattrindex "Gta Object" "TXD", loopIdx = getattrindex "Gta Object" "looped", IsFixedIdx = getattrindex "Gta Object" "Is Fixed", HasAnimIdx = getattrindex "Gta Object" "Has Anim", idxStatedAnimCompression = getAttrindex "RsStatedAnim" "Compression", idxAnimStart = getAttrindex "RsStatedAnim" "Animation Start", idxAnimEnd = getAttrindex "RsStatedAnim" "Animation End", currAnim = sRsStatedAnim(), hideObjs = true, currActiveObjectIndex = 1, -- not in particular order fn findSameAnimGroup animGroupName = ( for obj in objects where (0!=findItem allowedStateClasses (getAttrClass obj)) and (getAttr obj (getattrindex (getattrclass obj) "groupName") == animGroupName) collect obj ), fn IsInValidAnimGroup animgroupname tempStates: = ( local groupStates = findSameAnimGroup animgroupname if unsupplied!=tempStates then *tempStates = groupStates -- print ("groupStates for "+animgroupname+":"+*tempStates as string) local startStates = for o in groupStates where ((0!=finditem allowedStateClasses (Getattrclass o)) and ("Start"==(getAttr o (getattrindex (getattrclass o) "animState")))) collect o local animationStates = for o in groupStates where ((0!=finditem allowedStateClasses (Getattrclass o)) and ("Animation"==(getAttr o (getattrindex (getattrclass o) "animState")))) collect o local endStates = for o in groupStates where ((0!=finditem allowedStateClasses (Getattrclass o)) and ("End"==(getAttr o (getattrindex (getattrclass o) "animState")))) collect o if startStates.count>=1 and animationStates.count>=1 and endStates.count>=1 then return true else return false ), fn getCurrentAnimGroupName = ( if currAnim == undefined then "DEFAULT" else currAnim.animGroup ), fn GetStatedAnimGroupName obj = ( local className = getattrclass obj if undefined==className then return undefined local groupIdx = getattrindex className "groupName" if undefined==groupIdx then return undefined return getattr obj groupIdx ), fn IsStatedAnimGroupMember obj = ( isInStatedAnimGroup = false stateAnimGroup = GetStatedAnimGroupName obj if stateAnimGroup != "Default" and stateAnimGroup != "DEFAULT" then isInStatedAnimGroup = true isInStatedAnimGroup ), fn setTxdNames newName = ( for obj in currAnim.objectArray where 0!=findItem allowedAnimStateClasses (getattrclass obj) do setattr obj txdIdx newName ), fn getAnimationRange = ( return currAnim.getAnimationRange() ), fn StoreAnimationRange = ( local newrange = getAnimationRange() local myProxy = getnodeByName (curranim.animGroup+"_anim") if undefined!=myProxy then ( setAttr myProxy idxAnimStart newrange.start setAttr myProxy idxAnimEnd newrange.end gRsUlog.LogMessage ("Animation range ("+newrange.start as string+".."+newrange.end as string+") stored on "+myProxy.name) context:myProxy ) ), fn loadAnim animGroupName = ( if isValidNode animGroupName then animGroupName = GetStatedAnimGroupName animGroupName gStatedAnimFoundTXDs = #() if animGroupName == getCurrentAnimGroupName() then return false currAnim = sRsStatedAnim animGroup:animGroupName local states = #() local validGroup = IsInValidAnimGroup animGroupName tempStates:&states if not validGroup then ( print ("Not enough states found for group: \""+animGroupName+"\"\n\nObjects"+states as string) return false ) else ( for obj in states do ( currAnim.addObject obj loading:true ) -- currAnim.looped = getAttr states[1] loopIdx ) local proxyObj = getNodeByName (animGroupName+"_anim") if proxyObj != undefined then ( local compressionName = getattr proxyObj idxStatedAnimCompression if matchPattern compressionName pattern:"*default*" then compressionName = "Stated_Anim_Default" currAnim.compression = compressionName ) StoreAnimationRange() return true ), fn setCompression compression = ( if undefined==currAnim then return false local proxyObj = getNodeByName (curranim.animGroup+"_anim") local success = false if proxyObj != undefined then ( success = setattr proxyObj idxStatedAnimCompression compression ) currAnim.compression = compression return success ), fn getCompression = ( return currAnim.compression ), fn ResetAttributes objs = ( currAnim.resetAttributes objs ), fn findAnimGroups theProgressbar:undefined = ( local animGroups = #() local index = 1 for obj in objects where 0!=findItem allowedStateClasses (getAttrClass obj) do ( local groupIdx = getattrindex (getattrclass obj) "groupName" local currGroupName = (getAttr obj groupIdx) if undefined!=theProgressbar then ( local percentage = ((index as float)/objects.count)*100 theProgressbar.value = percentage ) index = index+1 if "DEFAULT"==currGroupName or "undefined"==(toLower currGroupName) or 0!=(findItem animGroups currGroupName) then continue local validGroup = IsInValidAnimGroup currGroupName if validGroup then appendIfUnique animGroups currGroupName ) if undefined!=theProgressbar then theProgressbar.value = 0 return animGroups ), fn selectObject num = ( if undefined==currAnim then return false currAnim.selectObject num ), fn isCurrentAnimGroupName checkName = ( checkName == currAnim.animGroup ), fn getObjectNames = ( local objectNames = for obj in currAnim.objectArray collect ( if not IsValidNode obj then ( currAnim.Reset() return #() ) local stateIdx = getattrindex (getattrclass obj) "animState" local objState = getAttr obj stateIdx local prefix = case objState of ( "Start": "start: " "Animation": "anim: " "End": "end: " default: "undefined: " ) prefix + obj.name ) return objectNames ), fn addObject newobj = ( local retObj = false if undefined==currAnim then return false else retObj = currAnim.addObject newobj if undefined!=RsStatedAnimRollout and RsStatedAnimRollout.open then RsStatedAnimRollout.updateList() StoreAnimationRange() return newObj ), fn deleteObject objNum = ( if undefined==currAnim then (return false) else ( currAnim.deleteObject objNum ) ), fn deleteAttributes = ( deleteObject -1 ), fn changeAnimGroup newName = ( if (matchPattern newName pattern:"DEFAULT") then ( deleteAttributes() ) else ( if (undefined==currAnim) then (return false) else ( local existingAnims = findAnimGroups() if (findItem existingAnims newName) != 0 then ( -- Add listed states to existing named state: local currObjs = for obj in currAnim.objectArray collect obj loadAnim newName for obj in currObjs do ( currAnim.addObject obj ) ) else ( currAnim.animGroup = newName if (currAnim.objectArray.count != 0) do ( for obj in currAnim.objectArray do ( setAttr obj groupIdx newName ) loadAnim newName ) ) ) ) ), fn setLooped state = ( if (currAnim != undefined) do (currAnim.setLooped state) ), fn setObjHierVisible obj vis = ( if undefined==obj or not IsValidNode obj then return false if vis then unhide obj else hide obj if undefined==obj.children then return false for c in obj.children do ( if vis then unhide c else hide c ) ), fn unhideAll = ( for objIndex=1 to currAnim.objectArray.count do ( setObjHierVisible currAnim.objectArray[objIndex] true ) ), fn hideInactiveObjects activeIndex = ( if undefined==currAnim then return false if hideObjs then ( for objIndex=1 to currAnim.objectArray.count do ( setObjHierVisible currAnim.objectArray[objIndex] (objIndex==activeIndex) ) ) else unhideAll() ), fn Deinit = ( currActiveObjectIndex=1 unhideAll() currAnim = sRsStatedAnim() gStatedAnimFoundTXDs = #() ), fn selectionChanged = ( local groupName for obj in selection do ( local objGrpName local checkName = true if (isKindOf obj statedAnimProxy) then ( if not matchPattern obj.name pattern:"*_anim*" then ( messagebox "no _anim suffix found on animation proxy. Deleting." title:"StatedAnim Warning" delete obj ) else ( objGrpName = substring obj.name 1 ((findString obj.name "_anim")-1) ) ) else ( -- Find topmost Gta Object parent: while (0!=findItem allowedStateClasses (getAttrClass obj)) and (not isKindOf obj.parent Container) and (obj.parent != undefined) do obj = obj.parent if (0!=findItem allowedStateClasses (getAttrClass obj)) then ( local groupIdx = getattrindex (getattrclass obj) "groupName" objGrpName = getAttr obj groupIdx ) else ( checkName = false ) ) if checkName do ( if (groupName == undefined) then ( groupName = objGrpName ) else ( -- Exit if multiple groupNames were found if (groupName != objGrpName) do (return false) ) ) ) -- Exit if groupname is default, or no groupNames were found if (groupName == undefined) or (objGrpName == "DEFAULT") do (return false) if (isCurrentAnimGroupName groupName) then ( return true ) else ( return (loadAnim groupName) ) ), fn buildProxy thename = ( if currAnim.objectArray.count<3 then ( messagebox "Need to have all states set." return false ) if "DEFAULT"==thename or ""==thename then ( messagebox "Need to have a sensible group name." return false ) local newName = thename+"_anim" -- delete old local oldProxies = for o in objects where o.name==newName collect o local selNewProxy = false for item in oldProxies where item.isSelected do (selNewProxy = true) local proxyObj = ::statedAnimProxy() proxyObj.testNodeForAnimation currAnim.objectArray[1] setattr proxyObj idxStatedAnimCompression curranim.compression if selNewProxy do (selectMore proxyObj) delete oldProxies StoreAnimationRange() return proxyObj ), fn findAnimations = ( local anims = #() -- for obj in objects do collect ), fn HasSceneAnyAnimations = ( local groups = findAnimGroups() if groups.count<1 then return false else return true ), fn PreExportSetup = ( local groups = findAnimGroups() for g in groups do loadAnim g ) ) global gRsStatedAnimTool = sRsStatedAnimTool()