-- -- File:: pipeline/ui/ObjectPosChecker.ms -- Description:: GTA Object Position Checker Import MAXScript -- This imports the output of the Object Position Checker that runs in-game. -- Once the text file has been read it provides a preview of the affected -- objects and then object position can be automatically changed for the -- loaded blocks. -- -- 25 June 2007 -- by David Muir -- ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- -- Uses ----------------------------------------------------------------------------- filein "pipeline\\util\\file.ms" ----------------------------------------------------------------------------- -- Rollouts ----------------------------------------------------------------------------- rollout GtaObjectPosCheckerImportRoll "Object Position Checker Import" ( ------------------------------------------------------------------------------- -- Structures ------------------------------------------------------------------------------- struct ObjectCheckerDef ( objName, -- Object name (string) initialPos, -- Initial position of object (Point3) initialRot, -- Initial rotation of object (Quat) finalPos, -- Final position of object (Point3) finalRot, -- Final rotation of object (Quat) -- Function to compare two ObjectCheckerDef structs function cmp o1 o2 = ( stricmp o1.objName o2.objName ) ) ------------------------------------------------------------------------------- -- constants ------------------------------------------------------------------------------- local degThreshold = 1.0 local useFullMatrixIdx = GetAttrIndex "Gta Object" "Use Full Matrix" ------------------------------------------------------------------------------- -- Data ------------------------------------------------------------------------------- local posZero = [ 0.0, 0.0, 0.0 ] local checkedObjects = #() local checkedObjectIndices = #() -- checkedObjects item indices shown local checkedObjectsInMap = #() -- Autorun stuff local mode = 0 -- [0 == normal, 1 == autorun] local autoRunObjIdx = undefined ------------------------------------------------------------------------------- -- UI ------------------------------------------------------------------------------- hyperlink lnkHelp "Help?" address:"https://devstar.rockstargames.com/wiki/index.php/Physical_Object_Position_Checker" align:#right color:(color 0 0 255) hoverColor:(color 0 0 255) visitedColor:(color 0 0 255) button btnImport "Import File..." across:6 button btnImportDir "Import Directory..." button btnAutoRun "Auto-Run..." button btnCheckAll "Check All" button btnInvChecked "Invert Checked" button btnFindObject "Find Checked" dotNetControl lstViewObjects "System.Windows.Forms.ListView" width:180 height:100 across:2 dotNetControl lstView "System.Windows.Forms.ListView" width:375 height:100 offset:[-100,0] groupbox grpAutoRun "Auto-Run" width:555 height:55 label lblInfo "" align:#left offset:[5,-45] button btnInitial "Initial" enabled:false width:100 across:5 button btnFinal "Final" enabled:false width:100 button btnBack "Back" enabled:false width:100 button btnNext "Next" enabled:false width:100 button btnStop "Stop" enabled:false width:100 progressbar barProgress across:2 offset:[0,10] button btnClose "Close" align:#right width:100 offset:[0,10] ------------------------------------------------------------------------------- -- Functions ------------------------------------------------------------------------------- local fEpsilon = 0.01 fn PosEqual a b = ( if ( a.x <= ( b.x + fEpsilon ) and a.x >= ( b.x - fEpsilon ) ) then if ( a.y <= ( b.y + fEpsilon ) and a.y >= ( b.y - fEpsilon ) ) then if ( a.z <= ( b.z + fEpsilon ) and a.z >= ( b.z - fEpsilon ) ) then return true return false ) fn RefreshTreeView = ( checkedObjectIndices = #() local i = 1 local n = 0 lvops.ClearLvItems lstView lvops.ClearLvItems lstViewObjects lstViewObjects.BeginUpdate() for o in checkedObjects do ( barProgress.value = 100.0 * i / checkedObjects.count i += 1 n += 1 lstViewObjects.Items.Add o.objName append checkedObjectIndices n ) lstViewObjects.EndUpdate() -- DEBUG --print checkedObjectIndices --print checkedObjects ) fn RefreshListView o = ( lstView.BeginUpdate() local xdiff = ( o.initialPos.x - o.finalPos.x ) as string local ydiff = ( o.initialPos.y - o.finalPos.y ) as string local zdiff = ( o.initialPos.z - o.finalPos.z ) as string lvops.ClearLvItems lstView lvops.AddLvItem lstView pTextItems:#( "1. Position Difference", "[ " + xdiff + ", " + ydiff + ", " + zdiff + " ]" ) lvops.AddLvItem lstView pTextItems:#( "2. Initial Position", o.initialPos as string ) lvops.AddLvItem lstView pTextItems:#( "3. Final Position", o.finalPos as string ) lvops.AddLvItem lstView pTextItems:#( "4. Initial Orientation", o.initialRot as string ) lvops.AddLvItem lstView pTextItems:#( "5. Final Orientation", o.finalRot as string ) lstView.EndUpdate() ) fn GetCheckedObjects = ( local items = ( lvops.GetLvItems lstViewObjects ) objDefs = #() for o in items do ( local idx = checkedObjectIndices[o.index+1] -- DEBUG --format "Item % checked: %; real item index: %\n" o.index (lvops.GetLvItemCheck lstView o.index ) idx if ( lvops.GetLvItemCheck lstViewObjects o.index ) then ( -- DEBUG -- format "Item % is checked, object: %\n" o.index checkedObjects[idx] append objDefs checkedObjects[idx] ) ) objDefs ) -- Build object definition cache for loaded objects fn BuildCache = ( checkedObjectsInMap = #() -- Ensure our list is initialised undefined for all for co in checkedObjects do ( append checkedObjectsInMap undefined ) -- Loop through all objects trying to find the checkedObjects local numObjects = $objects.count local i = 0 for o in $objects do ( barProgress.value = 100.0 * i / numObjects i += 1 if ( "Gta Object" != GetAttrClass o ) then continue -- Loop through all checkedObjects local nCheckedObj = 1 for co in checkedObjects do ( if ( XRefObject == classof o ) then ( if ( o.objectName == co.objName ) and ( PosEqual o.pos co.initialPos ) then ( checkedObjectsInMap[nCheckedObj] = o break ) ) else ( if ( o.name == co.objName ) and ( PosEqual o.pos co.initialPos ) then ( checkedObjectsInMap[nCheckedObj] = o break ) ) nCheckedObj += 1 ) ) print checkedObjectsInMap ) fn Import filename = ( -- Open file and process lines, constructing checkedObjects data if ( undefined != filename ) then ( fp = openFile filename mode:"rt" while ( not ( eof fp ) ) do ( local dataLine = readLine fp -- Skip empty lines if ( 0 == dataLine.count ) then continue -- Skip comment "#" lines if ( matchPattern dataLine pattern:"#*" ) then continue -- Filter data line as comma separated data local filtLine = filterString dataLine "," local posA = [ filtLine[2] as float, filtLine[3] as float, filtLine[4] as float ] local posB = [ filtLine[5] as float, filtLine[6] as float, filtLine[7] as float ] local rotA = undefined local rotB = undefined if ( filtLine.count > 7 ) then ( rotA = quat (filtLine[8] as float) (filtLine[9] as float) (filtLine[10] as float) (filtLine[11] as float) rotB = quat (filtLine[12] as float) (filtLine[13] as float) (filtLine[14] as float) (filtLine[15] as float) ) obj = ObjectCheckerDef objName:filtLine[1] initialPos:posA initialRot:rotA finalPos:posB finalRot:rotB append checkedObjects obj ) close fp ) ) -- Find previous checked object fn FindBackCheckedObject currIdx = ( local items = ( lvops.GetLvItems lstViewObjects ) local idx = currIdx for o in items do ( if ( o.index >= currIdx ) then continue if ( not o.checked ) then continue -- Skip objects not in our map section if ( undefined == checkedObjectsInMap[o.index+1] ) then continue idx = o.index ) idx ) -- Find next checked object fn FindNextCheckedObject currIdx = ( local items = ( lvops.GetLvItems lstViewObjects ) for o in items do ( if ( o.index <= currIdx ) then continue if ( not o.checked ) then continue -- Skip objects not in our map section if ( undefined == checkedObjectsInMap[o.index+1] ) then continue return ( o.index ) ) undefined ) fn UpdateInfoLabel = ( local ss = stringStream "" format "Object % of %." autoRunObjIdx checkedObjects.count to:ss lblInfo.text = ( ss as string ) ) ------------------------------------------------------------------------------- -- Events ------------------------------------------------------------------------------- -- Dialog open event on GtaObjectPosCheckerImportRoll open do ( -- Initialise TreeView lvops.InitListView lstViewObjects pLabelEdit:false pAllowReorder:false pCheckBoxes:true lvops.AddLvColumnHeader lstViewObjects pCaption:"Object" pWidth:150 -- Initialise ListView lvops.InitListView lstView pLabelEdit:false pAllowReorder:false pCheckBoxes:false lvops.AddLvColumnHeader lstView pCaption:"Parameter" pWidth:120 lvops.AddLvColumnHeader lstView pCaption:"Value" pWidth:230 ) -- Import File Button Event Handler on btnImport pressed do ( -- Initialisation fileName = getOpenFileName caption:"Select Object Checker output file:" \ types:"Object Checker Sector Files (*.objchk)|*.objchk|All Files (*.*)|*.*" checkedObjectIndices = #() checkedObjects = #() Import fileName -- Before refreshing our view, lets sort out objects so our view indicies -- match when they are sorted in the damn listview. qsort checkedObjects ObjectCheckerDef.cmp BuildCache() RefreshTreeView() local ss = stringStream "" format "% objects loaded." checkedObjects.count to:ss lblInfo.text = ( ss as string ) ) -- Import Directory Button Event Handler on btnImportDir pressed do ( -- Initialisation fileName = getOpenFileName caption:"Select Object Checker output file:" \ types:"Object Checker Sector Files (*.objchk)|*.objchk|All Files (*.*)|*.*" checkedObjectIndices = #() checkedObjects = #() local filepath = RsRemoveFile fileName local files = getFiles ( filepath + "\\*.objchk" ) for file in files do Import file -- Before refreshing our view, lets sort out objects so our view indicies -- match when they are sorted in the damn listview. qsort checkedObjects ObjectCheckerDef.cmp BuildCache() RefreshTreeView() local ss = stringStream "" format "% objects loaded." checkedObjects.count to:ss lblInfo.text = ( ss as string ) ) -- On autorun start do on btnAutoRun pressed do ( if ( 0 != mode ) then return false -- Setup first object autoRunObjIdx = FindNextCheckedObject -1 if ( undefined == autoRunObjIdx ) then ( MessageBox "No objects in loaded list are in this map section." return false ) -- Initialise UI controls for AutoRun Mode mode = 1 btnInitial.enabled = true btnFinal.enabled = true btnNext.enabled = true btnBack.enabled = true btnStop.enabled = true -- Select object and zoom into it clearSelection() selectMore checkedObjectsInMap[autoRunObjIdx+1] max zoomext sel redrawViews() UpdateInfoLabel() ) -- On node click on lstViewObjects ItemSelectionChanged e do ( -- Find objectDef struct this node references local idx = e.itemindex + 1 RefreshListView checkedObjects[idx] ) -- Check All Button Event Handler on btnCheckAll pressed do ( for i = 0 to lstViewObjects.Items.Count-1 do ( lvops.SetLvItemCheck lstViewObjects i true ) ) -- Invert checked status Button Event Handler on btnInvChecked pressed do ( for i = 0 to lstViewObjects.Items.Count-1 do ( lvops.SetLvItemCheck lstViewObjects i ( not ( lvops.GetLvItemCheck lstViewObjects i ) ) ) ) -- Find Checked object(s) on btnFindObject pressed do ( local items = ( lvops.GetLvItems lstViewObjects ) clearSelection() for o in items do ( if ( lvops.GetLvItemCheck lstViewObjects o.index ) then ( if ( undefined != checkedObjectsInMap[o.index+1] ) then selectMore checkedObjectsInMap[o.index+1] ) ) if ( 0 == $selection.count ) then MessageBox "No objects found. They will be in a different map section." else max zoomext sel ) -- Close Button Event Handler on btnClose pressed do ( closeRolloutFloater GtaObjectPosCheckerImportUtil ) ----------------------------------------------------------------------------- -- Auto-Run Mode Event Handlers ----------------------------------------------------------------------------- on btnInitial pressed do ( if ( 1 != mode ) then return false in coordsys world ( -- DEBUG --format "Moving to %\n\tobject def: %\n" checkedObjects[autoRunObjIdx+1].initialPos checkedObjects[autoRunObjIdx+1] local orientMat = inverse( checkedObjects[autoRunObjIdx+1].initialRot ) as Matrix3 orientMat.translation = checkedObjects[autoRunObjIdx+1].initialPos checkedObjectsInMap[autoRunObjIdx+1].transform = orientMat -- DEBUG --local angles = quatToEuler ( inverse( checkedObjects[autoRunObjIdx+1].finalRot ) ) --format "Object %\n\tX Rotation: %\n\tY Rotation:%\n\tZ Rotation: %\n\n" checkedObjects[autoRunObjIdx+1].objName angles.x angles.y angles.z ) ) on btnFinal pressed do ( if ( 1 != mode ) then return false in coordsys world ( -- DEBUG --format "Moving to %\n\tobject def: %\n" checkedObjects[autoRunObjIdx+1].finalPos checkedObjects[autoRunObjIdx+1] local orientMat = inverse( checkedObjects[autoRunObjIdx+1].finalRot ) as Matrix3 orientMat.translation = checkedObjects[autoRunObjIdx+1].finalPos checkedObjectsInMap[autoRunObjIdx+1].transform = orientMat local angles = quatToEuler ( inverse( checkedObjects[autoRunObjIdx+1].finalRot ) ) -- DEBUG --format "Object %\n\tX Rotation: %\n\tY Rotation:%\n\tZ Rotation: %\n\n" checkedObjects[autoRunObjIdx+1].objName angles.x angles.y angles.z -- If our X or Y angle is greater than our threshold then set our Use Full Matrix attribute if ( angles.x > degThreshold ) or ( angles.y > degThreshold ) or ( angles.x < ( -degThreshold ) ) or ( angles.y < ( -degThreshold ) ) then SetAttr checkedObjectsInMap[autoRunObjIdx+1] useFullMatrixIdx true ) ) on btnBack pressed do ( if ( 1 != mode ) then return false autoRunObjIdx = FindBackCheckedObject autoRunObjIdx -- Select object and zoom into it clearSelection() selectMore checkedObjectsInMap[autoRunObjIdx+1] max zoomext sel redrawViews() UpdateInfoLabel() ) on btnNext pressed do ( if ( 1 != mode ) then return false autoRunObjIdx = FindNextCheckedObject autoRunObjIdx if ( undefined == autoRunObjIdx ) then ( MessageBox "All objects processed." autoRunObjIdx = undefined mode = 0 btnInitial.enabled = false btnFinal.enabled = false btnBack.enabled = false btnNext.enabled = false btnStop.enabled = false local ss = stringStream "" format "% objects loaded." checkedObjects.count to:ss lblInfo.text = ( ss as string ) return false ) -- Select object and zoom into it clearSelection() selectMore checkedObjectsInMap[autoRunObjIdx+1] max zoomext sel redrawViews() UpdateInfoLabel() ) on btnStop pressed do ( if ( 1 != mode ) then return false autoRunObjIdx = undefined mode = 0 btnInitial.enabled = false btnFinal.enabled = false btnBack.enabled = false btnNext.enabled = false btnStop.enabled = false local ss = stringStream "" format "% objects loaded." checkedObjects.count to:ss lblInfo.text = ( ss as string ) ) ) try closeRolloutFloater GtaObjectPosCheckerImportUtil catch() GtaObjectPosCheckerImportUtil = newRolloutFloater "Physical Object Position Checker" 600 285 0 50 addRollout GtaObjectPosCheckerImportRoll GtaObjectPosCheckerImportUtil -- End of GtaObjectPositionChecker.ms MAXScript