mirror of
https://github.com/celisej567/LibBSP.git
synced 2026-01-05 10:10:12 +03:00
Refactor of BSP and BSPReader to enable lump structures to know what version of lump they represent.
As a result, fix reading v2 faces lump from Vindictus.
This commit is contained in:
@@ -232,12 +232,13 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="Plane"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was null.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
/// <remarks>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.</remarks>
|
||||
public static List<Plane> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<Plane> LumpFactory(byte[] data, MapType type, int version = 0) {
|
||||
if (data == null) {
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
@@ -71,12 +71,13 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>The resulting <see cref="UIVertex"/> object.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was null.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
/// <remarks><see cref="UIVertex"/> 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.</remarks>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="UIVertex"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
/// <remarks>This function goes here since I can't put it into Unity's <c>UIVertex</c> class, and so I can't
|
||||
/// depend on having a constructor taking a byte array.</remarks>
|
||||
public static List<UIVertex> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<UIVertex> 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;
|
||||
}
|
||||
|
||||
@@ -54,19 +54,20 @@ namespace LibBSP {
|
||||
/// <summary>
|
||||
/// Struct containing basic information for a lump in a BSP file.
|
||||
/// </summary>
|
||||
public struct LumpInfo {
|
||||
public class LumpInfo {
|
||||
public int ident;
|
||||
public int flags;
|
||||
public int version;
|
||||
public int offset;
|
||||
public int length;
|
||||
public FileInfo lumpFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds data for any and all BSP formats. Any unused lumps in a given format
|
||||
/// will be left as null.
|
||||
/// </summary>
|
||||
public class BSP {
|
||||
public class BSP : Dictionary<int, LumpInfo> {
|
||||
|
||||
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 {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="LumpInfo"/> object associated with the lump with index "<paramref name="index"/>".
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the lump to get information for.</param>
|
||||
/// <returns>A <see cref="LumpInfo"/> object containing information about lump "<paramref name="index"/>".</returns>
|
||||
public LumpInfo this[int index] {
|
||||
get {
|
||||
if (!ContainsKey(index)) {
|
||||
base[index] = reader.GetLumpInfo(index, version);
|
||||
}
|
||||
return base[index];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="BSP"/> instance pointing to the file at <paramref name="filePath"/>. The
|
||||
/// <c>List</c>s in this class will be read and populated when accessed through their properties.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The path to the .BSP file.</param>
|
||||
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 {
|
||||
/// <c>List</c>s in this class will be read and populated when accessed through their properties.
|
||||
/// </summary>
|
||||
/// <param name="file">A reference to the .BSP file.</param>
|
||||
public BSP(FileInfo file) {
|
||||
public BSP(FileInfo file) : base(16) {
|
||||
reader = new BSPReader(file);
|
||||
this.filePath = file.FullName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells the <see cref="BSPReader"/> object to release file handles for the BSP file.
|
||||
/// Gets the number of lumps in a given BSP version.
|
||||
/// </summary>
|
||||
public void Close() {
|
||||
reader.Close();
|
||||
/// <param name="version">The version to get the number of lumps for.</param>
|
||||
/// <returns>The number of lumps used by a BSP of version <paramref name="version"/>.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -17,9 +17,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="Brush"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
public static List<Brush> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<Brush> 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;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="BrushSide"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
public static List<BrushSide> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<BrushSide> 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;
|
||||
}
|
||||
|
||||
@@ -25,9 +25,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="Cubemap"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
public static List<Cubemap> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<Cubemap> 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;
|
||||
|
||||
@@ -28,9 +28,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="DisplacementInfo"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
public static List<DisplacementInfo> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<DisplacementInfo> 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;
|
||||
|
||||
@@ -26,8 +26,9 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <see cref="DisplacementVertices"/> object.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,9 +15,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="Edge"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was null.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
public static List<Edge> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<Edge> 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;
|
||||
}
|
||||
|
||||
@@ -48,9 +48,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="Face"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
public static List<Face> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<Face> 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;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="Leaf"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
public static List<Leaf> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<Leaf> 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;
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data">Array of <c>byte</c>s to parse.</param>
|
||||
/// <param name="type">Format identifier.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,9 +46,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A new <see cref="GameLump"/> object.</returns>
|
||||
/// <remarks>This is only here for consistency with the other lump structures.</remarks>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace LibBSP {
|
||||
/// <param name="type">Format identifier.</param>
|
||||
/// <param name="version">Version of static prop lump this is.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
public StaticProps(byte[] data, MapType type, int version) {
|
||||
public StaticProps(byte[] data, MapType type, int version = 0) {
|
||||
if (data == null) {
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
@@ -13,9 +13,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +28,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="Model"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
public static List<Model> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<Model> 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;
|
||||
|
||||
@@ -17,9 +17,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="Node"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
public static List<Node> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<Node> 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;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace LibBSP {
|
||||
/// <param name="version">The version of static prop lump this object is a member of.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of the Static Prop lump.</param>
|
||||
/// <returns>A <see cref="StaticProps"/> object.</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,9 +36,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <see cref="Textures"/> object.</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -30,8 +30,9 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="TextureData"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
public static List<TextureData> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<TextureData> 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;
|
||||
}
|
||||
|
||||
@@ -44,9 +44,10 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>byte</c> array to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
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 {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>A <c>List</c> of <see cref="TextureInfo"/> objects.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="data"/> was null.</exception>
|
||||
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
|
||||
public static List<TextureInfo> LumpFactory(byte[] data, MapType type) {
|
||||
public static List<TextureInfo> 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;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,9 @@ namespace LibBSP {
|
||||
/// Initializes a new instance of an <see cref="Entity"/>, parsing the given <c>byte</c> array into an <see cref="Entity"/> structure.
|
||||
/// </summary>
|
||||
/// <param name="data">Array to parse.</param>
|
||||
public Entity(byte[] data, MapType type) : this(Encoding.ASCII.GetString(data).Split('\n')) { }
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
public Entity(byte[] data, MapType type, int version = 0) : this(Encoding.ASCII.GetString(data).Split('\n')) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an <see cref="Entity"/> with the given classname.
|
||||
@@ -521,8 +523,9 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data">The data to parse.</param>
|
||||
/// <param name="type">The map type.</param>
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
/// <returns>An <see cref="Entities"/> object, which is a <c>List</c> of <see cref="Entity"/>s.</returns>
|
||||
public static Entities LumpFactory(byte[] data, MapType type) {
|
||||
public static Entities LumpFactory(byte[] data, MapType type, int version = 0) {
|
||||
return new Entities(data, type);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
/// <param name="data"><c>Byte</c>s read from a file.</param>
|
||||
/// <param name="type">The <see cref="MapType"/> of the source map.</param>
|
||||
public Entities(byte[] data, MapType type) : base() {
|
||||
/// <param name="version">The version of this lump.</param>
|
||||
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;
|
||||
|
||||
@@ -9,9 +9,7 @@ namespace LibBSP {
|
||||
/// </summary>
|
||||
public class BSPReader {
|
||||
private FileInfo bspFile;
|
||||
private FileStream stream;
|
||||
private BinaryReader binaryReader;
|
||||
private Dictionary<int, FileInfo> lumpFiles = null;
|
||||
private Dictionary<int, LumpInfo> 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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads this lump in the map.
|
||||
/// Gets the information for lump "<paramref name="index"/>" for this BSP file when reading it as "<paramref name="version"/>".
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the lump to get.</param>
|
||||
/// <param name="version">The version of BSP this is.</param>
|
||||
/// <returns>Array of bytes read from the BSP file.</returns>
|
||||
public byte[] ReadLumpNum(int index, MapType version) {
|
||||
/// <param name="index">The numerical index of this lump.</param>
|
||||
/// <param name="version">The type of BSP to interpret the file as.</param>
|
||||
/// <returns>A <see cref="LumpInfo"/> object containing information about the lump.</returns>
|
||||
/// <exception cref="IndexOutOfRandeException">"<paramref name="index"/>" is less than zero, or greater than the number of lumps allowed by "<paramref name="version"/>".</exception>
|
||||
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];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the lump information at offset "<paramref name="offset"/>" for this BSP file when reading it as "<paramref name="version"/>".
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset of the lump's information.</param>
|
||||
/// <param name="version">The type of BSP to interpret the file as.</param>
|
||||
/// <returns>A <see cref="LumpInfo"/> object containing information about the lump.</returns>
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the lump in the BSP file using the information in "<paramref name="info"/>".
|
||||
/// </summary>
|
||||
/// <param name="info">The <see cref="LumpInfo"/> object representing the lump's information.</param>
|
||||
/// <returns>A <c>byte</c> array containing the data from the file for the lump at the offset with the length from "<paramref name="info"/>".</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads any lump files associated with the BSP.
|
||||
/// </summary>
|
||||
private void LoadLumpFiles() {
|
||||
lumpFiles = new Dictionary<int, FileInfo>();
|
||||
lumpFiles = new Dictionary<int, LumpInfo>();
|
||||
// Scan the BSP's directory for lump files
|
||||
DirectoryInfo dir = bspFile.Directory;
|
||||
List<FileInfo> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the data contained in the lump file for the lump <paramref name="index"/>.
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the lump to get data from the lump file.</param>
|
||||
/// <returns>The lump data in the lump file.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the lump referenced by the offset/length pair at the specified <paramref name="offset"/>,
|
||||
/// read as two Int32.
|
||||
/// </summary>
|
||||
/// <param name="offset">The byte offset for the offset/length pair.</param>
|
||||
/// <param name="version">The version of BSP this is.</param>
|
||||
/// <returns>Array of bytes read from the BSP file.</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the lump <paramref name="length"/> bytes long at <paramref name="offset"/> in the file.
|
||||
/// </summary>
|
||||
/// <param name="offset">Offset to start reading from.</param>
|
||||
/// <param name="length">Length of the lump to read.</param>
|
||||
/// <param name="version">The version of BSP this is.</param>
|
||||
/// <returns>Array of bytes read from the BSP file.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xors the <paramref name="data"/> <c>byte</c> array with the localls stored key <c>byte</c> array, starting at a certain <paramref name="index"/> in the key.
|
||||
/// Xors the <paramref name="data"/> <c>byte</c> array with the locally stored key <c>byte</c> array, starting at a certain <paramref name="index"/> in the key.
|
||||
/// </summary>
|
||||
/// <param name="data">The byte array to Xor.</param>
|
||||
/// <param name="index">The index in the key byte array to start reading from.</param>
|
||||
@@ -250,213 +300,216 @@ namespace LibBSP {
|
||||
/// <returns>The <see cref="MapType"/> of this BSP, <see cref="MapType.Undefined"/> if it could not be determined.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of the <c>FileStream</c> and releases the handle to the File.
|
||||
/// </summary>
|
||||
public void Close() {
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user