public I3DSpline(BigEndianBinaryReader br) { try { Unknown1 = br.ReadUInt32(); Name = br.BaseStream.ReadNullTerminatedString(); br.BaseStream.Align(2); // Align the stream to short do { ShapeId = br.ReadUInt16(); } while (ShapeId == 0); Unknown2 = br.ReadUInt32(); VertexCount = br.ReadUInt32(); Vertices = new Vector3[VertexCount]; for (int i = 0; i < VertexCount; i++) { Vertices[i] = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); } } catch (Exception e) { if (string.IsNullOrEmpty(Name)) { throw; } if (ShapeId > 0) { throw new Exception($"Failed to parse I3DSpline {Name}, ShapeID: {ShapeId}", e); } throw new Exception($"Failed to parse I3DSpline {Name}", e); } }
public static I3DShape[] LoadShapesFile(string path) { if (Cache.ContainsKey(path)) { return(Cache[path]); } List <I3DShape> shapes; using (FileStream fs = File.OpenRead(path)) { string fileName = Path.GetFileName(fs.Name) ?? "N/A"; Debug.Log("Loading file: " + fileName); Debug.Log("File Size: " + new FileInfo(fs.Name).Length + " bytes"); I3DShapesHeader header = ParseFileHeader(fs); Debug.Log("File Seed: " + header.Seed); Debug.Log("File Version: " + header.Version); if (header.Version != 2 && header.Version != 3) { throw new NotSupportedException("Unsupported version"); } Debug.Log(""); using (I3DDecryptorStream dfs = new I3DDecryptorStream(fs, header.Seed)) { int itemCount = dfs.ReadInt32L(); shapes = new List <I3DShape>(); Debug.Log("Found " + itemCount + " shapes"); Debug.Log(""); for (int i = 0; i < itemCount; i++) { int type = dfs.ReadInt32L(); int size = dfs.ReadInt32L(); byte[] data = dfs.ReadBytes(size); //Debug.Log($"{i+1}: (Type {type}) {size} bytes"); string binFileName = $"{i+1}-{type}.bin"; //File.WriteAllBytes(Path.Combine(@"F:\SteamLibrary\steamapps\common\Farming Simulator 15\data\maps\decompile", binFileName), data); //File.WriteAllBytes(Path.Combine(@"D:\SteamLibrary\steamapps\common\Farming Simulator 2013\data\maps\decompile\chickenmesh", binFileName), data); using (MemoryStream ms = new MemoryStream(data)) { using (BigEndianBinaryReader br = new BigEndianBinaryReader(ms)) { try { switch (type) { case 1: shapes.Add(new I3DShape(br)); break; case 2: new I3DSpline(br); break; case 3: new I3DNavMesh(br); break; } } catch (Exception e) { Debug.Log(e.Message); } } } } Debug.Log($"Loaded {shapes.Count} shapes"); } } I3DShape[] shapesArr = shapes.ToArray(); Cache[path] = shapesArr; return(shapesArr); }
public I3DShape(BigEndianBinaryReader br) { try { Unknown1 = br.ReadUInt32(); Name = br.BaseStream.ReadNullTerminatedString(); br.BaseStream.Align(2); // Align the stream to short //This is pretty ugly, but they pretty much zero-pad after the alignment //So we read the padding until we found the shapeid do { ShapeId = br.ReadUInt16(); } while (ShapeId == 0); BVCenterX = br.ReadSingle(); BVCenterY = br.ReadSingle(); BVCenterZ = br.ReadSingle(); BVRadius = br.ReadSingle(); VertexCount = br.ReadUInt32(); Unknown6 = br.ReadUInt32(); Vertices = br.ReadUInt32(); Unknown7 = br.ReadUInt32(); Unknown8 = br.ReadUInt32(); UvCount = br.ReadUInt32(); Unknown9 = br.ReadUInt32(); VertexCount2 = br.ReadUInt32(); Mesh = new Mesh(); int[] tris = new int[VertexCount]; for (int i = 0; i < VertexCount; i++) { tris[i] = br.ReadUInt16(); } br.BaseStream.Align(4); Vector3[] vertices = new Vector3[Vertices]; for (int i = 0; i < Vertices; i++) { vertices[i] = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); } Vector3[] normals = new Vector3[Vertices]; for (int i = 0; i < Vertices; i++) { normals[i] = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); } Vector2[] uvs = new Vector2[UvCount]; for (int i = 0; i < UvCount; i++) { uvs[i] = new Vector2(br.ReadSingle(), br.ReadSingle()); } Mesh.vertices = vertices; Mesh.normals = normals; Mesh.triangles = tris; Mesh.uv = uvs; } catch (Exception e) { if (string.IsNullOrEmpty(Name)) { throw; } if (ShapeId > 0) { throw new Exception($"Failed to parse I3DShape {Name}, ShapeID: {ShapeId}", e); } throw new Exception($"Failed to parse I3DShape {Name}", e); } }