public static void AddObjectToSequence(ExportEntry newObject, ExportEntry sequenceExport, bool removeLinks = false) { ArrayProperty <ObjectProperty> seqObjs = sequenceExport.GetProperty <ArrayProperty <ObjectProperty> >("SequenceObjects") ?? new ArrayProperty <ObjectProperty>("SequenceObjects"); seqObjs.Add(new ObjectProperty(newObject)); sequenceExport.WriteProperty(seqObjs); PropertyCollection newObjectProps = newObject.GetProperties(); newObjectProps.AddOrReplaceProp(new ObjectProperty(sequenceExport, "ParentSequence")); newObject.WriteProperties(newObjectProps); if (removeLinks) { RemoveAllLinks(newObject); } newObject.Parent = sequenceExport; }
public static void CreateReachSpec(ExportEntry startNode, bool createTwoWay, ExportEntry destinationNode, string reachSpecClass, ReachSpecSize size, PropertyCollection externalGUIDProperties = null) { IMEPackage Pcc = startNode.FileRef; ExportEntry reachSpectoClone = Pcc.Exports.FirstOrDefault(x => x.ClassName == "ReachSpec"); if (externalGUIDProperties != null) //EXTERNAL { //external node //Debug.WriteLine("Num Exports: " + pcc.Exports.Count); if (reachSpectoClone != null) { ExportEntry outgoingSpec = reachSpectoClone.Clone(); Pcc.addExport(outgoingSpec); IEntry reachSpecClassImp = GetEntryOrAddImport(Pcc, reachSpecClass); //new class type. outgoingSpec.idxClass = reachSpecClassImp.UIndex; outgoingSpec.idxObjectName = reachSpecClassImp.idxObjectName; var properties = outgoingSpec.GetProperties(); ObjectProperty outgoingSpecStartProp = properties.GetProp <ObjectProperty>("Start"); //START StructProperty outgoingEndStructProp = properties.GetProp <StructProperty>("End"); //Embeds END ObjectProperty outgoingSpecEndProp = outgoingEndStructProp.Properties.GetProp <ObjectProperty>(SharedPathfinding.GetReachSpecEndName(outgoingSpec)); //END outgoingSpecStartProp.Value = startNode.UIndex; outgoingSpecEndProp.Value = 0; var endGuid = outgoingEndStructProp.GetProp <StructProperty>("Guid"); endGuid.Properties = externalGUIDProperties; //set the other guid values to our guid values //Add to source node prop ArrayProperty <ObjectProperty> PathList = startNode.GetProperty <ArrayProperty <ObjectProperty> >("PathList"); PathList.Add(new ObjectProperty(outgoingSpec.UIndex)); startNode.WriteProperty(PathList); outgoingSpec.WriteProperties(properties); //Write Spec Size SharedPathfinding.SetReachSpecSize(outgoingSpec, size.SpecRadius, size.SpecHeight); //Reindex reachspecs. SharedPathfinding.ReindexMatchingObjects(outgoingSpec); } } else { //Debug.WriteLine("Source Node: " + startNode.Index); //Debug.WriteLine("Num Exports: " + pcc.Exports.Count); //int outgoingSpec = pcc.ExportCount; //int incomingSpec = pcc.ExportCount + 1; if (reachSpectoClone != null) { ExportEntry outgoingSpec = reachSpectoClone.Clone(); Pcc.addExport(outgoingSpec); ExportEntry incomingSpec = null; if (createTwoWay) { incomingSpec = reachSpectoClone.Clone(); Pcc.addExport(incomingSpec); } IEntry reachSpecClassImp = GetEntryOrAddImport(Pcc, reachSpecClass); //new class type. outgoingSpec.idxClass = reachSpecClassImp.UIndex; outgoingSpec.idxObjectName = reachSpecClassImp.idxObjectName; var outgoingSpecProperties = outgoingSpec.GetProperties(); if (reachSpecClass == "Engine.SlotToSlotReachSpec") { outgoingSpecProperties.Add(new ByteProperty(1, "SpecDirection")); //We might need to find a way to support this edit } //Debug.WriteLine("Outgoing UIndex: " + outgoingSpecExp.UIndex); ObjectProperty outgoingSpecStartProp = outgoingSpecProperties.GetProp <ObjectProperty>("Start"); //START StructProperty outgoingEndStructProp = outgoingSpecProperties.GetProp <StructProperty>("End"); //Embeds END ObjectProperty outgoingSpecEndProp = outgoingEndStructProp.Properties.GetProp <ObjectProperty>(SharedPathfinding.GetReachSpecEndName(outgoingSpec)); //END outgoingSpecStartProp.Value = startNode.UIndex; outgoingSpecEndProp.Value = destinationNode.UIndex; //Add to source node prop var PathList = startNode.GetProperty <ArrayProperty <ObjectProperty> >("PathList"); PathList.Add(new ObjectProperty(outgoingSpec.UIndex)); startNode.WriteProperty(PathList); //Write Spec Size SetReachSpecSize(outgoingSpecProperties, size.SpecRadius, size.SpecHeight); outgoingSpec.WriteProperties(outgoingSpecProperties); if (createTwoWay) { incomingSpec.idxClass = reachSpecClassImp.UIndex; incomingSpec.idxObjectName = reachSpecClassImp.idxObjectName; var incomingSpecProperties = incomingSpec.GetProperties(); if (reachSpecClass == "Engine.SlotToSlotReachSpec") { incomingSpecProperties.Add(new ByteProperty(2, "SpecDirection")); } ObjectProperty incomingSpecStartProp = incomingSpecProperties.GetProp <ObjectProperty>("Start"); //START StructProperty incomingEndStructProp = incomingSpecProperties.GetProp <StructProperty>("End"); //Embeds END ObjectProperty incomingSpecEndProp = incomingEndStructProp.Properties.GetProp <ObjectProperty>(SharedPathfinding.GetReachSpecEndName(incomingSpec)); //END incomingSpecStartProp.Value = destinationNode.UIndex; //Uindex incomingSpecEndProp.Value = startNode.UIndex; //Add reachspec to destination node's path list (returning) var DestPathList = destinationNode.GetProperty <ArrayProperty <ObjectProperty> >("PathList"); DestPathList.Add(new ObjectProperty(incomingSpec.UIndex)); destinationNode.WriteProperty(DestPathList); //destNode.WriteProperty(DestPathList); SetReachSpecSize(incomingSpecProperties, size.SpecRadius, size.SpecHeight); incomingSpec.WriteProperties(incomingSpecProperties); } //Reindex reachspecs. SharedPathfinding.ReindexMatchingObjects(outgoingSpec); } } }
public void Write2DAToExport() { using (var stream = new MemoryStream()) { //Cell count if (IsIndexed) { //Indexed ones seem to have 0 at start stream.WriteBytes(BitConverter.GetBytes(0)); } stream.WriteBytes(BitConverter.GetBytes(PopulatedCellCount)); //Write cell data for (int rowindex = 0; rowindex < RowCount; rowindex++) { for (int colindex = 0; colindex < ColumnCount; colindex++) { Bio2DACell cell = Cells[rowindex, colindex]; if (cell != null) { if (IsIndexed) { //write index int index = (rowindex * ColumnCount) + colindex; //+1 because they are not zero based indexes since they are numerals stream.WriteBytes(BitConverter.GetBytes(index)); } stream.WriteByte((byte)cell.Type); stream.WriteBytes(cell.Data); } else { if (IsIndexed) { //this is a blank cell. It is not present in the table. continue; } else { Debug.WriteLine("THIS SHOULDN'T OCCUR!"); Debugger.Break(); throw new Exception("A non-indexed Bio2DA cannot have null cells."); } } } } //Write Columns if (!IsIndexed) { stream.WriteBytes(BitConverter.GetBytes(0)); //seems to be a 0 before column definitions } //Console.WriteLine("Columns defs start at " + stream.Position.ToString("X6")); stream.WriteBytes(BitConverter.GetBytes(ColumnCount)); for (int colindex = 0; colindex < ColumnCount; colindex++) { //Console.WriteLine("Writing column definition " + columnNames[colindex]); int nameIndexForCol = export.FileRef.FindNameOrAdd(ColumnNames[colindex]); stream.WriteBytes(BitConverter.GetBytes(nameIndexForCol)); stream.WriteBytes(BitConverter.GetBytes(0)); //second half of name reference in 2da is always zero since they're always indexed at 0 stream.WriteBytes(BitConverter.GetBytes(colindex)); } int propsEnd = export.propsEnd(); byte[] binarydata = stream.ToArray(); //Todo: Rewrite properties here PropertyCollection props = new PropertyCollection(); if (export.ClassName == "Bio2DA") { var indicies = new ArrayProperty <NameProperty>(ArrayType.Name, "m_sRowLabel"); foreach (var rowname in RowNames) { indicies.Add(new NameProperty { Value = rowname }); } props.Add(indicies); } else { var indices = new ArrayProperty <IntProperty>(ArrayType.Int, "m_lstRowNumbers"); foreach (var rowname in RowNames) { indices.Add(new IntProperty(int.Parse(rowname))); } props.Add(indices); } MemoryStream propsStream = new MemoryStream(); props.WriteTo(propsStream, export.FileRef); MemoryStream currentDataStream = new MemoryStream(export.Data); byte[] propertydata = propsStream.ToArray(); int propertyStartOffset = export.GetPropertyStart(); var newExportData = new byte[propertyStartOffset + propertydata.Length + binarydata.Length]; Buffer.BlockCopy(export.Data, 0, newExportData, 0, propertyStartOffset); propertydata.CopyTo(newExportData, propertyStartOffset); binarydata.CopyTo(newExportData, propertyStartOffset + propertydata.Length); //Console.WriteLine("Old data size: " + export.Data.Length); //Console.WriteLine("NEw data size: " + newExportData.Length); //This assumes the input and output data sizes are the same. We should not assume this with new functionality //if (export.Data.Length != newExportData.Length) //{ // Debug.WriteLine("FILES ARE WRONG SIZE"); // Debugger.Break(); //} export.Data = newExportData; } }
public static StructProperty CreateAggGeom(ICollection <Vector3> vertexBuffer, ICollection <uint> indexBuffer, uint depth = 4, double conservationThreshold = 24, int maxVerts = 12) { double[] vertices = vertexBuffer.SelectMany(vert => vert.ToArray().Select(v => (double)v)).ToArray(); uint[] indices = indexBuffer.ToArray(); var convexElems = new ArrayProperty <StructProperty>("ConvexElems") { Reference = "KConvexElem" }; #region Callback void DecompCallback(uint vertsLength, double[] verts, uint trisLength, int[] tris) { PropertyCollection props = new PropertyCollection(); var convexElem = new StructProperty("KConvexElem", props); convexElems.Add(convexElem); Box box = new Box(); //VertexData var vertexData = new ArrayProperty <StructProperty>("VertexData") { Reference = "Vector" }; var vertexes = new Vector3[vertsLength / 3]; for (int i = 0; i < vertsLength; i += 3) { var vert = new Vector3((float)verts[i], (float)verts[i + 1], (float)verts[i + 2]); vertexes[i / 3] = vert; vertexData.Add(new StructProperty("Vector", true, new FloatProperty(vert.X, "X"), new FloatProperty(vert.Y, "Y"), new FloatProperty(vert.Z, "Z"))); box.Add(vert); } //PermutedVertexData int leftover = vertexes.Length % 4; int numPlanes = vertexes.Length / 4; var permutedVertexData = new ArrayProperty <StructProperty>("PermutedVertexData") { Reference = "Plane" }; for (int i = 0; i < numPlanes; i++) { permutedVertexData.Add(new StructProperty("Plane", true, new FloatProperty(vertexes[i * 4 + 3].X, "W"), new FloatProperty(vertexes[i * 4 + 0].X, "X"), new FloatProperty(vertexes[i * 4 + 1].X, "Y"), new FloatProperty(vertexes[i * 4 + 2].X, "Z"))); permutedVertexData.Add(new StructProperty("Plane", true, new FloatProperty(vertexes[i * 4 + 3].Y, "W"), new FloatProperty(vertexes[i * 4 + 0].Y, "X"), new FloatProperty(vertexes[i * 4 + 1].Y, "Y"), new FloatProperty(vertexes[i * 4 + 2].Y, "Z"))); permutedVertexData.Add(new StructProperty("Plane", true, new FloatProperty(vertexes[i * 4 + 3].Z, "W"), new FloatProperty(vertexes[i * 4 + 0].Z, "X"), new FloatProperty(vertexes[i * 4 + 1].Z, "Y"), new FloatProperty(vertexes[i * 4 + 2].Z, "Z"))); } if (leftover > 0) { Vector3 vec1 = vertexes[numPlanes * 4], vec2 = vec1, vec3 = vec1, vec4 = vec1; switch (leftover) { case 3: vec3 = vertexes[numPlanes * 4 + 2]; goto case 2; //fallthrough! case 2: vec2 = vertexes[numPlanes * 4 + 1]; break; } permutedVertexData.Add(new StructProperty("Plane", true, new FloatProperty(vec1.X, "W"), new FloatProperty(vec2.X, "X"), new FloatProperty(vec3.X, "Y"), new FloatProperty(vec4.X, "Z"))); permutedVertexData.Add(new StructProperty("Plane", true, new FloatProperty(vec1.Y, "W"), new FloatProperty(vec2.Y, "X"), new FloatProperty(vec3.Y, "Y"), new FloatProperty(vec4.Y, "Z"))); permutedVertexData.Add(new StructProperty("Plane", true, new FloatProperty(vec1.Z, "W"), new FloatProperty(vec2.Z, "X"), new FloatProperty(vec3.Z, "Y"), new FloatProperty(vec4.Z, "Z"))); } //FaceTriData var faceTriData = new ArrayProperty <IntProperty>("FaceTriData"); faceTriData.AddRange(tris.Select(idx => new IntProperty(idx))); var allEdges = new List <(int edge0, int edge1)>(); var edgeDirs = new List <Vector3>(); var allNormals = new List <Vector3>(); var uniqueNormals = new List <Vector3>(); var planes = new List <Plane>(); for (int i = 0; i < trisLength; i += 3) { int idx0 = tris[i], idx1 = tris[i + 1], idx2 = tris[i + 2]; if (!allEdges.Contains((idx0, idx1))) { allEdges.Add((idx0, idx1)); } if (!allEdges.Contains((idx1, idx2))) { allEdges.Add((idx1, idx2)); } if (!allEdges.Contains((idx2, idx0))) { allEdges.Add((idx2, idx0)); } Vector3 vert0 = vertexes[idx0]; Vector3 vert1 = vertexes[idx1]; Vector3 vert2 = vertexes[idx2]; Vector3 normal = Vector3.Normalize(Vector3.Cross(vert2 - vert0, vert1 - vert0)); allNormals.Add(normal); AddVec(normal, uniqueNormals); AddPlane(new Plane(vert0, normal)); } //FacePlaneData var facePlaneData = new ArrayProperty <StructProperty>("FacePlaneData") { Reference = "Plane" }; foreach (Plane plane in planes) { facePlaneData.Add(new StructProperty("Plane", true, new FloatProperty(plane.D, "W"), new FloatProperty(plane.Normal.X, "X"), new FloatProperty(plane.Normal.Y, "Y"), new FloatProperty(plane.Normal.Z, "Z"))); } //FaceNormalDirections var faceNormalDirections = new ArrayProperty <StructProperty>("FaceNormalDirections") { Reference = "Vector" }; foreach (Vector3 normal in uniqueNormals) { faceNormalDirections.Add(new StructProperty("Vector", true, new FloatProperty(normal.X, "X"), new FloatProperty(normal.Y, "Y"), new FloatProperty(normal.Z, "Z"))); } //EdgeDirections var edgeDirections = new ArrayProperty <StructProperty>("EdgeDirections") { Reference = "Vector" }; foreach ((int edge0, int edge1) in allEdges) { int triIdx0 = -1, triIdx1 = -1; for (int i = 0; i < trisLength; i += 3) { int idx0 = tris[i], idx1 = tris[i + 1], idx2 = tris[i + 2]; if (idx0 == edge0 && idx1 == edge1 || idx0 == edge0 && idx2 == edge1 || idx1 == edge0 && idx0 == edge1 || idx1 == edge0 && idx2 == edge1 || idx2 == edge0 && idx0 == edge1 || idx2 == edge0 && idx1 == edge1) { if (triIdx0 == -1) { triIdx0 = i / 3; } else if (triIdx1 == -1) { triIdx1 = i / 3; } } } if (triIdx0 != -1 && triIdx1 != -1 && Vector3.Dot(allNormals[triIdx0], allNormals[triIdx1]) < 1f - 0.0003) { AddVec(Vector3.Normalize(vertexes[edge0] - vertexes[edge1]), edgeDirs); } } foreach (Vector3 edgeDir in edgeDirs) { edgeDirections.Add(new StructProperty("Vector", true, new FloatProperty(edgeDir.X, "X"), new FloatProperty(edgeDir.Y, "Y"), new FloatProperty(edgeDir.Z, "Z"))); } //ElemBox var elemBox = new StructProperty("Box", true, new StructProperty("Vector", true, new FloatProperty(box.Min.X, "X"), new FloatProperty(box.Min.Y, "Y"), new FloatProperty(box.Min.Z, "Z")) { Name = "Min" }, new StructProperty("Vector", true, new FloatProperty(box.Max.X, "X"), new FloatProperty(box.Max.Y, "Y"), new FloatProperty(box.Max.Z, "Z")) { Name = "Max" }, new ByteProperty(box.IsValid, "IsValid") ) { Name = "ElemBox" }; props.Add(vertexData); props.Add(permutedVertexData); props.Add(faceTriData); props.Add(edgeDirections); props.Add(faceNormalDirections); props.Add(facePlaneData); props.Add(elemBox); props.Add(new NoneProperty()); void AddVec(Vector3 vec, List <Vector3> vecs) { foreach (Vector3 uniqueVec in vecs) { float dot = Math.Abs(Vector3.Dot(uniqueVec, vec)); if (Math.Abs(dot - 1) < 0.0003) { return; } } vecs.Add(vec); } void AddPlane(Plane plane) { foreach (Plane uniquePlane in planes) { float dot = Vector3.Dot(uniquePlane.Normal, plane.Normal); if (Math.Abs(dot - 1) < 0.0003 && Math.Abs(uniquePlane.D - plane.D) < 0.1) { return; } } planes.Add(plane); } } #endregion CreateConvexHull(vertexBuffer.Count, vertices, indices.Length / 3, indices, depth, conservationThreshold, maxVerts, DecompCallback); return(new StructProperty("KAggregateGeom", new PropertyCollection { convexElems, new NoneProperty() }, "AggGeom")); }