-- -- 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/export/maps/globals.ms" filein "pipeline/helpers/animation/hierarchyBB.ms" filein "pipeline/util/RSProcess.ms" ----------------------------------------------------------------------------- -- Rollouts ----------------------------------------------------------------------------- rollout GtaObjectPosCheckerInitiatorRoll "Object Position Checker Initiator" ( ------------------------------------------------------------------------------- -- constants ------------------------------------------------------------------------------- local debug = true local connectionTimerInterval = 5000 --Tick every 5 seconds local sweepTimerInterval = 2500 --Tick every 2.5 seconds local RagSectorToolsStart = "Sector Tools/Start X Y Z World Coordinates:" local RagSectorToolsEnd = "Sector Tools/End X Y Z World Coordinates:" local RagObjPosCheckerBank = "Sector Tools/Physical Object Position Checker" local RagObjPosCheckerOutputDir = "Sector Tools/Physical Object Position Checker/Output directory:" local RagObjPosCheckerRestrictToEntities = "Sector Tools/Physical Object Position Checker/Restrict to Specific Entities" local RagObjPosCheckerEntityFile = "Sector Tools/Physical Object Position Checker/Entity Restriction File:" local RagObjPosCheckerScanArea = "Sector Tools/Physical Object Position Checker/Scan and Export Area" local RagObjPosCheckerScanInProgress = "Sector Tools/Physical Object Position Checker/Scan In Progress (read-only)" local RagObjPosCheckerAbort = "Sector Tools/Physical Object Position Checker/Abort Running Scan" local ps3BatchFile = "game_psn_bankrelease_snc.bat" local xboxBatchFile = "game_xenon_bankrelease.bat" local defaultCommandlineArgs = "-rag –nopeds –nocars –novehs -maponly -invincible -sectortools" local inputFilename = "object_position_sectors.txt" local entitiesFilename = "object_position_entities.txt" local responseFilename = "additional_game_args.txt" ------------------------------------------------------------------------------- -- Data ------------------------------------------------------------------------------- local connectionTimer = undefined local sweepTimer = undefined local buildDir = undefined ------------------------------------------------------------------------------- -- UI ------------------------------------------------------------------------------- dropDownList lstPlatforms "Platform:" items:#("PS3","Xbox360") width:200 across:2 dropDownList lstSweepMode "Sweep Mode:" items:#("Open Containers","Selected Containers","Selected Entities") width:200 label lblOutputDirHeader "Output Directory:" across:3 align:#left label lblOutputDir "c:\\temp" offset:[-90,0] align:#left button btnBrowse "Browse" width:80 align:#right label lblAdditionalArgsHeader "Commandline Args:" width:120 across:3 align:#left edittext edtAdditionalArgs text:defaultCommandlineArgs offset:[-90,0] width:400 align:#left label lblDummy width:1 align:#right button btnStart "Start In-Game Checker" width:200 label lblConnectionHeader "Game Connection Status:" across:2 align:#left label lblConnectionStatus "Not connected" align:#left offset:[-100,0] label lblSweepHeader "Sweep Status:" across:3 align:#left label lblSweepStatus "" width:300 align:#left button btnAbort "Abort" width:100 align:#right ------------------------------------------------------------------------------- -- Functions ------------------------------------------------------------------------------- -- Helper method for printing debug messages. fn PrintDebug message = ( if (debug == true) then ( print message ) ) -- Retrieves list of selected entity guids. fn GetSelectedEntityGuids = ( local selectedObjectGuids = #() local mapContainers = RsMapGetMapContainers() local maps = for map in RsMapGetMapContainers doingExport:true where map.is_exportable() and (map.selCount() != 0) collect map if (maps.count > 0) then ( for map in maps do ( local mapSectionMapNode = RsProjectContentFind (toLower map.name) type:"map" local containerAttrGuid = getattrguid map.cont containerAttrGuid = trimLeft containerAttrGuid "{" containerAttrGuid = trimRight containerAttrGuid "}" local containerHash32 = atStringHash containerAttrGuid seed:mapSectionMapNode.Seed PrintDebug (format "map section seed:%, guid:%, hash:%" mapSectionMapNode.Seed containerAttrGuid containerHash32) RsMapSetupGlobals map for obj in map.selObjects do ( local objAttrGuid = getattrguid obj objAttrGuid = trimLeft objAttrGuid "{" objAttrGuid = trimRight objAttrGuid "}" local objectHash32 = atStringHash objAttrGuid seed:containerHash32 PrintDebug (format "object:%, guid:%, hash:%" obj.name objAttrGuid objectHash32) append selectedObjectGuids objectHash32 ) ) ) return selectedObjectGuids ) -- Returns a list of export objects for a particular map container. fn GetExportObjects maps = ( local objs = #() for map in maps do ( for obj in map.exportObjects do ( if (GetAttrClass obj) == "Gta Object" then ( append objs obj ) ) ) return objs ) -- Returns the bounds that we need to send to the game. fn GetBounds = ( local bbox = undefined if (lstSweepMode.selected == "Open Containers") then ( local maps = for map in RsMapGetMapContainers doingExport:true where map.is_exportable() collect map if (maps.count > 0) then ( local expObjs = GetExportObjects maps if (expObjs.count > 0) then ( bbox = RsGetHierarchyBB expObjs[1] restrictToClass:"Gta Object" for obj in expObjs do ( RsExpandBB bbox (::RsGetHierarchyBB obj restrictToClass:"Gta Object") ) ) ) ) else if (lstSweepMode.selected == "Selected Containers") then ( local maps = for map in RsMapGetMapContainers doingExport:true where map.is_exportable() and (map.selCount() != 0) collect map if (maps.count > 0) then ( local expObjs = GetExportObjects maps if (expObjs.count > 0) then ( bbox = RsGetHierarchyBB expObjs[1] restrictToClass:"Gta Object" for obj in expObjs do ( RsExpandBB bbox (::RsGetHierarchyBB obj restrictToClass:"Gta Object") ) ) ) ) else if (lstSweepMode.selected == "Selected Entities") then ( local maps = for map in RsMapGetMapContainers doingExport:true where map.is_exportable() and (map.selCount() != 0) collect map if (maps.count > 0) then ( local expObjs = #() for map in maps do ( for obj in map.selObjects do ( if (GetAttrClass obj) == "Gta Object" then ( append expObjs obj ) ) ) if (expObjs.count > 0) then ( bbox = RsGetHierarchyBB expObjs[1] restrictToClass:"Gta Object" for obj in expObjs do ( RsExpandBB bbox (::RsGetHierarchyBB obj restrictToClass:"Gta Object") ) ) ) ) PrintDebug bbox return bbox ) -- Helper method that checks whether the game is already running with the sector tools enabled fn IsGameRunningWithSectorTools = ( local retVal = false if (RemoteConnection.IsConnected() == true) then ( retVal = RemoteConnection.WidgetExists(RagObjPosCheckerBank) ) return retVal ) -- Helper method that checks whether a object position sweep is already in progress. fn IsSweepInProgress = ( local retVal = false if (RemoteConnection.IsConnected() == true) then ( retVal = RemoteConnection.ReadBoolWidget(RagObjPosCheckerScanInProgress) ) return retVal ) -- Writes a file containing a single line per entity guid. fn CreateEntityGuidFile guids filepath = ( local guidStream = stringStream "" for guid in guids do ( local guidString = formattedPrint guid format "%\n" guidString to:guidStream ) PrintDebug guidStream local file = fopen filepath "wt" WriteString file guidStream fclose file ) -- Writes a file containing the start/end coords. fn CreateSectorInputFile bounds filepath = ( local coords = stringStream "" format "% % % %" bounds[1].x bounds[1].y bounds[2].x bounds[2].y to:coords PrintDebug coords local file = fopen filepath "wt" WriteString file coords fclose file ) -- Writes a file containing the additional arguments the game should use when booting. fn CreateResponseFile arguments filepath = ( local file = fopen filepath "wt" WriteString file arguments fclose file ) -- Starts the object position checker when the game is already running. fn StartObjectPositionChecker = ( -- Make sure we can determine some valid bounds to work with. local bounds = GetBounds() if (bounds == undefined) then ( messageBox "Nothing to do for the selected sweep mode. Have you selected some exportable entities?" ) else ( -- Set all the appropriate RAG widget values. local outputDir = lblOutputDir.text RemoteConnection.WriteStringWidget RagObjPosCheckerOutputDir outputDir local startStream = stringStream "" format "% % %" bounds[1].x bounds[1].y bounds[1].z to:startStream RemoteConnection.WriteStringWidget RagSectorToolsStart (startStream as string) local endStream = stringStream "" format "% % %" bounds[2].x bounds[2].y bounds[2].z to:endStream RemoteConnection.WriteStringWidget RagSectorToolsEnd (endStream as string) RemoteConnection.WriteBoolWidget RagObjPosCheckerRestrictToEntities (lstSweepMode.selected == "Selected Entities") -- Create the entities file (if required). if (lstSweepMode.selected == "Selected Entities") then ( local entitiesFilepath = buildDir + entitiesFilename CreateEntityGuidFile (GetSelectedEntityGuids()) entitiesFilepath RemoteConnection.WriteStringWidget RagObjPosCheckerEntityFile entitiesFilepath ) -- Start the object position checker process. RemoteConnection.SendCommand("widget \"" + RagObjPosCheckerScanArea + "\"") sweepTimer.Start() btnStart.Enabled = false lblSweepStatus.Text = "Sweep in Progress" ) ) -- Boots the game with the object position checker commandline parameters. fn BootAndStartObjectPositionChecker = ( -- Make sure we can determine some valid bounds to work with. local bounds = GetBounds() if (bounds == undefined) then ( messageBox "Nothing to do for the selected sweep mode. Have you selected some exportable entities?" ) else ( -- Use the appropriate batch file local batFilename = buildDir if (lstPlatforms.selected == "PS3") then ( batFilename += ps3BatchFile ) else ( batFilename += xboxBatchFile ) -- Build up the commandline args local arguments = defaultCommandlineArgs -- Create the intput sector tool files. local inputFilepath = buildDir + inputFilename CreateSectorInputFile (GetBounds()) inputFilepath local outputDir = lblOutputDir.text arguments += " -sectortools_input \"" + inputFilepath + "\" -sectortools_output \"" + outputDir + "\"" -- Create the entities file (if required). if (lstSweepMode.selected == "Selected Entities") then ( local entitiesFilepath = buildDir + entitiesFilename CreateEntityGuidFile (GetSelectedEntityGuids()) entitiesFilepath arguments += " -sectortools_entities \"" + entitiesFilepath + "\"" ) -- Create the arugments response file. local responseFilepath = buildDir + responseFilename CreateResponseFile arguments responseFilepath -- If it's 360, check to see whether watson is running and kill it. if (lstPlatforms.selected == "Xbox360") then ( local xboxSDKDir = "%xedk%\bin\win32" local cmd = ( "TASKKILL /F /IM \"xbwatson.exe\"" ) doscommand cmd ) -- Kick off the game with those files as inputs. PrintDebug (format "Running: % %" batFilename arguments) local gameBatchProcess = RsProcess() gameBatchProcess.RunProcess batFilename ("@" + responseFilepath) silent:false waitForExit:false workingDir:buildDir btnStart.Enabled = false -- Inform the user of what is happening progressStart "Establishing game connection (waiting for game to boot)." -- Times in seconds local timePassed = 0 local maxTimeToWait = 30 local checkFrequency = 0.25 local waitingForConnection = true while (waitingForConnection == true) do ( -- Offer to cancel if the user has been waiting too long if (timePassed >= maxTimeToWait) then ( keepGoing = queryBox "Unable to establish a game connection\n\nContinue waiting?" title:"Warning: Connection Error" -- If the user chooses to continue to wait, reset the timer. if keepGoing then ( timePassed = 0 ) else ( btnStart.Enabled = true waitingForConnection = false ) ) if waitingForConnection then ( if (RemoteConnection.IsConnected() == true and IsSweepInProgress() == true) then ( sweepTimer.Start() lblSweepStatus.Text = "Sweep in Progress" waitingForConnection = false ) else if (RemoteConnection.IsConnected() == false and RemoteConnection.Connect() == true) then ( lblConnectionStatus.Text = "Connected" connectionTimer.Start() ) else ( if not (progressUpdate (100.0 * timePassed / maxTimeToWait)) then ( btnStart.Enabled = true waitingForConnection = false ) else ( sleep checkFrequency timePassed += checkFrequency ) ) ) ) progressEnd() ) ) ------------------------------------------------------------------------------- -- Events ------------------------------------------------------------------------------- -- Tick called at regular intervals to check the game connection. fn ConnectionTimer_OnTick s e = ( if (RemoteConnection.IsConnected() == false) then ( --If connection has faltered, then notify the UI. PrintDebug ("Lost connection to the game!") if (btnStart.Enabled == false) then ( btnStart.Enabled = true lblSweepStatus.Text = "Unknown" sweepTimer.Stop() ) lblConnectionStatus.Text = "Lost connection." connectionTimer.Stop() ) ) -- Tick called at regular intervals to check whether the object position checker has completed. fn SweepTimer_OnTick s e = ( if (btnStart.Enabled == false) then ( -- Check whether the sweep's completed. if (IsSweepInProgress() == false) then ( btnStart.Enabled = true lblSweepStatus.Text = "Sweep Completed" sweepTimer.Stop() ) ) ) -- Called when the rollout is opened. on GtaObjectPosCheckerInitiatorRoll open do ( -- Get the projects build directory. buildDir = ( RsConfigGetProjRootDir() + "build/dev/" ) -- Initialise the two timers connectionTimer = dotNetObject "System.Windows.Forms.Timer" dotnet.addEventHandler connectionTimer "tick" ConnectionTimer_OnTick connectionTimer.Interval = connectionTimerInterval sweepTimer = dotNetObject "System.Windows.Forms.Timer" dotnet.addEventHandler sweepTimer "tick" SweepTimer_OnTick sweepTimer.Interval = sweepTimerInterval -- Attempt to connect to the game. if (RemoteConnection.Connect() == true) then ( lblConnectionStatus.Text = "Connected" connectionTimer.Start() -- Is a sweep already in progress? if (IsSweepInProgress() == true) then ( sweepTimer.Start() btnStart.Enabled = false lblSweepStatus.Text = "Sweep in Progress" ) ) ) -- Called when the rollout closes. on GtaObjectPosCheckerInitiatorRoll close do ( sweepTimer.Stop() connectionTimer.Stop() ) -- Called when the user wishes to browse for the output directory. on btnBrowse pressed do ( lblOutputDir.Text = getSavePath caption:"Select output directory:" initialDir:lblOutputDir.Text ) -- Called when the user wants to kick off the object position checker in game. on btnStart pressed do ( -- Attempt to connect to the game. if (RemoteConnection.Connect() == true) then ( lblConnectionStatus.Text = "Connected" connectionTimer.Start() ) -- Check whether the game is already running. if (IsGameRunningWithSectorTools() == true) then ( -- Is a sweep already in progress? if (IsSweepInProgress() == true) then ( -- Tell the user to wait for the current sweep to complete. messageBox "Object position check sweep already in progress.\nEither abort it or wait for it to complete before kicking off another one." title:"Sweep in Progress" sweepTimer.Start() btnStart.Enabled = false lblSweepStatus.Text = "Sweep in Progress" ) else ( PrintDebug "Using existing game" StartObjectPositionChecker() ) ) else ( PrintDebug "Booting game" BootAndStartObjectPositionChecker() ) ) -- Called when the user hits the abort button. on btnAbort pressed do ( if (btnStart.Enabled == false) then ( PrintDebug "Aborting sweep" RemoteConnection.SendCommand("widget \"" + RagObjPosCheckerAbort + "\"") btnStart.Enabled = true lblSweepStatus.Text = "Aborted" sweepTimer.Stop() ) ) ) 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 fn 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 -- Used to draw the extents of the objchk file local rectangleArray = #() ------------------------------------------------------------------------------- -- 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" button btnFindSelObject "Find Selected Object" dotNetControl lstViewObjects "System.Windows.Forms.ListView" width:180 height:525 across:2 dotNetControl lstView "System.Windows.Forms.ListView" width:400 height:125 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 local objName = undefined objName = if ( isRefObj o ) then ( toLower o.objectName ) else ( toLower o.name ) -- Loop through all checkedObjects local nCheckedObj = 1 for co in checkedObjects do ( if ( objName == (toLower 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" local rectMin, rectMax, rectCentre while ( not ( eof fp ) ) do ( local dataLine = readLine fp -- Skip empty lines if ( 0 == dataLine.count ) then continue if ( matchPattern dataLine pattern:"# Actual Player Pos*" ) then ( centreArray = filterString (filterString dataLine ":")[2] " " rectCentre = Point3 (centreArray[1] as float) (centreArray[2] as float) (centreArray[3] as float) continue ) if ( matchPattern dataLine pattern:"# Sector Min Coords*" ) then ( minArray = filterString (filterString dataLine ":")[2] " " rectMin = Point2 (minArray[1] as float) (minArray[2] as float) continue ) if ( matchPattern dataLine pattern:"# Sector Max Coords*" ) then ( maxArray = filterString (filterString dataLine ":")[2] " " rectMax = Point2 (maxArray[1] as float) (maxArray[2] as float) 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 ) if ( rectMin != undefined and rectMax != undefined and rectCentre != undefined ) do ( r = Rectangle length:(abs (rectMax.x - rectMin.x)) width:(abs (rectMax.y - rectMin.y)) pos:rectCentre append rectangleArray r ) 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:260 ) on GtaObjectPosCheckerImportRoll close do ( for o in rectangleArray do ( if classof o == Rectangle then delete o ) rectangleArray = #() ) -- Import File Button Event Handler on btnImport pressed do ( for o in rectangleArray do ( if classof o == Rectangle then delete o ) rectangleArray = #() -- 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 ( for o in rectangleArray do ( if classof o == Rectangle then delete o ) rectangleArray = #() -- 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 ) on btnFindSelObject pressed do ( if ( selection.count == 1 ) do ( objNameSelected = toLower $.objectName objPosSelected = $.pos for idx = 1 to checkedObjects.count do ( -- Might find multiple matches, so then check the positions to make sure right one found if (objNameSelected == (toLower checkedObjects[idx].objName)) do ( if (PosEqual objPosSelected checkedObjects[idx].initialPos ) do ( lvops.SetLvItemCheck lstViewObjects (idx - 1) true RefreshListView checkedObjects[idx] ) ) ) ) ) -- 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 730 0 50 addRollout GtaObjectPosCheckerInitiatorRoll GtaObjectPosCheckerImportUtil addRollout GtaObjectPosCheckerImportRoll GtaObjectPosCheckerImportUtil -- End of GtaObjectPositionChecker.ms MAXScript