601 lines
17 KiB
Plaintext
Executable File
601 lines
17 KiB
Plaintext
Executable File
--
|
|
-- 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 <david.muir@rockstarnorth.com>
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- 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
|