diff --git a/LibBSP/Source/Extensions/PlaneExtensions.cs b/LibBSP/Source/Extensions/PlaneExtensions.cs
index 8076273..6bd47b9 100644
--- a/LibBSP/Source/Extensions/PlaneExtensions.cs
+++ b/LibBSP/Source/Extensions/PlaneExtensions.cs
@@ -232,12 +232,13 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
/// This function goes here since it can't go into Unity's Plane class, and so can't depend
/// on having a constructor taking a byte array.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
diff --git a/LibBSP/Source/Extensions/UIVertexExtensions.cs b/LibBSP/Source/Extensions/UIVertexExtensions.cs
index 14f401a..f8459d4 100644
--- a/LibBSP/Source/Extensions/UIVertexExtensions.cs
+++ b/LibBSP/Source/Extensions/UIVertexExtensions.cs
@@ -71,12 +71,13 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// The resulting object.
/// was null.
/// This structure is not implemented for the given maptype.
/// has no constructor, so the object must be initialized field-by-field. Even if it
/// did have a constructor, the way data needs to be read wouldn't allow use of it.
- public static UIVertex CreateVertex(byte[] data, MapType type) {
+ public static UIVertex CreateVertex(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -135,12 +136,13 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
/// This function goes here since I can't put it into Unity's UIVertex class, and so I can't
/// depend on having a constructor taking a byte array.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -187,7 +189,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, i * structLength, bytes, 0, structLength);
- lump.Add(CreateVertex(bytes, type));
+ lump.Add(CreateVertex(bytes, type, version));
}
return lump;
}
diff --git a/LibBSP/Source/Structs/BSP/BSP.cs b/LibBSP/Source/Structs/BSP/BSP.cs
index 721dfa9..b9c4dcf 100644
--- a/LibBSP/Source/Structs/BSP/BSP.cs
+++ b/LibBSP/Source/Structs/BSP/BSP.cs
@@ -54,19 +54,20 @@ namespace LibBSP {
///
/// Struct containing basic information for a lump in a BSP file.
///
- public struct LumpInfo {
+ public class LumpInfo {
public int ident;
public int flags;
public int version;
public int offset;
public int length;
+ public FileInfo lumpFile;
}
///
/// Holds data for any and all BSP formats. Any unused lumps in a given format
/// will be left as null.
///
- public class BSP {
+ public class BSP : Dictionary {
private MapType _version;
@@ -137,7 +138,7 @@ namespace LibBSP {
if (_entities == null) {
int index = Entity.GetIndexForLump(version);
if (index >= 0) {
- _entities = Entity.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _entities = Entity.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _entities;
@@ -152,7 +153,7 @@ namespace LibBSP {
if (_planes == null) {
int index = PlaneExtensions.GetIndexForLump(version);
if (index >= 0) {
- _planes = PlaneExtensions.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _planes = PlaneExtensions.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _planes;
@@ -167,7 +168,7 @@ namespace LibBSP {
if (_textures == null) {
int index = Texture.GetIndexForLump(version);
if (index >= 0) {
- _textures = Texture.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _textures = Texture.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _textures;
@@ -182,7 +183,7 @@ namespace LibBSP {
if (_vertices == null) {
int index = UIVertexExtensions.GetIndexForLump(version);
if (index >= 0) {
- _vertices = UIVertexExtensions.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _vertices = UIVertexExtensions.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _vertices;
@@ -197,7 +198,7 @@ namespace LibBSP {
if (_nodes == null) {
int index = Node.GetIndexForLump(version);
if (index >= 0) {
- _nodes = Node.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _nodes = Node.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _nodes;
@@ -212,7 +213,7 @@ namespace LibBSP {
if (_texInfo == null) {
int index = TextureInfo.GetIndexForLump(version);
if (index >= 0) {
- _texInfo = TextureInfo.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _texInfo = TextureInfo.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _texInfo;
@@ -227,7 +228,7 @@ namespace LibBSP {
if (_faces == null) {
int index = Face.GetIndexForLump(version);
if (index >= 0) {
- _faces = Face.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _faces = Face.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _faces;
@@ -242,7 +243,7 @@ namespace LibBSP {
if (_leaves == null) {
int index = Leaf.GetIndexForLump(version);
if (index >= 0) {
- _leaves = Leaf.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _leaves = Leaf.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _leaves;
@@ -257,7 +258,7 @@ namespace LibBSP {
if (_edges == null) {
int index = Edge.GetIndexForLump(version);
if (index >= 0) {
- _edges = Edge.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _edges = Edge.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _edges;
@@ -272,7 +273,7 @@ namespace LibBSP {
if (_models == null) {
int index = Model.GetIndexForLump(version);
if (index >= 0) {
- _models = Model.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _models = Model.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _models;
@@ -287,7 +288,7 @@ namespace LibBSP {
if (_brushes == null) {
int index = Brush.GetIndexForLump(version);
if (index >= 0) {
- _brushes = Brush.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _brushes = Brush.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _brushes;
@@ -302,7 +303,7 @@ namespace LibBSP {
if (_brushSides == null) {
int index = BrushSide.GetIndexForLump(version);
if (index >= 0) {
- _brushSides = BrushSide.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _brushSides = BrushSide.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _brushSides;
@@ -317,7 +318,7 @@ namespace LibBSP {
if (_materials == null) {
int index = Texture.GetIndexForMaterialLump(version);
if (index >= 0) {
- _materials = Texture.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _materials = Texture.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _materials;
@@ -332,7 +333,7 @@ namespace LibBSP {
if (_originalFaces == null) {
int index = Face.GetIndexForOriginalFacesLump(version);
if (index >= 0) {
- _originalFaces = Face.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _originalFaces = Face.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _originalFaces;
@@ -347,7 +348,7 @@ namespace LibBSP {
if (_texDatas == null) {
int index = TextureData.GetIndexForLump(version);
if (index >= 0) {
- _texDatas = TextureData.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _texDatas = TextureData.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _texDatas;
@@ -362,7 +363,7 @@ namespace LibBSP {
if (_dispInfos == null) {
int index = DisplacementInfo.GetIndexForLump(version);
if (index >= 0) {
- _dispInfos = DisplacementInfo.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _dispInfos = DisplacementInfo.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _dispInfos;
@@ -377,7 +378,7 @@ namespace LibBSP {
if (_dispVerts == null) {
int index = DisplacementVertex.GetIndexForLump(version);
if (index >= 0) {
- _dispVerts = DisplacementVertex.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _dispVerts = DisplacementVertex.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _dispVerts;
@@ -392,7 +393,7 @@ namespace LibBSP {
if (_cubemaps == null) {
int index = Cubemap.GetIndexForLump(version);
if (index >= 0) {
- _cubemaps = Cubemap.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _cubemaps = Cubemap.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _cubemaps;
@@ -408,7 +409,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForMarkSurfacesLump(version, out type);
if (index >= 0) {
- _markSurfaces = NumList.LumpFactory(reader.ReadLumpNum(index, version), type);
+ _markSurfaces = NumList.LumpFactory(reader.ReadLump(this[index]), type);
}
}
return _markSurfaces;
@@ -424,7 +425,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForSurfEdgesLump(version, out type);
if (index >= 0) {
- _surfEdges = NumList.LumpFactory(reader.ReadLumpNum(index, version), type);
+ _surfEdges = NumList.LumpFactory(reader.ReadLump(this[index]), type);
}
}
return _surfEdges;
@@ -440,7 +441,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForMarkBrushesLump(version, out type);
if (index >= 0) {
- _markBrushes = NumList.LumpFactory(reader.ReadLumpNum(index, version), type);
+ _markBrushes = NumList.LumpFactory(reader.ReadLump(this[index]), type);
}
}
return _markBrushes;
@@ -456,7 +457,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForIndicesLump(version, out type);
if (index >= 0) {
- _indices = NumList.LumpFactory(reader.ReadLumpNum(index, version), type);
+ _indices = NumList.LumpFactory(reader.ReadLump(this[index]), type);
}
}
return _indices;
@@ -472,7 +473,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForTexTableLump(version, out type);
if (index >= 0) {
- _texTable = NumList.LumpFactory(reader.ReadLumpNum(index, version), type);
+ _texTable = NumList.LumpFactory(reader.ReadLump(this[index]), type);
}
}
return _texTable;
@@ -488,7 +489,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForDisplacementTrianglesLump(version, out type);
if (index >= 0) {
- _displacementTriangles = NumList.LumpFactory(reader.ReadLumpNum(index, version), type);
+ _displacementTriangles = NumList.LumpFactory(reader.ReadLump(this[index]), type);
}
}
return _displacementTriangles;
@@ -503,7 +504,7 @@ namespace LibBSP {
if (_gameLump == null) {
int index = GameLump.GetIndexForLump(version);
if (index >= 0) {
- _gameLump = GameLump.LumpFactory(reader.ReadLumpNum(index, version), version);
+ _gameLump = GameLump.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
}
}
return _gameLump;
@@ -584,12 +585,26 @@ namespace LibBSP {
}
}
+ ///
+ /// Gets the object associated with the lump with index "".
+ ///
+ /// Index of the lump to get information for.
+ /// A object containing information about lump "".
+ public LumpInfo this[int index] {
+ get {
+ if (!ContainsKey(index)) {
+ base[index] = reader.GetLumpInfo(index, version);
+ }
+ return base[index];
+ }
+ }
+
///
/// Creates a new instance pointing to the file at . The
/// Lists in this class will be read and populated when accessed through their properties.
///
/// The path to the .BSP file.
- public BSP(string filePath) {
+ public BSP(string filePath) : base(16) {
reader = new BSPReader(new FileInfo(filePath));
this.filePath = filePath;
}
@@ -599,16 +614,71 @@ namespace LibBSP {
/// Lists in this class will be read and populated when accessed through their properties.
///
/// A reference to the .BSP file.
- public BSP(FileInfo file) {
+ public BSP(FileInfo file) : base(16) {
reader = new BSPReader(file);
this.filePath = file.FullName;
}
///
- /// Tells the object to release file handles for the BSP file.
+ /// Gets the number of lumps in a given BSP version.
///
- public void Close() {
- reader.Close();
+ /// The version to get the number of lumps for.
+ /// The number of lumps used by a BSP of version .
+ public static int GetNumLumps(MapType version) {
+ switch (version) {
+ case MapType.Quake: {
+ return 15;
+ }
+ case MapType.Daikatana:
+ case MapType.Quake2: {
+ return 16;
+ }
+ case MapType.Quake3: {
+ return 17;
+ }
+ case MapType.Raven:
+ case MapType.Nightfire: {
+ return 18;
+ }
+ case MapType.FAKK:
+ case MapType.SiN: {
+ return 20;
+ }
+ case MapType.SoF: {
+ return 22;
+ }
+ case MapType.MOHAA: {
+ return 28;
+ }
+ case MapType.STEF2:
+ case MapType.STEF2Demo: {
+ return 30;
+ }
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return 31;
+ }
+ case MapType.CoD4: {
+ return 55;
+ }
+ case MapType.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Source17:
+ case MapType.Source18:
+ case MapType.Source19:
+ case MapType.Source20:
+ case MapType.Source21:
+ case MapType.Source22:
+ case MapType.Source23:
+ case MapType.Source27:
+ case MapType.L4D2:
+ case MapType.Vindictus: {
+ return 64;
+ }
+ default: {
+ return -1;
+ }
+ }
}
///
diff --git a/LibBSP/Source/Structs/BSP/Brush.cs b/LibBSP/Source/Structs/BSP/Brush.cs
index 0914ed3..c43f946 100644
--- a/LibBSP/Source/Structs/BSP/Brush.cs
+++ b/LibBSP/Source/Structs/BSP/Brush.cs
@@ -17,9 +17,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public Brush(byte[] data, MapType type) : this() {
+ public Brush(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -88,10 +89,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -136,7 +138,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new Brush(bytes, type));
+ lump.Add(new Brush(bytes, type, version));
}
return lump;
}
diff --git a/LibBSP/Source/Structs/BSP/BrushSide.cs b/LibBSP/Source/Structs/BSP/BrushSide.cs
index 1f8eca5..77909d0 100644
--- a/LibBSP/Source/Structs/BSP/BrushSide.cs
+++ b/LibBSP/Source/Structs/BSP/BrushSide.cs
@@ -19,9 +19,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public BrushSide(byte[] data, MapType type) : this() {
+ public BrushSide(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -107,10 +108,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -161,7 +163,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; i++) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new BrushSide(bytes, type));
+ lump.Add(new BrushSide(bytes, type, version));
}
return lump;
}
diff --git a/LibBSP/Source/Structs/BSP/Cubemap.cs b/LibBSP/Source/Structs/BSP/Cubemap.cs
index 6d882b8..2191081 100644
--- a/LibBSP/Source/Structs/BSP/Cubemap.cs
+++ b/LibBSP/Source/Structs/BSP/Cubemap.cs
@@ -25,9 +25,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public Cubemap(byte[] data, MapType type) : this() {
+ public Cubemap(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -58,10 +59,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -90,7 +92,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new Cubemap(bytes, type));
+ lump.Add(new Cubemap(bytes, type, version));
offset += structLength;
}
return lump;
diff --git a/LibBSP/Source/Structs/BSP/DisplacementInfo.cs b/LibBSP/Source/Structs/BSP/DisplacementInfo.cs
index d60c05d..958c9a6 100644
--- a/LibBSP/Source/Structs/BSP/DisplacementInfo.cs
+++ b/LibBSP/Source/Structs/BSP/DisplacementInfo.cs
@@ -28,9 +28,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public DisplacementInfo(byte[] data, MapType type) : this() {
+ public DisplacementInfo(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -78,10 +79,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -119,7 +121,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new DisplacementInfo(bytes, type));
+ lump.Add(new DisplacementInfo(bytes, type, version));
offset += structLength;
}
return lump;
diff --git a/LibBSP/Source/Structs/BSP/DisplacementVertex.cs b/LibBSP/Source/Structs/BSP/DisplacementVertex.cs
index 3ccdd3d..c12d4f6 100644
--- a/LibBSP/Source/Structs/BSP/DisplacementVertex.cs
+++ b/LibBSP/Source/Structs/BSP/DisplacementVertex.cs
@@ -26,8 +26,9 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
- public DisplacementVertex(byte[] data, MapType type) : this() {
+ public DisplacementVertex(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -41,13 +42,14 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A object.
/// was null.
- public static DisplacementVertices LumpFactory(byte[] data, MapType type) {
+ public static DisplacementVertices LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
- return new DisplacementVertices(data, type);
+ return new DisplacementVertices(data, type, version);
}
///
diff --git a/LibBSP/Source/Structs/BSP/Edge.cs b/LibBSP/Source/Structs/BSP/Edge.cs
index d40ab44..93a0b94 100644
--- a/LibBSP/Source/Structs/BSP/Edge.cs
+++ b/LibBSP/Source/Structs/BSP/Edge.cs
@@ -15,9 +15,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public Edge(byte[] data, MapType type) : this() {
+ public Edge(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -57,10 +58,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -96,7 +98,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new Edge(bytes, type));
+ lump.Add(new Edge(bytes, type, version));
}
return lump;
}
diff --git a/LibBSP/Source/Structs/BSP/Face.cs b/LibBSP/Source/Structs/BSP/Face.cs
index c6f6927..7515526 100644
--- a/LibBSP/Source/Structs/BSP/Face.cs
+++ b/LibBSP/Source/Structs/BSP/Face.cs
@@ -48,9 +48,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public Face(byte[] data, MapType type) : this() {
+ public Face(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -135,7 +136,11 @@ namespace LibBSP {
numEdges = BitConverter.ToInt32(data, 12);
textureScale = BitConverter.ToInt32(data, 16);
displacement = BitConverter.ToInt32(data, 20);
- original = BitConverter.ToInt32(data, 56);
+ if (version == 2) {
+ original = BitConverter.ToInt32(data, 60);
+ } else {
+ original = BitConverter.ToInt32(data, 56);
+ }
break;
}
case MapType.Nightfire: {
@@ -164,10 +169,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -208,7 +214,11 @@ namespace LibBSP {
break;
}
case MapType.Vindictus: {
- structLength = 72;
+ if (version == 2) {
+ structLength = 76;
+ } else {
+ structLength = 72;
+ }
break;
}
case MapType.Quake3: {
@@ -237,7 +247,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new Face(bytes, type));
+ lump.Add(new Face(bytes, type, version));
}
return lump;
}
diff --git a/LibBSP/Source/Structs/BSP/Leaf.cs b/LibBSP/Source/Structs/BSP/Leaf.cs
index 0138366..11f0a75 100644
--- a/LibBSP/Source/Structs/BSP/Leaf.cs
+++ b/LibBSP/Source/Structs/BSP/Leaf.cs
@@ -19,9 +19,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public Leaf(byte[] data, MapType type) : this() {
+ public Leaf(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -99,10 +100,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -161,7 +163,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new Leaf(bytes, type));
+ lump.Add(new Leaf(bytes, type, version));
}
return lump;
}
diff --git a/LibBSP/Source/Structs/BSP/Lumps/DisplacementVertices.cs b/LibBSP/Source/Structs/BSP/Lumps/DisplacementVertices.cs
index 47c02bc..5926091 100644
--- a/LibBSP/Source/Structs/BSP/Lumps/DisplacementVertices.cs
+++ b/LibBSP/Source/Structs/BSP/Lumps/DisplacementVertices.cs
@@ -12,8 +12,9 @@ namespace LibBSP {
///
/// Array of bytes to parse.
/// Format identifier.
+ /// The version of this lump.
/// was null.
- public DisplacementVertices(byte[] data, MapType type) : base(data.Length / 20) {
+ public DisplacementVertices(byte[] data, MapType type, int version = 0) : base(data.Length / 20) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -21,7 +22,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- Add(new DisplacementVertex(bytes, type));
+ Add(new DisplacementVertex(bytes, type, version));
}
}
diff --git a/LibBSP/Source/Structs/BSP/Lumps/GameLump.cs b/LibBSP/Source/Structs/BSP/Lumps/GameLump.cs
index d7ca61c..71a2fcf 100644
--- a/LibBSP/Source/Structs/BSP/Lumps/GameLump.cs
+++ b/LibBSP/Source/Structs/BSP/Lumps/GameLump.cs
@@ -46,9 +46,10 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public GameLump(byte[] data, MapType type) {
+ public GameLump(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -84,28 +85,28 @@ namespace LibBSP {
int lowestLumpOffset = Int32.MaxValue;
for (int i = 0; i < numGameLumps; ++i) {
- int ident = BitConverter.ToInt32(data, (i * structLength) + 4);
- int flags;
- int version;
- int offset;
- int length;
+ int lumpIdent = BitConverter.ToInt32(data, (i * structLength) + 4);
+ int lumpFlags;
+ int lumpVersion;
+ int lumpOffset;
+ int lumpLength;
if (type == MapType.Vindictus) {
- flags = BitConverter.ToInt32(data, (i * structLength) + 8);
- version = BitConverter.ToInt32(data, (i * structLength) + 12);
- offset = BitConverter.ToInt32(data, (i * structLength) + 16);
- length = BitConverter.ToInt32(data, (i * structLength) + 20);
+ lumpFlags = BitConverter.ToInt32(data, (i * structLength) + 8);
+ lumpVersion = BitConverter.ToInt32(data, (i * structLength) + 12);
+ lumpOffset = BitConverter.ToInt32(data, (i * structLength) + 16);
+ lumpLength = BitConverter.ToInt32(data, (i * structLength) + 20);
} else {
- flags = BitConverter.ToUInt16(data, (i * structLength) + 8);
- version = BitConverter.ToUInt16(data, (i * structLength) + 10);
- offset = BitConverter.ToInt32(data, (i * structLength) + 12);
- length = BitConverter.ToInt32(data, (i * structLength) + 16);
+ lumpFlags = BitConverter.ToUInt16(data, (i * structLength) + 8);
+ lumpVersion = BitConverter.ToUInt16(data, (i * structLength) + 10);
+ lumpOffset = BitConverter.ToInt32(data, (i * structLength) + 12);
+ lumpLength = BitConverter.ToInt32(data, (i * structLength) + 16);
}
LumpInfo info = new LumpInfo {
- ident = ident,
- flags = flags,
- version = version,
- offset = offset,
- length = length,
+ ident = lumpIdent,
+ flags = lumpFlags,
+ version = lumpVersion,
+ offset = lumpOffset,
+ length = lumpLength,
};
this[(GameLumpType)info.ident] = info;
@@ -124,10 +125,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A new object.
/// This is only here for consistency with the other lump structures.
- public static GameLump LumpFactory(byte[] data, MapType type) {
- return new GameLump(data, type);
+ public static GameLump LumpFactory(byte[] data, MapType type, int version = 0) {
+ return new GameLump(data, type, version);
}
///
diff --git a/LibBSP/Source/Structs/BSP/Lumps/StaticProps.cs b/LibBSP/Source/Structs/BSP/Lumps/StaticProps.cs
index ba8c1b2..220208e 100644
--- a/LibBSP/Source/Structs/BSP/Lumps/StaticProps.cs
+++ b/LibBSP/Source/Structs/BSP/Lumps/StaticProps.cs
@@ -16,7 +16,7 @@ namespace LibBSP {
/// Format identifier.
/// Version of static prop lump this is.
/// was null.
- public StaticProps(byte[] data, MapType type, int version) {
+ public StaticProps(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
diff --git a/LibBSP/Source/Structs/BSP/Lumps/Textures.cs b/LibBSP/Source/Structs/BSP/Lumps/Textures.cs
index 4eb1e2b..1609f4c 100644
--- a/LibBSP/Source/Structs/BSP/Lumps/Textures.cs
+++ b/LibBSP/Source/Structs/BSP/Lumps/Textures.cs
@@ -13,9 +13,10 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public Textures(byte[] data, MapType type) {
+ public Textures(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -68,7 +69,7 @@ namespace LibBSP {
// They are null-terminated strings, of non-constant length (not padded)
bytes = new byte[i - offset];
Array.Copy(data, offset, bytes, 0, i - offset);
- Add(new Texture(bytes, type));
+ Add(new Texture(bytes, type, version));
offset = i + 1;
}
}
@@ -80,7 +81,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < numElements; ++i) {
Array.Copy(data, BitConverter.ToInt32(data, (i + 1) * 4), bytes, 0, structLength);
- Add(new Texture(bytes, type));
+ Add(new Texture(bytes, type, version));
}
return;
}
@@ -93,7 +94,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- Add(new Texture(bytes, type));
+ Add(new Texture(bytes, type, version));
}
}
}
diff --git a/LibBSP/Source/Structs/BSP/Model.cs b/LibBSP/Source/Structs/BSP/Model.cs
index afe29b0..87dbf00 100644
--- a/LibBSP/Source/Structs/BSP/Model.cs
+++ b/LibBSP/Source/Structs/BSP/Model.cs
@@ -28,9 +28,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public Model(byte[] data, MapType type) : this() {
+ public Model(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -110,10 +111,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -169,7 +171,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new Model(bytes, type));
+ lump.Add(new Model(bytes, type, version));
offset += structLength;
}
return lump;
diff --git a/LibBSP/Source/Structs/BSP/Node.cs b/LibBSP/Source/Structs/BSP/Node.cs
index 3842982..52ae8a1 100644
--- a/LibBSP/Source/Structs/BSP/Node.cs
+++ b/LibBSP/Source/Structs/BSP/Node.cs
@@ -17,9 +17,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public Node(byte[] data, MapType type) : this() {
+ public Node(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -69,10 +70,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -126,7 +128,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new Node(bytes, type));
+ lump.Add(new Node(bytes, type, version));
offset += structLength;
}
return lump;
diff --git a/LibBSP/Source/Structs/BSP/StaticProp.cs b/LibBSP/Source/Structs/BSP/StaticProp.cs
index 2339365..bda4768 100644
--- a/LibBSP/Source/Structs/BSP/StaticProp.cs
+++ b/LibBSP/Source/Structs/BSP/StaticProp.cs
@@ -36,7 +36,7 @@ namespace LibBSP {
/// The version of static prop lump this object is a member of.
/// was null.
/// This structure is not implemented for the given maptype.
- public StaticProp(byte[] data, MapType type, int version) : this() {
+ public StaticProp(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -110,7 +110,7 @@ namespace LibBSP {
/// The map type.
/// The version of the Static Prop lump.
/// A object.
- public static StaticProps LumpFactory(byte[] data, MapType type, int version) {
+ public static StaticProps LumpFactory(byte[] data, MapType type, int version = 0) {
return new StaticProps(data, type, version);
}
}
diff --git a/LibBSP/Source/Structs/BSP/Texture.cs b/LibBSP/Source/Structs/BSP/Texture.cs
index 7aa0687..5aea978 100644
--- a/LibBSP/Source/Structs/BSP/Texture.cs
+++ b/LibBSP/Source/Structs/BSP/Texture.cs
@@ -36,9 +36,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public Texture(byte[] data, MapType type) : this() {
+ public Texture(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -108,9 +109,10 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A object.
- public static Textures LumpFactory(byte[] data, MapType type) {
- return new Textures(data, type);
+ public static Textures LumpFactory(byte[] data, MapType type, int version = 0) {
+ return new Textures(data, type, version);
}
///
diff --git a/LibBSP/Source/Structs/BSP/TextureData.cs b/LibBSP/Source/Structs/BSP/TextureData.cs
index b3e950c..b51102c 100644
--- a/LibBSP/Source/Structs/BSP/TextureData.cs
+++ b/LibBSP/Source/Structs/BSP/TextureData.cs
@@ -30,8 +30,9 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
- public TextureData(byte[] data, MapType type) : this() {
+ public TextureData(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
@@ -48,9 +49,10 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -59,7 +61,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; i++) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new TextureData(bytes, type));
+ lump.Add(new TextureData(bytes, type, version));
}
return lump;
}
diff --git a/LibBSP/Source/Structs/BSP/TextureInfo.cs b/LibBSP/Source/Structs/BSP/TextureInfo.cs
index 3b4692b..213c391 100644
--- a/LibBSP/Source/Structs/BSP/TextureInfo.cs
+++ b/LibBSP/Source/Structs/BSP/TextureInfo.cs
@@ -44,9 +44,10 @@ namespace LibBSP {
///
/// byte array to parse.
/// The map type.
+ /// The version of this lump.
/// was null.
/// This structure is not implemented for the given maptype.
- public TextureInfo(byte[] data, MapType type) {
+ public TextureInfo(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -142,10 +143,11 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// A List of objects.
/// was null.
/// This structure is not implemented for the given maptype.
- public static List LumpFactory(byte[] data, MapType type) {
+ public static List LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
@@ -184,7 +186,7 @@ namespace LibBSP {
byte[] bytes = new byte[structLength];
for (int i = 0; i < data.Length / structLength; ++i) {
Array.Copy(data, (i * structLength), bytes, 0, structLength);
- lump.Add(new TextureInfo(bytes, type));
+ lump.Add(new TextureInfo(bytes, type, version));
}
return lump;
}
diff --git a/LibBSP/Source/Structs/Common/Entity.cs b/LibBSP/Source/Structs/Common/Entity.cs
index c18a6b7..7951370 100644
--- a/LibBSP/Source/Structs/Common/Entity.cs
+++ b/LibBSP/Source/Structs/Common/Entity.cs
@@ -156,7 +156,9 @@ namespace LibBSP {
/// Initializes a new instance of an , parsing the given byte array into an structure.
///
/// Array to parse.
- public Entity(byte[] data, MapType type) : this(Encoding.ASCII.GetString(data).Split('\n')) { }
+ /// The map type.
+ /// The version of this lump.
+ public Entity(byte[] data, MapType type, int version = 0) : this(Encoding.ASCII.GetString(data).Split('\n')) { }
///
/// Initializes a new instance of an with the given classname.
@@ -521,8 +523,9 @@ namespace LibBSP {
///
/// The data to parse.
/// The map type.
+ /// The version of this lump.
/// An object, which is a List of s.
- public static Entities LumpFactory(byte[] data, MapType type) {
+ public static Entities LumpFactory(byte[] data, MapType type, int version = 0) {
return new Entities(data, type);
}
diff --git a/LibBSP/Source/Structs/Common/Lumps/Entities.cs b/LibBSP/Source/Structs/Common/Lumps/Entities.cs
index cb2818b..e03ffee 100644
--- a/LibBSP/Source/Structs/Common/Lumps/Entities.cs
+++ b/LibBSP/Source/Structs/Common/Lumps/Entities.cs
@@ -37,7 +37,8 @@ namespace LibBSP {
///
/// Bytes read from a file.
/// The of the source map.
- public Entities(byte[] data, MapType type) : base() {
+ /// The version of this lump.
+ public Entities(byte[] data, MapType type, int version = 0) : base() {
// Keep track of whether or not we're currently in a set of quotation marks.
// I came across a map where the idiot map maker used { and } within a value. This broke the code before.
bool inQuotes = false;
diff --git a/LibBSP/Source/Util/BSPReader.cs b/LibBSP/Source/Util/BSPReader.cs
index 45e2448..8221dbf 100644
--- a/LibBSP/Source/Util/BSPReader.cs
+++ b/LibBSP/Source/Util/BSPReader.cs
@@ -9,9 +9,7 @@ namespace LibBSP {
///
public class BSPReader {
private FileInfo bspFile;
- private FileStream stream;
- private BinaryReader binaryReader;
- private Dictionary lumpFiles = null;
+ private Dictionary lumpFiles = null;
private bool _bigEndian = false;
@@ -34,22 +32,25 @@ namespace LibBSP {
throw new FileNotFoundException("Unable to open BSP file; file " + file.FullName + " not found.");
} else {
this.bspFile = file;
- this.stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
- this.binaryReader = new BinaryReader(this.stream);
}
}
///
- /// Reads this lump in the map.
+ /// Gets the information for lump "" for this BSP file when reading it as "".
///
- /// The index of the lump to get.
- /// The version of BSP this is.
- /// Array of bytes read from the BSP file.
- public byte[] ReadLumpNum(int index, MapType version) {
+ /// The numerical index of this lump.
+ /// The type of BSP to interpret the file as.
+ /// A object containing information about the lump.
+ /// "" is less than zero, or greater than the number of lumps allowed by "".
+ public LumpInfo GetLumpInfo(int index, MapType version) {
+ if (index < 0 || index >= BSP.GetNumLumps(version)) {
+ throw new IndexOutOfRangeException();
+ }
+
switch (version) {
case MapType.Quake:
case MapType.Nightfire: {
- return ReadLumpFromOffsetLengthPairAtOffset(4 + (8 * index), version);
+ return GetLumpInfoAtOffset(4 + (8 * index), version);
}
case MapType.Quake2:
case MapType.Daikatana:
@@ -57,35 +58,15 @@ namespace LibBSP {
case MapType.SoF:
case MapType.Quake3:
case MapType.Raven:
- case MapType.CoD: {
- return ReadLumpFromOffsetLengthPairAtOffset(8 + (8 * index), version);
- }
+ case MapType.CoD:
case MapType.CoD2: {
- stream.Seek(8 + (8 * index), SeekOrigin.Begin);
- int temp = binaryReader.ReadInt32();
- return ReadLump(binaryReader.ReadInt32(), temp, version);
+ return GetLumpInfoAtOffset(8 + (8 * index), version);
}
case MapType.STEF2:
case MapType.STEF2Demo:
case MapType.MOHAA:
case MapType.FAKK: {
- return ReadLumpFromOffsetLengthPairAtOffset(12 + (8 * index), version);
- }
- case MapType.CoD4: {
- stream.Seek(8, SeekOrigin.Begin);
- int numlumps = binaryReader.ReadInt32();
- int offset = (numlumps * 8) + 12;
- for (int i = 0; i < numlumps; i++) {
- int id = binaryReader.ReadInt32();
- int length = binaryReader.ReadInt32();
- if (id == index) {
- return ReadLump(offset, length, version);
- } else {
- offset += length;
- while (offset % 4 != 0) { offset++; }
- }
- }
- break;
+ return GetLumpInfoAtOffset(12 + (8 * index), version);
}
case MapType.Source17:
case MapType.Source18:
@@ -101,18 +82,147 @@ namespace LibBSP {
if (lumpFiles == null) {
LoadLumpFiles();
}
- if (lumpFiles.ContainsKey(index)) { return ReadLumpFile(index); }
- return ReadLumpFromOffsetLengthPairAtOffset(8 + (16 * index), version);
+ if (lumpFiles.ContainsKey(index)) { return lumpFiles[index]; }
+ return GetLumpInfoAtOffset(8 + (16 * index), version);
+ }
+ case MapType.CoD4: {
+ using (FileStream stream = new FileStream(bspFile.FullName, FileMode.Open, FileAccess.Read)) {
+ BinaryReader binaryReader = new BinaryReader(stream);
+ stream.Seek(8, SeekOrigin.Begin);
+ int numlumps = binaryReader.ReadInt32();
+ int offset = (numlumps * 8) + 12;
+ for (int i = 0; i < numlumps; i++) {
+ int id = binaryReader.ReadInt32();
+ int length = binaryReader.ReadInt32();
+ if (id == index) {
+ return new LumpInfo() {
+ offset = offset,
+ length = length
+ };
+ } else {
+ offset += length;
+ while (offset % 4 != 0) { offset++; }
+ }
+ }
+ binaryReader.Close();
+ }
+ return new LumpInfo();
+ }
+ default: {
+ return null;
}
}
- return new byte[0];
+ }
+
+ ///
+ /// Gets the lump information at offset "" for this BSP file when reading it as "".
+ ///
+ /// The offset of the lump's information.
+ /// The type of BSP to interpret the file as.
+ /// A object containing information about the lump.
+ private LumpInfo GetLumpInfoAtOffset(int offset, MapType version) {
+ if (bspFile.Length < offset + 16) {
+ return new LumpInfo();
+ }
+ byte[] input;
+ using (FileStream stream = new FileStream(bspFile.FullName, FileMode.Open, FileAccess.Read)) {
+ BinaryReader binaryReader = new BinaryReader(stream);
+ stream.Seek(offset, SeekOrigin.Begin);
+ input = binaryReader.ReadBytes(16);
+ binaryReader.Close();
+ }
+ if (version == MapType.TacticalInterventionEncrypted) {
+ input = XorWithKeyStartingAtIndex(input, offset);
+ }
+
+ int lumpOffset = 0;
+ int lumpLength = 0;
+ int lumpVersion = 0;
+ int lumpIdent = 0;
+ if (version == MapType.L4D2) {
+ lumpVersion = BitConverter.ToInt32(input, 0);
+ lumpOffset = BitConverter.ToInt32(input, 4);
+ lumpLength = BitConverter.ToInt32(input, 8);
+ lumpIdent = BitConverter.ToInt32(input, 12);
+ // TODO: This is awful. Let's rework the enum to have internal ways to check engine forks.
+ } else if (version == MapType.Source17 ||
+ version == MapType.Source18 ||
+ version == MapType.Source19 ||
+ version == MapType.Source20 ||
+ version == MapType.Source21 ||
+ version == MapType.Source22 ||
+ version == MapType.Source23 ||
+ version == MapType.Source27 ||
+ version == MapType.Vindictus ||
+ version == MapType.DMoMaM ||
+ version == MapType.TacticalInterventionEncrypted) {
+ lumpOffset = BitConverter.ToInt32(input, 0);
+ lumpLength = BitConverter.ToInt32(input, 4);
+ lumpVersion = BitConverter.ToInt32(input, 8);
+ lumpIdent = BitConverter.ToInt32(input, 12);
+ } else if (version == MapType.CoD2) {
+ lumpLength = BitConverter.ToInt32(input, 0);
+ lumpOffset = BitConverter.ToInt32(input, 4);
+ } else {
+ lumpOffset = BitConverter.ToInt32(input, 0);
+ lumpLength = BitConverter.ToInt32(input, 4);
+ }
+
+ /*if (bigEndian) {
+ byte[] bytes = BitConverter.GetBytes(lumpLength);
+ Array.Reverse(bytes);
+ lumpLength = BitConverter.ToInt32(bytes, 0);
+ bytes = BitConverter.GetBytes(lumpOffset);
+ Array.Reverse(bytes);
+ lumpOffset = BitConverter.ToInt32(bytes, 0);
+ }*/
+
+ return new LumpInfo() {
+ offset = lumpOffset,
+ length = lumpLength,
+ version = lumpVersion,
+ ident = lumpIdent
+ };
+ }
+
+ ///
+ /// Reads the lump in the BSP file using the information in "".
+ ///
+ /// The object representing the lump's information.
+ /// A byte array containing the data from the file for the lump at the offset with the length from "".
+ public byte[] ReadLump(LumpInfo info) {
+ if (info.length == 0) { return new byte[0]; }
+ byte[] output;
+
+ if (info.lumpFile != null) {
+ using (FileStream fs = new FileStream(info.lumpFile.FullName, FileMode.Open, FileAccess.Read)) {
+ BinaryReader br = new BinaryReader(fs);
+ fs.Seek(info.offset, SeekOrigin.Begin);
+ output = br.ReadBytes(info.length);
+ br.Close();
+ return output;
+ }
+ }
+
+ using (FileStream stream = new FileStream(bspFile.FullName, FileMode.Open, FileAccess.Read)) {
+ BinaryReader binaryReader = new BinaryReader(stream);
+ stream.Seek(info.offset, SeekOrigin.Begin);
+ output = binaryReader.ReadBytes(info.length);
+ binaryReader.Close();
+ }
+
+ if (key.Length != 0) {
+ output = XorWithKeyStartingAtIndex(output, info.offset);
+ }
+
+ return output;
}
///
/// Loads any lump files associated with the BSP.
///
private void LoadLumpFiles() {
- lumpFiles = new Dictionary();
+ lumpFiles = new Dictionary();
// Scan the BSP's directory for lump files
DirectoryInfo dir = bspFile.Directory;
List files = dir.GetFiles(bspFile.Name.Substring(0, bspFile.Name.Length - 4) + "_?_*.lmp").ToList();
@@ -127,87 +237,27 @@ namespace LibBSP {
});
// Read the files in order. The last file in the list for a specific lump will replace that lump.
foreach (FileInfo file in files) {
- FileStream fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
- BinaryReader br = new BinaryReader(fs);
- fs.Seek(4, SeekOrigin.Begin);
- int lumpIndex = BitConverter.ToInt32(br.ReadBytes(4), 0);
- lumpFiles[lumpIndex] = file;
- br.Dispose();
- fs.Dispose();
+ using (FileStream fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read)) {
+ BinaryReader br = new BinaryReader(fs);
+ fs.Seek(0, SeekOrigin.Begin);
+ byte[] input = br.ReadBytes(20);
+ int offset = BitConverter.ToInt32(input, 0);
+ int lumpIndex = BitConverter.ToInt32(input, 4);
+ int version = BitConverter.ToInt32(input, 8);
+ int length = BitConverter.ToInt32(input, 12);
+ lumpFiles[lumpIndex] = new LumpInfo() {
+ offset = offset,
+ version = version,
+ length = length,
+ lumpFile = file
+ };
+ br.Close();
+ }
}
}
///
- /// Returns the data contained in the lump file for the lump .
- ///
- /// Index of the lump to get data from the lump file.
- /// The lump data in the lump file.
- private byte[] ReadLumpFile(int index) {
- FileInfo file = lumpFiles[index];
- FileStream fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
- BinaryReader br = new BinaryReader(fs);
- fs.Seek(0, SeekOrigin.Begin);
- byte[] input = br.ReadBytes(20);
- int offset = BitConverter.ToInt32(input, 0);
- int length = BitConverter.ToInt32(input, 12);
- fs.Seek(offset, SeekOrigin.Begin);
- byte[] output = br.ReadBytes(length);
- br.Dispose();
- fs.Dispose();
- return output;
- }
-
- ///
- /// Returns the lump referenced by the offset/length pair at the specified ,
- /// read as two Int32.
- ///
- /// The byte offset for the offset/length pair.
- /// The version of BSP this is.
- /// Array of bytes read from the BSP file.
- private byte[] ReadLumpFromOffsetLengthPairAtOffset(int offset, MapType version) {
- stream.Seek(offset, SeekOrigin.Begin);
- byte[] input = binaryReader.ReadBytes(12);
- if (version == MapType.TacticalInterventionEncrypted) {
- input = XorWithKeyStartingAtIndex(input, offset);
- }
- int lumpOffset;
- int lumpLength;
- if (version == MapType.L4D2) {
- lumpOffset = BitConverter.ToInt32(input, 4);
- lumpLength = BitConverter.ToInt32(input, 8);
- } else {
- lumpOffset = BitConverter.ToInt32(input, 0);
- lumpLength = BitConverter.ToInt32(input, 4);
- }
- /*if (bigEndian) {
- byte[] bytes = BitConverter.GetBytes(lumpLength);
- Array.Reverse(bytes);
- lumpLength = BitConverter.ToInt32(bytes, 0);
- bytes = BitConverter.GetBytes(lumpOffset);
- Array.Reverse(bytes);
- lumpOffset = BitConverter.ToInt32(bytes, 0);
- }*/
- return ReadLump(lumpOffset, lumpLength, version);
- }
-
- ///
- /// Reads the lump bytes long at in the file.
- ///
- /// Offset to start reading from.
- /// Length of the lump to read.
- /// The version of BSP this is.
- /// Array of bytes read from the BSP file.
- public byte[] ReadLump(int offset, int length, MapType version) {
- stream.Seek(offset, SeekOrigin.Begin);
- byte[] input = binaryReader.ReadBytes(length);
- if (version == MapType.TacticalInterventionEncrypted) {
- input = XorWithKeyStartingAtIndex(input, offset);
- }
- return input;
- }
-
- ///
- /// Xors the byte array with the localls stored key byte array, starting at a certain in the key.
+ /// Xors the byte array with the locally stored key byte array, starting at a certain in the key.
///
/// The byte array to Xor.
/// The index in the key byte array to start reading from.
@@ -250,213 +300,216 @@ namespace LibBSP {
/// The of this BSP, if it could not be determined.
private MapType GetVersion(bool bigEndian) {
MapType current = MapType.Undefined;
- stream.Seek(0, SeekOrigin.Begin);
- int data = binaryReader.ReadInt32();
- if (bigEndian) {
- byte[] bytes = BitConverter.GetBytes(data);
- Array.Reverse(bytes);
- data = BitConverter.ToInt32(bytes, 0);
- }
- if (data == 1347633737) {
- // 1347633737 reads in ASCII as "IBSP"
- // Versions: CoD, CoD2, CoD4, Quake 2, Daikatana, Quake 3 (RtCW), Soldier of Fortune
- data = binaryReader.ReadInt32();
+ using (FileStream stream = new FileStream(bspFile.FullName, FileMode.Open, FileAccess.Read)) {
+ BinaryReader binaryReader = new BinaryReader(stream);
+ stream.Seek(0, SeekOrigin.Begin);
+ int data = binaryReader.ReadInt32();
if (bigEndian) {
byte[] bytes = BitConverter.GetBytes(data);
Array.Reverse(bytes);
data = BitConverter.ToInt32(bytes, 0);
}
- switch (data) {
- case 4: {
- current = MapType.CoD2;
- break;
+ if (data == 1347633737) {
+ // 1347633737 reads in ASCII as "IBSP"
+ // Versions: CoD, CoD2, CoD4, Quake 2, Daikatana, Quake 3 (RtCW), Soldier of Fortune
+ data = binaryReader.ReadInt32();
+ if (bigEndian) {
+ byte[] bytes = BitConverter.GetBytes(data);
+ Array.Reverse(bytes);
+ data = BitConverter.ToInt32(bytes, 0);
}
- case 22: {
- current = MapType.CoD4;
- break;
- }
- case 38: {
- current = MapType.Quake2;
- break;
- }
- case 41: {
- current = MapType.Daikatana;
- break;
- }
- case 46: {
- current = MapType.Quake3;
- // This version number is both Quake 3 and Soldier of Fortune. Find out the length of the
- // header, based on offsets.
- for (int i = 0; i < 17; i++) {
- stream.Seek((i + 1) * 8, SeekOrigin.Begin);
- int temp = binaryReader.ReadInt32();
- if (bigEndian) {
- byte[] bytes = BitConverter.GetBytes(temp);
- Array.Reverse(bytes);
- temp = BitConverter.ToInt32(bytes, 0);
- }
- if (temp == 184) {
- current = MapType.SoF;
- break;
- } else {
- if (temp == 144) {
+ switch (data) {
+ case 4: {
+ current = MapType.CoD2;
+ break;
+ }
+ case 22: {
+ current = MapType.CoD4;
+ break;
+ }
+ case 38: {
+ current = MapType.Quake2;
+ break;
+ }
+ case 41: {
+ current = MapType.Daikatana;
+ break;
+ }
+ case 46: {
+ current = MapType.Quake3;
+ // This version number is both Quake 3 and Soldier of Fortune. Find out the length of the
+ // header, based on offsets.
+ for (int i = 0; i < 17; i++) {
+ stream.Seek((i + 1) * 8, SeekOrigin.Begin);
+ int temp = binaryReader.ReadInt32();
+ if (bigEndian) {
+ byte[] bytes = BitConverter.GetBytes(temp);
+ Array.Reverse(bytes);
+ temp = BitConverter.ToInt32(bytes, 0);
+ }
+ if (temp == 184) {
+ current = MapType.SoF;
break;
+ } else {
+ if (temp == 144) {
+ break;
+ }
}
}
+ break;
+ }
+ case 47: {
+ current = MapType.Quake3;
+ break;
+ }
+ case 59: {
+ current = MapType.CoD;
+ break;
}
- break;
}
- case 47: {
- current = MapType.Quake3;
- break;
- }
- case 59: {
- current = MapType.CoD;
- break;
- }
- }
- } else {
- if (data == 892416050) {
- // 892416050 reads in ASCII as "2015," the game studio which developed MoHAA
- current = MapType.MOHAA;
} else {
- if (data == 1095516485) {
- // 1095516485 reads in ASCII as "EALA," the ones who developed MoHAA Spearhead and Breakthrough
+ if (data == 892416050) {
+ // 892416050 reads in ASCII as "2015," the game studio which developed MoHAA
current = MapType.MOHAA;
} else {
- if (data == 1347633750) {
- // 1347633750 reads in ASCII as "VBSP." Indicates Source engine.
- // Some source games handle this as 2 shorts.
- // TODO: Big endian?
- // Formats: Source 17-23 and 27, DMoMaM, Vindictus
- data = (int)binaryReader.ReadUInt16();
- switch (data) {
- case 17: {
- current = MapType.Source17;
- break;
- }
- case 18: {
- current = MapType.Source18;
- break;
- }
- case 19: {
- current = MapType.Source19;
- break;
- }
- case 20: {
- int version2 = (int)binaryReader.ReadUInt16();
- if (version2 == 4) {
- // TODO: This doesn't necessarily mean the whole map should be read as DMoMaM.
- current = MapType.DMoMaM;
- } else {
- // TODO: Vindictus? Before I was determining these by looking at the Game Lump data, is there a better way?
- current = MapType.Source20;
- }
- break;
- }
- case 21: {
- current = MapType.Source21;
- // Hack to determine if this is a L4D2 map. Read what would normally be the offset of
- // a lump. If it is less than the header length it's probably not an offset, indicating L4D2.
- stream.Seek(8, SeekOrigin.Begin);
- int test = binaryReader.ReadInt32();
- if (bigEndian) {
- byte[] bytes = BitConverter.GetBytes(test);
- Array.Reverse(bytes);
- test = BitConverter.ToInt32(bytes, 0);
- }
- if (test < 1032) {
- current = MapType.L4D2;
- }
- break;
- }
- case 22: {
- current = MapType.Source22;
- break;
- }
- case 23: {
- current = MapType.Source23;
- break;
- }
- case 27: {
- current = MapType.Source27;
- break;
- }
- }
+ if (data == 1095516485) {
+ // 1095516485 reads in ASCII as "EALA," the ones who developed MoHAA Spearhead and Breakthrough
+ current = MapType.MOHAA;
} else {
- if (data == 1347633746) {
- // Reads in ASCII as "RBSP". Raven software's modification of Q3BSP, or Ritual's modification of Q2.
- // Formats: Raven, SiN
- current = MapType.Raven;
- for (int i = 0; i < 17; i++) {
- // Find out where the first lump starts, based on offsets.
- stream.Seek((i + 1) * 8, SeekOrigin.Begin);
- int temp = binaryReader.ReadInt32();
- if (bigEndian) {
- byte[] bytes = BitConverter.GetBytes(temp);
- Array.Reverse(bytes);
- temp = BitConverter.ToInt32(bytes, 0);
- }
- if (temp == 168) {
- current = MapType.SiN;
+ if (data == 1347633750) {
+ // 1347633750 reads in ASCII as "VBSP." Indicates Source engine.
+ // Some source games handle this as 2 shorts.
+ // TODO: Big endian?
+ // Formats: Source 17-23 and 27, DMoMaM, Vindictus
+ data = (int)binaryReader.ReadUInt16();
+ switch (data) {
+ case 17: {
+ current = MapType.Source17;
break;
- } else {
- if (temp == 152) {
- break;
+ }
+ case 18: {
+ current = MapType.Source18;
+ break;
+ }
+ case 19: {
+ current = MapType.Source19;
+ break;
+ }
+ case 20: {
+ int version2 = (int)binaryReader.ReadUInt16();
+ if (version2 == 4) {
+ // TODO: This doesn't necessarily mean the whole map should be read as DMoMaM.
+ current = MapType.DMoMaM;
+ } else {
+ // TODO: Vindictus? Before I was determining these by looking at the Game Lump data, is there a better way?
+ current = MapType.Source20;
}
+ break;
+ }
+ case 21: {
+ current = MapType.Source21;
+ // Hack to determine if this is a L4D2 map. Read what would normally be the offset of
+ // a lump. If it is less than the header length it's probably not an offset, indicating L4D2.
+ stream.Seek(8, SeekOrigin.Begin);
+ int test = binaryReader.ReadInt32();
+ if (bigEndian) {
+ byte[] bytes = BitConverter.GetBytes(test);
+ Array.Reverse(bytes);
+ test = BitConverter.ToInt32(bytes, 0);
+ }
+ if (test < 1032) {
+ current = MapType.L4D2;
+ }
+ break;
+ }
+ case 22: {
+ current = MapType.Source22;
+ break;
+ }
+ case 23: {
+ current = MapType.Source23;
+ break;
+ }
+ case 27: {
+ current = MapType.Source27;
+ break;
}
}
} else {
- if (data == 556942917) {
- // "EF2!"
- current = MapType.STEF2;
- } else {
- if (data == 1263223110) {
- // "FAKK"
- // Formats: STEF2 demo, Heavy Metal FAKK2 (American McGee's Alice)
- data = binaryReader.ReadInt32();
+ if (data == 1347633746) {
+ // Reads in ASCII as "RBSP". Raven software's modification of Q3BSP, or Ritual's modification of Q2.
+ // Formats: Raven, SiN
+ current = MapType.Raven;
+ for (int i = 0; i < 17; i++) {
+ // Find out where the first lump starts, based on offsets.
+ stream.Seek((i + 1) * 8, SeekOrigin.Begin);
+ int temp = binaryReader.ReadInt32();
if (bigEndian) {
- byte[] bytes = BitConverter.GetBytes(data);
+ byte[] bytes = BitConverter.GetBytes(temp);
Array.Reverse(bytes);
- data = BitConverter.ToInt32(bytes, 0);
+ temp = BitConverter.ToInt32(bytes, 0);
}
- switch (data) {
- case 19: {
- current = MapType.STEF2Demo;
- break;
- }
- case 12:
- case 42: {// American McGee's Alice
- current = MapType.FAKK;
+ if (temp == 168) {
+ current = MapType.SiN;
+ break;
+ } else {
+ if (temp == 152) {
break;
}
}
+ }
+ } else {
+ if (data == 556942917) {
+ // "EF2!"
+ current = MapType.STEF2;
} else {
- switch (data) {
- // Various numbers not representing a string
- // Formats: HL1, Quake, Nightfire, or perhaps Tactical Intervention's encrypted format
- case 29:
- case 30: {
- current = MapType.Quake;
- break;
+ if (data == 1263223110) {
+ // "FAKK"
+ // Formats: STEF2 demo, Heavy Metal FAKK2 (American McGee's Alice)
+ data = binaryReader.ReadInt32();
+ if (bigEndian) {
+ byte[] bytes = BitConverter.GetBytes(data);
+ Array.Reverse(bytes);
+ data = BitConverter.ToInt32(bytes, 0);
}
- case 42: {
- current = MapType.Nightfire;
- break;
- }
- default: {
- // Hack to get Tactical Intervention's encryption key. At offset 384, there are two unused lumps whose
- // values in the header are always 0s. Grab these 32 bytes (256 bits) and see if they match an expected value.
- stream.Seek(384, SeekOrigin.Begin);
- key = binaryReader.ReadBytes(32);
- stream.Seek(0, SeekOrigin.Begin);
- data = BitConverter.ToInt32(XorWithKeyStartingAtIndex(binaryReader.ReadBytes(4)), 0);
- if (data == 1347633750) {
- current = MapType.TacticalInterventionEncrypted;
- } else {
- current = MapType.Undefined;
+ switch (data) {
+ case 19: {
+ current = MapType.STEF2Demo;
+ break;
+ }
+ case 12:
+ case 42: {// American McGee's Alice
+ current = MapType.FAKK;
+ break;
+ }
+ }
+ } else {
+ switch (data) {
+ // Various numbers not representing a string
+ // Formats: HL1, Quake, Nightfire, or perhaps Tactical Intervention's encrypted format
+ case 29:
+ case 30: {
+ current = MapType.Quake;
+ break;
+ }
+ case 42: {
+ current = MapType.Nightfire;
+ break;
+ }
+ default: {
+ // Hack to get Tactical Intervention's encryption key. At offset 384, there are two unused lumps whose
+ // values in the header are always 0s. Grab these 32 bytes (256 bits) and see if they match an expected value.
+ stream.Seek(384, SeekOrigin.Begin);
+ key = binaryReader.ReadBytes(32);
+ stream.Seek(0, SeekOrigin.Begin);
+ data = BitConverter.ToInt32(XorWithKeyStartingAtIndex(binaryReader.ReadBytes(4)), 0);
+ if (data == 1347633750) {
+ current = MapType.TacticalInterventionEncrypted;
+ } else {
+ current = MapType.Undefined;
+ }
+ break;
}
- break;
}
}
}
@@ -465,15 +518,9 @@ namespace LibBSP {
}
}
}
+ binaryReader.Close();
}
return current;
}
-
- ///
- /// Disposes of the FileStream and releases the handle to the File.
- ///
- public void Close() {
- stream.Dispose();
- }
}
}