PDA

View Full Version : 3dsmax Script Help



Delta4907
September 16th, 2008, 05:32 PM
So this biped in 3dsmax has the ValveBiped.Bip01 prefix for its bone names. Obviously extracted from HL2, its a combine soldier. This poses a problem because Jms Exporter and CAD's Anim Exporter wont export the bones because of their names. I am going to use HL2 Animations btw.

Easy Way:

But I learned some maxscript and edited the Jms Exporter so it also exports models with the prefix ValveBiped.Bip01. Unfortunately CAD's Animation Exporter script is encrypted. All I ask for is an unencrypted version of the Animation Exporter. Thanks in advance.

Hard Way:

I could rename all the bones so they dont have the ValveBiped.Bip01 prefix, but because the only way to import HL2 anims in max is if the bone has the ValveBiped.Bip01 prefix, I would have to rename all the bones (around 43) to Bip01 blah blah blah..., for each animation that I want to import. VERY time consuming if you ask me.

P.S. Either its just me, or the model node limit is not 40, because i compiled the combine solder with 43 bones, with no errors in the default tool. (not tool_pro or tool star.)

CtrlAltDestroy
September 16th, 2008, 05:52 PM
lastPath = "C:\\Program Files\\Microsoft Games\\Halo Custom Edition\\data\\"
saveDir = undefined

frameCount = 0
nodeListChecksum = 0
nodeNames = #()
nodeArray = #()
nodeArraySorted = #()
nodeChildIndices = #()
nodeFirstChildIndices = #()
nodeNextSiblingIndices = #()
rootSceneNode = undefined

rollout animExporter "Animation Exporter" width:400 height:343
(
activeXControl animExportQueue "MSComctlLib.ListViewCtrl.2" pos:[7,7] width:386 height:155
dropDownList animType "" pos:[7,168] width:193 height:21 items:#("JMA (base; dx,dy)", "JMO (overlay; none)", "JMR (replacement; none)", "JMM (base; none)", "JMT (base; dx,dy,dyaw)", "JMZ (base; dx,dy,dz,dyaw)", "JMW (base; none; world-relative)") selection:1
button animRemoveUnchecked "- Unchecked" pos:[318,168] width:75 height:20
button animAddFile "+ File" pos:[206,168] width:50 height:20
button animAddFolder "+ Folder" pos:[262,168] width:50 height:20

groupBox groupSave "Save Parameters" pos:[7,191] width:386 height:77
radioButtons saveMethod "" pos:[16,206] width:220 height:32 labels:#("Save Exported Files to Original Directories", "Save Exported Files to...") columns:1
button saveDirPick "Pick" pos:[15,241] width:35 height:19 enabled:false
button saveDirClear "Clear" pos:[54,241] width:35 height:19 enabled:false
editText saveDirText "" pos:[89,241] width:296 height:19 enabled:false

groupBox groupExecute "Execute" pos:[7,270] width:386 height:53
button exportAnim "Export Animation" pos:[125,287] width:150 height:25

label credits "Zteam - CtrlAltDestroy" pos:[8,326] width:103 height:13 enabled:false

fn calcNodeListChecksum =
(
/* not consistent! */
nodeListCheck = 0
for i = 1 to nodeArraySorted.count do
(
nodeCheck = 0
for j = 1 to nodeArraySorted[i].name.count do (nodeCheck += bit.charAsInt nodeArraySorted[i].name[j])
nodeCheck *= (nodeArraySorted.count * (nodeFirstChildIndices[i] + nodeNextSiblingIndices[i]))
nodeListCheck += nodeCheck
)
return nodeListCheck
)

fn flushInstances =
(
frameCount = 0
nodeListChecksum = 0
nodeNames = #()
nodeArray = #()
nodeArraySorted = #()
nodeChildIndices = #()
nodeFirstChildIndices = #()
nodeNextSiblingIndices = #()
rootSceneNode = undefined
)

fn indexNodes =
(
failed = false

try
(
nodeArray = (($'frame*' as array) + ($'bip01*' as array))
nodeArray = for i in nodeArray where (not i.isHidden) collect i
for w = 1 to nodeArray.count do
(
if (nodeArray[w].parent != undefined) then
(
if (((substring nodeArray[w].parent.name 1 5 as name) != ("frame" as name)) and ((substring nodeArray[w].parent.name 1 5 as name) != ("bip01" as name))) then
(
failed = true
exit
)
)
)
if not failed then
(
for i = 1 to nodeArray.count do
(
if (nodeArray[i].parent == undefined) then
(
if (rootSceneNode != undefined) then
(
failed = true
exit
)
else
(
rootSceneNode = nodeArray[i]
nodeArray[i].name = ("01" + nodeArray[i].name)
)
)
else
(
tempParentNode = nodeArray[i].parent
n = 1
do
(
tempRootSceneNode = tempParentNode
tempParentNode = tempParentNode.parent
n += 1
)
while (tempParentNode != undefined)

if (tempRootSceneNode != rootSceneNode) then
(
failed = true
exit
)
else
(
if n < 10 then (nodeArray[i].name = ("0" + (n as string) + nodeArray[i].name))
else (nodeArray[i].name = ((n as string) + nodeArray[i].name))
)
)
)
if not failed then
(
nodeNames = for j in nodeArray collect j.name
sort nodeNames
for k = 1 to nodeArray.count do (nodeArraySorted[k] = getNodeByName nodeNames[k])
for h = 1 to nodeArray.count do (nodeArray[h].name = (substring nodeArray[h].name 3 -1))
nodeNames = for j in nodeArray collect j.name

for b = 1 to nodeArraySorted.count do
(
tempNodeChildIndices = #()
for c = 1 to nodeArraySorted[b].children.count do
(
tempNodeChild = nodeArraySorted[b].children[c]
if (tempNodeChild != undefined) then
(
tempChildIndex = findItem nodeArraySorted tempNodeChild
if (tempChildIndex != 0) then (append tempNodeChildIndices tempChildIndex)
)
)
nodeChildIndices[b] = tempNodeChildIndices
if (nodeChildIndices[b].count == 0) then (nodeFirstChildIndices[b] = 0)
else
(
sort nodeChildIndices[b]
nodeFirstChildIndices[b] = nodeChildIndices[b][1]
)
)

nodeNextSiblingIndices[1] = 0
for s = 1 to nodeChildIndices.count do
(
if ((nodeChildIndices[s].count < 2) and (nodeChildIndices[s][1] != undefined)) then (nodeNextSiblingIndices[nodeChildIndices[s][1]] = 0)
else
(
for f = 1 to nodeChildIndices[s].count do
(
if (f == nodeChildIndices[s].count) then (nodeNextSiblingIndices[nodeChildIndices[s][f]] = 0)
else (nodeNextSiblingIndices[nodeChildIndices[s][f]] = nodeChildIndices[s][f + 1])
)
)
)
)
)
if failed then
(
for i in nodeArray do
(
if (((substring i.name 1 5 as name) != ("frame" as name)) and ((substring i.name 1 5 as name) != ("bip01" as name))) then (i.name = (substring i.name 3 -1))
nodeNames = #()
nodeArraySorted = #()
)
)

)
catch
(
failed = true
)

return failed
)

fn writeAnim target =
(
frameCount = ((animationRange.end - animationRange.start) as integer/160) + 1
nodeListChecksum = calcNodeListChecksum()

format "%\n" 16392 to:target
format "%\n" frameCount to:target
format "%\n" frameRate to:target
format "%\n" 1 to:target
format "%\n" "unnamedActor" to:target
format "%\n" nodeArraySorted.count to:target
format "%\n" nodeListChecksum to:target

for i = 1 to nodeArraySorted.count do
(
format "%\n" nodeArraySorted[i].name to:target
format "%\n" (nodeFirstChildIndices[i] - 1) to:target
format "%\n" (nodeNextSiblingIndices[i] - 1) to:target
)

tempNodes = #()
for a = 1 to nodeArraySorted.count do
(
tempNode = Box length:0.5 width:0.5 height:0.5
tempNode.name = ("temp__" + nodeArraySorted[a].name)
tempNode.wirecolor = color 255 0 0
tempNodes[a] = tempNode
)
for b = 1 to tempNodes.count do
(
try (tempNodes[b].parent = tempNodes[(findItem nodeArraySorted nodeArraySorted[b].parent)])
catch ()
)

max tool animmode
set animate on

sliderTime = animationRange.start
for j = 1 to frameCount do
(
for d = 1 to tempNodes.count do (tempNodes[d].transform = nodeArraySorted[d].transform)
for k = 1 to nodeArraySorted.count do
(
in coordsys parent nodePosition = tempNodes[k].pos
in coordsys parent tempNodeRotation = tempNodes[k].rotation
nodeRotation = quat -tempNodeRotation.x -tempNodeRotation.y -tempNodeRotation.z tempNodeRotation.w
in coordsys parent nodeScale = (tempNodes[k].scale.x + tempNodes[k].scale.y + tempNodes[k].scale.z)/3

format "%\t%\t%\n" nodePosition.x nodePosition.y nodePosition.z to:target
format "%\t%\t%\t%\n" nodeRotation.x nodeRotation.y nodeRotation.z nodeRotation.w to:target
format "%\n" nodeScale to:target
)
if (j != (animationRange.start + frameCount)) do (sliderTime += 1)
)
format "\n// exported with zteam animation exporter\n\n" to:target

max tool animmode
set animate off
try (delete tempNodes)
catch ()
tempNodes = #()

sliderTime = animationRange.start
)

fn exportSingleAnim target =
(
outputFile = createFile target
flushInstances ()
failed = indexNodes ()
if not failed then (writeAnim outputFile)
flushInstances ()
try (close outputFile)
catch ()
)

fn exportAllAnims =
(
try
(
messageStream = stringStream ""
format "%" "Done." to:messageStream
for i in animExportQueue.listItems where i.checked do
(
if (i.index != 1) then (valid = loadMaxFile i.tag quiet:true)
else (valid = true)
if valid then
(
if (saveMethod.state == 1) then
(
if (maxFilePath == "") then (dirPart = trimRight (getDir #scene) "\\")
else (dirPart = trimRight maxFilePath "\\")
)
else (dirPart = trimRight saveDir "\\")
if (maxFileName == "") then (namePart = "z_scene_animation")
else (namePart = getFilenameFile maxFileName)
typePart = i.listSubItems[1].text

if ((getFiles (dirPart + "\\" + namePart + "." + typePart)).count < 1) then (savePath = (dirPart + "\\" + namePart + "." + typePart))
else
(
suffix = 0
while ((getFiles (dirPart + "\\" + namePart + suffix as string + "." + typePart)).count > 0) do (suffix += 1)
savePath = (dirPart + "\\" + namePart + suffix as string + "." + typePart)

format "\n\nAnimation #% had a conflicting filename.\n" i.index to:messageStream
format "It was saved as %" (filenameFromPath savePath) to:messageStream
)

if ((maxFilePath == "") and (maxFileName == "")) then
(
if (saveMethod.state == 1) then
(
format "\n\nAnimation #% did not have an initial filepath.\n" i.index to:messageStream
format "It was saved as % in %" (filenameFromPath savePath) (getFilenamePath savePath) to:messageStream
)
else
(
format "\n\nAnimation #% did not have an initial filename.\n" i.index to:messageStream
format "It was saved as %" (filenameFromPath savePath) to:messageStream
)
)


exportSingleAnim savePath
)
)
messageBox (messageStream as string) title:"Done"
)
catch (messageBox "Export failed." title:"Failed")
)

fn adjustQueue =
(
if (animExportQueue.listItems.count > 8) then (animExportQueue.columnHeaders[1].width = 8750)
else (animExportQueue.columnHeaders[1].width = 9175)
checkedCount = 0
for i in animExportQueue.listItems do
(
if i.checked then
(
checkedCount += 1
i.text = (checkedCount as string + ". " + getFilenameFile i.tag)
)
else (i.text = getFilenameFile i.tag)
)
if (checkedCount > 1) then (exportAnim.caption = "Export Animations")
else
(
exportAnim.caption = "Export Animation"
if (checkedCount < 1) then (exportAnim.enabled = false)
else (exportAnim.enabled = true)
)
)

fn addQueueItem scenePath =
(
animExportQueue.listItems.add ()
animExportQueue.listItems[animExportQueue.listItems.count].tag = scenePath
animExportQueue.listItems[animExportQueue.listItems.count].text = getFilenameFile scenePath
animExportQueue.listItems[animExportQueue.listItems.count].checked = true
animExportQueue.listItems[animExportQueue.listItems.count].listSubItems.add ()
animExportQueue.listItems[animExportQueue.listItems.count].listSubItems[1].text = (substring animType.selected 1 3)
animExportQueue.listItems[animExportQueue.listItems.count].listSubItems[1].tag = animType.selection
adjustQueue ()
)

fn removeQueueItemsUnchecked =
(
for i in animExportQueue.listItems where (not i.checked and (i.index != 1)) do (animExportQueue.listItems.remove i.index)
adjustQueue ()
)

fn addFile =
(
scenePath = getOpenFileName caption:"Add MAX Scene" \
filename:lastPath \
types:"MAX Scene (*.MAX)|*.MAX|"
if (scenePath != undefined) then (addQueueItem scenePath)
)

fn addDir =
(
sceneDir = getSavePath caption:"Add MAX Scenes from Directroy" initialDir:lastPath
if (sceneDir != undefined) then
(
scenePaths = getFiles (sceneDir + "\\*.MAX")
for i in scenePaths do (addQueueItem i)
)
)

fn clearSaveDir =
(
saveDir = undefined
saveDirText.text = ""
saveDirClear.enabled = false
)

fn pickSaveDir =
(
clearSaveDir ()
saveDir = getSavePath caption:"Pick Output File Directory" initialDir:lastPath
if (saveDir != undefined) then
(
saveDirText.text = saveDir
saveDirClear.enabled = true
)
else (clearSaveDir ())
)

fn populateQueue =
(
animExportQueue.checkboxes = true
animExportQueue.fullRowSelect = true
animExportQueue.gridLines = true
animExportQueue.appearance = #ccFlat
animExportQueue.view = #lvwReport
animExportQueue.labelEdit = #lvwManual
animExportQueue.columnHeaders.add ()
animExportQueue.columnHeaders[1].text = "Queue"
animExportQueue.columnHeaders[1].width = 9175
animExportQueue.columnHeaders.add ()
animExportQueue.columnHeaders[2].text = "Type"
animExportQueue.columnHeaders[2].width = 1000
addQueueItem "Current Scene Animation"
)

on animExporter open do
(
populateQueue ()
)
on animRemoveUnchecked pressed do (removeQueueItemsUnchecked ())
on animAddFile pressed do (addFile ())
on animAddFolder pressed do (addDir ())
on animExportQueue itemClick item do (animType.selection = item.listSubItems[1].tag)
on animExportQueue itemCheck item do (adjustQueue ())
on animType selected element do
(
animExporter.animExportQueue.selectedItem.listSubI tems[1].text = (substring animType.selected 1 3)
animExporter.animExportQueue.selectedItem.listSubI tems[1].tag = element
)
on saveMethod changed state do
(
if (state == 1) then
(
saveDirPick.enabled = false
saveDirClear.enabled = false
)
else
(
saveDirPick.enabled = true
saveDirClear.enabled = (saveDir != undefined)
)
)
on saveDirPick pressed do (pickSaveDir ())
on saveDirClear pressed do (clearSaveDir ())
on exportAnim pressed do (exportAllAnims ())
)

createDialog animExporter

Enjoy.

Delta4907
September 16th, 2008, 06:01 PM
You.........are.........awesome. +rep

CtrlAltDestroy
September 16th, 2008, 06:07 PM
Also, if you did want to rename all the nodes:


nodePrfx = "ValveBiped.Bip01" -- we define the node prefix we wish to replace
nodePrfxRplc = "frame" -- we define the string we wish to replace the prefix with

execute ("select $'" + nodePrfx + "*'") -- we can use the execute method to select every instance of a node with the prefix
nodeArray = $selection as array -- we take the node selection and store it as an array
for i = 1 to nodeArray.count do -- we loop through the array we created
(
tempname = nodeArray[i].name -- we store the node name we're going to use
namePostfix = substring tempname (nodePrfx.count + 1) -1 -- we get the part of the node name that is after the prefix, including the whitespace between
newName = nodePrfxRplc + namePostfix -- we construct the new node name based on the specified new prefix and postfix from above
nodeArray[i].name = newName -- we assign the new name back to the node
)

Commented for easy understanding. :)

Zeph
September 16th, 2008, 06:34 PM
Did you just take the time to write that or did you just copy/paste it from somewhere?

jngrow
September 16th, 2008, 06:38 PM
Yeah, cus holy shit if so.

CtrlAltDestroy
September 16th, 2008, 06:45 PM
If youre talking about the first script, it's simply the source to a script i released a few months ago.

Delta4907
September 16th, 2008, 06:51 PM
Question: I just realized that the bones have underscores (_) instead of spaces, would this affect anything? By this I mean the bones are ValveBiped.Bip01_L_Upperarm, instead of ValveBiped.Bip01 L Upperarm.

CtrlAltDestroy
September 16th, 2008, 06:58 PM
It shouldn't affect anything.

Delta4907
September 16th, 2008, 07:35 PM
I must've done something wrong, whenever i extract the animations it saves the jma with 0 KB, obviously I edited the script wrong.

CtrlAltDestroy
September 16th, 2008, 07:43 PM
I would get rid of the try()catch() statements for debugging.

Delta4907
September 16th, 2008, 08:52 PM
.

Delta4907
September 18th, 2008, 02:40 PM
.

Delta4907
September 18th, 2008, 04:13 PM
.

Choking Victim
September 18th, 2008, 04:27 PM
Post one more time, I don't understand.

Delta4907
September 18th, 2008, 07:24 PM
Wow im sorry, every time I came to the topic it said the last message was the first time I said it. I didnt mean to post that many times. My bad.



I would get rid of the try()catch() statements for debugging.

Ok I'll try that.

Delta4907
September 19th, 2008, 07:48 PM
Darn, it didn't even play the animation in the viewport upon extraction this time, just says Done, then saves the jma with 0 kb.

Zeph
September 19th, 2008, 07:53 PM
Yeah, cus holy shit if so.

No, not really. If you know scripting, it's easy to spit out. I was just going to be surprised he just put it up in quote tags instead of just linking a source file or something.

Delta4907
September 21st, 2008, 04:07 PM
My friend told me just changing the bip01 names in the Max Script to ValveBiped.Bip01 would make 3dsmax extract whatever with that name. I guess that didn't work because like I said:


just says Done, then saves the jma with 0 kb.

So is there anything else I have to change other than swapping bip01 with ValveBiped.Bip01?