// METHODS public void readBSP() { try { version = Version; byte[] theLump = new byte[0]; BSPObject = new BSP(BSPFile.FullName, version); switch(version) { case mapType.TYPE_VINDICTUS: case mapType.TYPE_TACTICALINTERVENTION: case mapType.TYPE_SOURCE17: case mapType.TYPE_SOURCE18: case mapType.TYPE_SOURCE19: case mapType.TYPE_SOURCE20: case mapType.TYPE_SOURCE21: case mapType.TYPE_SOURCE22: case mapType.TYPE_SOURCE23: case mapType.TYPE_SOURCE27: case mapType.TYPE_DMOMAM: DecompilerThread.OnMessage(this, "Source BSP"); stream.Seek(8, SeekOrigin.Begin); int test = br.ReadInt32(); if(bigEndian) { test = DataReader.swapEndian(test); } if(test < 1032) { // If what's usually the offset is less than the length of the header and directory isL4D2 = true; // This is Left 4 Dead 2 } // Lump 35, Game lump // Need to handle this here in order to detect Vindictus maps. // This lump SUCKS. It's a lump containing nested lumps for game specific data. // What we need out of it is the static prop lump. theLump = readLumpNum(35); try { readGameLump(theLump, lumpOffset); } catch { dumpLump(theLump); } for(int i=0;i<64;i++) { try { switch(i) { case 0: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.TexDatas = SourceTexData.createLump(theLump); break; case 3: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.Nodes = Node.createLump(theLump, version); break; case 6: theLump = readLumpNum(i); BSPObject.TexInfo = TexInfo.createLump(theLump, version); break; case 7: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 10: theLump = readLumpNum(i); BSPObject.Leaves = Leaf.createLump(theLump, version); break; case 12: theLump = readLumpNum(i); BSPObject.Edges = Edge.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.SurfEdges = new NumList(theLump, NumList.dataType.INT); break; case 14: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 17: theLump = readLumpNum(i); if(version == mapType.TYPE_VINDICTUS) { BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.UINT); } else { BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.USHORT); } break; case 18: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 19: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 26: theLump = readLumpNum(i); BSPObject.DispInfos = SourceDispInfo.createLump(theLump, version); break; case 27: theLump = readLumpNum(i); BSPObject.OriginalFaces = Face.createLump(theLump, version); break; case 33: theLump = readLumpNum(i); BSPObject.DispVerts = SourceDispVertex.createLump(theLump); break; case 40: theLump = readLumpNum(i); if (Settings.extractZip) { Console.Write("Extracting internal PAK file... "); writeLump(BSPObject.MapName+".zip", theLump); } break; case 42: theLump = readLumpNum(i); BSPObject.Cubemaps = SourceCubemap.createLump(theLump, version); break; case 43: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 44: theLump = readLumpNum(i); BSPObject.TexTable = new NumList(theLump, NumList.dataType.INT); break; case 48: theLump = readLumpNum(i); BSPObject.DispTris = new NumList(theLump, NumList.dataType.USHORT); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_NIGHTFIRE: DecompilerThread.OnMessage(this, "BSP v42 (Nightfire)"); for(int i=0;i<18;i++) { try { switch(i) { case 0: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 3: theLump = readLumpNum(i); BSPObject.Materials = Texture.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 9: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 11: theLump = readLumpNum(i); BSPObject.Leaves = Leaf.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.UINT); break; case 14: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 15: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 16: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 17: theLump = readLumpNum(i); BSPObject.TexInfo = TexInfo.createLump(theLump, version); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_QUAKE2: case mapType.TYPE_SIN: case mapType.TYPE_DAIKATANA: case mapType.TYPE_SOF: DecompilerThread.OnMessage(this, "BSP v38 (Quake 2/SiN/Daikatana/Soldier of Fortune)"); for(int i=0;i<19;i++) { try { switch(i) { case 0: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Nodes = Node.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 6: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 8: theLump = readLumpNum(i); BSPObject.Leaves = Leaf.createLump(theLump, version); break; case 10: theLump = readLumpNum(i); BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.USHORT); break; case 11: theLump = readLumpNum(i); BSPObject.Edges = Edge.createLump(theLump, version); break; case 12: theLump = readLumpNum(i); BSPObject.SurfEdges = new NumList(theLump, NumList.dataType.INT); break; case 13: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 14: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 15: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; /*case 18: theLump = readLumpNum(i); BSPObject.AreaPortals = AreaPortal.createLump(theLump, version); break;*/ } } catch { dumpLump(theLump); } } break; case mapType.TYPE_QUAKE: DecompilerThread.OnMessage(this, "Quake 1/Half-life BSP"); for (int i = 0; i < 15; i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 3: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.Nodes = Node.createLump(theLump, version); break; case 6: theLump = readLumpNum(i); BSPObject.TexInfo = TexInfo.createLump(theLump, version); break; case 7: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 10: theLump = readLumpNum(i); BSPObject.Leaves = Leaf.createLump(theLump, version); break; case 11: theLump = readLumpNum(i); BSPObject.MarkSurfaces = new NumList(theLump, NumList.dataType.USHORT); break; case 12: theLump = readLumpNum(i); BSPObject.Edges = Edge.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.SurfEdges = new NumList(theLump, NumList.dataType.INT); break; case 14: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_STEF2: case mapType.TYPE_STEF2DEMO: DecompilerThread.OnMessage(this, "Star Trek Elite Force 2 BSP"); for (int i = 0; i < 30; i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 6: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 12: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 15: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 16: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_MOHAA: DecompilerThread.OnMessage(this, "MOHAA BSP (modified id Tech 3)"); for(int i=0;i<28;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 3: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 11: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 12: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 14: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; //case 24: // theLump = readLumpNum(i); // BSPObject.StaticProps = StaticProp.createLump(theLump); // break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_FAKK: DecompilerThread.OnMessage(this, "Heavy Metal FAKK² BSP"); for(int i=0;i<20;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 1: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 10: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 11: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 14: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_RAVEN: case mapType.TYPE_QUAKE3: DecompilerThread.OnMessage(this, "BSP v46 (id Tech 3)"); for(int i=0;i<18;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; case 1: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 7: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 8: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 9: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 10: theLump = readLumpNum(i); BSPObject.Vertices = Vertex.createLump(theLump, version); break; case 13: theLump = readLumpNum(i); BSPObject.Faces = Face.createLump(theLump, version); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_COD: DecompilerThread.OnMessage(this, "BSP v59 (Call of Duty)"); for(int i=0;i<33;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 2: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 3: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 27: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 29: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_COD2: DecompilerThread.OnMessage(this, "Call of Duty 2 BSP"); for(int i=0;i<40;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 6: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 35: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 37: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_COD4: DecompilerThread.OnMessage(this, "Call of Duty 4 BSP"); for(int i=0;i<55;i++) { try { switch (i) { case 0: theLump = readLumpNum(i); BSPObject.Textures = Texture.createLump(theLump, version); break; case 4: theLump = readLumpNum(i); BSPObject.Planes = Plane.createLump(theLump, version); break; case 5: theLump = readLumpNum(i); BSPObject.BrushSides = BrushSide.createLump(theLump, version); break; case 8: theLump = readLumpNum(i); BSPObject.Brushes = Brush.createLump(theLump, version); break; case 37: theLump = readLumpNum(i); BSPObject.Models = Model.createLump(theLump, version); break; case 39: theLump = readLumpNum(i); BSPObject.Entities = Entity.createLump(theLump); break; } } catch { dumpLump(theLump); } } break; case mapType.TYPE_DOOM: case mapType.TYPE_HEXEN: DecompilerThread.OnMessage(this, "WAD file found"); stream.Seek(4, SeekOrigin.Begin); int numLumps = br.ReadInt32(); for(int i=0;i<numLumps;i++) { string name = getLumpName(i); if((name.Length == 5 && name[0] == 'M' && name[1] == 'A' && name[2] == 'P' && name[3] >= '0' && name[3] <= '9' && name[4] >= '0' && name[4] <= '9') || ((name.Length == 4 && name[0] == 'E' && name[1] >= '0' && name[1] <= '9' && name[2] == 'M' && name[3] >= '0' && name[3] <= '9'))) { if(getLumpName(i+11) == "BEHAVIOR") { version = mapType.TYPE_HEXEN; } DecompilerThread.OnMessage(this, "Map: " + name); DoomMap currentMap = new DoomMap(BSPFile.FullName, name, version); int[] headerInfo = getLumpInfo(i); if (headerInfo[1] > 0 && Settings.extractZip) { Console.Write("Extracting Map Header "); writeLump(name+".txt", readLumpNum(i)); } currentMap.Things = DThing.createLump(readLumpNum(i+1), version); currentMap.Linedefs = DLinedef.createLump(readLumpNum(i+2), version); currentMap.Sidedefs = DSidedef.createLump(readLumpNum(i+3)); currentMap.Vertices = Vertex.createLump(readLumpNum(i+4), version); currentMap.Segments = DSegment.createLump(readLumpNum(i+5)); currentMap.SubSectors = Edge.createLump(readLumpNum(i+6), version); currentMap.Nodes = DNode.createLump(readLumpNum(i+7)); currentMap.Sectors = DSector.createLump(readLumpNum(i+8)); doomMaps.Add(currentMap); currentMap.printBSPReport(); } } break; default: DecompilerThread.OnMessage(this, "Tried to populate structures for a format not implemented yet!"); break; } BSPObject.printBSPReport(); } catch (System.IO.IOException) { DecompilerThread.OnMessage(this, "Unable to access BSP file! Is it open in another program?"); } br.Close(); }
// METHODS public void readBSP() { try { byte[] theLump = new byte[0]; byte[] vis = new byte[0]; BSPObject = new BSP(BSPFile.FullName); Console.WriteLine("Opening " + BSPFile.FullName); for (int i = 0; i < 18; i++) { try { theLump = readLumpNum(i); switch (i) { case 0: BSPObject.Entities = Entity.createLump(theLump); break; case 1: BSPObject.Planes = Plane.createLump(theLump); break; case 2: BSPObject.Textures = Texture.createLump(theLump); break; case 3: BSPObject.Materials = Texture.createLump(theLump); break; case 4: BSPObject.Vertices = Vertex.createLump(theLump); break; case 5: BSPObject.Normals = new Lump <LumpObject>(theLump.Length, 0); break; case 6: BSPObject.Indices = new NumList(theLump, NumList.dataType.UINT); break; case 7: vis = theLump; break; case 8: BSPObject.Nodes = Node.createLump(theLump); break; case 9: BSPObject.Faces = Face.createLump(theLump); break; case 10: BSPObject.Lightmaps = new NumList(theLump, NumList.dataType.UBYTE); break; case 11: BSPObject.Leaves = Leaf.createLump(theLump); break; case 12: BSPObject.MarkSurfaces = new NumList(theLump, NumList.dataType.UINT); break; case 13: BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.UINT); break; case 14: BSPObject.Models = Model.createLump(theLump); break; case 15: BSPObject.Brushes = Brush.createLump(theLump); break; case 16: BSPObject.BrushSides = BrushSide.createLump(theLump); break; case 17: BSPObject.TexInfo = TexInfo.createLump(theLump); break; } } catch { dumpLump(theLump); } } try { int visLength = BSPObject.Leaves[2].PVS; if (visLength > 0 && vis.Length > 0) { BSPObject.Vis = new Lump <LumpObject>(vis, visLength); } } catch (ArgumentOutOfRangeException) {; } if (BSPObject.Vis == null) { BSPObject.Vis = new Lump <LumpObject>(0, 0); } BSPObject.printBSPReport(); } catch (System.IO.IOException) { Console.WriteLine("Unable to access BSP file! Is it open in another program?"); } br.Close(); }