1123 lines
32 KiB
Plaintext
Executable File
1123 lines
32 KiB
Plaintext
Executable File
-- Fragment tuning glabals
|
|
filein "rockstar/export/settings.ms"
|
|
filein "pipeline/helpers/physics.ms"
|
|
filein "pipeline/util/xml.ms"
|
|
|
|
global gFragEditMode = #default
|
|
global gCpyChildren = false
|
|
|
|
global gReloadFileMode = true
|
|
global gPrvntCollSel = true
|
|
global copyPasteErrors = ""
|
|
|
|
global gPresetElem = undefined
|
|
|
|
fn getPresetNames =
|
|
(
|
|
local presetNames = #("none")
|
|
|
|
local xmlDoc = XmlDocument()
|
|
xmlDoc.load (RsProjectGetCommonDir() + "/data/fragment.xml")
|
|
xmlDoc.ParseIntoMaxscripthierarchy()
|
|
gPresetElem = xmlDoc.maxXmlObject.children[2].findChild withName:"BreakPresets"
|
|
if undefined!=gPresetElem then
|
|
for presetItem in gPresetElem.children do
|
|
(
|
|
local nameChild = presetItem.children[1]
|
|
append presetNames nameChild.textValue
|
|
)
|
|
return presetNames
|
|
)
|
|
|
|
fn updatePresetProps theRollout presetName groupName =
|
|
(
|
|
if undefined==theRollout or undefined==gPresetElem then
|
|
return false
|
|
|
|
local thePreset = undefined
|
|
for presetItem in gPresetElem.children while undefined==thePreset do
|
|
(
|
|
local nameChild = presetItem.children[1]
|
|
if nameChild.textValue==presetName then
|
|
(
|
|
thePreset = presetItem
|
|
)
|
|
)
|
|
if undefined!=thePreset then
|
|
(
|
|
for presetProp in thePreset.children do
|
|
(
|
|
-- first the control
|
|
local theControl = undefined
|
|
for ctrl in theRollout.controls while undefined==theControl do
|
|
(
|
|
if 0!=findItem #(GroupStartControl, GroupEndControl) (classof ctrl) then
|
|
continue
|
|
if (0==stricmp ctrl.name presetProp.tagname) then
|
|
theControl = ctrl
|
|
)
|
|
if undefined!=theControl then
|
|
(
|
|
try
|
|
(
|
|
theControl.value = (presetProp.attrs.item "value") as float
|
|
case classof theControl of
|
|
(
|
|
SpinnerControl:theControl.changed theControl.value
|
|
CheckboxControl:theControl.changed theControl.value
|
|
)
|
|
)
|
|
catch
|
|
(
|
|
print (getCurrentException())
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
struct sRsFragAttribLUT
|
|
(
|
|
------------------------------------------------------------------------
|
|
-- FRAG ATTRIBS
|
|
------------------------------------------------------------------------
|
|
-- identifier --standard export --readable name -default value selection-data change-callback
|
|
RsFragAttribLUT = #(
|
|
#("minMoveForce", true, "Min force to move me", 0),
|
|
#("artAssetID", true, undefined, -1),
|
|
#("attachBottomEnd", true, undefined, 0),
|
|
#("estimatedCacheSize", true, undefined, 0),
|
|
#("estimatedArticulatedCacheSize", true, undefined, 0),
|
|
#("cloneBoundPartsInCache", true, undefined, 0),
|
|
#("unbrokenCGOffset", true, undefined, #(0,0,0)),
|
|
#("unbrokenElasticity", true, "Unbroken elasticity", 0),
|
|
#("gravityFactor", true, undefined, 1.0),
|
|
#("buoyancyFactor", true, undefined, 1.0),
|
|
#("breakImpulseSourceTypeFlags", true, undefined, 0),
|
|
#("dampingLinearC", true, undefined, #(0.02,0.02,0.02)),
|
|
#("dampingLinearV", true, undefined, #(0.02,0.02,0.02)),
|
|
#("dampingLinearV2", true, undefined, #(0.01,0.01,0.01)),
|
|
#("dampingAngularC", true, undefined, #(0.02,0.02,0.02)),
|
|
#("dampingAngularV", true, undefined, #(0.02,0.02,0.02)),
|
|
#("dampingAngularV2", true, undefined, #(0.01,0.01,0.01)),
|
|
#("selfCollisionCount", true, undefined, 0)
|
|
),
|
|
------------------------------------------------------------------------
|
|
-- GROUP ATTRIBS
|
|
------------------------------------------------------------------------
|
|
RsGroupAttribLUT = #(
|
|
#("strength", true, "Break Strength", 100.0),
|
|
#("forceTransmissionScaleUp", true, "ForceTransmission Up", 0.25),
|
|
#("forceTransmissionScaleDown", true, "ForceTransmission Down", 0.25),
|
|
#("jointStiffness", true, undefined, 0),
|
|
#("minSoftAngle1", true, undefined, -1),
|
|
#("maxSoftAngle1", true, undefined, 1),
|
|
#("maxSoftAngle2", true, undefined, 1),
|
|
#("maxSoftAngle3", true, undefined, 1),
|
|
#("rotationSpeed", true, undefined, 0),
|
|
#("rotationStrength", true, undefined, 0),
|
|
#("restoringStrength", true, undefined, 0),
|
|
#("restoringMaxTorque", true, undefined, 0),
|
|
#("latchStrength", true, "Contraint latch strength", 0),
|
|
#("disappearsWhenDead", true, "Disappear when dead", false),
|
|
#("madeOfGlass", true, "Made of glass", false),
|
|
#("minDamageForce", true, "MinDamage force", 0),
|
|
#("damageHealth", true, "Intial damage health", 0),
|
|
#("weaponHealth", true, "Weapon health", 0),
|
|
#("weaponScale", true, "Weapons", 1.0),
|
|
#("vehicleScale", true, "Vehicles", 1.0),
|
|
#("pedScale", true, "Peds", 1.0),
|
|
#("ragdollScale", true, "Ragdolls", 1.0),
|
|
#("explosionScale", true, "Explosions", 1.0),
|
|
#("objectScale", true, "Objects", 1.0),
|
|
#("preset", true, "Preset", "none", ::getPresetNames, "updatePresetProps")
|
|
),
|
|
------------------------------------------------------------------------
|
|
-- CHILD ATTRIBS
|
|
------------------------------------------------------------------------
|
|
RsChildAttribLUT = #(
|
|
#("pristineMass", true, "Pristine mass", calculateMass),
|
|
#("damagedMass", true, "Damaged mass", calculateMass)
|
|
),
|
|
RsAttribLUT = RsFragAttribLUT + RsGroupAttribLUT + RsChildAttribLUT,
|
|
|
|
-- accessors
|
|
fn getDefault key =
|
|
(
|
|
for tuple in RsAttribLUT do
|
|
(
|
|
if (tuple[1]==key) then return tuple[3]
|
|
)
|
|
return undefined
|
|
),
|
|
fn getDefaultExport key =
|
|
(
|
|
for tuple in RsAttribLUT do
|
|
(
|
|
if (tuple[1]==key) then return tuple[2]
|
|
)
|
|
return false
|
|
),
|
|
fn getDataFunc key =
|
|
(
|
|
for tuple in RsAttribLUT do
|
|
(
|
|
if (tuple[1]==key) then return tuple[5]
|
|
)
|
|
return undefined
|
|
),
|
|
fn getCallback key =
|
|
(
|
|
for tuple in RsAttribLUT do
|
|
(
|
|
if (tuple[1]==key) then return tuple[6]
|
|
)
|
|
return undefined
|
|
),
|
|
fn getValue key =
|
|
(
|
|
if gFragEditMode==#verbose then return key
|
|
for tuple in RsAttribLUT do
|
|
(
|
|
if (tuple[1]==key) then
|
|
(
|
|
return tuple[3]
|
|
)
|
|
)
|
|
return undefined
|
|
)
|
|
)
|
|
global gRsFragAttribLUT = sRsFragAttribLUT()
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- data holding/processing structs
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
struct sFragGroup
|
|
(
|
|
groupName = "fragments",
|
|
parentGroup = undefined,
|
|
groupValues = #(),
|
|
groupArray = #(),
|
|
childArray = #()
|
|
)
|
|
struct sFragChild
|
|
(
|
|
childName = "dummyname",
|
|
parentGroup = undefined,
|
|
childValues = #()
|
|
)
|
|
|
|
#typeBool
|
|
#typeScalar
|
|
#typeArray
|
|
#typeString
|
|
#typeScope
|
|
struct sAttrValue
|
|
(
|
|
attrName,
|
|
attrValue,
|
|
attrType,
|
|
attrExportFlag = false,
|
|
fn copyme =
|
|
(
|
|
local newOne = sAttrValue()
|
|
newOne.attrName = attrName
|
|
newOne.attrValue = attrValue
|
|
newOne.attrType = attrType
|
|
newOne.attrExportFlag = attrExportFlag
|
|
return newOne
|
|
)
|
|
)
|
|
struct sFragTuner
|
|
(
|
|
tuneArray = #(),
|
|
|
|
currFrag = 0.0,
|
|
currFragName = "initial",
|
|
currFragRoot = sFragGroup(),
|
|
currFragGroup = currFragRoot,
|
|
currObj,
|
|
|
|
copyFragHier = undefined,
|
|
|
|
childObj,
|
|
groupObj,
|
|
fragObj,
|
|
|
|
isFrag,
|
|
isGroup,
|
|
|
|
currHirarchyErrors = "",
|
|
|
|
-- fn RsTrimAndChopLine idx currLine = (
|
|
-- filteredLine = filterstring currLine " "
|
|
--
|
|
-- if filteredLine[idx] != undefined then (
|
|
-- --currTrimLine = RsGetTrimParamFromString filteredLine[idx]
|
|
-- currLine = RsRemoveSpacesFromString filteredLine[idx]
|
|
-- currLine = RsRemoveTabsFromString currLine
|
|
-- )
|
|
--
|
|
-- return currLine
|
|
-- ),
|
|
|
|
-- fn RsGetTrimParamFromString currLine = (
|
|
--
|
|
-- currLine = RsRemoveSpacesFromString currLine
|
|
-- currLine = RsRemoveTabsFromString currLine
|
|
--
|
|
-- return currLine
|
|
-- ),
|
|
|
|
fn SetReloadFileMode val =
|
|
(
|
|
gReloadFileMode = val
|
|
if undefined!=::RsButtonRoll then
|
|
(
|
|
::RsButtonRoll.checkReloadFile.checked = val
|
|
)
|
|
),
|
|
|
|
fn ResetFragTune =
|
|
(
|
|
currHirarchyErrors = undefined
|
|
currFragRoot = sFragGroup()
|
|
currFragGroup = currFragRoot
|
|
currFragname = ""
|
|
SetReloadFileMode true
|
|
),
|
|
|
|
fn GetTunePath =
|
|
(
|
|
RsConfigGetAssetsDir() + "fragments/" + currFragName + ".tune"
|
|
),
|
|
|
|
fn RetrieveIndentation obj = (
|
|
indentation = 1
|
|
while classof(obj.parent) != UndefinedClass do (
|
|
obj = obj.parent
|
|
indentation = indentation + 1
|
|
)
|
|
return indentation + 1
|
|
),
|
|
|
|
fn isObjInCurrHierarchy obj =
|
|
(
|
|
do
|
|
(
|
|
if (matchpattern obj.name pattern:("*"+currFragName+"*")) then
|
|
return true
|
|
obj = obj.parent
|
|
) while undefined!=obj
|
|
return false
|
|
),
|
|
|
|
--------------------------------------------------------------------------
|
|
-- Extract hierarchical information from selected object
|
|
--------------------------------------------------------------------------
|
|
fn DetermineObject = (
|
|
isFrag = false
|
|
isGroup = false
|
|
|
|
sel = selection as array
|
|
obj = sel[1]
|
|
|
|
if obj != Undefined then (
|
|
if "GtaObject"==(getattrclass obj) or Point == (classof obj) and obj.parent != undefined then (
|
|
groupObj = obj
|
|
isGroup = true
|
|
groupName = obj.name
|
|
)
|
|
else if "GtaObject"==(getattrclass obj) then (
|
|
fragIndex = getattrindex "Gta Object" "Is Fragment"
|
|
if getattr obj fragIndex == true then (
|
|
isFrag = true
|
|
isGroup = false
|
|
)
|
|
)
|
|
|
|
-- get the absolute parent
|
|
while classof(obj.parent) != UndefinedClass do (
|
|
obj = obj.parent
|
|
)
|
|
|
|
fragObjName = tolower obj.name
|
|
|
|
-- Get rid of any of the skinned helper nodes
|
|
if matchPattern fragObjName pattern:"dummy_*" then
|
|
fragObjName = substring fragObjName 7 fragObjName.count
|
|
if matchPattern fragObjName pattern:"mover_*" then
|
|
fragObjName = substring fragObjName 7 fragObjName.count
|
|
if matchPattern fragObjName pattern:"root_*" then
|
|
fragObjName = substring fragObjName 7 fragObjName.count
|
|
if matchPattern fragObjName pattern:"main_*" then
|
|
fragObjName = substring fragObjName 7 fragObjName.count
|
|
|
|
--getting rid of suffix
|
|
local fragStringIndex = findString fragObjName "_frag_"
|
|
if fragStringIndex!=undefined then
|
|
fragObjName = substring fragObjName 1 (fragStringIndex-1)
|
|
|
|
currFragName = fragObjName
|
|
)
|
|
),
|
|
|
|
fn dumpGroup theGroup theFile indentDepth isRoot =
|
|
(
|
|
local indent = ""
|
|
local borderindent = ""
|
|
local i=0
|
|
while i<indentDepth do
|
|
(
|
|
borderindent+="\t"
|
|
i+=1
|
|
)
|
|
i=0
|
|
while i<indentDepth+1 do
|
|
(
|
|
indent+="\t"
|
|
i+=1
|
|
)
|
|
if isRoot then
|
|
format ("fragments\n{\n") to:theFile
|
|
else
|
|
format (borderindent+"group "+theGroup.groupName+"\t\t\t{\n") to:theFile
|
|
for val in theGroup.groupValues where val.attrExportFlag do
|
|
(
|
|
case val.attrType of
|
|
(
|
|
#typeScalar:
|
|
(
|
|
if (findString val.attrName "Mass")!=undefined then
|
|
format (indent+val.attrName+" all\t"+(val.attrValue as string)+"\n") to:theFile
|
|
else
|
|
format (indent+val.attrName+"\t"+(val.attrValue as string)+"\n") to:theFile
|
|
)
|
|
#typeArray:
|
|
(
|
|
format (indent+val.attrName+"\t"+(val.attrValue[1] as string)+"\t"+(val.attrValue[2] as string)+"\t"+(val.attrValue[3] as string)+"\n") to:theFile
|
|
)
|
|
#typeBool:
|
|
(
|
|
if val.attrValue then
|
|
format (indent+val.attrName+"\n") to:theFile
|
|
)
|
|
#typeString:
|
|
(
|
|
if undefined!=val.attrValue then
|
|
format (indent+val.attrName+"\t<"+(val.attrValue as string)+">\n") to:theFile
|
|
)
|
|
)
|
|
)
|
|
for c in theGroup.childArray do
|
|
(
|
|
format (indent+"child\t\t\t\t{\n") to:theFile
|
|
local childIndent = ""
|
|
i=0
|
|
while i<indentDepth+2 do
|
|
(
|
|
childIndent+="\t"
|
|
i+=1
|
|
)
|
|
for val in c.childvalues where val.attrExportFlag do
|
|
(
|
|
case val.attrType of
|
|
(
|
|
#typeScalar:
|
|
(
|
|
if (findString val.attrName "Mass")!=undefined then
|
|
format (childIndent+val.attrName+" all\t"+(val.attrValue as string)+"\n") to:theFile
|
|
else
|
|
format (childIndent+val.attrName+"\t"+(val.attrValue as string)+"\n") to:theFile
|
|
)
|
|
#typeArray:
|
|
(
|
|
format (childIndent+val.attrName+"\t"+(val.attrValue[1] as string)+"\t"+(val.attrValue[2] as string)+"\t"+(val.attrValue[3] as string)+"\n") to:theFile
|
|
)
|
|
#typeString:
|
|
(
|
|
if undefined!=val.attrValue then
|
|
format (indent+val.attrName+"\t<"+(val.attrValue as string)+">\n") to:theFile
|
|
)
|
|
)
|
|
)
|
|
format (indent+"}\n") to:theFile
|
|
)
|
|
for grp in theGroup.groupArray do
|
|
(
|
|
dumpGroup grp theFile (indentDepth+1) false
|
|
)
|
|
format (borderindent+"}\n") to:theFile
|
|
),
|
|
|
|
fn WriteOutAttrib tunePath = (
|
|
sel = selection as array
|
|
|
|
try
|
|
(
|
|
|
|
if tunePath != "" then (
|
|
tuneFile = openFile tunePath mode:"w+"
|
|
|
|
gRsPerforce.add_or_edit tunePath
|
|
|
|
if tuneFile != undefined and sel != undefined then
|
|
(
|
|
dumpGroup currFragRoot tuneFile 0 true
|
|
close tuneFile
|
|
SetReloadFileMode true
|
|
return true
|
|
)
|
|
messagebox ("Error writing to " + tunePath + ". Check to see file is writable.")
|
|
close tuneFile
|
|
return false
|
|
--commandLine = "attrib +r " + tunePath
|
|
--doscommand commandLine
|
|
)
|
|
messagebox "no valid path"
|
|
close tuneFile
|
|
)
|
|
catch(
|
|
messagebox ("Fragment save error: "+getCurrentException())
|
|
)
|
|
return false
|
|
),
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Parsing attributes
|
|
--------------------------------------------------------------------------------------------------------------------------------------------------
|
|
fn ParseNextSubString str =
|
|
(
|
|
if str[1]=="<" then
|
|
return #(substring str 2 (str.count-2))
|
|
--find first intersector
|
|
local intersector = " "
|
|
local firstWhite = findString str " "
|
|
local firstTab = findString str "\t"
|
|
if firstWhite==undefined or (firstTab!=undefined and firstTab<firstWhite) then
|
|
intersector = "\t"
|
|
back = filterstring str intersector
|
|
|
|
-- local found = false
|
|
-- look for tag brackets
|
|
-- for i=1 to back.count where matchpattern back[i] pattern:"<*" while not found do
|
|
-- (
|
|
-- back[i] = substring back[i] 2 back[i].count
|
|
-- -- join them together
|
|
-- local ended = false
|
|
-- while not ended do
|
|
-- (
|
|
-- back[i] = join back[i] back[i+1]
|
|
-- if matchpattern back[i+1] pattern:"*>*" then
|
|
-- ended = true
|
|
-- deleteItem back (i=1)
|
|
-- )
|
|
-- found = true
|
|
-- )
|
|
return back
|
|
),
|
|
fn ParseNameAndValueFromString str =
|
|
(
|
|
while str[1]=="\t" or str[1]==" " do str = substring str 2 str.count
|
|
back = sAttrValue()
|
|
|
|
-- parse name
|
|
local nameParseStep = ParseNextSubString str
|
|
back.attrName = nameParseStep[1]
|
|
|
|
-- parse Value
|
|
back.attrValue = undefined
|
|
back.attrType = #typeScope
|
|
if nameParseStep[2]!=undefined then
|
|
(
|
|
local valueParseStep = ParseNextSubString (substring str (nameParseStep[1].count+2) str.count)
|
|
if valueParseStep.count>0 then
|
|
(
|
|
if (valueParseStep[1] as number)!=undefined then
|
|
(
|
|
if valueParseStep.count>1 then
|
|
(
|
|
back.attrType = #typeArray
|
|
back.attrValue = valueParseStep
|
|
)
|
|
else
|
|
(
|
|
back.attrType = #typeScalar
|
|
back.attrValue = valueParseStep[1]
|
|
)
|
|
)
|
|
else
|
|
(
|
|
if valueParseStep.count>1 and valueParseStep[1]=="all" then -- masses on children have the all suffix
|
|
(
|
|
back.attrType = #typeScalar
|
|
back.attrValue = valueParseStep[2]
|
|
)
|
|
else
|
|
(
|
|
back.attrType = #typeString
|
|
back.attrValue = valueParseStep[1]
|
|
)
|
|
)
|
|
)
|
|
)
|
|
else
|
|
(
|
|
back.attrType = #typeBool
|
|
back.attrValue =true
|
|
)
|
|
back.attrExportFlag = true
|
|
return back
|
|
),
|
|
|
|
--------------------------------------------------------------------------
|
|
-- Stream in tune data
|
|
--------------------------------------------------------------------------
|
|
fn ReadInAttrib tunePath = (
|
|
local currScope = #("root")
|
|
|
|
sel = selection as array
|
|
currObj = sel[1]
|
|
|
|
tuneFile = openFile tunePath
|
|
local addedGroupValues = #()
|
|
if tuneFile != undefined then
|
|
(
|
|
while eof tuneFile == false do (
|
|
currentLine = readLine tuneFile
|
|
-- remove trailing spaces
|
|
local nameAndValueTuple = ParseNameAndValueFromString currentLine
|
|
prefix = nameAndValueTuple.attrName
|
|
value = nameAndValueTuple.attrValue
|
|
|
|
if prefix == "}" then
|
|
(
|
|
if currScope.count>0 then
|
|
(
|
|
if currScope[currScope.count]=="groupScope" then
|
|
(
|
|
for groupVal in gRsFragAttribLUT.RsGroupAttribLUT do
|
|
(
|
|
if 0== (for v in currFragGroup.groupValues where v.attrName==groupVal[1] collect v).count then
|
|
(
|
|
local defaultNameAndValueTuple = sAttrValue attrName:groupVal[1] attrValue:groupVal[4] attrExportFlag:false
|
|
if (classof groupVal[4] == number) then defaultNameAndValueTuple.attrType = #typeScalar
|
|
else if (classof groupVal[4] == booleanclass) then defaultNameAndValueTuple.attrType = #typeBool
|
|
else if (classof groupVal[4] == array) then defaultNameAndValueTuple.attrType = #typeArray
|
|
else if (classof groupVal[4] == string) then defaultNameAndValueTuple.attrType = #typeString
|
|
append currFragGroup.groupValues defaultNameAndValueTuple
|
|
)
|
|
)
|
|
addedGroupValues = #()
|
|
|
|
currFragGroup = currFragGroup.parentGroup
|
|
)
|
|
deleteItem currScope currScope.count
|
|
)
|
|
-- try( print ("< "+currScope[currScope.count]+", "+(currScope.count as string)) )catch()
|
|
continue
|
|
)
|
|
else if prefix == "group" then
|
|
(
|
|
groupName = value
|
|
append currScope "groupScope"
|
|
|
|
local formerFragGroup = currFragGroup
|
|
currFragGroup = sFragGroup()
|
|
currFragGroup.parentGroup = formerFragGroup
|
|
currFragGroup.groupName = groupName
|
|
|
|
append formerFragGroup.groupArray currFragGroup
|
|
)
|
|
else if prefix == "child" then
|
|
(
|
|
currChild = sFragChild()
|
|
append currScope "childScope"
|
|
|
|
currentLine = readLine tuneFile
|
|
local nameAndValueTuple = ParseNameAndValueFromString currentLine
|
|
append currChild.childValues nameAndValueTuple
|
|
|
|
currentLine = readLine tuneFile
|
|
local nameAndValueTuple = ParseNameAndValueFromString currentLine
|
|
append currChild.childValues nameAndValueTuple
|
|
|
|
append currFragGroup.childArray currChild
|
|
)
|
|
else if
|
|
not matchPattern prefix pattern:"fragments" and
|
|
not matchPattern prefix pattern:"{" then
|
|
(
|
|
-- tis a value
|
|
append addedGroupValues nameAndValueTuple.attrName
|
|
append currFragGroup.groupValues nameAndValueTuple
|
|
)
|
|
)
|
|
close tuneFile
|
|
return true
|
|
)
|
|
else
|
|
return false
|
|
),
|
|
|
|
--------------------------------------------------------------------------
|
|
-- Create the tune hierarchy to show from actual scene data
|
|
--------------------------------------------------------------------------
|
|
fn ParseNameAndValueFromDefault val obj =
|
|
(
|
|
back = sAttrValue()
|
|
|
|
back.attrName = val[1]
|
|
|
|
back.attrValue = val[4]
|
|
if MAXScriptFunction == (classof back.attrValue) then
|
|
back.attrValue = back.attrValue(obj)
|
|
back.attrType = \
|
|
if (classof back.attrValue) == BooleanClass then #typeBool \
|
|
else if (superClassOf back.attrValue)==number then #typeScalar \
|
|
else if (classof back.attrValue)==array then #typeArray \
|
|
else #typeString
|
|
|
|
back.attrExportFlag = val[2]
|
|
|
|
return back
|
|
),
|
|
fn createGroup sceneNode =
|
|
(
|
|
local formerFragGroup = currFragGroup
|
|
currFragGroup = sFragGroup()
|
|
currFragGroup.parentGroup = formerFragGroup
|
|
currFragGroup.groupName = sceneNode.name
|
|
|
|
if matchPattern currFragGroup.groupName pattern:"*_frag_*" then
|
|
(
|
|
local index = findString currFragGroup.groupName "_frag_"
|
|
currFragGroup.groupName = replace currFragGroup.groupName index 6 ""
|
|
)
|
|
|
|
-- print currFragGroup.groupName
|
|
|
|
if undefined!=formerFragGroup then
|
|
(
|
|
append formerFragGroup.groupArray currFragGroup
|
|
-- print formerFragGroup.groupName
|
|
-- print formerFragGroup.groupArray.count
|
|
)
|
|
|
|
-- create attributes
|
|
for val in gRsFragAttribLUT.RsGroupAttribLUT do
|
|
(
|
|
local nameAndValueTuple = ParseNameAndValueFromDefault val sceneNode
|
|
append currFragGroup.groupValues nameAndValueTuple
|
|
)
|
|
-- bounds data
|
|
local childBounds = for c in sceneNode.children where "Gta Collision"==(getAttrClass c) collect c
|
|
for b in childBounds do
|
|
(
|
|
currChild = sFragChild()
|
|
for val in gRsFragAttribLUT.RsChildAttribLUT do
|
|
(
|
|
local nameAndValueTuple = ParseNameAndValueFromDefault val b
|
|
append currChild.childValues nameAndValueTuple
|
|
)
|
|
append currFragGroup.childArray currChild
|
|
)
|
|
-- child data
|
|
local childMeshes = for c in sceneNode.children where "Gta Object"==(getAttrClass c) or Point == (classof c) collect c
|
|
for c in childMeshes do
|
|
(
|
|
createGroup c
|
|
)
|
|
if undefined!=formerFragGroup then
|
|
currFragGroup = formerFragGroup
|
|
return true
|
|
),
|
|
|
|
fn CreateHierarachyFromNodes saveImmediately:false overWriteIfExistent:false = (
|
|
local obj = selection[1]
|
|
if obj == undefined then
|
|
(
|
|
messagebox "Select an object!"
|
|
return false
|
|
)
|
|
|
|
local fragName = obj.name
|
|
local fragNode = getNodeByName (obj.name+"_frag_")
|
|
local foundRootFragmentBone = false
|
|
if undefined!=fragNode then
|
|
(
|
|
obj = fragNode
|
|
if (undefined != obj.modifiers[#Skin]) then
|
|
(
|
|
rootBone = rexGetSkinRootBone obj
|
|
if rootBone != undefined then
|
|
(
|
|
obj = rootBone
|
|
local mainRootBone = obj.children[1]
|
|
if (mainRootBone != undefined and matchPattern mainRootBone.name pattern:"main_*") then
|
|
(
|
|
obj = mainRootBone.children[1]
|
|
|
|
if (obj == undefined) then messagebox "Frag is not setup correctly with skinning!"
|
|
else foundRootFragmentBone = true
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
-- If we found the root fragment bone then we don't need to try to find the parent in the hierarchy
|
|
if not foundRootFragmentBone then
|
|
(
|
|
while obj.parent != undefined do obj = obj.parent
|
|
)
|
|
select obj
|
|
local tunePath = GetTunePath()
|
|
if doesFileExist tunePath then
|
|
(
|
|
print ("file already exists:"+tunePath)
|
|
if not overWriteIfExistent then
|
|
return false
|
|
)
|
|
|
|
ResetFragTune()
|
|
DetermineObject()
|
|
currFragGroup = sFragGroup()
|
|
currFragGroup.parentGroup = undefined
|
|
currFragGroup.groupName = "root"
|
|
currFragRoot = currFragGroup
|
|
for val in gRsFragAttribLUT.RsFragAttribLUT do
|
|
(
|
|
local nameAndValueTuple = ParseNameAndValueFromDefault val fragNode
|
|
append currFragGroup.groupValues nameAndValueTuple
|
|
)
|
|
print "create hierarchy"
|
|
if not (createGroup obj) then
|
|
return false
|
|
SetReloadFileMode false
|
|
|
|
if saveImmediately then ::gFragTuner.WriteFragTuneData()
|
|
return true
|
|
),
|
|
|
|
|
|
--------------------------------------------------------------------------
|
|
-- Hierarchy manipulation
|
|
--------------------------------------------------------------------------
|
|
fn findGroup root grpName =
|
|
(
|
|
if matchPattern grpName pattern:"*_frag_*" then
|
|
(
|
|
grpName = substring grpName 1 ((findString grpName "_frag_")-1)
|
|
)
|
|
-- if currFragname == grpName then return currFragRoot
|
|
if root.groupName==grpName then return root
|
|
for grp in root.groupArray do
|
|
(
|
|
local back = findGroup grp grpName
|
|
if back != undefined then return back
|
|
)
|
|
return undefined
|
|
),
|
|
fn setGroupValueDirect grp valName newVal arrayIndex:undefined setAllChildren:false =
|
|
(
|
|
if grp!=undefined then
|
|
(
|
|
for val in grp.groupValues do
|
|
(
|
|
if val.attrName==valname then
|
|
(
|
|
-- print (val.attrName+" set to "+newVal as string)
|
|
if arrayindex!=undefined then
|
|
(
|
|
val.attrValue[arrayIndex] = newVal
|
|
)
|
|
else if
|
|
-- Array==(classof val.attrValue) and
|
|
Array==(classof newVal) then
|
|
(
|
|
val.attrValue = deepCopy newVal
|
|
)
|
|
else
|
|
(
|
|
val.attrValue = newVal
|
|
)
|
|
)
|
|
)
|
|
if setAllChildren then
|
|
for g in grp.groupArray do
|
|
setGroupValueDirect g valName newVal arrayIndex:arrayIndex setAllChildren:setAllChildren
|
|
)
|
|
),
|
|
fn setGroupValue grpName valName newVal arrayIndex setAllChildren:false =
|
|
(
|
|
local grp = findGroup currFragRoot grpName
|
|
setGroupValueDirect grp valName newVal arrayIndex:arrayIndex
|
|
),
|
|
fn setGroupExportFlag grpName valName newVal =
|
|
(
|
|
local grp = findGroup currFragRoot grpName
|
|
if grp!=undefined then
|
|
(
|
|
for val in grp.groupValues do
|
|
if val.attrName==valname then
|
|
(
|
|
print (val.attrName+" exportflag set to "+newVal as string)
|
|
val.attrExportFlag = newVal
|
|
)
|
|
)
|
|
),
|
|
fn setChildValueDirect grp childIndex valName newVal =
|
|
(
|
|
childIndex = childIndex as integer
|
|
if grp!=undefined and grp.childArray.count>=childIndex then
|
|
(
|
|
for val in grp.childArray[childIndex].childValues do
|
|
if val.attrName==valname then val.attrValue = newVal
|
|
)
|
|
),
|
|
fn setChildValue grpName childIndex valName newVal =
|
|
(
|
|
local grp = findGroup currFragRoot grpName
|
|
setChildValueDirect grp childIndex valName newVal
|
|
),
|
|
|
|
fn checkGroup theGroup sceneNode =
|
|
(
|
|
-- if theGroup.groupName=="fragments" then
|
|
-- if theGroup.childArray.count != sceneNode then
|
|
|
|
local childMeshes = for c in sceneNode.children where "Gta Object"==(getAttrClass c) or Point == (classof c) collect c
|
|
local childBounds = for c in sceneNode.children where "Gta Collision"==(getAttrClass c) collect c
|
|
if theGroup.groupArray.count != childMeshes.count then
|
|
(
|
|
currHirarchyErrors = (sceneNode.name+"'s child mesh count "+(childMeshes.count as string)+" not equal to "+(theGroup.groupName)+"'s group count "+(theGroup.groupArray.count as string))
|
|
return false
|
|
)
|
|
if theGroup.childArray.count != childBounds.count then
|
|
(
|
|
currHirarchyErrors = (sceneNode.name+"'s child collision count "+(childBounds.count as string)+" not equal to "+(theGroup.groupName)+"'s child count "+(theGroup.childArray.count as string))
|
|
return false
|
|
)
|
|
for grp in theGroup.groupArray do
|
|
(
|
|
if not (checkGroup grp (getNodeByName grp.groupName)) then
|
|
return false
|
|
)
|
|
return true
|
|
),
|
|
fn checkFragHirarchy obj =
|
|
(
|
|
local fragNode = getNodeByName (obj.name+"_frag_")
|
|
if undefined!=fragNode then obj = fragNode
|
|
return (checkGroup currFragGroup obj)
|
|
),
|
|
|
|
fn PopulateFragTuner = (
|
|
|
|
if $selection.count<=0 then
|
|
(
|
|
::ResetRollouts undefined
|
|
return false
|
|
)
|
|
local isSameFragment = false
|
|
local obj = selection[1]
|
|
if gPrvntCollSel and "Gta Collision"==(getAttrClass obj) and undefined!=obj.parent then
|
|
(
|
|
obj = obj.parent
|
|
select obj
|
|
return false
|
|
)
|
|
if undefined!=obj then
|
|
(
|
|
currFragGroup = findGroup currFragRoot obj.name
|
|
isSameFragment = undefined!=currFragGroup
|
|
)
|
|
|
|
local isHierarchyValid = true
|
|
if gReloadFileMode or not isSameFragment then
|
|
(
|
|
ResetFragTune()
|
|
-- create new
|
|
DetermineObject()
|
|
-- currFragRoot.groupName = currFragName
|
|
local tunePath = GetTunePath()
|
|
if ReadInAttrib tunePath then
|
|
(
|
|
currFragGroup = findGroup currFragRoot obj.name
|
|
)
|
|
else
|
|
isHierarchyValid = false
|
|
)
|
|
if isHierarchyValid then
|
|
(
|
|
if undefined==currFragGroup then currFragGroup = currFragRoot
|
|
checkFragHirarchy obj
|
|
if undefined!=ResetRollouts then
|
|
ResetRollouts currFragGroup.groupName
|
|
)
|
|
else
|
|
(
|
|
if undefined!=ResetRollouts then
|
|
ResetRollouts undefined
|
|
)
|
|
return true
|
|
),
|
|
|
|
fn RefreshUI =
|
|
(
|
|
if undefined!=::RsTreeViewRoll then
|
|
::RsTreeViewRoll.reset()
|
|
|
|
local selectionValid = PopulateFragTuner()
|
|
|
|
if selectionValid and undefined!=::RsTreeViewRoll then
|
|
(
|
|
::RsTreeViewRoll.updateTV currFragRoot currFragGroup
|
|
::RsFragRoll.setFragName currFragname
|
|
)
|
|
),
|
|
|
|
fn WriteFragTuneData = (
|
|
tunePath = GetTunePath()
|
|
WriteOutAttrib tunePath
|
|
),
|
|
|
|
-------------------------------------------------------------------------------------
|
|
-- copy hierarchy
|
|
-------------------------------------------------------------------------------------
|
|
fn copyGroup theGroup =
|
|
(
|
|
local newGroup = sFragGroup()
|
|
for val in theGroup.groupValues where val.attrExportFlag do
|
|
(
|
|
append newGroup.groupValues (val.copyMe())
|
|
)
|
|
for c in theGroup.childArray do
|
|
(
|
|
local newChild = sFragChild()
|
|
append newGroup.childArray newChild
|
|
for val in c.childvalues where val.attrExportFlag do
|
|
(
|
|
append newChild.childvalues (val.copyMe())
|
|
)
|
|
)
|
|
if gCpyChildren then
|
|
for grp in theGroup.groupArray do
|
|
(
|
|
append newGroup.groupArray (copyGroup grp)
|
|
)
|
|
return newGroup
|
|
),
|
|
fn copyFragHierarchy =
|
|
(
|
|
copyFragHier = copyGroup (if gCpyChildren then currFragRoot else currFragGroup)
|
|
),
|
|
--------------------------------------------------------------------------
|
|
fn pasteGroup fromGroup toGroup=
|
|
(
|
|
for fromVal in fromGroup.groupValues do
|
|
(
|
|
setGroupValueDirect toGroup fromVal.attrName fromVal.attrValue
|
|
)
|
|
for childIndex=1 to fromGroup.childArray.count do
|
|
(
|
|
if toGroup.childArray.count<childIndex then
|
|
(
|
|
copyPasteErrors += ("less collision meshes on "+toGroup.groupName+" than children from copybuffer\n")
|
|
exit
|
|
)
|
|
else
|
|
(
|
|
local fromChild = fromGroup.childArray[childIndex]
|
|
local toChild = toGroup.childArray[childIndex]
|
|
for fromVal in fromChild.childvalues do
|
|
(
|
|
setChildValueDirect toGroup childIndex fromVal.attrName fromVal.attrValue
|
|
)
|
|
)
|
|
)
|
|
for grpindex=1 to fromGroup.groupArray.count do
|
|
(
|
|
if toGroup.groupArray.count<grpindex then
|
|
(
|
|
copyPasteErrors += ("less submeshes on "+toGroup.groupName+" than groups from copybuffer\n")
|
|
exit
|
|
)
|
|
else
|
|
(
|
|
pasteGroup fromGroup.groupArray[grpindex] toGroup.groupArray[grpindex]
|
|
)
|
|
)
|
|
return newGroup
|
|
),
|
|
fn pasteFragHierarchy =
|
|
(
|
|
if selection.count<=0 then
|
|
(
|
|
messagebox "Select at least one object (and less than 10) to copy values to."
|
|
return false
|
|
)
|
|
if undefined==copyFragHier then
|
|
(
|
|
messagebox "No values copied yet."
|
|
return false
|
|
)
|
|
local selectionCopy = deepCopy (selection as array)
|
|
for obj in selectionCopy do
|
|
(
|
|
-- select submesh
|
|
select obj
|
|
CreateHierarachyFromNodes()
|
|
-- re-select for correct group selection
|
|
select obj
|
|
copyPasteErrors = ""
|
|
(pasteGroup copyFragHier (if gCpyChildren then currFragRoot else currFragGroup))
|
|
if copyPasteErrors != "" then messagebox copyPasteErrors
|
|
WriteFragTuneData()
|
|
)
|
|
RefreshUI()
|
|
),
|
|
----------------------------------------------------------------------------
|
|
-- ticking
|
|
fn tickGroup theGroup tickType =
|
|
(
|
|
for val in theGroup.groupValues do
|
|
(
|
|
case tickType of
|
|
(
|
|
#ticknone: val.attrExportFlag = false
|
|
#tickall: val.attrExportFlag = true
|
|
#tickdefault: val.attrExportFlag = (gRsFragAttribLUT.getDefaultExport val.attrName)
|
|
#tickinvert: val.attrExportFlag = not val.attrExportFlag
|
|
)
|
|
)
|
|
for c in theGroup.childArray do
|
|
(
|
|
for val in c.childvalues do
|
|
(
|
|
case tickType of
|
|
(
|
|
#ticknone: val.attrExportFlag = false
|
|
#tickall: val.attrExportFlag = true
|
|
#tickdefault: val.attrExportFlag = (undefined!=(gRsFragAttribLUT.getDefault val.attrName))
|
|
#tickinvert: val.attrExportFlag = not val.attrExportFlag
|
|
)
|
|
)
|
|
)
|
|
if gCpyChildren then
|
|
for grp in theGroup.groupArray do
|
|
(
|
|
tickGroup grp tickType
|
|
)
|
|
),
|
|
fn tickFragHierarchy tickType =
|
|
(
|
|
tickGroup (if gCpyChildren then currFragRoot else currFragGroup) tickType
|
|
::ResetRollouts currFragGroup.groupName
|
|
)
|
|
|
|
) -- struct sFragTuner
|
|
|
|
global gFragTuner = sFragTuner()
|