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); } }