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