public static Vdf ParseVdf(string filename) { using (Bwd2Reader br = new Bwd2Reader(filename)) { Vdf vdf = new Vdf(); br.FindNext("VDFC"); vdf.Name = br.ReadCString(20); vdf.VehicleType = br.ReadUInt32(); vdf.VehicleSize = br.ReadUInt32(); vdf.LODDistance1 = br.ReadSingle(); vdf.LODDistance2 = br.ReadSingle(); vdf.LODDistance3 = br.ReadSingle(); vdf.LODDistance4 = br.ReadSingle(); vdf.LODDistance5 = br.ReadSingle(); vdf.Mass = br.ReadSingle(); vdf.CollisionMultiplier = br.ReadSingle(); vdf.DragCoefficient = br.ReadSingle(); vdf.Unknown = br.ReadUInt32(); if (br.Current.DataLength == 77) { vdf.EltFile = br.ReadCString(13); } br.FindNext("SOBJ"); vdf.SOBJGeoName = br.ReadCString(8); vdf.VLocs = new List <VLoc>(); br.FindNext("VLOC"); while (br.Current != null && br.Current.Name != "EXIT") { VLoc vloc = new VLoc { Number = br.ReadUInt32(), Right = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Up = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Forward = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()) }; vdf.VLocs.Add(vloc); br.Next(); } br.FindNext("VGEO"); uint numParts = br.ReadUInt32(); vdf.PartsThirdPerson = new List <SdfPart[]>(4); for (int damageState = 0; damageState < 4; damageState++) { SdfPart[] parts = new SdfPart[numParts]; for (int i = 0; i < numParts; i++) { SdfPart sdfPart = new SdfPart(); sdfPart.Name = br.ReadCString(8); sdfPart.Right = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); sdfPart.Up = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); sdfPart.Forward = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); sdfPart.Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); sdfPart.ParentName = br.ReadCString(8); br.Position += 36; parts[i] = sdfPart; } vdf.PartsThirdPerson.Add(parts); } br.Position += 100 * numParts * 12; vdf.PartsFirstPerson = new SdfPart[numParts]; for (int i = 0; i < numParts; i++) { SdfPart sdfPart = new SdfPart(); sdfPart.Name = br.ReadCString(8); sdfPart.Right = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); sdfPart.Up = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); sdfPart.Forward = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); sdfPart.Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); sdfPart.ParentName = br.ReadCString(8); br.Position += 36; vdf.PartsFirstPerson[i] = sdfPart; } br.FindNext("COLP"); float zMaxOuter = br.ReadSingle(); float zMaxInner = br.ReadSingle(); float zMinInner = br.ReadSingle(); float zMinOuter = br.ReadSingle(); float xMaxOuter = br.ReadSingle(); float xMaxInner = br.ReadSingle(); float xMinInner = br.ReadSingle(); float xMinOuter = br.ReadSingle(); float yMaxOuter = br.ReadSingle(); float yMaxInner = br.ReadSingle(); float yMinInner = br.ReadSingle(); float yMinOuter = br.ReadSingle(); Bounds innerBounds = new Bounds(); innerBounds.SetMinMax(new Vector3(xMinInner, yMinInner, zMinInner), new Vector3(xMaxInner, yMaxInner, zMaxInner)); vdf.BoundsInner = innerBounds; Bounds outerBounds = new Bounds(); outerBounds.SetMinMax(new Vector3(xMinOuter, yMinOuter, zMinOuter), new Vector3(xMaxOuter, yMaxOuter, zMaxOuter)); vdf.BoundsOuter = outerBounds; br.FindNext("WLOC"); vdf.WheelLoc = new WheelLoc[6]; for (int i = 0; i < 6; i++) { WheelLoc wheelLoc = vdf.WheelLoc[i] = new WheelLoc(); uint unk1 = br.ReadUInt32(); wheelLoc.Right = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); wheelLoc.Up = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); wheelLoc.Forward = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); wheelLoc.Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); float unk2 = br.ReadSingle(); } vdf.HLocs = new List <HLoc>(); br.FindNext("HLOC"); while (br.Current != null && br.Current.Name != "EXIT") { HLoc hloc = new HLoc { Label = br.ReadCString(16), HardpointIndex = br.ReadUInt32(), FacingDirection = br.ReadUInt32(), MeshType = (HardpointMeshType)br.ReadUInt32(), Right = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Up = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Forward = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Unk = br.ReadSingle() }; vdf.HLocs.Add(hloc); br.Next(); } if (!SpriteManager.Instance.Initialised) { if (vdf.EltFile == null) { vdf.Etbls = new List <ETbl>(); br.FindNext("ETBL"); while (br.Current != null && br.Current.Name != "EXIT") { long tableEnd = br.Current.DataPosition + br.Current.DataLength; while (br.Position < tableEnd) { ETbl etbl = new ETbl { MapFile = br.ReadCString(13), IsReferenceImage = br.ReadUInt32() == 1, ItemCount = br.ReadUInt32(), }; uint itemCount = etbl.ItemCount; etbl.Items = new Dictionary <string, ETbl.ETblItem>((int)itemCount); for (uint i = 0; i < itemCount; ++i) { ETbl.ETblItem etblItem = new ETbl.ETblItem { Name = br.ReadCString(16), XOffset = br.ReadInt32(), YOffset = br.ReadInt32(), Width = br.ReadInt32(), Height = br.ReadInt32() }; etbl.Items.Add(etblItem.Name, etblItem); } vdf.Etbls.Add(etbl); } br.Next(); } } else { vdf.Etbls = EltParser.ParseElt(vdf.EltFile); } if (vdf.Etbls != null && vdf.Etbls.Count > 0) { SpriteManager.Instance.Initialise(vdf); } } return(vdf); } }
public static Vcf ParseVcf(string filename) { Vcf vcf = new Vcf(); using (Bwd2Reader br = new Bwd2Reader(filename)) { br.FindNext("VCFC"); vcf.VariantName = br.ReadCString(16); vcf.VdfFilename = br.ReadCString(13); vcf.VtfFilename = br.ReadCString(13); vcf.EngineType = br.ReadUInt32(); vcf.SuspensionType = br.ReadUInt32(); vcf.BrakesType = br.ReadUInt32(); vcf.WdfFrontFilename = br.ReadCString(13); vcf.WdfMidFilename = br.ReadCString(13); vcf.WdfBackFilename = br.ReadCString(13); vcf.ArmorFront = br.ReadUInt32(); vcf.ArmorLeft = br.ReadUInt32(); vcf.ArmorRight = br.ReadUInt32(); vcf.ArmorRear = br.ReadUInt32(); vcf.ChassisFront = br.ReadUInt32(); vcf.ChassisLeft = br.ReadUInt32(); vcf.ChassisRight = br.ReadUInt32(); vcf.ChassisRear = br.ReadUInt32(); vcf.ArmorOrChassisLeftToAdd = br.ReadUInt32(); vcf.Specials = new List <SpecialType>(); if (br.TryFindNext("SPEC")) { vcf.Specials.Add((SpecialType)br.ReadInt32()); } if (br.TryFindNext("SPEC")) { vcf.Specials.Add((SpecialType)br.ReadInt32()); } if (br.TryFindNext("SPEC")) { vcf.Specials.Add((SpecialType)br.ReadInt32()); } br.FindNext("WEPN"); vcf.Weapons = new List <VcfWeapon>(); while (br.Current != null && br.Current.Name != "EXIT") { VcfWeapon vcfWeapon = new VcfWeapon { MountPoint = br.ReadInt32(), GdfFilename = br.ReadCString(13) }; vcfWeapon.Gdf = GdfParser.ParseGdf(vcfWeapon.GdfFilename); vcf.Weapons.Add(vcfWeapon); br.Next(); } } if (vcf.WdfFrontFilename.ToUpper() != "NULL") { vcf.FrontWheelDef = WdfParser.ParseWdf(vcf.WdfFrontFilename); } if (vcf.WdfMidFilename.ToUpper() != "NULL") { vcf.MidWheelDef = WdfParser.ParseWdf(vcf.WdfMidFilename); } if (vcf.WdfBackFilename.ToUpper() != "NULL") { vcf.BackWheelDef = WdfParser.ParseWdf(vcf.WdfBackFilename); } return(vcf); }
public static MissonDefinition ReadMsnMission(string filename) { MissonDefinition mdef = new MissonDefinition(); using (Bwd2Reader msn = new Bwd2Reader(filename)) { msn.FindNext("WDEF"); using (Bwd2Reader wdef = new Bwd2Reader(msn)) { wdef.FindNext("WRLD"); wdef.Position += 30; mdef.PaletteFilePath = wdef.ReadCString(13); mdef.LumaTableFilePath = wdef.ReadCString(13); mdef.XlucencyTableFilePath = wdef.ReadCString(13); mdef.ObjectiveFilePath = wdef.ReadCString(13); mdef.SkyTextureFilePath = wdef.ReadCString(13); mdef.ScroungeTextureFilePath = wdef.ReadCString(13); mdef.SurfaceTextureFilePath = wdef.ReadCString(13); mdef.LevelMapFilePath = wdef.ReadCString(13); mdef.HzdFilePath = wdef.ReadCString(13); } msn.FindNext("TDEF"); List <float[, ]> heights = new List <float[, ]>(); using (Bwd2Reader tdef = new Bwd2Reader(msn)) { tdef.FindNext("ZMAP"); byte numUniqueTerrainPatches = tdef.ReadByte(); byte[] patchConfig = tdef.ReadBytes(80 * 80); tdef.FindNext("ZONE"); byte unk = tdef.ReadByte(); string terrainFilePath = tdef.ReadCString(13); using (FastBinaryReader terr = VirtualFilesystem.Instance.GetFileStream(terrainFilePath)) { for (int i = 0; i < numUniqueTerrainPatches; i++) { float[,] h = new float[129, 129]; for (int z = 0; z < 128; z++) { for (int x = 0; x < 128; x++) { ushort tpoint = terr.ReadUInt16(); float height = (tpoint & 0xFFF) / 4096.0f; h[z, x] = height; } } heights.Add(h); } } Vector2 botLeft = new Vector2(80, 80); Vector2 topRight = new Vector2(0, 0); float[,] defaultHeights = new float[129, 129]; for (int z = 0; z < 80; z++) { for (int x = 0; x < 80; x++) { byte patchIdx = patchConfig[z * 80 + x]; if (patchIdx == 0xFF) { //mdef.TerrainPatches[x, z] = new TerrainPatch(defaultTerrainData); } else { if (x < botLeft.x) { botLeft.x = x; } if (z < botLeft.y) { botLeft.y = z; } if (x > topRight.x) { topRight.x = x; } if (z > topRight.y) { topRight.y = z; } float[,] h = heights[patchIdx]; int rightPatchIdx = x == 79 ? 0xFF : patchConfig[z * 80 + x + 1]; float[,] rightHeights = rightPatchIdx == 0xFF ? defaultHeights : heights[rightPatchIdx]; for (int xx = 0; xx < 129; xx++) { h[xx, 128] = rightHeights[xx, 0]; } int bottomPatchIdx = z == 79 ? 0xFF : patchConfig[(z + 1) * 80 + x]; float[,] bottomHeights = bottomPatchIdx == 0xFF ? defaultHeights : heights[bottomPatchIdx]; for (int zz = 0; zz < 129; zz++) { h[128, zz] = bottomHeights[0, zz]; } int bottomRightPatchIdx = z == 79 || x == 79 ? 0xFF : patchConfig[(z + 1) * 80 + x + 1]; float[,] bottomRightHeights = bottomRightPatchIdx == 0xFF ? defaultHeights : heights[bottomRightPatchIdx]; h[128, 128] = bottomRightHeights[0, 0]; TerrainData tdata = CreateTerrainData(); tdata.SetHeights(0, 0, h); mdef.TerrainPatches[x, z] = new TerrainPatch(tdata); } } } mdef.Middle = (topRight + botLeft) / 2.0f; } msn.FindNext("RDEF"); using (Bwd2Reader rdef = new Bwd2Reader(msn)) { rdef.FindNext("RSEG"); while (rdef.Current != null && rdef.Current.Name != "EXIT") { uint segmentType = rdef.ReadUInt32(); uint segmentPieceCount = rdef.ReadUInt32(); Road road = new Road { SegmentType = (RoadSegmentType)segmentType, RoadSegments = new RoadSegment[segmentPieceCount] }; for (int i = 0; i < segmentPieceCount; i++) { RoadSegment roadSegment = new RoadSegment { Left = new Vector3(rdef.ReadSingle(), rdef.ReadSingle(), rdef.ReadSingle()), Right = new Vector3(rdef.ReadSingle(), rdef.ReadSingle(), rdef.ReadSingle()) }; Vector3 pos = roadSegment.Left; int patchPosX = (int)(pos.x / 640.0f); int patchPosZ = (int)(pos.z / 640.0f); float localPositionX = (pos.x % 640) / 640.0f; float localPositionZ = (pos.z % 640) / 640.0f; float y = mdef.TerrainPatches[patchPosX, patchPosZ].TerrainData.GetInterpolatedHeight(localPositionX, localPositionZ) + 0.1f; pos.y = y; roadSegment.Left = pos; pos = roadSegment.Right; patchPosX = (int)(pos.x / 640.0f); patchPosZ = (int)(pos.z / 640.0f); localPositionX = (pos.x % 640) / 640.0f; localPositionZ = (pos.z % 640) / 640.0f; y = mdef.TerrainPatches[patchPosX, patchPosZ].TerrainData.GetInterpolatedHeight(localPositionX, localPositionZ) + 0.1f; pos.y = y; roadSegment.Right = pos; road.RoadSegments[i] = roadSegment; //TODO: Figure out } mdef.Roads.Add(road); rdef.Next(); } } msn.FindNext("ODEF"); using (Bwd2Reader odef = new Bwd2Reader(msn)) { odef.FindNext("OBJ"); while (odef.Current.Name != "EXIT") { byte[] rawlabel = odef.ReadBytes(8); int labelhigh = 0; StringBuilder labelBuilder = new StringBuilder(); for (int i = 0; i < 8; i++) { byte v = rawlabel[i]; if (v > 0x7f) { labelhigh = (labelhigh << 1) | 0x01; } else { labelhigh = (labelhigh << 1) & 0xfe; } v = (byte)(v & 0x7f); if (v != 0) { labelBuilder.Append((char)v); } } string label = labelBuilder.ToString(); Vector3 right = new Vector3(odef.ReadSingle(), odef.ReadSingle(), odef.ReadSingle()); Vector3 upwards = new Vector3(odef.ReadSingle(), odef.ReadSingle(), odef.ReadSingle()); Vector3 forward = new Vector3(odef.ReadSingle(), odef.ReadSingle(), odef.ReadSingle()); Vector3 pos = new Vector3(odef.ReadSingle(), odef.ReadSingle(), odef.ReadSingle()); odef.Position += 36; ClassId classId = (ClassId)odef.ReadUInt32(); ushort flags = odef.ReadUInt16(); ushort teamId = odef.ReadUInt16(); Vector3 localPosition = new Vector3(pos.x % 640, pos.y, pos.z % 640); int patchPosX = (int)(pos.x / 640.0f); int patchPosZ = (int)(pos.z / 640.0f); mdef.TerrainPatches[patchPosX, patchPosZ].Objects.Add(new Odef { Label = label, Id = labelhigh, LocalPosition = localPosition, ClassId = classId, TeamId = teamId, IsPlayer = flags == 16, LocalRotation = Quaternion.LookRotation(forward, upwards) }); odef.Next(); } } msn.FindNext("LDEF"); using (Bwd2Reader ldef = new Bwd2Reader(msn)) { ldef.FindNext("OBJ"); while (ldef.Current != null && ldef.Current.Name != "EXIT") { string label = ldef.ReadCString(8); ldef.Position += 84; ClassId classId = (ClassId)ldef.ReadUInt32(); ldef.ReadUInt32(); uint numStrings = ldef.ReadUInt32(); Vector3[] stringPositions = new Vector3[numStrings]; for (int i = 0; i < numStrings; i++) { Vector3 stringPos = new Vector3(ldef.ReadSingle(), ldef.ReadSingle(), ldef.ReadSingle()); stringPositions[i] = stringPos; } mdef.StringObjects.Add(new Ldef { Label = label, StringPositions = stringPositions }); ldef.Next(); } } msn.FindNext("ADEF"); using (Bwd2Reader adef = new Bwd2Reader(msn)) { adef.FindNext("FSM"); if (adef.Current != null && adef.Current.DataLength > 0) { mdef.FSM = new FSM(); mdef.FSM.ActionTable = new string[adef.ReadUInt32()]; for (int i = 0; i < mdef.FSM.ActionTable.Length; i++) { mdef.FSM.ActionTable[i] = adef.ReadCString(40); } uint numEntities = adef.ReadUInt32(); mdef.FSM.EntityTable = new FSMEntity[numEntities]; for (int i = 0; i < numEntities; i++) { string label = adef.ReadCString(40); byte[] rawlabel = adef.ReadBytes(8); int labelhigh = 0; StringBuilder labelBuilder = new StringBuilder(); for (int j = 0; j < 8; j++) { byte v = rawlabel[j]; if (v > 0x7f) { labelhigh = (labelhigh << 1) | 0x01; } else { labelhigh = (labelhigh << 1) & 0xfe; } v = (byte)(v & 0x7f); if (v != 0) { labelBuilder.Append((char)v); } } mdef.FSM.EntityTable[i] = new FSMEntity { Label = label, Value = labelBuilder.ToString(), Id = labelhigh }; } mdef.FSM.SoundClipTable = new string[adef.ReadUInt32()]; for (int i = 0; i < mdef.FSM.SoundClipTable.Length; i++) { mdef.FSM.SoundClipTable[i] = adef.ReadCString(40); } uint numPaths = adef.ReadUInt32(); mdef.FSM.Paths = new FSMPath[numPaths]; for (int i = 0; i < numPaths; i++) { string name = adef.ReadCString(40); I76Vector3[] nodes = new I76Vector3[adef.ReadUInt32()]; for (int p = 0; p < nodes.Length; p++) { nodes[p] = new I76Vector3(adef.ReadSingle(), adef.ReadSingle(), adef.ReadSingle()); } mdef.FSM.Paths[i] = new FSMPath { Name = name, Nodes = nodes }; } uint numMachines = adef.ReadUInt32(); mdef.FSM.StackMachines = new StackMachine[numMachines]; for (int i = 0; i < numMachines; i++) { long next = adef.Position + 168; StackMachine machine = new StackMachine(); machine.StartAddress = adef.ReadUInt32(); machine.InitialArguments = new int[adef.ReadUInt32()]; for (int j = 0; j < machine.InitialArguments.Length; j++) { machine.InitialArguments[j] = adef.ReadInt32(); } adef.Position = next; mdef.FSM.StackMachines[i] = machine; } mdef.FSM.Constants = new IntRef[adef.ReadUInt32()]; for (int i = 0; i < mdef.FSM.Constants.Length; i++) { mdef.FSM.Constants[i] = new IntRef(adef.ReadInt32()); } mdef.FSM.ByteCode = new ByteCode[adef.ReadUInt32()]; for (int i = 0; i < mdef.FSM.ByteCode.Length; i++) { ByteCode byteCode = mdef.FSM.ByteCode[i] = new ByteCode(); byteCode.OpCode = (OpCode)adef.ReadUInt32(); byteCode.Value = adef.ReadInt32(); } } } } return(mdef); }
public static Gdf ParseGdf(string filename) { using (Bwd2Reader br = new Bwd2Reader(filename)) { Gdf gdf = new Gdf(); br.FindNext("REV"); int rev = br.ReadInt32(); br.FindNext("GDFC"); { gdf.Name = br.ReadCString(16); int unk1 = br.ReadInt32(); int unk2 = br.ReadInt32(); float unk3 = br.ReadSingle(); float unk4 = br.ReadSingle(); float unk5 = br.ReadSingle(); float unk6 = br.ReadSingle(); br.ReadBytes(4); gdf.Damage = br.ReadInt32(); gdf.Health = br.ReadInt32(); gdf.WeaponMass = br.ReadSingle(); string unk7 = br.ReadCString(12); ushort unk8 = br.ReadUInt16(); float unk9 = br.ReadSingle(); gdf.BurstRate = 1f / br.ReadSingle(); gdf.FiringRate = 1f / br.ReadSingle(); gdf.FireAmount = br.ReadInt32(); gdf.BulletVelocity = br.ReadSingle(); gdf.WeaponGroup = br.ReadInt32(); gdf.AmmoCount = br.ReadInt32(); float unk10 = br.ReadSingle(); gdf.FireSpriteName = br.ReadCString(13); gdf.SoundName = br.ReadCString(13); if (rev == 8) { int unk11 = br.ReadInt32(); // Always 1? gdf.EnabledSpriteName = br.ReadCString(16); gdf.DisabledSpriteName = br.ReadCString(16); } } br.FindNext("GPOF"); // 192 bytes SdfPart[] parts = new SdfPart[4]; for (int i = 0; i < 4; ++i) { SdfPart part = new SdfPart(); part.Right = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); part.Up = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); part.Forward = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); part.Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); parts[i] = part; } br.FindNext("GGEO"); // 4 bytes { int numParts = br.ReadInt32(); if (numParts > 0) { int topPartsIndex = 0; int sidePartsIndex = 0; int turretPartsIndex = 0; int insidePartsIndex = 0; const int weaponSlots = 4; int totalSlots = weaponSlots * numParts; for (int i = 0; i < totalSlots; ++i) { string partName = br.ReadCString(8); if (partName == "NULL") { br.Position += 92; } else { SdfPart sdfPart = new SdfPart { Name = partName, Right = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Up = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Forward = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), ParentName = br.ReadCString(8) }; char partType = partName[3]; switch (partType) { case 'P': if (gdf.TopParts == null) { gdf.TopParts = new SdfPart[numParts]; } gdf.TopParts[topPartsIndex++] = sdfPart; break; case 'S': if (gdf.SideParts == null) { gdf.SideParts = new SdfPart[numParts]; } gdf.SideParts[sidePartsIndex++] = sdfPart; break; case 'T': if (gdf.TurretParts == null) { gdf.TurretParts = new SdfPart[numParts]; } gdf.TurretParts[turretPartsIndex++] = sdfPart; break; case 'I': if (gdf.InsideParts == null) { gdf.InsideParts = new SdfPart[numParts]; } gdf.InsideParts[insidePartsIndex++] = sdfPart; break; default: Debug.LogWarningFormat("Unknown part type '{0}' for part name '{1}'.", partType, partName); break; } br.Position += 36; } // Skip Lower LOD levels - do we want to use these at all? br.Position += 200; } } } br.FindNext("ORDF"); // 133 bytes br.FindNext("OGEO"); // 104 bytes br.ReadInt32(); gdf.Projectile = new SdfPart { Name = br.ReadCString(8), Right = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Up = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Forward = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()), ParentName = br.ReadCString(8) }; return(gdf); } }