685 lines
22 KiB
Plaintext
Executable File
685 lines
22 KiB
Plaintext
Executable File
--
|
|
-- File:: pipeline/util/placement.ms
|
|
-- Description:: Placement Toolkit
|
|
--
|
|
-- Author:: Marissa Warner-Wu <marissa.warner-wu@rockstarnorth.com>
|
|
-- Date:: 15 March 2010
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
-- HISTORY
|
|
--
|
|
-- by David Muir <david.muir@rockstarnorth.com>
|
|
-- Authored some scripts used here
|
|
--
|
|
-----------------------------------------------------------------------------
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Uses
|
|
-----------------------------------------------------------------------------
|
|
filein "pipeline/helpers/maps/EPlanter.ms"
|
|
filein "pipeline/util/MeshUtil.ms"
|
|
filein "rockstar/helpers/pathnodecheck.ms"
|
|
filein "rockstar/util/datimporter.ms"
|
|
filein "pipeline/helpers/climbing/handhold_importer.ms"
|
|
|
|
-----------------------------------------------------------------------------
|
|
-- Rollouts
|
|
-----------------------------------------------------------------------------
|
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
--------------------------------- PLACEMENT
|
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
rollout PlaceHelpersRoll "Placement Helpers"
|
|
(
|
|
local fSectorSize = 50.0
|
|
local fWidthInSectors = 120.0
|
|
local fDepthInSectors = 120.0
|
|
-- FILTERS
|
|
fn objFilter obj = isProperty obj "mesh"
|
|
|
|
--////////////////////////////////////////////////////////////
|
|
-- interface
|
|
--////////////////////////////////////////////////////////////
|
|
hyperlink lnkHelp "Help?" address:"https://devstar.rockstargames.com/wiki/index.php/Placement_Toolkit#Placement_Helpers" align:#right color:(color 0 0 255) hoverColor:(color 0 0 255) visitedColor:(color 0 0 255)
|
|
|
|
local btnWidth = 110
|
|
local btnHeight = 24
|
|
|
|
local grpWidth = btnWidth + 12
|
|
|
|
group "Decal Surface Snap"
|
|
(
|
|
spinner spnDecalPush "Push:" tooltip:"Distance(m) for mesh to be pushed away from the surface beneath once snapped." range:[0.0, 5.0, 0.0] type:#float align:#left across:2 offset:[15,0]
|
|
button btnDecalSurfaceSnap "Snap Selected" tooltip:"Snap the decal verts to the mesh selected underneath" width:120 offset:[0, -3]
|
|
)
|
|
|
|
group "Conform To Ground"
|
|
(
|
|
spinner spnPush "Push:" tooltip:"Distance(m) for mesh to be pushed away from the surface beneath once conformed." range:[0.0, 5.0, 0.0] type:#float align:#left across:2 offset:[15,0]
|
|
button btnConformToGround "Conform Selected" tooltip:"Conform the selected meshes to whatever mesh are below them." width:120 offset:[0, -3]
|
|
)
|
|
|
|
group "Move to Ground"
|
|
(
|
|
--groupBox grpAlignZ "Move to Ground" pos:[(PlaceHelpersRoll.width / 2) - 4 - grpWidth,40] width:grpWidth height:73
|
|
pickbutton pbn_ground "Pick Ground" width:120 offset:[0, 0] across:2 filter:objFilter autoDisplay:true
|
|
button btnAlignZ "Move Selection" tooltip:"Move selected objects up/down until they sit on top of this picked object" width:130
|
|
|
|
checkbox chkGndAlign "Align to Ground" tooltip:"Align selection to ground-object" width:130 offset:[10,2]
|
|
|
|
spinner spnPercentOfGroundMin "Min %:" tooltip:"" range:[0, 100, 0] type:#integer align:#right offset:[0,2] width:130 across:2 enabled:false
|
|
spinner spnPercentOfGroundMax "Max %:" tooltip:"" range:[0, 100, 100] type:#integer align:#right offset:[0,2] width:130 enabled:false
|
|
|
|
)
|
|
|
|
group "Instancer"
|
|
(
|
|
--groupBox grpInstancer "Instancer" pos:[(PlaceHelpersRoll.width / 2) + 4,40] width:grpWidth height:73
|
|
pickbutton btnChooseInst "Choose Master Obj" autoDisplay:true tooltip:"Choose master-object for instancing" across:2 width:120
|
|
button btnChangeModels "Replace Selected" tooltip:"Replace selected objects with instances of above object" width:120
|
|
)
|
|
|
|
group "Random rotate in Z"
|
|
(
|
|
--groupBox grpRandRotZ "Random rotate in Z" pos:(grpAlignZ.pos + [0, grpAlignZ.height + 2]) width:grpWidth height:68
|
|
button btnRandRotZ "Rotate selected" tooltip:"Rotated selected objects randomly around Z axis" across:2 width:120
|
|
radioButtons radAxisChoice "" labels:#("Local", "World") align:#left tooltip:"Rotate in Local or World Z-axis" width:120 offset:[20,2]
|
|
)
|
|
|
|
group "Random Scale"
|
|
(
|
|
--groupBox grpRandScale "Random Scale" pos:(grpInstancer.pos + [0, grpInstancer.height + 2]) width:grpWidth height:68
|
|
button btnRandScale "Scale selected" \
|
|
tooltip:"Scales (non-dynamic) selected objects randomly within the jitter value\nDynamic objects will be de-selected" \
|
|
across:2 width:120
|
|
spinner spnScaleJitter "Jitter %:" range:[0,100,10] type:#integer align:#left width:120 offset:[10,0]
|
|
)
|
|
|
|
group "World Sector Calculator"
|
|
(
|
|
--groupBox grpWorld "World Sector Calculator" offset:[4,8] width:252 height:92
|
|
--label lblWorld "World Centre:" width:77 height:16
|
|
spinner spnWorldX "World Centre: X: " across:2 offset:[40, 0]
|
|
spinner spnWorldY "Y: " range:[0,100,0]
|
|
--label lblSector "Sector:" width:77 height:16
|
|
spinner spnSecX "Sector: X: " range:[0,100,0] across:2 offset:[40, 0]
|
|
spinner spnSecY "Y: " range:[0,100,0]
|
|
)
|
|
--////////////////////////////////////////////////////////////
|
|
-- methods
|
|
--////////////////////////////////////////////////////////////
|
|
--------------------------------------------------------------
|
|
-- Move to Ground
|
|
--------------------------------------------------------------
|
|
fn pickFilter obj =
|
|
(
|
|
(isProperty obj "mesh")
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- World-Sector Calculator
|
|
--------------------------------------------------------------
|
|
fn Refresh worldUpdate = (
|
|
|
|
if ( worldUpdate ) then
|
|
(
|
|
-- World coordinates updated, reflect change in sector coords
|
|
spnSecX.value = floor( ( ( spnWorldX.value as float ) / fSectorSize ) + ( fWidthInSectors / 2.0 ) )
|
|
spnSecY.value = floor( ( ( spnWorldY.value as float ) / fSectorSize ) + ( fDepthInSectors / 2.0 ) )
|
|
)
|
|
else
|
|
(
|
|
-- Sector coordinates updated, reflect change in world coords
|
|
spnWorldX.value = ( ( ( spnSecX.value as float ) - fWidthInSectors / 2.0 ) * fSectorSize ) + fSectorSize / 2.0
|
|
spnWorldY.value = ( ( ( spnSecY.value as float ) - fDepthInSectors / 2.0 ) * fSectorSize ) + fSectorSize / 2.0
|
|
)
|
|
)
|
|
|
|
--////////////////////////////////////////////////////////////
|
|
-- events
|
|
--////////////////////////////////////////////////////////////
|
|
|
|
on chkGndAlign changed arg do
|
|
(
|
|
spnPercentOfGroundMin.enabled = spnPercentOfGroundMax.enabled = arg
|
|
)
|
|
-------------------------------------------------------------
|
|
-- Decal Surface Snap
|
|
-------------------------------------------------------------
|
|
on btnDecalSurfaceSnap pressed do
|
|
(
|
|
--check selection
|
|
if selection.count == 0 then
|
|
(
|
|
messageBox "Nothing Selected\nPick surface then decal before running" title:"Bad Selection"
|
|
return false
|
|
)
|
|
|
|
if selection.count == 1 then
|
|
(
|
|
messageBox "Select the surface and decal before running" title:"Bad Selection"
|
|
return false
|
|
)
|
|
|
|
local surfaceMesh = convertToMesh selection[1]
|
|
local decalMesh = convertToMesh selection[2] --needs to be editable mesh
|
|
|
|
--setup RayMeshGridIntersect
|
|
local rayMesh = RayMeshGridIntersect()
|
|
rayMesh.Initialize 10
|
|
rayMesh.addNode surfaceMesh
|
|
raymesh.BuildGrid()
|
|
|
|
--raycast from target decal normal into the the surfaceMesh
|
|
for vtx=1 to (getNumVerts decalMesh) do
|
|
(
|
|
--the Position
|
|
local position = in coordsys #world (meshop.getVert decalMesh vtx node:decalMesh)
|
|
|
|
--get the normal
|
|
local normal = normalize(getnormal decalMesh vtx)
|
|
--normal = [0,0,1]
|
|
|
|
--cast a ray
|
|
local hits = raymesh.intersectRay position -normal true
|
|
|
|
--if we get a hit then....
|
|
if hits > 0 then
|
|
(
|
|
--get the face hit
|
|
local theIndex = rayMesh.getClosestHit() --get the index of the closest hit by the ray
|
|
local theFace = rayMesh.getHitFace theIndex
|
|
|
|
--get the barycentric coords of the face hit
|
|
--local baryPt = rayMesh.getHitBary theIndex
|
|
|
|
--get the verts for the face hit
|
|
local faceVerts = (meshop.getVertsUsingFace surfaceMesh theFace) as Array
|
|
|
|
--get the closestvert, the smallest value in baryPt should give the index of the closest vert
|
|
local minTest = 9999999
|
|
--local baryArray = #(baryPt.x, baryPt.y, baryPt.z) --shifted order otherwise it goes further than it should
|
|
local vIdx = 0
|
|
local closestVertPos = [0, 0, 0]
|
|
|
|
for pt=1 to 3 do
|
|
(
|
|
local thisVertPos = meshop.getvert surfaceMesh faceVerts[pt]
|
|
local dist = distance thisVertPos position
|
|
if dist < minTest then
|
|
(
|
|
closestVertPos = thisVertPos
|
|
minTest = dist
|
|
)
|
|
)
|
|
|
|
--move the decal vert to closesVert Pos + push
|
|
local finalPos = closestVertPos + (spnDecalPush.value * normal)
|
|
in coordsys #world meshop.setVert decalMesh #{vtx} finalPos node:decalMesh
|
|
)
|
|
)
|
|
|
|
)
|
|
|
|
-------------------------------------------------------------
|
|
-- Conform To Ground
|
|
-------------------------------------------------------------
|
|
on btnConformToGround pressed do
|
|
(
|
|
--check anythign selected
|
|
if $selection.count == 0 then
|
|
(
|
|
messageBox "Nothing Selected!" title:"Error"
|
|
return false
|
|
)
|
|
|
|
--get the user selection
|
|
local meshes = for obj in $selection where classOf obj == Editable_Poly or classOf obj == Editable_mesh collect obj
|
|
if meshes.count == 0 then
|
|
(
|
|
messageBox "No Meshes Selected!" title:"Error"
|
|
return false
|
|
)
|
|
|
|
coordsys #world
|
|
--iterate through those we got
|
|
for item in meshes do
|
|
(
|
|
undo "drop to ground" on
|
|
(
|
|
local geoClass = classOf item
|
|
local numVerts = getNumVerts item.mesh
|
|
|
|
local theVerts = for v=1 to (getNumVerts item.mesh) collect v
|
|
if subObjectLevel != 0 then theVerts = for v=1 to item.selectedVerts.count collect item.selectedVerts[v].index
|
|
|
|
local progMsg = "Calculating positions for: " + item.name
|
|
progressStart progMsg
|
|
progressUpdate 1
|
|
|
|
--for each vert get its position
|
|
for v in theVerts do
|
|
(
|
|
if getProgressCancel() then
|
|
(
|
|
progressEnd()
|
|
max undo
|
|
return false
|
|
)
|
|
|
|
local vertPos = meshop.getVert item.mesh v node:item
|
|
local hitPosZ = vertPos
|
|
|
|
-- fire a ray down from that position
|
|
local hits = intersectRayScene (ray vertPos [0, 0, -1])
|
|
--take the hit objects that are not our dropee
|
|
local hitObj = for o in hits where o[1] != item collect o[2] --collect rays
|
|
|
|
--set the new position if we have one
|
|
if hitObj.count != 0 then
|
|
(
|
|
if hitObj.count > 1 then --find the closest
|
|
(
|
|
local nearestDist = 9999999.0
|
|
local nearestObj = hitObj[1]
|
|
for hit in hitObj where abs(vertPos.z - hit.pos.z) < nearestDist do
|
|
(
|
|
nearestDist = abs(vertPos.z - hit.pos.z)
|
|
nearestObj = hit
|
|
)
|
|
|
|
hitPosZ = nearestObj.pos.z
|
|
)
|
|
else
|
|
(
|
|
hitPosZ = hitObj[1].pos.z
|
|
)
|
|
--add any push value the user set in the UI
|
|
vertPos.z = hitPosZ + spnPush.value
|
|
|
|
--set the vert position to be the new position
|
|
case geoClass of
|
|
(
|
|
Editable_Poly:
|
|
(
|
|
polyop.setVert item v vertPos
|
|
)
|
|
|
|
Editable_Mesh:
|
|
(
|
|
setVert item v vertPos
|
|
)
|
|
)--end case
|
|
)-- end hit
|
|
progressUpdate (100.0 * (v / numVerts as Float))
|
|
--progressUpdate v
|
|
)--end vert
|
|
progressEnd()
|
|
)
|
|
CenterPivot item
|
|
)--end item
|
|
|
|
CompleteRedraw()
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- Move to Ground
|
|
--------------------------------------------------------------
|
|
on btnAlignZ pressed do
|
|
(
|
|
undo "move to ground" on
|
|
(
|
|
local selObjs = for obj in selection where (isProperty obj "mesh") collect obj
|
|
|
|
if (selObjs.count == 0) do
|
|
(
|
|
messagebox "Please select at least one object with a mesh."
|
|
return false
|
|
)
|
|
if (pbn_ground.object == undefined) do
|
|
(
|
|
messagebox "Please set a ground object first."
|
|
return false
|
|
)
|
|
|
|
if (chkGndAlign.checked) then RSmoveToGround selObjs pbn_ground.object spnPercentOfGroundMin.value spnPercentOfGroundMax.value
|
|
else RSmoveToGround selObjs pbn_ground.object 0 0
|
|
)
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- Random Rotate
|
|
--------------------------------------------------------------
|
|
on btnRandRotZ pressed do
|
|
(
|
|
undo "random rotate" on
|
|
(
|
|
for obj in selection do
|
|
(
|
|
local rndRot = eulerangles 0 0 (random -180.0 180.0)
|
|
|
|
case radAxisChoice.state of
|
|
(
|
|
1:(in coordSys local rotate obj rndRot)
|
|
2:(in coordSys world rotate obj rndRot)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- Random Scale
|
|
--------------------------------------------------------------
|
|
on btnRandScale pressed do
|
|
(
|
|
undo "random scale" on
|
|
(
|
|
local nonDynSel = for obj in selection where
|
|
(
|
|
case of
|
|
(
|
|
(isRsRef obj):((obj.refDef != undefined) and (not obj.refDef.isDynamic))
|
|
(isInternalRef obj):(not RsMapObjectIsDynamic (getIRefSource obj))
|
|
default:(not RsMapObjectIsDynamic obj)
|
|
)
|
|
)
|
|
collect obj
|
|
|
|
-- Deselect non-dynamic objects:
|
|
if nonDynSel.count != selection.count do
|
|
(
|
|
clearSelection()
|
|
select nonDynSel
|
|
)
|
|
|
|
for obj in nonDynSel do
|
|
(
|
|
local jitterAmt = spnScaleJitter.value / 100.0
|
|
local rndScale = random (1 - jitterAmt) (1 + jitterAmt)
|
|
scale obj [rndScale, rndScale, rndScale]
|
|
)
|
|
)
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- Instancer
|
|
--------------------------------------------------------------
|
|
on btnChooseInst picked obj do
|
|
(
|
|
global RSinstMasterobj = obj
|
|
)
|
|
|
|
on btnChangeModels pressed do
|
|
(
|
|
if (RSinstMasterobj == undefined) then
|
|
(
|
|
messagebox "Please select an object to instance."
|
|
)
|
|
else
|
|
(
|
|
local models = selection as array
|
|
instanceMgr.MakeObjectsUnique models #group
|
|
|
|
local mastermat=RSinstMasterobj.material
|
|
copyAttrs RSinstMasterobj
|
|
|
|
for model in models do
|
|
(
|
|
model.objectoffsetpos = [0,0,0]
|
|
model.objectoffsetrot = (quat 0 0 0 1)
|
|
instancereplace model RSinstMasterobj
|
|
model.material=mastermat
|
|
pasteAttrs model
|
|
)
|
|
|
|
if isRSrefSuperClass RSinstMasterobj do
|
|
(
|
|
RsRefFuncs.clearObjRememberNames models
|
|
RSrefFuncs.setObjNames models
|
|
)
|
|
)
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- World-Sector Calculator
|
|
--------------------------------------------------------------
|
|
on spnWorldX changed val do
|
|
(
|
|
Refresh true
|
|
)
|
|
|
|
on spnWorldY changed val do
|
|
(
|
|
Refresh true
|
|
)
|
|
|
|
on spnSecX changed val do
|
|
(
|
|
Refresh false
|
|
)
|
|
|
|
on spnSecY changed val do
|
|
(
|
|
Refresh false
|
|
)
|
|
|
|
on GtaWorldSectorRoll open do
|
|
(
|
|
Refresh true
|
|
)
|
|
)
|
|
|
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
--------------------------------- CHECKS
|
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
rollout ChecksRoll "Checks"
|
|
(
|
|
--////////////////////////////////////////////////////////////
|
|
-- interface
|
|
--////////////////////////////////////////////////////////////
|
|
hyperlink lnkHelp "Help?" address:"https://devstar.rockstargames.com/wiki/index.php/Placement_Toolkit#Checks" align:#right color:(color 0 0 255) hoverColor:(color 0 0 255) visitedColor:(color 0 0 255)
|
|
|
|
group "Path Node Checker"
|
|
(
|
|
spinner spnDeviation "Deviation " width:97 align:#right
|
|
button btnFixPos "Fix Positions" width:130 across:2 offset:[-2,0]
|
|
button btnCheck "Check Link Deviation"width:130 offset:[2,0]
|
|
)
|
|
|
|
group "Bad Object Position Finder"
|
|
(
|
|
button btnFind "Find" width:130 across:2 offset:[-2,0]
|
|
button btnSelect "Select" width:130 offset:[2,0]
|
|
)
|
|
|
|
progressBar barLoad "ProgressBar" width:280 offset:[-10,0] height:10 color:red
|
|
|
|
--////////////////////////////////////////////////////////////
|
|
-- methods
|
|
--////////////////////////////////////////////////////////////
|
|
--------------------------------------------------------------
|
|
-- Path Node Checker
|
|
--------------------------------------------------------------
|
|
fn RecGetFixNodes rootobj setlist = (
|
|
for i = 1 to rootobj.children.count do (
|
|
obj = rootobj.children[i]
|
|
|
|
if obj.ishidden == false then (
|
|
if classof obj == Col_Mesh then (
|
|
append RsCollisionList obj
|
|
) else if classof obj == VehicleNode then (
|
|
append setlist obj
|
|
)
|
|
)
|
|
|
|
RecGetFixNodes obj setlist
|
|
)
|
|
)
|
|
|
|
fn RecGetCheckNodes rootobj setlist = (
|
|
for i = 1 to rootobj.children.count do (
|
|
obj = rootobj.children[i]
|
|
|
|
if obj.ishidden == false then (
|
|
if classof obj == Col_Mesh then (
|
|
append RsCollisionList obj
|
|
) else if classof obj == VehicleLink then (
|
|
append setlist obj
|
|
)
|
|
)
|
|
|
|
RecGetCheckNodes obj setlist
|
|
)
|
|
)
|
|
|
|
--////////////////////////////////////////////////////////////
|
|
-- events
|
|
--////////////////////////////////////////////////////////////
|
|
--------------------------------------------------------------
|
|
-- Path Node Checker
|
|
--------------------------------------------------------------
|
|
on btnFixPos pressed do (
|
|
local RsPathNodeList = #()
|
|
RecGetFixNodes rootnode RsPathNodeList
|
|
|
|
for i = 1 to RsPathNodeList.count do (
|
|
obj = RsPathNodeList[i]
|
|
barLoad.value = 100.0 * ((i as float)/ RsPathNodeList.count)
|
|
checkNodePathAgainstCollision obj
|
|
)
|
|
)
|
|
|
|
on btnCheck pressed do (
|
|
|
|
local RsPathList = #()
|
|
RecGetCheckNodes rootnode RsPathList
|
|
RsErrorList = #()
|
|
|
|
for i = 1 to RsPathList.count do (
|
|
obj = RsPathList[i]
|
|
barLoad.value = 100.0 * ((i as float)/ RsPathList.count)
|
|
|
|
if checkLinkAgainstCollision obj spnDeviation.value then (
|
|
append RsErrorList obj.name
|
|
)
|
|
)
|
|
|
|
rollout RsLinkErrors "Errors"
|
|
(
|
|
listbox lstErrors "Links:" items:RsErrorList height:10
|
|
button btnOK "OK"
|
|
|
|
on lstErrors selected item do (
|
|
foundobj = getnodebyname RsErrorList[item] exact:true
|
|
|
|
if (foundobj != undefined) then (
|
|
if isdeleted foundobj == false then (
|
|
select foundobj
|
|
max zoomext sel
|
|
)
|
|
)
|
|
)
|
|
|
|
on btnOK pressed do (
|
|
DestroyDialog RsLinkErrors
|
|
)
|
|
)
|
|
|
|
CreateDialog RsLinkErrors width:300 modal:false
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- Bad Object Position Finder
|
|
--------------------------------------------------------------
|
|
on btnFind pressed do
|
|
(
|
|
format "Finding bad objects...\n"
|
|
barLoad.value = 0
|
|
i = 0
|
|
cnt = 0
|
|
for obj in $objects do
|
|
(
|
|
i += 1
|
|
barLoad.value = 100.* i / $objects.count
|
|
if ( bit.isFinite( obj.pos.x ) and bit.isFinite( obj.pos.y ) and
|
|
bit.isFinite( obj.pos.z ) ) then
|
|
continue
|
|
|
|
cnt += 1
|
|
format "Invalid object position: %s %s\n" obj.name obj.pos
|
|
)
|
|
format "% objects found.\n" cnt
|
|
)
|
|
|
|
on btnSelect pressed do
|
|
(
|
|
clearSelection()
|
|
barLoad.value = 0
|
|
i = 0
|
|
cnt = 0
|
|
for obj in $objects do
|
|
(
|
|
i += 1
|
|
barLoad.value = 100.* i / $objects.count
|
|
if ( bit.isFinite( obj.pos.x ) and bit.isFinite( obj.pos.y ) and
|
|
bit.isFinite( obj.pos.z ) ) then
|
|
continue
|
|
|
|
cnt += 1
|
|
selectMore obj
|
|
)
|
|
format "% objects selected.\n" cnt
|
|
)
|
|
)
|
|
|
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
--------------------------------- FILE IMPORTER
|
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
rollout FileImportRoll "File Importer"
|
|
(
|
|
--////////////////////////////////////////////////////////////
|
|
-- interface
|
|
--////////////////////////////////////////////////////////////
|
|
hyperlink lnkHelp "Help?" address:"https://devstar.rockstargames.com/wiki/index.php/Placement_Toolkit#File_Importer" align:#right color:(color 0 0 255) hoverColor:(color 0 0 255) visitedColor:(color 0 0 255)
|
|
|
|
group "DAT Importer"
|
|
(
|
|
button btnImport "Import" width:130 across:2 offset:[-2,0]
|
|
button btnExport "Export" width:130 offset:[2,0]
|
|
)
|
|
|
|
group "Handhold Importer"
|
|
(
|
|
button btnLoadHandHoldXml "Load File" width:260
|
|
)
|
|
|
|
--////////////////////////////////////////////////////////////
|
|
-- events
|
|
--////////////////////////////////////////////////////////////
|
|
--------------------------------------------------------------
|
|
-- DAT Importer
|
|
--------------------------------------------------------------
|
|
on btnImport pressed do (
|
|
file = getopenfilename caption:"dat file to import" filename:"x:\\gta\\build\\common\\data\\paths\\" types:"DAT (*.dat)|*.dat|"
|
|
if file != undefined then BuildLine file
|
|
)
|
|
|
|
on btnExport pressed do (
|
|
file = getsavefilename caption:"dat file to export" filename:"x:\\gta\\build\\common\\data\\paths\\" types:"DAT (*.dat)|*.dat|"
|
|
if file != undefined then ExportSpline file
|
|
)
|
|
|
|
--------------------------------------------------------------
|
|
-- Handhold Importer
|
|
--------------------------------------------------------------
|
|
on btnLoadHandHoldXml pressed do (
|
|
LoadHandholdFile (getOpenFilename caption:"Handhold File" types:"xml file (*.xml)|*.xml")
|
|
)
|
|
)
|
|
|
|
try CloseRolloutFloater PlacementToolkit catch()
|
|
global PlacementToolkit = newRolloutFloater "Placement Toolkit" 300 750 50 96
|
|
addRollout Eplanter_roll PlacementToolkit
|
|
addRollout PlaceHelpersRoll PlacementToolkit
|
|
addRollout ChecksRoll PlacementToolkit
|
|
addRollout FileImportRoll PlacementToolkit
|