1255 lines
36 KiB
Plaintext
Executable File
1255 lines
36 KiB
Plaintext
Executable File
|
|
struct DataNode
|
|
(
|
|
parent,
|
|
key = "",
|
|
value = ""
|
|
)
|
|
|
|
struct ContentNode
|
|
(
|
|
parent,
|
|
type, --#source #export #scenexml #processed #target
|
|
id = "",
|
|
data = #(),
|
|
|
|
fn addData item =
|
|
(
|
|
append this.data (DataNode parent:this key:item.key value:item.value)
|
|
)
|
|
)
|
|
|
|
struct ContentEdge
|
|
(
|
|
parent,
|
|
source,
|
|
target,
|
|
type, --#export #preprocess #rage
|
|
data = #(),
|
|
|
|
fn addData item =
|
|
(
|
|
append this.data (DataNode parent:this key:item.key value:item.value)
|
|
)
|
|
)
|
|
|
|
struct ContentGraphNode
|
|
(
|
|
id = "",
|
|
edgedefault = "directed",
|
|
children = #()
|
|
)
|
|
|
|
|
|
struct ContentCreator
|
|
(
|
|
--dlcPathRoot = "X:/gta5_dlc/dlc_maps_test",
|
|
--assetType = "interior",
|
|
contentRoot = "",
|
|
assetName = "",
|
|
contentConfigPath = "",
|
|
parentContentPath = "",
|
|
contentGraph,
|
|
contentType,
|
|
writer,
|
|
|
|
archetypes,
|
|
entities,
|
|
slod2link,
|
|
prefix = "",
|
|
|
|
sourceAssetPath = "",
|
|
sourcePathRoot = "$(art)/models/",
|
|
exportPathRoot = ("$(export)/levels/" + (RsConfigGetProjectName()) + "/" ),
|
|
processedPathRoot = ("$(processed)/levels/" + (RsConfigGetProjectName()) + "/" ),
|
|
targetPathRoot = ("$(target)/levels/" + (RsConfigGetProjectName()) + "/" ),
|
|
area,
|
|
block,
|
|
|
|
/***
|
|
|
|
***/
|
|
fn graphNameSolver =
|
|
(
|
|
local id = "level:"
|
|
id += RsConfigGetProjectName()
|
|
|
|
id += ":"
|
|
id += contentType
|
|
|
|
return id
|
|
|
|
),
|
|
|
|
/***
|
|
return a name for a node based on the content
|
|
***/
|
|
fn nodeIdNameSolver inputNode =
|
|
(
|
|
local id = "level:"
|
|
|
|
--projectname
|
|
id += RsConfigGetProjectName()
|
|
|
|
--content type
|
|
id += ":"
|
|
|
|
local pathbits = filterString sourceAssetPath "\\"
|
|
local modelsIdx = findItem pathbits "models"
|
|
if modelsIdx != 0 then
|
|
(
|
|
id += pathbits[modelsIdx + 1]
|
|
)
|
|
|
|
--id += inputNode.
|
|
|
|
--filename
|
|
id += ":"
|
|
id += assetName
|
|
|
|
--node type
|
|
id += ":"
|
|
id += inputNode.type
|
|
|
|
|
|
--replace any :: with :
|
|
id = substituteString id "::" ":"
|
|
|
|
--return
|
|
id
|
|
),
|
|
|
|
|
|
/***
|
|
|
|
***/
|
|
fn createNode parentGraph type: =
|
|
(
|
|
local newNode = ContentNode parent:parentGraph
|
|
newNode.type = type
|
|
append newNode.parent.children newNode
|
|
newNode.id = nodeIdNameSolver newNode
|
|
|
|
return newNode
|
|
),
|
|
|
|
/***
|
|
create and edge between two nodes
|
|
***/
|
|
fn createEdge node1 node2 parentGraph type: =
|
|
(
|
|
local newEdge = ContentEdge parent:parentGraph
|
|
newEdge.source = node1
|
|
newEdge.target = node2
|
|
--newEdge.parent = parentGraph
|
|
newEdge.type = type
|
|
|
|
append newEdge.parent.children newEdge
|
|
|
|
return newEdge
|
|
),
|
|
|
|
/***
|
|
Create a data processor
|
|
***/
|
|
fn createProcessorDataNode type parentNode =
|
|
(
|
|
|
|
),
|
|
|
|
/***
|
|
Create a interior content graph
|
|
***/
|
|
fn constructInteriorGraph =
|
|
(
|
|
this.contentGraph = ContentGraphNode()
|
|
this.contentGraph.id = graphNameSolver()
|
|
|
|
--paths
|
|
local pathValue = "$(art)/models/interiors/" + assetName + ".max"
|
|
local exportPathValue = "$(export)/levels/" + gRsCoreConfig.project.name + "/interiors/" + assetName + ".zip"
|
|
local processedPathValue = processedPathRoot + "interiors/" + assetName + ".zip"
|
|
local targetPathValue = "$(target)/levels/" + gRsCoreConfig.project.name + "/interiors/" + assetName + ".rpf"
|
|
|
|
--create Source nodes
|
|
local sourceNode = createNode this.contentGraph type:#source
|
|
sourceNode.addData (DataPair key:"content_type" value:"file")
|
|
sourceNode.addData (DataPair key:"path" value:pathValue)
|
|
sourceNode.addData (DataPair key:"max_type" value:"interior")
|
|
sourceNode.addData (DataPair key:"archetypes" value:archetypes)
|
|
sourceNode.addData (DataPair key:"entities" value:entities)
|
|
sourceNode.addData (DataPair key:"prefix" value:prefix)
|
|
|
|
--create Export nodes
|
|
local zipExportNode = createNode this.contentGraph type:#export
|
|
zipExportNode.addData (DataPair key:"content_type" value:"file")
|
|
zipExportNode.addData (DataPair key:"path" value:exportPathValue)
|
|
|
|
local sceneExportNode = createNode this.contentGraph type:#scenexml
|
|
sceneExportNode.addData (DataPair key:"content_type" value:"file")
|
|
exportPathValue = "$(export)/levels/" + gRsCoreConfig.project.name + "/interiors/" + assetName + ".xml"
|
|
sceneExportNode.addData (DataPair key:"path" value:exportPathValue)
|
|
|
|
--create Processed Nodes
|
|
local processedNode = createNode this.contentGraph type:#processed
|
|
processedNode.addData (DataPair key:"content_type" value:"file")
|
|
processedNode.addData (DataPair key:"path" value:processedPathValue)
|
|
|
|
--create Target nodes
|
|
local targetNode = createNode this.contentGraph type:#target
|
|
targetNode.addData (DataPair key:"content_type" value:"file")
|
|
targetNode.addData (DataPair key:"path" value:targetPathValue)
|
|
|
|
--create ExportEdges
|
|
local exportEdge1 = createEdge sourceNode zipExportNode this.contentGraph type:#export
|
|
exportEdge1.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Common.Dcc3dsmaxExportProcessor")
|
|
exportEdge1.addData (DataPair key:"dcc_export_process" value:"true")
|
|
|
|
local exportEdge2 = createEdge sourceNode sceneExportNode this.contentGraph type:#export
|
|
exportEdge2.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Common.Dcc3dsmaxExportProcessor")
|
|
exportEdge2.addData (DataPair key:"dcc_export_process" value:"true")
|
|
|
|
--create Processed Edges
|
|
local processEdge1 = createEdge zipExportNode processedNode this.contentGraph type:#preprocess
|
|
processEdge1.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Map.PreProcess")
|
|
|
|
local processEdge2 = createEdge sceneExportNode processedNode this.contentGraph type:#preprocess
|
|
processEdge2.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Map.PreProcess")
|
|
|
|
--create Target Edge
|
|
local targetEdge = createEdge processedNode targetNode this.contentGraph type:#rage
|
|
targetEdge.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Platform.Rage")
|
|
),
|
|
|
|
/***
|
|
Create a map_container content graph
|
|
***/
|
|
fn constructMapContainerGraph =
|
|
(
|
|
this.contentGraph = ContentGraphNode()
|
|
this.contentGraph.id = graphNameSolver()
|
|
|
|
--PATHS
|
|
local localityPath
|
|
local sourcePathValue
|
|
local exportPathValue
|
|
local exportSceneXml
|
|
local processedPathValue
|
|
local targetPathValue
|
|
if prefix == "" then
|
|
(
|
|
prefix = assetName
|
|
)
|
|
|
|
case gRsCoreConfig.project.name of
|
|
(
|
|
"gta5":
|
|
(
|
|
localityPath = block + "/" + area
|
|
sourcePathValue = sourcePathRoot + localityPath + assetName + ".maxc"
|
|
exportPathValue = exportPathRoot + localityPath + assetName + ".zip"
|
|
exportSceneXml = exportPathRoot + localityPath + assetName + ".xml"
|
|
processedPathValue = "$(processed)/levels/" + gRsCoreConfig.project.name + "/" + localityPath + assetName + ".zip"
|
|
targetPathValue = targetPathRoot + localityPath + assetName + ".rpf"
|
|
)
|
|
|
|
"gta5_liberty":
|
|
(
|
|
localityPath = block + "/" + area
|
|
sourcePathValue = sourcePathRoot + area + assetName + ".maxc"
|
|
exportPathValue = exportPathRoot + area + assetName + ".zip"
|
|
exportSceneXml = exportPathRoot + area + assetName + ".xml"
|
|
processedPathValue = "$(processed)/levels/" + gRsCoreConfig.project.name + "/" + area + assetName + ".zip"
|
|
targetPathValue = targetPathRoot + area + assetName + ".rpf"
|
|
)
|
|
)
|
|
|
|
--create Source nodes
|
|
local sourceNode = createNode this.contentGraph type:#source
|
|
sourceNode.addData (DataPair key:"content_type" value:"file")
|
|
sourceNode.addData (DataPair key:"path" value:sourcePathValue)
|
|
sourceNode.addData (DataPair key:"max_type" value:"map_container")
|
|
sourceNode.addData (DataPair key:"archetypes" value:archetypes)
|
|
sourceNode.addData (DataPair key:"entities" value:entities)
|
|
sourceNode.addData (DataPair key:"prefix" value:prefix)
|
|
|
|
--create Export nodes
|
|
local zipExportNode = createNode this.contentGraph type:#export
|
|
zipExportNode.addData (DataPair key:"content_type" value:"file")
|
|
zipExportNode.addData (DataPair key:"path" value:exportPathValue)
|
|
|
|
local sceneExportNode = createNode this.contentGraph type:#scenexml
|
|
sceneExportNode.addData (DataPair key:"content_type" value:"file")
|
|
sceneExportNode.addData (DataPair key:"path" value:exportSceneXml)
|
|
|
|
--create Processed Nodes
|
|
local processedNode = createNode this.contentGraph type:#processed
|
|
processedNode.addData (DataPair key:"content_type" value:"file")
|
|
processedNode.addData (DataPair key:"path" value:processedPathValue)
|
|
processedNode.addData (DataPair key:"slod2link" value:slod2link)
|
|
|
|
--create Target nodes
|
|
local targetNode = createNode this.contentGraph type:#target
|
|
targetNode.addData (DataPair key:"content_type" value:"file")
|
|
targetNode.addData (DataPair key:"path" value:targetPathValue)
|
|
|
|
--create ExportEdges
|
|
local exportEdge1 = createEdge sourceNode zipExportNode this.contentGraph type:#export
|
|
exportEdge1.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Common.Dcc3dsmaxExportProcessor")
|
|
exportEdge1.addData (DataPair key:"dcc_export_process" value:"true")
|
|
|
|
local exportEdge2 = createEdge sourceNode sceneExportNode this.contentGraph type:#export
|
|
exportEdge2.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Common.Dcc3dsmaxExportProcessor")
|
|
exportEdge2.addData (DataPair key:"dcc_export_process" value:"true")
|
|
|
|
--create Processed Edges
|
|
local processEdge1 = createEdge zipExportNode processedNode this.contentGraph type:#preprocess
|
|
processEdge1.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Map.PreProcess")
|
|
|
|
local processEdge2 = createEdge sceneExportNode processedNode this.contentGraph type:#preprocess
|
|
processEdge2.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Map.PreProcess")
|
|
|
|
--create Target Edge
|
|
local targetEdge = createEdge processedNode targetNode this.contentGraph type:#rage
|
|
targetEdge.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Platform.Rage")
|
|
|
|
|
|
),
|
|
|
|
/***
|
|
Create a lod_container graph
|
|
***/
|
|
fn constructLodContainerGraph =
|
|
(
|
|
|
|
),
|
|
|
|
/***
|
|
Create a occl_container graph
|
|
***/
|
|
fn constructOcclContainerGraph =
|
|
(
|
|
|
|
),
|
|
|
|
/***
|
|
Create a prop graph
|
|
***/
|
|
fn constructPropGraph =
|
|
(
|
|
--like interior except dont export entities
|
|
this.contentGraph = ContentGraphNode()
|
|
this.contentGraph.id = graphNameSolver()
|
|
|
|
--paths
|
|
local propFolder
|
|
local pathValue
|
|
local exportPathValue
|
|
local sceneXmlPathValue
|
|
local processedPathValue
|
|
local targetPathValue
|
|
|
|
case gRsCoreConfig.project.name of
|
|
(
|
|
"gta5":
|
|
(
|
|
propFolder = substituteString (pathConfig.stripPathToLeaf maxfilepath) "\\" "/"
|
|
pathValue = "$(art)/models/" + propFolder + assetName + ".max"
|
|
exportPathValue = "$(export)/levels/" + gRsCoreConfig.project.name + "/props/" + assetName + ".zip"
|
|
sceneXmlPathValue = "$(export)/levels/" + gRsCoreConfig.project.name + "/props/" + propFolder + assetName + ".xml"
|
|
processedPathValue = processedPathRoot + "props/" + assetName + ".zip"
|
|
targetPathValue = "$(target)/levels/" + gRsCoreConfig.project.name + "/props/" + assetName + ".rpf"
|
|
)
|
|
|
|
"gta5_liberty":
|
|
(
|
|
propFolder = substituteString (pathConfig.stripPathToLeaf maxfilepath) "\\" "/"
|
|
pathValue = "$(art)/models/gta5/props/" + propFolder + assetName + ".max"
|
|
exportPathValue = "$(export)/levels/" + "gta5" + "/props/" + propFolder + assetName + ".zip"
|
|
sceneXmlPathValue = "$(export)/levels/" + "gta5" + "/props/" + propFolder + assetName + ".xml"
|
|
processedPathValue = processedPathRoot + "props/" + propFolder + assetName + ".zip"
|
|
targetPathValue = "$(target)/levels/" + gRsCoreConfig.project.name + "/props/" + propFolder + assetName + ".rpf"
|
|
)
|
|
)
|
|
|
|
--create Source nodes
|
|
local sourceNode = createNode this.contentGraph type:#source
|
|
sourceNode.addData (DataPair key:"content_type" value:"file")
|
|
sourceNode.addData (DataPair key:"path" value:pathValue)
|
|
sourceNode.addData (DataPair key:"max_type" value:"props")
|
|
sourceNode.addData (DataPair key:"archetypes" value:archetypes)
|
|
sourceNode.addData (DataPair key:"entities" value:entities)
|
|
sourceNode.addData (DataPair key:"prefix" value:prefix)
|
|
|
|
--create Export nodes
|
|
local zipExportNode = createNode this.contentGraph type:#export
|
|
zipExportNode.addData (DataPair key:"content_type" value:"file")
|
|
zipExportNode.addData (DataPair key:"path" value:exportPathValue)
|
|
|
|
local sceneExportNode = createNode this.contentGraph type:#scenexml
|
|
sceneExportNode.addData (DataPair key:"content_type" value:"file")
|
|
sceneExportNode.addData (DataPair key:"path" value:sceneXmlPathValue)
|
|
|
|
--create Processed Nodes
|
|
local processedNode = createNode this.contentGraph type:#processed
|
|
processedNode.addData (DataPair key:"content_type" value:"file")
|
|
processedNode.addData (DataPair key:"path" value:processedPathValue)
|
|
|
|
--create Target nodes
|
|
local targetNode = createNode this.contentGraph type:#target
|
|
targetNode.addData (DataPair key:"content_type" value:"file")
|
|
targetNode.addData (DataPair key:"path" value:targetPathValue)
|
|
|
|
--create ExportEdges
|
|
local exportEdge1 = createEdge sourceNode zipExportNode this.contentGraph type:#export
|
|
exportEdge1.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Common.Dcc3dsmaxExportProcessor")
|
|
exportEdge1.addData (DataPair key:"dcc_export_process" value:"true")
|
|
|
|
local exportEdge2 = createEdge sourceNode sceneExportNode this.contentGraph type:#export
|
|
exportEdge2.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Common.Dcc3dsmaxExportProcessor")
|
|
exportEdge2.addData (DataPair key:"dcc_export_process" value:"true")
|
|
|
|
--create Processed Edges
|
|
local processEdge1 = createEdge zipExportNode processedNode this.contentGraph type:#preprocess
|
|
processEdge1.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Map.PreProcess")
|
|
|
|
local processEdge2 = createEdge sceneExportNode processedNode this.contentGraph type:#preprocess
|
|
processEdge2.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Map.PreProcess")
|
|
|
|
--create Target Edge
|
|
local targetEdge = createEdge processedNode targetNode this.contentGraph type:#rage
|
|
targetEdge.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Platform.Rage")
|
|
),
|
|
|
|
/***
|
|
Create a vehicle graph
|
|
***/
|
|
fn constructVehicleGraph =
|
|
(
|
|
this.contentGraph = ContentGraphNode()
|
|
this.contentGraph.id = graphNameSolver()
|
|
|
|
--PATHS
|
|
--local sourcePathValue = "$(art)/models/props/weapons/" + assetName + "/" + assetName + ".max"
|
|
local exportPathValue = "$(export)/levels/gta5/vehicles_packed"
|
|
local targetPathValue = "$(target)/models/cdimages/" + assetName + ".rpf"
|
|
|
|
),
|
|
|
|
/***
|
|
Create a weapon graph
|
|
***/
|
|
fn constructWeaponGraph =
|
|
(
|
|
this.contentGraph = ContentGraphNode()
|
|
this.contentGraph.id = graphNameSolver()
|
|
|
|
--PATHS
|
|
local sourcePathValue = "$(art)/models/props/weapons/" + assetName + "/" + assetName + ".max"
|
|
local exportPathValue = "$(export)/models/cdimages/weapons.zip"
|
|
local targetPathValue = "$(target)/models/cdimages/weapons.rpf"
|
|
|
|
--create Source nodes
|
|
local sourceNode = createNode this.contentGraph type:#source
|
|
sourceNode.addData (DataPair key:"content_type" value:"file")
|
|
sourceNode.addData (DataPair key:"path" value:sourcePathValue)
|
|
sourceNode.addData (DataPair key:"archetypes" value:archetypes)
|
|
sourceNode.addData (DataPair key:"entities" value:entities)
|
|
|
|
--create Export nodes
|
|
local zipExportNode = createNode this.contentGraph type:#export
|
|
zipExportNode.addData (DataPair key:"content_type" value:"file")
|
|
zipExportNode.addData (DataPair key:"path" value:exportPathValue)
|
|
|
|
--create Target nodes
|
|
local targetNode = createNode this.contentGraph type:#target
|
|
targetNode.addData (DataPair key:"content_type" value:"file")
|
|
targetNode.addData (DataPair key:"path" value:targetPathValue)
|
|
|
|
--create ExportEdges
|
|
local exportEdge1 = createEdge sourceNode zipExportNode this.contentGraph type:#export
|
|
exportEdge1.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Common.Dcc3dsmaxExportProcessor")
|
|
|
|
--create Target Edge
|
|
local targetEdge = createEdge zipExportNode targetNode this.contentGraph type:#rage
|
|
targetEdge.addData (DataPair key:"processor" value:"RSG.Pipeline.Processor.Platform.Rage")
|
|
),
|
|
|
|
/***
|
|
Create a graph
|
|
***/
|
|
fn createGraph =
|
|
(
|
|
print contentType
|
|
|
|
case contentType of
|
|
(
|
|
"map_container": constructMapContainerGraph()
|
|
"lod_container": constructLodContainerGraph()
|
|
"occl_container": constructOcclContainerGraph()
|
|
"interior": constructInteriorGraph()
|
|
"prop": constructPropGraph()
|
|
"weapon": constructWeaponGraph()
|
|
"vehicle": constructVehicleGraph()
|
|
default: print "da fuq!?"
|
|
|
|
)
|
|
),
|
|
|
|
/**********************************************************************************************************************
|
|
IO Functions
|
|
|
|
|
|
**********************************************************************************************************************/
|
|
|
|
/***
|
|
Read an existing content tree document and create an internal node tree representation
|
|
***/
|
|
fn readContent =
|
|
(
|
|
|
|
),
|
|
|
|
|
|
/***
|
|
|
|
***/
|
|
fn harvestContentNodePaths xmlRoot =
|
|
(
|
|
--collect all the paths in the content tree using the input xml
|
|
local pathNodes = xmlRoot.SelectNodes ".//data[@key=\"path\"]"
|
|
local pathValues = for i=0 to (pathNodes.count - 1) collect pathNodes.item[i].innerText
|
|
|
|
return pathValues
|
|
),
|
|
|
|
|
|
/***
|
|
|
|
***/
|
|
fn harvestContentGraphPaths =
|
|
(
|
|
local contentNodes = for item in this.contentGraph.children where (classOf item == ContentNode) collect item
|
|
local paths = #()
|
|
for item in contentNodes do
|
|
(
|
|
local pathVal = for elem in item.data where elem.key == "path" collect elem.value
|
|
appendifunique paths pathVal[1]
|
|
)
|
|
|
|
return paths
|
|
),
|
|
|
|
/***
|
|
Validate conent that is being created or appended against existing content tree to check that these paths are not already being
|
|
defined for data conversion, which could lead to errors in the build pipeline
|
|
***/
|
|
fn validateContent xml contentNodePaths =
|
|
(
|
|
--gRsProject.name
|
|
local foundConflict = false
|
|
|
|
--get the XInclude nodes
|
|
local nt = dotnetobject "System.Xml.NameTable"
|
|
local xmlns = dotnetobject "System.Xml.XmlNamespaceManager" nt
|
|
xmlns.AddNameSpace "xi" "http://www.w3.org/2003/XInclude"
|
|
local includedXml = xml.SelectNodes ".//xi:include/@href" xmlns
|
|
--print includedXml.count
|
|
|
|
for i=0 to (includedXml.count - 1) do
|
|
(
|
|
local thisXml = includedXml.item[i].value
|
|
local xmlDoc = dotNetObject "System.Xml.XmlDocument"
|
|
try
|
|
(
|
|
xmlDoc.load thisXml
|
|
)
|
|
catch
|
|
(
|
|
print "Could not load this xml"
|
|
print thisXml
|
|
continue
|
|
)
|
|
|
|
local xmlRoot = xmlDoc.DocumentElement
|
|
|
|
local pathValues = harvestContentNodePaths xmlRoot
|
|
|
|
--see if any match against the supplied paths for the new content
|
|
for path in pathValues do
|
|
(
|
|
if (findItem contentNodePaths path) != 0 then
|
|
(
|
|
--break()
|
|
foundConflict = true
|
|
return foundConflict
|
|
)
|
|
)
|
|
)
|
|
|
|
return foundConflict
|
|
|
|
),
|
|
|
|
/***
|
|
|
|
***/
|
|
fn writeEdges type =
|
|
(
|
|
for item in this.contentGraph.children where (classOf item == ContentEdge) and (item.type == type) do
|
|
(
|
|
writer.WriteStartElement("edge")
|
|
writer.WriteAttributeString "source" item.source.id
|
|
writer.WriteAttributeString "target" item.target.id
|
|
for data in item.data do
|
|
(
|
|
writer.WriteStartElement("data")
|
|
writer.WriteAttributeString "key" data.key
|
|
writer.WriteValue data.value
|
|
writer.WriteEndElement()
|
|
)
|
|
writer.WriteEndElement()
|
|
)
|
|
),
|
|
|
|
/***
|
|
|
|
***/
|
|
fn writeNodes type =
|
|
(
|
|
for item in this.contentGraph.children where (classOf item == ContentNode) and (item.type == type) do
|
|
(
|
|
writer.WriteStartElement("node")
|
|
writer.WriteAttributeString "id" item.id
|
|
for data in item.data do
|
|
(
|
|
writer.WriteStartElement("data")
|
|
writer.WriteAttributeString "key" data.key
|
|
writer.WriteValue data.value
|
|
writer.WriteEndElement()
|
|
)
|
|
writer.WriteEndElement()
|
|
)
|
|
),
|
|
|
|
/***
|
|
|
|
***/
|
|
fn removeContent xmlDoc graphNode id =
|
|
(
|
|
--find all the nodes and get their names
|
|
local matchingNodes = graphNode.SelectNodes (".//node[contains(@id, \"" + id + "\")]")
|
|
|
|
--now match the node names for edges that use them
|
|
local nodeIt = matchingNodes.GetEnumerator()
|
|
while nodeIt.MoveNext() do
|
|
(
|
|
local idAttr = nodeIt.Current.GetAttribute "id"
|
|
|
|
--find edges referencing this node
|
|
local dependentEdges = graphNode.SelectNodes (".//edge[contains(@source, \"" + idAttr + "\") or contains(@target, \"" + idAttr + "\")]")
|
|
local edgeIt = dependentEdges.GetEnumerator()
|
|
while edgeIt.MoveNext() do
|
|
(
|
|
graphNode.RemoveChild edgeIt.Current
|
|
)
|
|
graphNode.RemoveChild nodeIt.Current
|
|
)
|
|
|
|
),
|
|
|
|
/***
|
|
|
|
***/
|
|
fn appendEdges xmlDoc graph type =
|
|
(
|
|
for item in this.contentGraph.children where (classOf item == ContentEdge) and (item.type == type) do
|
|
(
|
|
local newEdge = xmlDoc.CreateElement "edge"
|
|
local sourceAttr = xmlDoc.CreateAttribute "source"
|
|
sourceAttr.value = item.source.id
|
|
newEdge.SetAttributeNode sourceAttr
|
|
local targetAttr = xmlDoc.CreateAttribute "target"
|
|
targetAttr.value = item.target.id
|
|
newEdge.SetAttributeNode targetAttr
|
|
|
|
for data in item.data do
|
|
(
|
|
local dataNode = xmlDoc.CreateElement "data"
|
|
local keyAttr = xmlDoc.CreateAttribute "key"
|
|
keyAttr.value = data.key
|
|
dataNode.InnerText = data.value
|
|
dataNode.SetAttributeNode keyAttr
|
|
newEdge.AppendChild dataNode
|
|
)
|
|
graph.AppendChild newEdge
|
|
)
|
|
),
|
|
|
|
/***
|
|
|
|
***/
|
|
fn appendNodes xmlDoc graph type =
|
|
(
|
|
for item in this.contentGraph.children where (classOf item == ContentNode) and (item.type == type) do
|
|
(
|
|
local newNode = xmlDoc.CreateElement "node"
|
|
local idAttr = xmlDoc.CreateAttribute "id"
|
|
idAttr.value = item.id
|
|
newNode.SetAttributeNode idAttr
|
|
|
|
for data in item.data do
|
|
(
|
|
local dataNode = xmlDoc.CreateElement "data"
|
|
local keyAttr = xmlDoc.CreateAttribute "key"
|
|
keyAttr.value = data.key
|
|
dataNode.InnerText = data.value
|
|
dataNode.SetAttributeNode keyAttr
|
|
newNode.AppendChild dataNode
|
|
)
|
|
|
|
graph.AppendChild newNode
|
|
)
|
|
),
|
|
|
|
/***
|
|
Append to a content tree document
|
|
***/
|
|
fn appendContent =
|
|
(
|
|
local xmlDoc = dotNetObject "System.Xml.XmlDocument"
|
|
|
|
--load the xml doc
|
|
xmlDoc.load this.contentConfigPath
|
|
local xmlRoot = xmlDoc.DocumentElement
|
|
|
|
local nt = dotnetobject "System.Xml.NameTable"
|
|
local xmlns = dotnetobject "System.Xml.XmlNamespaceManager" nt
|
|
xmlns.AddNameSpace "ns" "http://graphml.graphdrawing.org/xmlns"
|
|
|
|
local graphNode = xmlRoot.SelectSingleNode "//graph" xmlns
|
|
if (graphNode == undefined) then
|
|
(
|
|
graphNode = xmlRoot.SelectSingleNode "//ns:graph" xmlns
|
|
)
|
|
|
|
local foundConflicts = validateContent xmlRoot (harvestContentGraphPaths())
|
|
|
|
if not foundConflicts then
|
|
(
|
|
--create a changelist to store the file changes
|
|
local changeListNum = gRsPerforce.createChangelist "Append content"
|
|
|
|
--maybe check if there is content to overwrite
|
|
--using this.assetName
|
|
local matchingNodes = graphNode.SelectNodes (".//node[contains(@id, \"" + assetName + "\")]")
|
|
if (matchingNodes.count != 0) then --we have some nodes already in place that need removing
|
|
(
|
|
removeContent xmlDoc graphNode assetName
|
|
)
|
|
|
|
--append the nodes and edges
|
|
appendNodes xmlDoc graphNode #source
|
|
appendNodes xmlDoc graphNode #export
|
|
appendNodes xmlDoc graphNode #scenexml
|
|
appendNodes xmlDoc graphNode #processed
|
|
appendNodes xmlDoc graphNode #target
|
|
|
|
appendEdges xmlDoc graphNode #export
|
|
appendEdges xmlDoc graphNode #preprocess
|
|
appendEdges xmlDoc graphNode #rage
|
|
|
|
--is it writable? check out of perforce?
|
|
if ( (getFileAttribute this.contentConfigPath #readonly) == true) then
|
|
(
|
|
local p4Exists = gRsPerforce.exists #(this.contentConfigPath)
|
|
if p4Exists[1] then
|
|
(
|
|
gRsPerforce.add_or_edit #(this.contentConfigPath)
|
|
gRsPerforce.addToChangelist changeListNum this.contentConfigPath
|
|
)
|
|
else
|
|
(
|
|
setFileAttribute this.contentConfigPath #readonly false
|
|
)
|
|
)
|
|
|
|
--save it
|
|
try
|
|
(
|
|
xmlDoc.save this.contentConfigPath
|
|
)
|
|
catch
|
|
(
|
|
messagebox "failed to save the conent document" title:"Failed Save"
|
|
)
|
|
)
|
|
else
|
|
(
|
|
messagebox "This content already exists in the content tree" title:"Content Tree Conflict"
|
|
)
|
|
),
|
|
|
|
/***
|
|
Create a new content tree document
|
|
***/
|
|
fn createContent =
|
|
(
|
|
--check for valid output path
|
|
if (this.contentConfigPath == undefined ) or (pathConfig.isLegalPath this.contentConfigPath == false) then
|
|
(
|
|
messagebox "No valid path set" title:"Bad Path"
|
|
return false
|
|
)
|
|
|
|
--create a changelist to store the file changes
|
|
local changeListNum = gRsPerforce.createChangelist "Create contenttree"
|
|
|
|
--init the document
|
|
|
|
--create the xml doc
|
|
--initiate writer
|
|
local xmlFormatter = dotnetobject "System.Xml.XMLWriterSettings"
|
|
xmlFormatter.Indent = true
|
|
|
|
writer = dotnetclass "System.Xml.XMLWriter"
|
|
writer = writer.Create this.contentConfigPath xmlFormatter
|
|
|
|
--make the header
|
|
writer.WriteStartDocument()
|
|
writer.WriteStartElement("graphml")
|
|
-- writer.WriteAttributeString "xmlns" "http://graphml.graphdrawing.org/xmlns"
|
|
-- writer.WriteAttributeString "xmlns:xsi" "http://www.w3.org/2001/XMLSchema-instance"
|
|
-- writer.WriteAttributeString "xmlns:xi" "http://www.w3.org/2003/XInclude"
|
|
-- writer.WriteAttributeString "xsi:schemaLocation" "http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"
|
|
|
|
writer.WriteStartElement("graph")
|
|
writer.WriteAttributeString "id" (this.contentGraph.id)
|
|
writer.WriteAttributeString "edgedefault" "directed"
|
|
|
|
writer.WriteComment("Nodes")
|
|
--make the nodes
|
|
writeNodes #source
|
|
writeNodes #export
|
|
writeNodes #scenexml
|
|
writeNodes #processed
|
|
writeNodes #target
|
|
|
|
writer.WriteComment("Edges")
|
|
--make the edges
|
|
writeEdges #export
|
|
writeEdges #preprocess
|
|
writeEdges #rage
|
|
|
|
--make the footer
|
|
writer.WriteEndElement()
|
|
writer.WriteEndElement()
|
|
|
|
--finish up
|
|
writer.WriteEndDocument()
|
|
|
|
--save the document
|
|
try
|
|
(
|
|
writer.Flush()
|
|
writer.Close()
|
|
|
|
gRsPerforce.add_or_edit #(this.contentConfigPath)
|
|
gRsPerforce.addToChangelist changeListNum this.contentConfigPath
|
|
)
|
|
catch
|
|
(
|
|
messagebox "Problem saving the content tree file" title:"File Save Error"
|
|
return false
|
|
)
|
|
|
|
|
|
--Now check if parentContnetPath is set and add this new file into that
|
|
if (parentContentPath != "") then
|
|
(
|
|
--check writable
|
|
if ( (getFileAttribute this.parentContentPath #readonly) == true) then
|
|
(
|
|
local p4Exists = gRsPerforce.exists #(this.parentContentPath)
|
|
if p4Exists[1] then
|
|
(
|
|
gRsPerforce.add_or_edit #(this.parentContentPath)
|
|
gRsPerforce.addToChangelist changeListNum this.parentContentPath
|
|
)
|
|
else
|
|
(
|
|
setFileAttribute this.parentContentPath #readonly false
|
|
)
|
|
)
|
|
|
|
local xmlDoc = dotNetObject "System.Xml.XmlDocument"
|
|
|
|
--load the xml doc
|
|
xmlDoc.load this.parentContentPath
|
|
local xmlRoot = xmlDoc.DocumentElement
|
|
|
|
--check for content clashes
|
|
local paths = harvestContentGraphPaths()
|
|
local foundConflicts = validateContent xmlRoot paths
|
|
format "foundConflicts: % \n" foundConflicts as String
|
|
|
|
if not foundConflicts then
|
|
(
|
|
local includeNode = xmlDoc.CreateElement "xi" "include" "http://www.w3.org/2003/XInclude"
|
|
local keyAttr = xmlDoc.CreateAttribute "href"
|
|
keyAttr.value = (getfilenamefile this.contentConfigPath) + ".xml"
|
|
includeNode.SetAttributeNode keyAttr
|
|
|
|
xmlRoot.AppendChild includeNode
|
|
|
|
try
|
|
(
|
|
xmlDoc.save this.parentContentPath
|
|
)
|
|
catch
|
|
(
|
|
messagebox "Problem saving the parent content tree file" title:"File Save Error"
|
|
return false
|
|
)
|
|
)
|
|
else
|
|
(
|
|
messagebox "This content already exists in the content tree" title:"Content Tree Conflict"
|
|
try
|
|
(
|
|
deletefile this.contentConfigPath
|
|
)
|
|
catch
|
|
(
|
|
print "Tried to delete the new content file, but failed"
|
|
)
|
|
gRsPerforce.deleteChangelistIfItHasNoChanges changeListNum
|
|
)
|
|
)
|
|
),
|
|
|
|
/***
|
|
|
|
***/
|
|
on create do
|
|
(
|
|
--Init ContentCreator struct
|
|
)
|
|
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
-- UI
|
|
--/////////////////////////////////////////
|
|
try(destroyDialog ContentCreatorUI)catch()
|
|
rollout ContentCreatorUI "Content Tree Creator" width:400 height:350
|
|
(
|
|
--/////////////////////////////////////////
|
|
-- VARIABLES
|
|
--/////////////////////////////////////////
|
|
local contentTree = ContentCreator()
|
|
--local max_TypeList = #("map_container", "lod_container", "occl_container", "interior", "prop", "weapon", "vehicle")
|
|
local max_TypeList = #("interior", "weapon", "prop")
|
|
local contentPath
|
|
|
|
--/////////////////////////////////////////
|
|
-- CONTROLS
|
|
--/////////////////////////////////////////
|
|
dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:(ContentCreatorUI.width)
|
|
local banner = makeRsBanner dn_Panel:rsBannerPanel wiki:"DLC_ContentTree_Creator" versionNum:0.57 versionName:"Amethyst Fist" filename:(getThisScriptFilename())
|
|
|
|
--label lblAssetPath "Asset Path"
|
|
|
|
--checkbox chkDlc "DLC"
|
|
|
|
group "Asset settings"
|
|
(
|
|
dropdownlist ddlMax_Type items:max_TypeList
|
|
checkbox chkArchetypes "Archetypes" across:3
|
|
checkbox chkEntities "Entities"
|
|
checkbox chkSLOD2Link "Slod2 Link"
|
|
edittext edtPrefix "Prefix:"
|
|
|
|
)
|
|
|
|
group "Create Content"
|
|
(
|
|
edittext edtContentFolderPath "DLC Folder: " text:"" edittable:false width:(ContentCreatorUI.width - 75) across:2
|
|
button btnContentPathBrowse "..." align:#right
|
|
edittext edtParentContentFilePath "Parent Content: " text:"dlc_content.xml" width:(ContentCreatorUI.width - 75) across:2
|
|
button btnParentContentPathBrowse "..." align:#right
|
|
edittext edtContentName "Name:" width:(ContentCreatorUI.width - 75)
|
|
button btnCreateConfig "Create" width:(ContentCreatorUI.width - 25)
|
|
)
|
|
|
|
group "Append Content"
|
|
(
|
|
edittext edtContentAppendFilePath "Asset Path: " text:"" edittable:false width:(ContentCreatorUI.width - 75) across:2
|
|
button btnContentAppendPathBrowse "..." align:#right
|
|
button btnAppendConfig "Append" width:(ContentCreatorUI.width - 25)
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
-- FUNCTIONS
|
|
--/////////////////////////////////////////
|
|
fn setOpts =
|
|
(
|
|
if (contentPath == "") then
|
|
(
|
|
messageBox "No asset path set" title:":'("
|
|
return false
|
|
)
|
|
|
|
--set config from UI
|
|
local sceneFileName = getFileNameFile maxFileName
|
|
local containerSelected = if (classof selection[1] == Container) then true else false
|
|
if (sceneFileName == "") and (not containerSelected) then
|
|
(
|
|
messageBox "Select a container or load a valid scene to proceed" title:"no content"
|
|
return false
|
|
)
|
|
|
|
if containerSelected then
|
|
(
|
|
local containerPath = undefined
|
|
containerPath = selection[1].sourceDefinitionFilename
|
|
if (containerPath == undefined) or (containerPath == "") then
|
|
(
|
|
containerPath = selection[1].localDefinitionFilename
|
|
)
|
|
if (containerPath == undefined) or (containerPath == "") then
|
|
(
|
|
print "cant get a container path"
|
|
messageBox "Cant get a container path" title:"Error: Container Path"
|
|
return false
|
|
)
|
|
contentTree.sourceAssetPath = containerPath
|
|
contentTree.assetName = tolower (getFileNameFile containerPath)
|
|
contentTree.area = substituteString (pathConfig.stripPathToLeaf (getFileNamePath containerPath)) "\\" "/"
|
|
local trimmed = pathConfig.removePathLeaf (getFileNamePath containerPath)
|
|
contentTree.block = substituteString (pathConfig.stripPathToLeaf trimmed) "\\" "/"
|
|
)
|
|
else
|
|
(
|
|
contentTree.sourceAssetPath = maxFilePath
|
|
contentTree.assetName = tolower(getFileNameFile maxFileName)
|
|
contentTree.area = ""
|
|
contentTree.block = ""
|
|
|
|
)
|
|
|
|
contentTree.archetypes = chkArchetypes.state as String
|
|
contentTree.entities = chkEntities.state as String
|
|
contentTree.prefix = edtPrefix.text
|
|
contentTree.slod2link = chkSLOD2Link.state as String
|
|
contentTree.contentConfigPath = contentPath
|
|
|
|
return true
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
-- EVENTS
|
|
--/////////////////////////////////////////
|
|
|
|
/***
|
|
Browse for a content file path
|
|
***/
|
|
on btnContentPathBrowse pressed do
|
|
(
|
|
local savePath = getSavePath caption:"Content Save Folder" initialDir:(RsConfigGetProjRootDir())
|
|
if (savePath == undefined) then
|
|
(
|
|
return false
|
|
)
|
|
else
|
|
(
|
|
edtContentFolderPath.text = savePath
|
|
)
|
|
|
|
if (edtContentName.text == "") then--set a default name
|
|
(
|
|
edtContentName.text = (RsConfigGetProjectName()) + "_content_level_" + gRsCoreConfig.project.name + "_" + ContentCreatorUI.ddlMax_Type.selected + ".xml"
|
|
savePath += ("/" + edtContentName.text)
|
|
print savePath
|
|
)
|
|
else
|
|
(
|
|
savePath += ("/" + edtContentName.text)
|
|
)
|
|
|
|
contentTree.contentConfigPath = savePath
|
|
contentPath = savePath
|
|
|
|
--set the Parent content control using this path if it hasnt been changed from the default
|
|
if edtParentContentFilePath.text == "dlc_content.xml" then
|
|
(
|
|
edtParentContentFilePath.text = edtContentFolderPath.text + "/" + edtParentContentFilePath.text
|
|
contentTree.parentContentPath = RsMakeSafeSlashes edtParentContentFilePath.text
|
|
)
|
|
)
|
|
|
|
/***
|
|
Update the output path when new text is entered in the create content name field
|
|
***/
|
|
on edtContentName entered val do
|
|
(
|
|
print val
|
|
local newVal = ""
|
|
|
|
--add extension if need be
|
|
if ( matchpattern val pattern:"*.xml" == false ) then --add the extension
|
|
(
|
|
newVal = val + ".xml"
|
|
)
|
|
else
|
|
(
|
|
newVal = val
|
|
)
|
|
|
|
edtContentName.text = newVal
|
|
local savePath = edtContentFolderPath.text + "\\" + newVal
|
|
contentTree.contentConfigPath = savePath
|
|
contentPath = savePath
|
|
print savePath
|
|
)
|
|
|
|
/***
|
|
Browse for a parent content path to add the created content to
|
|
***/
|
|
on btnParentContentPathBrowse pressed do
|
|
(
|
|
local savePath = getOpenFileName caption:"Content Path" types:"Content (*.xml)|*.xml"
|
|
if (savePath == undefined) then
|
|
(
|
|
return false
|
|
)
|
|
|
|
edtParentContentFilePath.text = savePath
|
|
contentTree.parentContentPath = savePath
|
|
)
|
|
|
|
|
|
/***
|
|
Browse for an existing content file path to append to
|
|
***/
|
|
on btnContentAppendPathBrowse pressed do
|
|
(
|
|
local savePath = getOpenFileName caption:"Content Path" types:"Content (*.xml)|*.xml"
|
|
if (savePath == undefined) then
|
|
(
|
|
return false
|
|
)
|
|
|
|
edtContentAppendFilePath.text = savePath
|
|
--contentTree.contentConfigPath = savePath
|
|
contentPath = savePath
|
|
)
|
|
|
|
/***
|
|
Set the ContentCreator based on the type of content chosen in this dropdown
|
|
***/
|
|
fn ddlMax_TypeSelected arg =
|
|
(
|
|
contentTree.contentType = max_TypeList[arg]
|
|
case contentTree.contentType of
|
|
(
|
|
"map_container":
|
|
(
|
|
chkArchetypes.state = true
|
|
chkEntities.state = true
|
|
|
|
|
|
)
|
|
"interior":
|
|
(
|
|
chkArchetypes.state = true
|
|
chkEntities.state = false
|
|
)
|
|
"weapon":
|
|
(
|
|
chkArchetypes.state = true
|
|
chkEntities.state = false
|
|
)
|
|
"prop":
|
|
(
|
|
chkArchetypes.state = true
|
|
chkEntities.state = false
|
|
)
|
|
)
|
|
)
|
|
on ddlMax_Type selected arg do ddlMax_TypeSelected arg
|
|
|
|
|
|
/***
|
|
|
|
***/
|
|
on btnCreateConfig pressed do
|
|
(
|
|
local success = setOpts()
|
|
if (not success) then
|
|
(
|
|
return false
|
|
)
|
|
|
|
contentTree.createGraph()
|
|
contentTree.createContent()
|
|
|
|
)
|
|
|
|
/***
|
|
|
|
***/
|
|
on btnAppendConfig pressed do
|
|
(
|
|
case contentTree.contentType of
|
|
(
|
|
"map_container":
|
|
(
|
|
for item in (selection as array) do
|
|
(
|
|
clearSelection()
|
|
|
|
select item
|
|
|
|
local success = setOpts()
|
|
if (not success) then
|
|
(
|
|
return false
|
|
)
|
|
|
|
contentTree.createGraph()
|
|
contentTree.appendContent()
|
|
)
|
|
)
|
|
|
|
default:
|
|
(
|
|
local success = setOpts()
|
|
if (not success) then
|
|
(
|
|
return false
|
|
)
|
|
|
|
contentTree.createGraph()
|
|
contentTree.appendContent()
|
|
)
|
|
)
|
|
)
|
|
|
|
--/////////////////////////////////////////
|
|
--
|
|
--/////////////////////////////////////////
|
|
on ContentCreatorUI open do
|
|
(
|
|
banner.setup()
|
|
contentTree.contentType = max_TypeList[1]
|
|
contentTree.contentRoot = RsConfigGetProjRootDir()
|
|
|
|
--set default asset type
|
|
ddlMax_TypeSelected 1
|
|
)
|
|
|
|
|
|
)
|
|
|
|
createDialog ContentCreatorUI |