filein "pipeline/util/xml.ms" filein "pipeline/export/models/RsObjectFlags.ms" filein "pipeline/export/maps/globals.ms" struct sRsStatedAnim ( objectArray = #(), animLengthArray = #(), looped = false, fn Reset = ( objectArray = #() animLengthArray = #() looped = false ), fn getAnimationLength obj = ( local maxLength = 0 if undefined==obj.children then ( print "object doesn't have anim - start or end state" ) for c in obj.children do ( allKeys = c.pos.controller.keys if allKeys.count<=0 then ( continue ) local lastKey = allKeys[allKeys.count] local lastFrame = lastKey.time.frame if lastFrame>maxLength then maxLength = lastFrame ) --print ("animation length:"+maxLength as string) return maxLength ), fn selectWithChildren obj = ( selectMore obj for c in obj.children where IsValidNode c do selectWithChildren c ), fn selectObject num = ( if undefined==objectArray[num] then return false clearSelection() selectWithChildren objectArray[num] ), fn addObject newobj listSelectionIndex = ( while undefined!=newobj.parent do newobj = newobj.parent for obj in objectArray do if obj==newobj then ( messagebox "already added" return false ) if objectArray.count<3 then ( append objectArray newobj append animLengthArray (getAnimationLength newobj) ) else ( local oldObject = objectArray[listSelectionIndex] local groupIdx = getattrindex "Gta Object" "groupName" local stateIdx = getattrindex "Gta Object" "animState" if (IsValidNode oldObject) then ( setAttr newobj groupIdx (getAttr oldObject groupIdx) setAttr newobj stateIdx (getAttr oldObject stateIdx) ) else ( local otherStatesGroupNames = "DEFAULT" for o in objectArray where (IsValidNode o) and ("Gta Object"==getAttrClass) do (otherStatesGroupNames = (getAttr o groupIdx); break) setAttr newobj groupIdx otherStatesGroupNames setAttr newobj stateIdx (case listSelectionIndex of (1:"Start"; 2:"Animation"; 3:"End");) ) messagebox ("old object reset in addObject:"+oldObject as string) setAttr oldObject groupIdx "DEFAULT" setAttr oldObject stateIdx "" objectArray[listSelectionIndex] = newobj animLengthArray[listSelectionIndex] = (getAnimationLength newobj) ) return newobj ), fn deleteObject objName = ( if objectArray.count<1 then return false for objIndex=1 to objectArray.count do ( print (objectArray[objIndex].name) if objectArray[objIndex].name==objName then ( deleteItem objectArray objIndex deleteItem animLengthArray objIndex return true ) objIndex+=1 ) return false ) ) struct sRsStatedAnimTool ( currAnim = sRsStatedAnim(), hideObjs = true, currActiveObjectIndex = 1, fn findSameAnimGroup animGroupName = ( local groupIdx = getattrindex "Gta Object" "groupName" local stateIdx = getattrindex "Gta Object" "animState" local tempStates = #() for obj in objects where "Gta Object"==(getAttrClass obj) do ( if animGroupName==(getAttr obj groupIdx) then ( case (getAttr obj stateIdx) of ( "Start":tempStates[1] = obj "Animation":tempStates[2] = obj "End":tempStates[3] = obj ) ) ) return tempStates ), fn getCurrentAnimGroupName = ( if currAnim.objectArray.count<1 then return "DEFAULT" local obj = currAnim.objectArray[1] local groupIdx = getattrindex "Gta Object" "groupName" if "Gta Object"==(getAttrClass obj) then return getAttr obj groupIdx else return "DEFAULT" ), fn loadAnim animGroupName = ( if animGroupName==getCurrentAnimGroupName() then return false currAnim = sRsStatedAnim() local loopIdx = getattrindex "Gta Object" "looped" local tempStates = findSameAnimGroup animGroupName if undefined==tempStates[1] or undefined==tempStates[2] or undefined==tempStates[3] then ( print ("Not enough states found for group: \""+animGroupName+"\"\n\nObjects"+tempStates as string) return false ) else ( for oi=1 to tempStates.count do currAnim.addObject tempStates[oi] oi currAnim.looped = getAttr tempStates[1] loopIdx ) return true ), fn findAnimGroups theProgressbar:undefined = ( local groupIdx = getattrindex "Gta Object" "groupName" local stateIdx = getattrindex "Gta Object" "animState" local loopIdx = getattrindex "Gta Object" "looped" local animGroups = #() local index = 1 for obj in objects where "Gta Object"==(getAttrClass obj) do ( 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 0!=(findItem animGroups currGroupName) then continue tempStates = findSameAnimGroup currGroupName if undefined!=tempStates[1] and undefined!=tempStates[2] and undefined!=tempStates[3] then append 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 = ( local groupIdx = getattrindex "Gta Object" "groupName" if currAnim.objectArray.count<1 then return false if checkName==(getAttr currAnim.objectArray[1] groupIdx) then return true else return false ), fn getObjectNames = ( objectNames = #() for obj in currAnim.objectArray do ( if not IsValidNode obj then ( currAnim.Reset() return #() ) append objectNames obj.name ) return objectNames ), fn addObject newobj listSelectionIndex = ( local retObj = false if undefined==currAnim then return false else retObj = currAnim.addObject newobj listSelectionIndex if undefined!=RsStatedAnimRollout and RsStatedAnimRollout.open then RsStatedAnimRollout.updateList() return newObj ), fn deleteObject objName = ( if undefined==currAnim then return false else currAnim.deleteObject objName ), 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 advancePlaybackState = ( currActiveObjectIndex+=1 hideInactiveObjects currActiveObjectIndex print ("currActiveObjectIndex:"+currActiveObjectIndex as string) if currAnim.animLengthArray[currActiveObjectIndex]>animationRange.end.frame then messagebox "Warning:Animation longer than current global animation range: animation will loop." slidertime = 0 ), fn playbackCallback = ( -- print ((currActiveObjectIndex as string)+", "+(objectArray.count as string)) if currActiveObjectIndex>=currAnim.objectArray.count then ( stopanimation() unRegisterTimeCallback playbackCallback slidertime = 0 return false ) if currAnim.objectArray==undefined or currAnim.objectArray.count<1 then return false local activeStateObject = currAnim.objectArray[currActiveObjectIndex] if activeStateObject!=undefined then ( if slidertime>=currAnim.animLengthArray[currActiveObjectIndex] then advancePlaybackState() ) else print "activeStateObject=undefined" ), -- can't use this in the callback above since it's not defined yet and cant define before since then the callback doesn't get deleted properly on stop. =( fn stopPlayback = ( stopanimation() unRegisterTimeCallback playbackCallback slidertime = 0 ), fn Deinit = ( currActiveObjectIndex=1 stopplayback() unhideAll() currAnim = sRsStatedAnim() unRegisterTimeCallback playbackCallback ), fn selectionChanged = ( if undefined==selection[1] then ( return false ) local obj = selection[1] while undefined!=obj.parent do obj = obj.parent local groupIdx = getattrindex "Gta Object" "groupName" if "Gta Object"==(getAttrClass obj) then ( local theGroupName = getAttr obj groupIdx if "DEFAULT"==theGroupName then return false if not (isCurrentAnimGroupName theGroupName) then return (loadAnim theGroupName) return true ) else if statedAnimProxy==(classof obj) then ( if undefined==(findString obj.name "_anim") then ( messagebox "no _anim suffix found on animation proxy. Deleting." delete obj return false ) local theGroupName = substring obj.name 1 ((findString obj.name "_anim")-1) if not (isCurrentAnimGroupName theGroupName) then ( print "reloading" return (loadAnim theGroupName) ) return true ) else return false ), fn startplayback = ( slidertime = 0 currActiveObjectIndex = 1 print ("start animation- currActiveObjectIndex:"+currActiveObjectIndex as string) registerTimeCallback playbackCallback -- hideInactiveObjects 1 playanimation immediatereturn:true ), 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 senseful group name." return false ) local newName = thename+"_anim" -- delete old local oldProxies = for o in objects where o.name==newName collect o delete oldProxies local proxyObj = statedAnimProxy() proxyObj.testNodeForAnimation currAnim.objectArray[1] ), fn saveAttributes groupName = ( if currAnim.objectArray.count<3 then ( local msg = stringstream "" format "You need to set all states before saving the group %" (currAnim.objectArray as string) to:msg messagebox msg return false ) local groupIdx = getattrindex "Gta Object" "groupName" local stateIdx = getattrindex "Gta Object" "animState" local loopIdx = getattrindex "Gta Object" "looped" idxDontAddIPL = getattrindex "Gta Object" "Dont Add To IPL" local oldGroupName = getAttr currAnim.objectArray[1] groupIdx local buildNewProxy = true if "DEFAULT"==groupName then ( messagebox "groupname must not be DEFAULT for saving" return false ) else if oldGroupName!=groupName then ( print ("oldProxy:"+oldGroupName) -- check for old proxy local newName = oldGroupName+"_anim" -- delete old local oldProxies = for o in objects where o.name==newName collect o delete oldProxies buildNewProxy = true ) for i=1 to 3 do ( setAttr currAnim.objectArray[i] groupIdx groupName setAttr currAnim.objectArray[i] loopIdx currAnim.looped setattr currAnim.objectArray[i] idxDontAddIPL true ) setAttr currAnim.objectArray[1] stateIdx "Start" setAttr currAnim.objectArray[2] stateIdx "Animation" setAttr currAnim.objectArray[3] stateIdx "End" if buildNewProxy then buildProxy groupName ), fn deleteAttributes = ( local groupIdx = getattrindex "Gta Object" "groupName" local stateIdx = getattrindex "Gta Object" "animState" for i=1 to currAnim.objectArray.count do ( setAttr currAnim.objectArray[i] groupIdx "DEFAULT" setAttr currAnim.objectArray[i] stateIdx "" ) ), 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 ExportXML = ( local groups = findAnimGroups() if groups.count<1 then ( print "No stated anims to export!" return true -- valid, just skip. ) -- RsStatedAnimFilename = "D:/temp.xml" if undefined==RsStatedAnimFilename then ( Messagebox "stated anim xml export only works on export!" return false ) else if ""==RsStatedAnimFilename then ( print "Trying to export a stated anim from a generic map... bailing out." return true -- valid, just skip. ) else print ("Exporting anim to "+RsStatedAnimFilename) -- init xml doc local animDoc = XmlDocument() animDoc.init() -- -- -- -- -- blocktest -- -- -- -- -- -- -- -- v_inttest -- v_ray_root -- V_RAY_START -- V_RAY_ROOT -- V_RAY_END -- -- -- -- -- -- -- local animDocRoot = animDoc.createelement("CMapTypes") animDoc.document.AppendChild animDocRoot local rfArrayXML = animDoc.createelement("compositeEntityTypes") animDocRoot.AppendChild rfArrayXML for g in groups do ( local rfItem = animDoc.createelement("Item") rfArrayXML.AppendChild rfItem loadAnim g -- safety save saveAttributes g -- find effects on animated children local effectBones = #() local boneHier = currAnim.objectArray[2] if undefined!=currAnim.objectArray[2].modifiers[#Skin] then ( boneHier = rexGetSkinRootBone currAnim.objectArray[2] ) for c in boneHier.children do ( for b in c.children where (classof b)==GtaExplosion or (classof b)==RAGE_Particle do ( append effectBones c.name break ) ) print effectBones if undefined==currAnim.objectArray[1] or undefined==currAnim.objectArray[2] or undefined==currAnim.objectArray[3] then ( print ("anim "+g+" hasn't got enough states") continue ) local rfNodeNameXML = animDoc.createelement("Name") local rfname = animDoc.createTextNode g rfItem.AppendChild rfNodeNameXML rfNodeNameXML.AppendChild rfname local lodIdx = getAttrIndex "Gta Object" "LOD distance" local rfNodeLodDistXML = animDoc.createelement("lodDist") local rflodDist = animDoc.createattribute "value" attributeValue:((getattr currAnim.objectArray[1] lodIdx) as string) rfItem.AppendChild rfNodeLodDistXML rfNodeLodDistXML.Attributes.Append rflodDist local rfNodeFlagsXML = animDoc.createelement("flags") local rfFlags = animDoc.createattribute "value" attributeValue:((getObjectFlags currAnim.objectArray[1]) as string) rfItem.AppendChild rfNodeFlagsXML rfNodeFlagsXML.Attributes.Append rfFlags local attrIdx = getAttrIndex "Gta Object" "Attribute" local rfNodeSpecialXML = animDoc.createelement("specialAttribute") local rfSpecial = animDoc.createattribute "value" attributeValue:((getattr currAnim.objectArray[1] attrIdx) as string) rfItem.AppendChild rfNodeSpecialXML rfNodeSpecialXML.Attributes.Append rfSpecial local themin = (point3 0 0 0) local themax = (point3 0 0 0) for o in currAnim.objectArray do ( bb= nodeLocalBoundingBox o local localmin = bb[1] local localmax = bb[2] if localmin[1]themax[1] then themax[1]=localmax[1] if localmax[2]>themax[2] then themax[2]=localmax[2] if localmax[3]>themax[3] then themax[3]=localmax[3] ) local thecentre = (themin+themax)/2 local rfNodeMinXML = animDoc.createelement("bbMin") rfItem.AppendChild rfNodeMinXML local x = animDoc.createattribute "x" attributeValue:themin[1] local y = animDoc.createattribute "y" attributeValue:themin[2] local z = animDoc.createattribute "z" attributeValue:themin[3] rfNodeMinXML.Attributes.Append x rfNodeMinXML.Attributes.Append y rfNodeMinXML.Attributes.Append z local rfNodeMaxXML = animDoc.createelement("bbMax") rfItem.AppendChild rfNodeMaxXML local x = animDoc.createattribute "x" attributeValue:themax[1] local y = animDoc.createattribute "y" attributeValue:themax[2] local z = animDoc.createattribute "z" attributeValue:themax[3] rfNodeMaxXML.Attributes.Append x rfNodeMaxXML.Attributes.Append y rfNodeMaxXML.Attributes.Append z local rfNodeCentreXML = animDoc.createelement("bsCentre") rfItem.AppendChild rfNodeCentreXML local x = animDoc.createattribute "x" attributeValue:thecentre[1] local y = animDoc.createattribute "y" attributeValue:thecentre[2] local z = animDoc.createattribute "z" attributeValue:thecentre[3] rfNodeCentreXML.Attributes.Append x rfNodeCentreXML.Attributes.Append y rfNodeCentreXML.Attributes.Append z local radius = length (theCentre - themin) local rfNodeRadiusXML = animDoc.createelement("bsRadius") local rfRadius = animDoc.createattribute "value" attributeValue:(radius as string) rfItem.AppendChild rfNodeRadiusXML rfNodeRadiusXML.Attributes.Append rfRadius local rfNodeDictnameXML = animDoc.createelement("AnimDict") local rfdictname = animDoc.createTextNode (getFilenameFile maxFileName) rfItem.AppendChild rfNodeDictnameXML rfNodeDictnameXML.AppendChild rfdictname local rfNodeAnimNameXML = animDoc.createelement("AnimName") -- get skin root node if it's a skinned mesh local model = currAnim.objectArray[2] local rootbone = rexGetSkinRootBone currAnim.objectArray[2] if undefined!=rootbone then ( while undefined!=rootbone.parent do rootbone=rootbone.parent model = rootbone ) local rfgroupname = animDoc.createTextNode model.name -- animName rfItem.AppendChild rfNodeAnimNameXML rfNodeAnimNameXML.AppendChild rfgroupname local rfNodeStartModelXML = animDoc.createelement("StartModel") local rfStartname = animDoc.createTextNode currAnim.objectArray[1].name rfItem.AppendChild rfNodeStartModelXML rfNodeStartModelXML.AppendChild rfStartname local rfNodeAnimModelXML = animDoc.createelement("AnimatedModel") local rfAnimname = animDoc.createTextNode currAnim.objectArray[2].name rfItem.AppendChild rfNodeAnimModelXML rfNodeAnimModelXML.AppendChild rfAnimname local rfNodeEndmodelXML = animDoc.createelement("EndModel") local rfendname = animDoc.createTextNode currAnim.objectArray[3].name rfItem.AppendChild rfNodeEndmodelXML rfNodeEndmodelXML.AppendChild rfendname -- particleEffect bones local rfEffectBones = animDoc.createelement("effectBones") rfItem.AppendChild rfEffectBones for eb in effectBones do ( local rfEffectBone = animDoc.createelement("effectBone") local rfBone = animDoc.createattribute "value" attributeValue:((rexgetbonehash eb) as string) rfEffectBones.AppendChild rfEffectBone rfEffectBone.Attributes.Append rfBone ) ) try( animDoc.save RsStatedAnimFilename )catch(messagebox (getCurrentException())) ) ) try gRsStatedAnimTool.Deinit() catch() global gRsStatedAnimTool = sRsStatedAnimTool()