diff --git a/LibBSP/LibBSP.csproj b/LibBSP/LibBSP.csproj
index 282ac8f..747a009 100644
--- a/LibBSP/LibBSP.csproj
+++ b/LibBSP/LibBSP.csproj
@@ -49,6 +49,9 @@
+
+
+
diff --git a/LibBSP/Source/Extensions/ColorExtensions.cs b/LibBSP/Source/Extensions/ColorExtensions.cs
index 3ed74f6..912a287 100644
--- a/LibBSP/Source/Extensions/ColorExtensions.cs
+++ b/LibBSP/Source/Extensions/ColorExtensions.cs
@@ -30,5 +30,26 @@ namespace LibBSP {
#endif
}
+ ///
+ /// Gets this Color as R8G8B8A8.
+ ///
+ /// This Color.
+ /// A byte array with four members, RGBA.
+ public static byte[] GetBytes(this Color color) {
+ byte[] bytes = new byte[4];
+#if UNITY
+ bytes[0] = color.r;
+ bytes[1] = color.g;
+ bytes[2] = color.b;
+ bytes[3] = color.a;
+#else
+ bytes[0] = color.R;
+ bytes[1] = color.G;
+ bytes[2] = color.B;
+ bytes[3] = color.A;
+#endif
+ return bytes;
+ }
+
}
}
diff --git a/LibBSP/Source/Extensions/PlaneExtensions.cs b/LibBSP/Source/Extensions/PlaneExtensions.cs
index 5a1dc28..8d5f940 100644
--- a/LibBSP/Source/Extensions/PlaneExtensions.cs
+++ b/LibBSP/Source/Extensions/PlaneExtensions.cs
@@ -18,6 +18,18 @@ namespace LibBSP {
///
public static class PlaneExtensions {
+ ///
+ /// Array of base texture axes. When referenced properly, provides a good default texture axis for any given plane.
+ ///
+ public static readonly Vector3d[] baseAxes = new Vector3d[] {
+ new Vector3d(0, 0, 1), new Vector3d(1, 0, 0), new Vector3d(0, -1, 0),
+ new Vector3d(0, 0, -1), new Vector3d(1, 0, 0), new Vector3d(0, -1, 0),
+ new Vector3d(1, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, -1),
+ new Vector3d(-1, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, -1),
+ new Vector3d(0, 1, 0), new Vector3d(1, 0, 0), new Vector3d(0, 0, -1),
+ new Vector3d(0, -1, 0), new Vector3d(1, 0, 0), new Vector3d(0, 0, -1)
+ };
+
///
/// Intersects three s at a . Returns NaN for all components if two or more s are parallel.
///
@@ -262,14 +274,32 @@ namespace LibBSP {
/// 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, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
- int structLength = 0;
+ int structLength = GetStructLength(type, version);
+ int numObjects = data.Length / structLength;
+ List lump = new List(numObjects);
+ for (int i = 0; i < numObjects; ++i) {
+ Vector3d normal = new Vector3d(BitConverter.ToSingle(data, structLength * i), BitConverter.ToSingle(data, (structLength * i) + 4), BitConverter.ToSingle(data, (structLength * i) + 8));
+ float distance = BitConverter.ToSingle(data, (structLength * i) + 12);
+ lump.Add(new Plane(normal, distance));
+ }
+ return lump;
+ }
+
+ ///
+ /// Gets this as a byte array to be used in a BSP of type .
+ ///
+ /// This .
+ /// The of BSP this is from.
+ /// The version of the planes lump in the BSP.
+ /// byte array representing this 's components.
+ public static byte[] GetBytes(this Plane p, MapType type, int version = 0) {
+ byte[] bytes = new byte[GetStructLength(type, version)];
switch (type) {
case MapType.Quake:
case MapType.Nightfire:
@@ -289,33 +319,39 @@ namespace LibBSP {
case MapType.Quake2:
case MapType.Daikatana:
case MapType.TacticalInterventionEncrypted: {
- structLength = 20;
+ BitConverter.GetBytes(BestAxis(p)).CopyTo(bytes, 16);
break;
}
- case MapType.STEF2:
- case MapType.MOHAA:
- case MapType.STEF2Demo:
- case MapType.Raven:
- case MapType.Quake3:
- case MapType.FAKK:
- case MapType.CoD:
- case MapType.CoD2:
- case MapType.CoD4: {
- structLength = 16;
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " doesn't use a Plane lump or the lump is unknown.");
+ }
+ p.normal.GetBytes().CopyTo(bytes, 0);
+ BitConverter.GetBytes(p.distance).CopyTo(bytes, 12);
+ return bytes;
+ }
+
+ ///
+ /// Gets the axis this 's normal is closest to (the 's normal
+ /// and the axis have the largest dot product).
+ /// 0 = Positive Z
+ /// 1 = Negative Z
+ /// 2 = Positive X
+ /// 3 = Negative X
+ /// 4 = Positive Y
+ /// 5 = Negative Y
+ ///
+ /// This .
+ /// The best-match axis for this .
+ public static int BestAxis(this Plane p) {
+ int bestaxis = 0;
+ double best = 0; // "Best" dot product so far
+ for (int i = 0; i < 6; ++i) {
+ // For all possible axes, positive and negative
+ double dot = Vector3d.Dot(p.normal, baseAxes[i * 3]);
+ if (dot > best) {
+ best = dot;
+ bestaxis = i;
}
}
- int numObjects = data.Length / structLength;
- List lump = new List(numObjects);
- for (int i = 0; i < numObjects; ++i) {
- Vector3d normal = new Vector3d(BitConverter.ToSingle(data, structLength * i), BitConverter.ToSingle(data, (structLength * i) + 4), BitConverter.ToSingle(data, (structLength * i) + 8));
- float distance = BitConverter.ToSingle(data, (structLength * i) + 12);
- lump.Add(new Plane(normal, distance));
- }
- return lump;
+ return bestaxis;
}
///
@@ -363,5 +399,45 @@ namespace LibBSP {
}
}
}
+
+ public static int GetStructLength(MapType type, int version) {
+ int structLength = 0;
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Nightfire:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.DMoMaM:
+ case MapType.Vindictus:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.TacticalInterventionEncrypted: {
+ structLength = 20;
+ break;
+ }
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ structLength = 16;
+ break;
+ }
+ }
+ return structLength;
+ }
}
}
diff --git a/LibBSP/Source/Extensions/Vector2dExtensions.cs b/LibBSP/Source/Extensions/Vector2dExtensions.cs
new file mode 100644
index 0000000..b6e3ef6
--- /dev/null
+++ b/LibBSP/Source/Extensions/Vector2dExtensions.cs
@@ -0,0 +1,36 @@
+#if UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_3_OR_NEWER
+#define UNITY
+#endif
+
+using System;
+using System.Collections.Generic;
+#if UNITY
+using UnityEngine;
+# endif
+
+namespace LibBSP {
+#if UNITY
+ using Vector2d = Vector2;
+#endif
+
+ ///
+ /// Class containing helper methods for objects.
+ ///
+ public static class Vector2dExtensions {
+
+ ///
+ /// Gets a byte array representing the components of this as floats.
+ ///
+ /// This .
+ /// byte array with the components' bytes.
+ public static byte[] GetBytes(this Vector2d vector) {
+ byte[] ret = new byte[8];
+ byte[] bytes = BitConverter.GetBytes((float)vector.x);
+ bytes.CopyTo(ret, 0);
+ bytes = BitConverter.GetBytes((float)vector.y);
+ bytes.CopyTo(ret, 4);
+ return ret;
+ }
+
+ }
+}
diff --git a/LibBSP/Source/Extensions/Vector3dExtensions.cs b/LibBSP/Source/Extensions/Vector3dExtensions.cs
new file mode 100644
index 0000000..98ac3d2
--- /dev/null
+++ b/LibBSP/Source/Extensions/Vector3dExtensions.cs
@@ -0,0 +1,38 @@
+#if UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_3_OR_NEWER
+#define UNITY
+#endif
+
+using System;
+using System.Collections.Generic;
+#if UNITY
+using UnityEngine;
+#endif
+
+namespace LibBSP {
+#if UNITY
+ using Vector3d = Vector3;
+#endif
+
+ ///
+ /// Class containing helper methods for objects.
+ ///
+ public static class Vector3dExtensions {
+
+ ///
+ /// Gets a byte array representing the components of this as floats.
+ ///
+ /// This .
+ /// byte array with the components' bytes.
+ public static byte[] GetBytes(this Vector3d vector) {
+ byte[] ret = new byte[12];
+ byte[] bytes = BitConverter.GetBytes((float)vector.x);
+ bytes.CopyTo(ret, 0);
+ bytes = BitConverter.GetBytes((float)vector.y);
+ bytes.CopyTo(ret, 4);
+ bytes = BitConverter.GetBytes((float)vector.z);
+ bytes.CopyTo(ret, 8);
+ return ret;
+ }
+
+ }
+}
diff --git a/LibBSP/Source/Extensions/Vector4dExtensions.cs b/LibBSP/Source/Extensions/Vector4dExtensions.cs
new file mode 100644
index 0000000..a54388f
--- /dev/null
+++ b/LibBSP/Source/Extensions/Vector4dExtensions.cs
@@ -0,0 +1,40 @@
+#if UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_3_OR_NEWER
+#define UNITY
+#endif
+
+using System;
+using System.Collections.Generic;
+#if UNITY
+using UnityEngine;
+#endif
+
+namespace LibBSP {
+#if UNITY
+ using Vector4d = Vector4;
+#endif
+
+ ///
+ /// Class containing helper methods for objects.
+ ///
+ public static class Vector4dExtensions {
+
+ ///
+ /// Gets a byte array representing the components of this as floats.
+ ///
+ /// This .
+ /// byte array with the components' bytes.
+ public static byte[] GetBytes(this Vector4d vector) {
+ byte[] ret = new byte[16];
+ byte[] bytes = BitConverter.GetBytes((float)vector.x);
+ bytes.CopyTo(ret, 0);
+ bytes = BitConverter.GetBytes((float)vector.y);
+ bytes.CopyTo(ret, 4);
+ bytes = BitConverter.GetBytes((float)vector.z);
+ bytes.CopyTo(ret, 8);
+ bytes = BitConverter.GetBytes((float)vector.w);
+ bytes.CopyTo(ret, 12);
+ return ret;
+ }
+
+ }
+}
diff --git a/LibBSP/Source/Extensions/VertexExtensions.cs b/LibBSP/Source/Extensions/VertexExtensions.cs
index 7bfdc60..ec7ca9c 100644
--- a/LibBSP/Source/Extensions/VertexExtensions.cs
+++ b/LibBSP/Source/Extensions/VertexExtensions.cs
@@ -15,6 +15,7 @@ namespace LibBSP {
#if UNITY
using Vector2d = Vector2;
using Vector3d = Vector3;
+ using Vector4d = Vector4;
#if !OLDUNITY
using Vertex = UIVertex;
#endif
@@ -122,6 +123,9 @@ namespace LibBSP {
result.color = ColorExtensions.FromArgb(data[27], data[24], data[25], data[26]);
result.uv0 = new Vector2d(BitConverter.ToSingle(data, 28), BitConverter.ToSingle(data, 32));
result.uv1 = new Vector2d(BitConverter.ToSingle(data, 36), BitConverter.ToSingle(data, 40));
+ // Use these fields to store additional unknown information
+ result.tangent = new Vector4d(BitConverter.ToSingle(data, 44), BitConverter.ToSingle(data, 48), BitConverter.ToSingle(data, 52), BitConverter.ToSingle(data, 56));
+ result.uv3 = new Vector2d(BitConverter.ToSingle(data, 60), BitConverter.ToSingle(data, 64));
goto case MapType.Quake;
}
case MapType.MOHAA:
@@ -137,14 +141,20 @@ namespace LibBSP {
case MapType.Raven: {
result.uv0 = new Vector2d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 16));
result.uv1 = new Vector2d(BitConverter.ToSingle(data, 20), BitConverter.ToSingle(data, 24));
+ result.uv2 = new Vector2d(BitConverter.ToSingle(data, 28), BitConverter.ToSingle(data, 32));
+ result.uv3 = new Vector2d(BitConverter.ToSingle(data, 36), BitConverter.ToSingle(data, 40));
result.normal = new Vector3d(BitConverter.ToSingle(data, 52), BitConverter.ToSingle(data, 56), BitConverter.ToSingle(data, 60));
result.color = ColorExtensions.FromArgb(data[67], data[64], data[65], data[66]);
+ // Use for two more float fields and two more colors.
+ // There's actually another field that seems to be color but I've only ever seen it be FFFFFFFF.
+ result.tangent = new Vector4d(BitConverter.ToSingle(data, 44), BitConverter.ToSingle(data, 48), BitConverter.ToSingle(data, 68), BitConverter.ToSingle(data, 72));
goto case MapType.Quake;
}
case MapType.STEF2:
case MapType.STEF2Demo: {
result.uv0 = new Vector2d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 16));
result.uv1 = new Vector2d(BitConverter.ToSingle(data, 20), BitConverter.ToSingle(data, 24));
+ result.uv2 = new Vector2d(BitConverter.ToSingle(data, 28), 0);
result.color = ColorExtensions.FromArgb(data[35], data[32], data[33], data[34]);
result.normal = new Vector3d(BitConverter.ToSingle(data, 36), BitConverter.ToSingle(data, 40), BitConverter.ToSingle(data, 44));
goto case MapType.Quake;
@@ -186,66 +196,13 @@ namespace LibBSP {
/// 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
+ /// This function goes here since it can't be in 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, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
- int structLength = 0;
- switch (type) {
- case MapType.Quake:
- case MapType.Nightfire:
- case MapType.SiN:
- case MapType.SoF:
- 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.TacticalInterventionEncrypted:
- case MapType.Quake2:
- case MapType.Daikatana:
- case MapType.Vindictus:
- case MapType.DMoMaM: {
- structLength = 12;
- break;
- }
- case MapType.CoD: {
- if (version == 0) {
- goto case MapType.Quake3;
- } else if (version == 1) {
- goto case MapType.Quake;
- }
- break;
- }
- case MapType.CoD2: {
- structLength = 68;
- break;
- }
- case MapType.MOHAA:
- case MapType.Quake3:
- case MapType.FAKK: {
- structLength = 44;
- break;
- }
- case MapType.STEF2:
- case MapType.STEF2Demo: {
- structLength = 48;
- break;
- }
- case MapType.Raven: {
- structLength = 80;
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " doesn't use a Vertex lump or the lump is unknown.");
- }
- }
+ int structLength = GetStructLength(type, version);
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
byte[] bytes = new byte[structLength];
@@ -325,5 +282,164 @@ namespace LibBSP {
}
}
+ ///
+ /// Gets the length of the struct for the given and .
+ ///
+ /// The type of BSP to get struct length for.
+ /// Version of the lump.
+ /// The length of the struct for the given of the given .
+ public static int GetStructLength(MapType type, int version) {
+ int structLength = 0;
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Nightfire:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ structLength = 12;
+ break;
+ }
+ case MapType.CoD: {
+ if (version == 0) {
+ goto case MapType.Quake3;
+ } else if (version == 1) {
+ goto case MapType.Quake;
+ }
+ break;
+ }
+ case MapType.CoD2: {
+ structLength = 68;
+ break;
+ }
+ case MapType.MOHAA:
+ case MapType.Quake3:
+ case MapType.FAKK: {
+ structLength = 44;
+ break;
+ }
+ case MapType.STEF2:
+ case MapType.STEF2Demo: {
+ structLength = 48;
+ break;
+ }
+ case MapType.Raven: {
+ structLength = 80;
+ break;
+ }
+ default: {
+ throw new ArgumentException("Map type " + type + " doesn't use a Vertex lump or the lump is unknown.");
+ }
+ }
+ return structLength;
+ }
+
+ ///
+ /// Gets a byte array for this to be inserted into a map of type with lump version .
+ ///
+ /// This .
+ /// The this is from.
+ /// The version of the lump this is from.
+ /// byte array of the data for this .
+ public static byte[] GetBytes(this Vertex v, MapType type, int version) {
+ byte[] bytes = new byte[GetStructLength(type, version)];
+
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Nightfire:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ v.position.GetBytes().CopyTo(bytes, 0);
+ break;
+ }
+ case MapType.CoD: {
+ if (version == 0) {
+ goto case MapType.Quake3;
+ } else if (version == 1) {
+ goto case MapType.Quake;
+ }
+ break;
+ }
+ case MapType.CoD2: {
+ v.normal.GetBytes().CopyTo(bytes, 12);
+ v.color.GetBytes().CopyTo(bytes, 24);
+ v.uv0.GetBytes().CopyTo(bytes, 28);
+ v.uv1.GetBytes().CopyTo(bytes, 36);
+ // Use these fields to store additional unknown information
+ v.tangent.GetBytes().CopyTo(bytes, 44);
+ v.uv3.GetBytes().CopyTo(bytes, 60);
+ break;
+ }
+ case MapType.MOHAA:
+ case MapType.Quake3:
+ case MapType.CoD4:
+ case MapType.FAKK: {
+ v.uv0.GetBytes().CopyTo(bytes, 12);
+ v.uv1.GetBytes().CopyTo(bytes, 20);
+ v.normal.GetBytes().CopyTo(bytes, 28);
+ v.color.GetBytes().CopyTo(bytes, 40);
+ goto case MapType.Quake;
+ }
+ case MapType.Raven: {
+ v.uv0.GetBytes().CopyTo(bytes, 12);
+ v.uv1.GetBytes().CopyTo(bytes, 20);
+ v.uv2.GetBytes().CopyTo(bytes, 28);
+ v.uv3.GetBytes().CopyTo(bytes, 36);
+ BitConverter.GetBytes((float)v.tangent.x).CopyTo(bytes, 44);
+ BitConverter.GetBytes((float)v.tangent.y).CopyTo(bytes, 48);
+ v.normal.GetBytes().CopyTo(bytes, 52);
+ v.color.GetBytes().CopyTo(bytes, 64);
+ BitConverter.GetBytes((float)v.tangent.z).CopyTo(bytes, 68);
+ BitConverter.GetBytes((float)v.tangent.w).CopyTo(bytes, 72);
+ // There's actually another field that seems to be a color but I've only ever seen it be FFFFFFFF.
+ bytes[76] = 255;
+ bytes[77] = 255;
+ bytes[78] = 255;
+ bytes[79] = 255;
+ goto case MapType.Quake;
+ }
+ case MapType.STEF2:
+ case MapType.STEF2Demo: {
+ v.uv0.GetBytes().CopyTo(bytes, 12);
+ v.uv1.GetBytes().CopyTo(bytes, 20);
+ BitConverter.GetBytes(v.uv2.x).CopyTo(bytes, 28);
+ v.color.GetBytes().CopyTo(bytes, 32);
+ v.normal.GetBytes().CopyTo(bytes, 36);
+ goto case MapType.Quake;
+ }
+ default: {
+ bytes = new byte[0];
+ break;
+ }
+ }
+ return bytes;
+ }
+
}
}
diff --git a/LibBSP/Source/Structs/BSP/BSP.cs b/LibBSP/Source/Structs/BSP/BSP.cs
index 848c7bb..9dace54 100644
--- a/LibBSP/Source/Structs/BSP/BSP.cs
+++ b/LibBSP/Source/Structs/BSP/BSP.cs
@@ -606,8 +606,19 @@ namespace LibBSP {
if (_staticProps == null) {
if (gameLump != null && gameLump.ContainsKey(GameLumpType.sprp)) {
LumpInfo info = gameLump[GameLumpType.sprp];
- byte[] thisLump = new byte[info.length];
- Array.Copy(gameLump.rawData, info.offset - gameLump.gameLumpOffset, thisLump, 0, info.length);
+ byte[] thisLump;
+ // GameLump lumps may have their offset specified from either the beginning of the GameLump, or the beginning of the file.
+ if (gameLump.GetLowestLumpOffset() < this[GameLump.GetIndexForLump(version)].offset) {
+ thisLump = reader.ReadLump(new LumpInfo() {
+ ident = info.ident,
+ flags = info.flags,
+ version = info.version,
+ offset = info.offset + this[GameLump.GetIndexForLump(version)].offset,
+ length = info.length
+ });
+ } else {
+ thisLump = reader.ReadLump(info);
+ }
_staticProps = StaticProp.LumpFactory(thisLump, version, info.version);
}
}
@@ -832,9 +843,16 @@ namespace LibBSP {
int count = (int)(countProperty.GetGetMethod().Invoke(o, null));
// Get the lump from this class
- List theLump = targetLump.GetGetMethod().Invoke(this, null) as List;
-
- return theLump.GetRange(index, count);
+ IList theLump = targetLump.GetGetMethod().Invoke(this, null) as IList;
+
+ // Copy items from the lump into a return list.
+ // IList lacks AddRange and this is faster and creates less garbage than any Linq trickery I could come up with.
+ // Passing references to IList out of this method just eats obscene amounts of memory until the system runs out.
+ List ret = new List(count);
+ for (int i = 0; i < count; ++i) {
+ ret.Add(theLump[index + i]);
+ }
+ return ret;
}
}
diff --git a/LibBSP/Source/Structs/BSP/Brush.cs b/LibBSP/Source/Structs/BSP/Brush.cs
index eaa118e..231d4e3 100644
--- a/LibBSP/Source/Structs/BSP/Brush.cs
+++ b/LibBSP/Source/Structs/BSP/Brush.cs
@@ -8,10 +8,270 @@ namespace LibBSP {
///
public struct Brush {
- [Index("brushSides")] public int firstSide { get; private set; }
- [Count("brushSides")] public int numSides { get; private set; }
- public int texture { get; private set; }
- public int contents { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ [Index("brushSides")] public int firstSide {
+ get {
+ switch (type) {
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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:
+ case MapType.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 0);
+ }
+ case MapType.Nightfire:
+ case MapType.STEF2: {
+ return BitConverter.ToInt32(data, 4);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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:
+ case MapType.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ case MapType.Nightfire:
+ case MapType.STEF2: {
+ bytes.CopyTo(data, 4);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("brushSides")] public int numSides {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ return BitConverter.ToInt16(data, 0);
+ }
+ case MapType.STEF2: {
+ return BitConverter.ToInt32(data, 0);
+ }
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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:
+ case MapType.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 4);
+ }
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 8);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ data[0] = bytes[0];
+ data[1] = bytes[1];
+ break;
+ }
+ case MapType.STEF2: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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:
+ case MapType.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 4);
+ break;
+ }
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 8);
+ break;
+ }
+ }
+ }
+ }
+
+ public int texture {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ return BitConverter.ToInt16(data, 2);
+ }
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2: {
+ return BitConverter.ToInt32(data, 8);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ bytes.CopyTo(data, 2);
+ break;
+ }
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2: {
+ bytes.CopyTo(data, 8);
+ break;
+ }
+ }
+ }
+ }
+
+ public int contents {
+ get {
+ switch (type) {
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 0);
+ }
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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:
+ case MapType.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt32(data, 8);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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:
+ case MapType.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ bytes.CopyTo(data, 8);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -20,70 +280,13 @@ namespace LibBSP {
/// 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, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- firstSide = -1;
- numSides = -1;
- texture = -1;
- contents = -1;
- switch (type) {
- case MapType.Quake2:
- case MapType.Daikatana:
- case MapType.SiN:
- case MapType.SoF:
- 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:
- case MapType.TacticalInterventionEncrypted:
- case MapType.DMoMaM: {
- firstSide = BitConverter.ToInt32(data, 0);
- numSides = BitConverter.ToInt32(data, 4);
- contents = BitConverter.ToInt32(data, 8);
- break;
- }
- case MapType.Nightfire: {
- contents = BitConverter.ToInt32(data, 0);
- firstSide = BitConverter.ToInt32(data, 4);
- numSides = BitConverter.ToInt32(data, 8);
- break;
- }
- case MapType.MOHAA:
- case MapType.STEF2Demo:
- case MapType.Raven:
- case MapType.Quake3:
- case MapType.FAKK: {
- firstSide = BitConverter.ToInt32(data, 0);
- numSides = BitConverter.ToInt32(data, 4);
- texture = BitConverter.ToInt32(data, 8);
- break;
- }
- case MapType.STEF2: {
- numSides = BitConverter.ToInt32(data, 0);
- firstSide = BitConverter.ToInt32(data, 4);
- texture = BitConverter.ToInt32(data, 8);
- break;
- }
- case MapType.CoD:
- case MapType.CoD2:
- case MapType.CoD4: {
- numSides = BitConverter.ToInt16(data, 0);
- texture = BitConverter.ToInt16(data, 2);
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the Brush class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -139,8 +342,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new Brush(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/BSP/BrushSide.cs b/LibBSP/Source/Structs/BSP/BrushSide.cs
index 9a3e228..ea6f08f 100644
--- a/LibBSP/Source/Structs/BSP/BrushSide.cs
+++ b/LibBSP/Source/Structs/BSP/BrushSide.cs
@@ -1,23 +1,374 @@
using System;
using System.Collections.Generic;
-using System.Runtime.InteropServices;
namespace LibBSP {
///
/// Holds the data used by the brush side structures of all formats of BSP.
///
- [StructLayout(LayoutKind.Explicit)]
public struct BrushSide {
+
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public int plane {
+ get {
+ switch (type) {
+ case MapType.SiN:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return BitConverter.ToUInt16(data, 0);
+ }
+ case MapType.Raven:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 0);
+ }
+ case MapType.STEF2:
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 4);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.SiN:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ data[0] = bytes[0];
+ data[1] = bytes[1];
+ break;
+ }
+ case MapType.Raven:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ case MapType.STEF2:
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 4);
+ break;
+ }
+ }
+ }
+ }
- // Call of Duty's format sucks. The first field is either a float or an int
- // depending on whether or not it's one of the first six sides in a brush.
- [FieldOffset(0)] public int plane;
- [FieldOffset(0)] public float dist;
- [FieldOffset(4)] public int texture; // -1 is a valid texture index in Quake 2. However it means "unused" there
- [FieldOffset(8)] public int face;
- [FieldOffset(12)] public int displacement; // In theory, this should always point to the side's displacement info. In practice, displacement brushes are removed on compile, leaving only the faces.
- [FieldOffset(16)] public bool bevel;
+ public float dist {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ return BitConverter.ToSingle(data, 0);
+ }
+ default: {
+ return float.NaN;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ }
+ }
+ }
+
+ public int texture {
+ get {
+ switch (type) {
+ case MapType.STEF2: {
+ return BitConverter.ToInt32(data, 0);
+ }
+ case MapType.SiN:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt16(data, 2);
+ }
+ case MapType.Vindictus:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.Raven: {
+ return BitConverter.ToInt32(data, 4);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.STEF2: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ case MapType.SiN:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ data[2] = bytes[0];
+ data[3] = bytes[1];
+ break;
+ }
+ case MapType.Vindictus:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.Raven: {
+ bytes.CopyTo(data, 4);
+ break;
+ }
+ }
+ }
+ }
+
+ public int face {
+ get {
+ switch (type) {
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 0);
+ }
+ case MapType.Raven: {
+ return BitConverter.ToInt32(data, 8);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ case MapType.Raven: {
+ bytes.CopyTo(data, 8);
+ break;
+ }
+ }
+ }
+ }
+
+ public int displacement {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt16(data, 4);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 8);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ data[4] = bytes[0];
+ data[5] = bytes[1];
+ break;
+ }
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 8);
+ break;
+ }
+ }
+ }
+ }
+
+ public bool bevel {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return data[6] > 0;
+ }
+ case MapType.Vindictus: {
+ return data[12] > 0;
+ }
+ default: {
+ return false;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ data[6] = (byte)(value ? 1 : 0);
+ break;
+ }
+ case MapType.Vindictus: {
+ data[12] = (byte)(value ? 1 : 0);
+ break;
+ }
+ }
+ }
+ }
+
+ public bool thin {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return data[7] > 0;
+ }
+ default: {
+ return false;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ data[7] = (byte)(value ? 1 : 0);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -26,80 +377,13 @@ namespace LibBSP {
/// 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, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- plane = -1;
- texture = -1;
- face = -1;
- displacement = -1;
- bevel = false;
- switch (type) {
- case MapType.CoD:
- case MapType.CoD2:
- case MapType.CoD4:
- case MapType.Quake3:
- case MapType.FAKK:
- case MapType.STEF2Demo:
- case MapType.MOHAA: {
- plane = BitConverter.ToInt32(data, 0);
- texture = BitConverter.ToInt32(data, 4);
- break;
- }
- case MapType.STEF2: {
- texture = BitConverter.ToInt32(data, 0);
- plane = BitConverter.ToInt32(data, 4);
- break;
- }
- case MapType.Raven: {
- plane = BitConverter.ToInt32(data, 0);
- texture = BitConverter.ToInt32(data, 4);
- face = BitConverter.ToInt32(data, 8);
- break;
- }
- 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.TacticalInterventionEncrypted:
- case MapType.DMoMaM: {
- this.displacement = BitConverter.ToInt16(data, 4);
- // In little endian format, this byte takes the least significant bits of a short
- // and can therefore be used for all Source engine formats, including Portal 2.
- this.bevel = data[6] > 0;
- goto case MapType.SiN;
- }
- case MapType.SiN:
- case MapType.Quake2:
- case MapType.Daikatana:
- case MapType.SoF: {
- plane = BitConverter.ToUInt16(data, 0);
- texture = BitConverter.ToInt16(data, 2);
- break;
- }
- case MapType.Vindictus: {
- plane = BitConverter.ToInt32(data, 0);
- texture = BitConverter.ToInt32(data, 4);
- displacement = BitConverter.ToInt32(data, 8);
- bevel = data[12] > 0;
- break;
- }
- case MapType.Nightfire: {
- face = BitConverter.ToInt32(data, 0);
- plane = BitConverter.ToInt32(data, 4);
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the BrushSide class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -161,8 +445,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; i++) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new BrushSide(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/BSP/Cubemap.cs b/LibBSP/Source/Structs/BSP/Cubemap.cs
index 2421ce1..55efcee 100644
--- a/LibBSP/Source/Structs/BSP/Cubemap.cs
+++ b/LibBSP/Source/Structs/BSP/Cubemap.cs
@@ -18,8 +18,96 @@ namespace LibBSP {
///
public struct Cubemap {
- public Vector3d origin { get; private set; }
- public int size { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public Vector3d origin {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.L4D2:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ return new Vector3d(BitConverter.ToInt32(data, 0), BitConverter.ToInt32(data, 4), BitConverter.ToInt32(data, 8));
+ }
+ default: {
+ return new Vector3d(float.NaN, float.NaN, float.NaN);
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.L4D2:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ value.GetBytes().CopyTo(data, 0);
+ break;
+ }
+ }
+ }
+ }
+
+ public int size {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.L4D2:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt32(data, 12);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.L4D2:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ bytes.CopyTo(data, 12);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -28,32 +116,13 @@ namespace LibBSP {
/// 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, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- switch (type) {
- 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.TacticalInterventionEncrypted:
- case MapType.L4D2:
- case MapType.Vindictus:
- case MapType.DMoMaM: {
- origin = new Vector3d(BitConverter.ToInt32(data, 0), BitConverter.ToInt32(data, 4), BitConverter.ToInt32(data, 8));
- size = BitConverter.ToInt32(data, 12);
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the SourceCubemap class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -92,8 +161,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new Cubemap(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/BSP/DisplacementInfo.cs b/LibBSP/Source/Structs/BSP/DisplacementInfo.cs
index 9a199c4..f6340a9 100644
--- a/LibBSP/Source/Structs/BSP/DisplacementInfo.cs
+++ b/LibBSP/Source/Structs/BSP/DisplacementInfo.cs
@@ -18,17 +18,175 @@ namespace LibBSP {
///
public struct DisplacementInfo {
- public Vector3d startPosition { get; private set; }
- public int dispVertStart { get; private set; }
- public int dispTriStart { get; private set; }
- public int power { get; private set; }
- public int minTess { get; private set; }
- public float smoothingAngle { get; private set; }
- public int contents { get; private set; }
- public ushort mapFace { get; private set; }
- public int lightmapAlphaStart { get; private set; }
- public int lightmapSamplePositionStart { get; private set; }
- public uint[] allowedVerts { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public Vector3d startPosition {
+ get {
+ return new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
+ }
+ set {
+ value.GetBytes().CopyTo(data, 0);
+ }
+ }
+
+ public int dispVertStart {
+ get {
+ return BitConverter.ToInt32(data, 12);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 12);
+ }
+ }
+
+ public int dispTriStart {
+ get {
+ return BitConverter.ToInt32(data, 16);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 16);
+ }
+ }
+
+ public int power {
+ get {
+ return BitConverter.ToInt32(data, 20);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 20);
+ }
+ }
+
+ public int minTess {
+ get {
+ return BitConverter.ToInt32(data, 24);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 24);
+ }
+ }
+
+ public float smoothingAngle {
+ get {
+ return BitConverter.ToSingle(data, 28);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 28);
+ }
+ }
+
+ public int contents {
+ get {
+ return BitConverter.ToInt32(data, 32);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 32);
+ }
+ }
+
+ public ushort mapFace {
+ get {
+ return BitConverter.ToUInt16(data, 36);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 36);
+ }
+ }
+
+ public int lightmapAlphaStart {
+ get {
+ return BitConverter.ToInt32(data, 38);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 38);
+ }
+ }
+
+ public int lightmapSamplePositionStart {
+ get {
+ return BitConverter.ToInt32(data, 42);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 42);
+ }
+ }
+
+ public uint[] allowedVerts {
+ get {
+ uint[] allowedVerts = new uint[10];
+ int offset = -1;
+ switch (type) {
+ case MapType.Source17:
+ case MapType.Source18:
+ case MapType.Source19:
+ case MapType.Source20:
+ case MapType.Source21:
+ case MapType.Source27:
+ case MapType.L4D2:
+ case MapType.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ offset = 136;
+ break;
+ }
+ case MapType.Source22: {
+ offset = 140;
+ break;
+ }
+ case MapType.Source23: {
+ offset = 144;
+ break;
+ }
+ case MapType.Vindictus: {
+ offset = 192;
+ break;
+ }
+ }
+ if (offset >= 0) {
+ for (int i = 0; i < 10; ++i) {
+ allowedVerts[i] = BitConverter.ToUInt32(data, offset + (i * 4));
+ }
+ }
+ return allowedVerts;
+ }
+ set {
+ if (value.Length != 10) {
+ throw new ArgumentException("AllowedVerts array must have 10 elements.");
+ }
+ int offset = -1;
+ switch (type) {
+ case MapType.Source17:
+ case MapType.Source18:
+ case MapType.Source19:
+ case MapType.Source20:
+ case MapType.Source21:
+ case MapType.Source27:
+ case MapType.L4D2:
+ case MapType.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ offset = 136;
+ break;
+ }
+ case MapType.Source22: {
+ offset = 140;
+ break;
+ }
+ case MapType.Source23: {
+ offset = 144;
+ break;
+ }
+ case MapType.Vindictus: {
+ offset = 192;
+ break;
+ }
+ }
+ if (offset >= 0) {
+ for (int i = 0; i < value.Length; ++i) {
+ BitConverter.GetBytes(value[i]).CopyTo(data, offset + (i * 4));
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -37,55 +195,13 @@ namespace LibBSP {
/// 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, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- startPosition = new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
- dispVertStart = BitConverter.ToInt32(data, 12);
- dispTriStart = BitConverter.ToInt32(data, 16);
- power = BitConverter.ToInt32(data, 20);
- minTess = BitConverter.ToInt32(data, 24);
- smoothingAngle = BitConverter.ToSingle(data, 28);
- contents = BitConverter.ToInt32(data, 32);
- mapFace = BitConverter.ToUInt16(data, 36);
- lightmapAlphaStart = BitConverter.ToInt32(data, 38);
- lightmapSamplePositionStart = BitConverter.ToInt32(data, 42);
- allowedVerts = new uint[10];
- int offset = 0;
- switch (type) {
- case MapType.Source17:
- case MapType.Source18:
- case MapType.Source19:
- case MapType.Source20:
- case MapType.Source21:
- case MapType.Source27:
- case MapType.L4D2:
- case MapType.TacticalInterventionEncrypted:
- case MapType.DMoMaM: {
- offset = 136;
- break;
- }
- case MapType.Source22: {
- offset = 140;
- break;
- }
- case MapType.Source23: {
- offset = 144;
- break;
- }
- case MapType.Vindictus: {
- offset = 192;
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the SourceDispInfo class.");
- }
- }
- for (int i = 0; i < 10; ++i) {
- allowedVerts[i] = BitConverter.ToUInt32(data, offset + (i * 4));
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -133,8 +249,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new DisplacementInfo(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/BSP/DisplacementVertex.cs b/LibBSP/Source/Structs/BSP/DisplacementVertex.cs
index 7fcf213..b51d3dd 100644
--- a/LibBSP/Source/Structs/BSP/DisplacementVertex.cs
+++ b/LibBSP/Source/Structs/BSP/DisplacementVertex.cs
@@ -17,9 +17,45 @@ namespace LibBSP {
///
public struct DisplacementVertex {
- public Vector3d normal { get; private set; } // The normalized vector direction this vertex points from "flat"
- public float dist { get; private set; } // Magnitude of normal, before normalization
- public float alpha { get; private set; } // Alpha value of texture at this vertex
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ ///
+ /// The normalized vector direction this vertex points from "flat".
+ ///
+ public Vector3d normal {
+ get {
+ return new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
+ }
+ set {
+ value.GetBytes().CopyTo(data, 0);
+ }
+ }
+
+ ///
+ /// Magnitude of normal, before normalization.
+ ///
+ public float dist {
+ get {
+ return BitConverter.ToSingle(data, 12);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 12);
+ }
+ }
+
+ ///
+ /// Alpha value of texture at this vertex.
+ ///
+ public float alpha {
+ get {
+ return BitConverter.ToSingle(data, 16);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 16);
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -32,9 +68,9 @@ namespace LibBSP {
if (data == null) {
throw new ArgumentNullException();
}
- normal = new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
- dist = BitConverter.ToSingle(data, 12);
- alpha = BitConverter.ToSingle(data, 16);
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
diff --git a/LibBSP/Source/Structs/BSP/Edge.cs b/LibBSP/Source/Structs/BSP/Edge.cs
index aa838b4..0299f3d 100644
--- a/LibBSP/Source/Structs/BSP/Edge.cs
+++ b/LibBSP/Source/Structs/BSP/Edge.cs
@@ -8,8 +8,129 @@ namespace LibBSP {
///
public struct Edge {
- public int firstVertex { get; private set; }
- public int secondVertex { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public int firstVertex {
+ get {
+ switch (type) {
+ case MapType.Quake:
+ case MapType.SiN:
+ case MapType.Daikatana:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Quake2:
+ case MapType.SoF: {
+ return BitConverter.ToUInt16(data, 0);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 0);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake:
+ case MapType.SiN:
+ case MapType.Daikatana:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Quake2:
+ case MapType.SoF: {
+ data[0] = bytes[0];
+ data[1] = bytes[1];
+ break;
+ }
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ }
+ }
+ }
+
+ public int secondVertex {
+ get {
+ switch (type) {
+ case MapType.Quake:
+ case MapType.SiN:
+ case MapType.Daikatana:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Quake2:
+ case MapType.SoF: {
+ return BitConverter.ToUInt16(data, 2);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 4);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake:
+ case MapType.SiN:
+ case MapType.Daikatana:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Quake2:
+ case MapType.SoF: {
+ data[2] = bytes[0];
+ data[3] = bytes[1];
+ break;
+ }
+ case MapType.Vindictus: {
+ BitConverter.GetBytes(value).CopyTo(data, 4);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -18,41 +139,13 @@ namespace LibBSP {
/// 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, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- switch (type) {
- case MapType.Quake:
- case MapType.SiN:
- case MapType.Daikatana:
- 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.TacticalInterventionEncrypted:
- case MapType.DMoMaM:
- case MapType.Quake2:
- case MapType.SoF: {
- firstVertex = BitConverter.ToUInt16(data, 0);
- secondVertex = BitConverter.ToUInt16(data, 2);
- break;
- }
- case MapType.Vindictus: {
- firstVertex = BitConverter.ToInt32(data, 0);
- secondVertex = BitConverter.ToInt32(data, 4);
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the Edge class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -99,8 +192,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new Edge(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/BSP/Face.cs b/LibBSP/Source/Structs/BSP/Face.cs
index a36d460..a805f9c 100644
--- a/LibBSP/Source/Structs/BSP/Face.cs
+++ b/LibBSP/Source/Structs/BSP/Face.cs
@@ -24,24 +24,870 @@ namespace LibBSP {
///
public struct Face {
- public int plane { get; private set; }
- public int side { get; private set; }
- [Index("edges")] public int firstEdge { get; private set; }
- [Count("edges")] public int numEdges { get; private set; }
- public int texture { get; private set; }
- [Index("vertices")] public int firstVertex { get; private set; }
- [Count("vertices")] public int numVertices { get; private set; }
- public int material { get; private set; }
- public int textureInfo { get; private set; }
- public int displacement { get; private set; }
- public int original { get; private set; }
- public int flags { get; private set; }
- [Index("indices")] public int firstIndex { get; private set; }
- [Count("indices")] public int numIndices { get; private set; }
- public int unknown { get; private set; }
- public int lightStyles { get; private set; }
- public int lightMaps { get; private set; }
- public Vector2d patchSize { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public int plane {
+ get {
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return BitConverter.ToUInt16(data, 0);
+ }
+ case MapType.Source17: {
+ return BitConverter.ToUInt16(data, 32);
+ }
+ case MapType.Nightfire:
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 0);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ data[0] = bytes[0];
+ data[1] = bytes[1];
+ break;
+ }
+ case MapType.Source17: {
+ data[32] = bytes[0];
+ data[33] = bytes[1];
+ break;
+ }
+ case MapType.Nightfire:
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ }
+ }
+ }
+
+ public int side {
+ get {
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF: {
+ return BitConverter.ToUInt16(data, 2);
+ }
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return (int)data[2];
+ }
+ case MapType.Vindictus: {
+ return (int)data[4];
+ }
+ case MapType.Source17: {
+ return (int)data[34];
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF: {
+ data[2] = bytes[0];
+ data[3] = bytes[1];
+ break;
+ }
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ data[2] = bytes[0];
+ break;
+ }
+ case MapType.Vindictus: {
+ data[4] = bytes[0];
+ break;
+ }
+ case MapType.Source17: {
+ data[34] = bytes[0];
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("edges")] public int firstEdge {
+ get {
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt32(data, 4);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 8);
+ }
+ case MapType.Source17: {
+ return BitConverter.ToInt32(data, 36);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ bytes.CopyTo(data, 4);
+ break;
+ }
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 8);
+ break;
+ }
+ case MapType.Source17: {
+ bytes.CopyTo(data, 36);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("edges")] public int numEdges {
+ get {
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return BitConverter.ToUInt16(data, 8);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 12);
+ }
+ case MapType.Source17: {
+ return BitConverter.ToUInt16(data, 40);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ data[8] = bytes[0];
+ data[9] = bytes[1];
+ break;
+ }
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 12);
+ break;
+ }
+ case MapType.Source17: {
+ data[40] = bytes[0];
+ data[41] = bytes[1];
+ break;
+ }
+ }
+ }
+ }
+
+ public int texture {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt16(data, 0);
+ }
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 0);
+ }
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF: {
+ return BitConverter.ToUInt16(data, 10);
+ }
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 24);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ data[0] = bytes[0];
+ data[1] = bytes[1];
+ break;
+ }
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF: {
+ data[10] = bytes[0];
+ data[11] = bytes[1];
+ break;
+ }
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 24);
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("vertices")] public int firstVertex {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 4);
+ }
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 12);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 4);
+ break;
+ }
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 12);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("vertices")] public int numVertices {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt16(data, 8);
+ }
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 8);
+ }
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 16);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ data[8] = bytes[0];
+ data[9] = bytes[1];
+ break;
+ }
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 8);
+ break;
+ }
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 16);
+ break;
+ }
+ }
+ }
+ }
+
+ public int material {
+ get {
+ switch (type) {
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 28);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 28);
+ break;
+ }
+ }
+ }
+ }
+
+ public int textureInfo {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return BitConverter.ToUInt16(data, 10);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 16);
+ }
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 32);
+ }
+ case MapType.Source17: {
+ return BitConverter.ToUInt16(data, 42);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ data[10] = bytes[0];
+ data[11] = bytes[1];
+ break;
+ }
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 16);
+ break;
+ }
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 32);
+ break;
+ }
+ case MapType.Source17: {
+ data[42] = bytes[0];
+ data[43] = bytes[1];
+ break;
+ }
+ }
+ }
+ }
+
+ public int displacement {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt16(data, 12);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 20);
+ }
+ case MapType.Source17: {
+ return BitConverter.ToInt16(data, 44);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ data[12] = bytes[0];
+ data[13] = bytes[1];
+ break;
+ }
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 20);
+ break;
+ }
+ case MapType.Source17: {
+ data[44] = bytes[0];
+ data[45] = bytes[1];
+ break;
+ }
+ }
+ }
+ }
+
+ public int original {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt32(data, 44);
+ }
+ case MapType.Vindictus: {
+ if (version == 2) {
+ return BitConverter.ToInt32(data, 60);
+ }
+ else {
+ return BitConverter.ToInt32(data, 56);
+ }
+ }
+ case MapType.Source17: {
+ return BitConverter.ToInt32(data, 96);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM: {
+ bytes.CopyTo(data, 44);
+ break;
+ }
+ case MapType.Vindictus: {
+ if (version == 2) {
+ bytes.CopyTo(data, 60);
+ }
+ else {
+ bytes.CopyTo(data, 56);
+ }
+ break;
+ }
+ case MapType.Source17: {
+ bytes.CopyTo(data, 96);
+ break;
+ }
+ }
+ }
+ }
+
+ public int flags {
+ get {
+ switch (type) {
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 8);
+ }
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 20);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 8);
+ break;
+ }
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 20);
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("indices")] public int firstIndex {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 12);
+ }
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 20);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 12);
+ break;
+ }
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 20);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("indices")] public int numIndices {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt16(data, 10);
+ }
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 16);
+ }
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 24);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ data[10] = bytes[0];
+ data[11] = bytes[1];
+ return;
+ }
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 16);
+ break;
+ }
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 24);
+ break;
+ }
+ }
+ }
+ }
+
+ public int unknown {
+ get {
+ switch (type) {
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 36);
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 36);
+ break;
+ }
+ }
+ }
+ }
+
+ public int lightStyles {
+ get {
+ switch (type) {
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 40);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 40);
+ break;
+ }
+ }
+ }
+ }
+
+ public int lightMaps {
+ get {
+ switch (type) {
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 44);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 44);
+ break;
+ }
+ }
+ }
+ }
+
+ public Vector2d patchSize {
+ get {
+ switch (type) {
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ return new Vector2d(BitConverter.ToInt32(data, 96), BitConverter.ToInt32(data, 100));
+ }
+ default: {
+ return new Vector2d(float.NaN, float.NaN);
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.Quake3:
+ case MapType.Raven:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.MOHAA:
+ case MapType.FAKK: {
+ byte[] bytes = BitConverter.GetBytes((int)value.x);
+ bytes.CopyTo(data, 96);
+ bytes = BitConverter.GetBytes((int)value.y);
+ bytes.CopyTo(data, 100);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -50,127 +896,13 @@ namespace LibBSP {
/// 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, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- plane = -1;
- side = -1;
- firstEdge = -1;
- numEdges = -1;
- texture = -1;
- firstVertex = -1;
- numVertices = -1;
- material = -1;
- textureInfo = -1;
- displacement = -1;
- original = -1;
- flags = -1;
- firstIndex = -1;
- numIndices = -1;
- unknown = -1;
- lightStyles = -1;
- lightMaps = -1;
- patchSize = new Vector2d(float.NaN, float.NaN);
- switch (type) {
- case MapType.CoD: {
- texture = BitConverter.ToInt16(data, 0);
- firstVertex = BitConverter.ToInt32(data, 4);
- numVertices = BitConverter.ToInt16(data, 8);
- numIndices = BitConverter.ToInt16(data, 10);
- firstIndex = BitConverter.ToInt32(data, 12);
- break;
- }
- case MapType.Quake:
- case MapType.Quake2:
- case MapType.Daikatana:
- case MapType.SiN:
- case MapType.SoF: {
- plane = BitConverter.ToUInt16(data, 0);
- side = BitConverter.ToUInt16(data, 2);
- firstEdge = BitConverter.ToInt32(data, 4);
- numEdges = BitConverter.ToUInt16(data, 8);
- texture = BitConverter.ToUInt16(data, 10);
- break;
- }
- case MapType.Quake3:
- case MapType.Raven:
- case MapType.STEF2:
- case MapType.STEF2Demo:
- case MapType.MOHAA:
- case MapType.FAKK: {
- texture = BitConverter.ToInt32(data, 0);
- flags = BitConverter.ToInt32(data, 8);
- firstVertex = BitConverter.ToInt32(data, 12);
- numVertices = BitConverter.ToInt32(data, 16);
- firstIndex = BitConverter.ToInt32(data, 20);
- numIndices = BitConverter.ToInt32(data, 24);
- patchSize = new Vector2d(BitConverter.ToInt32(data, 96), BitConverter.ToInt32(data, 100));
- break;
- }
- case MapType.Source17: {
- plane = BitConverter.ToUInt16(data, 32);
- side = (int)data[34];
- firstEdge = BitConverter.ToInt32(data, 36);
- numEdges = BitConverter.ToUInt16(data, 40);
- textureInfo = BitConverter.ToUInt16(data, 42);
- displacement = BitConverter.ToInt16(data, 44);
- original = BitConverter.ToInt32(data, 96);
- break;
- }
- 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.TacticalInterventionEncrypted:
- case MapType.DMoMaM: {
- plane = BitConverter.ToUInt16(data, 0);
- side = (int)data[2];
- firstEdge = BitConverter.ToInt32(data, 4);
- numEdges = BitConverter.ToUInt16(data, 8);
- textureInfo = BitConverter.ToUInt16(data, 10);
- displacement = BitConverter.ToInt16(data, 12);
- original = BitConverter.ToInt32(data, 44);
- break;
- }
- case MapType.Vindictus: {
- plane = BitConverter.ToInt32(data, 0);
- side = (int)data[4];
- firstEdge = BitConverter.ToInt32(data, 8);
- numEdges = BitConverter.ToInt32(data, 12);
- textureInfo = BitConverter.ToInt32(data, 16);
- displacement = BitConverter.ToInt32(data, 20);
- if (version == 2) {
- original = BitConverter.ToInt32(data, 60);
- } else {
- original = BitConverter.ToInt32(data, 56);
- }
- break;
- }
- case MapType.Nightfire: {
- plane = BitConverter.ToInt32(data, 0);
- firstVertex = BitConverter.ToInt32(data, 4);
- numVertices = BitConverter.ToInt32(data, 8);
- firstIndex = BitConverter.ToInt32(data, 12);
- numIndices = BitConverter.ToInt32(data, 16);
- flags = BitConverter.ToInt32(data, 20);
- texture = BitConverter.ToInt32(data, 24);
- material = BitConverter.ToInt32(data, 28);
- textureInfo = BitConverter.ToInt32(data, 32);
- unknown = BitConverter.ToInt32(data, 36);
- lightStyles = BitConverter.ToInt32(data, 40);
- lightMaps = BitConverter.ToInt32(data, 44);
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the Face class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -188,7 +920,8 @@ namespace LibBSP {
}
int structLength = 0;
switch (type) {
- case MapType.CoD: {
+ case MapType.CoD:
+ case MapType.CoD2: {
structLength = 16;
break;
}
@@ -259,8 +992,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new Face(bytes, type, version));
}
@@ -289,6 +1022,9 @@ namespace LibBSP {
case MapType.CoD: {
return 6;
}
+ case MapType.CoD2: {
+ return 7;
+ }
case MapType.Vindictus:
case MapType.TacticalInterventionEncrypted:
case MapType.Source17:
diff --git a/LibBSP/Source/Structs/BSP/LODTerrain.cs b/LibBSP/Source/Structs/BSP/LODTerrain.cs
index 1c4f9d8..4e2f90b 100644
--- a/LibBSP/Source/Structs/BSP/LODTerrain.cs
+++ b/LibBSP/Source/Structs/BSP/LODTerrain.cs
@@ -8,17 +8,274 @@ namespace LibBSP {
///
public struct LODTerrain {
- public byte flags { get; private set; }
- public byte scale { get; private set; }
- public byte[] lightmapCoords { get; private set; }
- public float[] textureCoords { get; private set; }
- public sbyte x { get; private set; }
- public sbyte y { get; private set; }
- public short baseZ { get; private set; }
- public ushort texture { get; private set; }
- public short lightmap { get; private set; }
- public short[][] vertexFlags { get; private set; }
- public byte[][] heightmap { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public byte flags {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return data[0];
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.MOHAA: {
+ data[0] = value;
+ break;
+ }
+ }
+ }
+ }
+
+ public byte scale {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return data[1];
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.MOHAA: {
+ data[1] = value;
+ break;
+ }
+ }
+ }
+ }
+
+ public byte[] lightmapCoords {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return new byte[] { data[2], data[3] };
+ }
+ default: {
+ return null;
+ }
+ }
+ }
+ set {
+ if (value.Length != 2) {
+ throw new ArgumentException("LightmapCoords array must have 2 elements.");
+ }
+ switch (type) {
+ case MapType.MOHAA: {
+ data[2] = value[0];
+ data[3] = value[1];
+ break;
+ }
+ }
+ }
+ }
+
+ public float[] textureCoords {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return new float[] {
+ BitConverter.ToSingle(data, 4),
+ BitConverter.ToSingle(data, 8),
+ BitConverter.ToSingle(data, 12),
+ BitConverter.ToSingle(data, 16),
+ BitConverter.ToSingle(data, 20),
+ BitConverter.ToSingle(data, 24),
+ BitConverter.ToSingle(data, 28),
+ BitConverter.ToSingle(data, 32),
+ };
+ }
+ default: {
+ return null;
+ }
+ }
+ }
+ set {
+ if (value.Length != 8) {
+ throw new ArgumentException("TextureCoords array must have 8 elements.");
+ }
+ switch (type) {
+ case MapType.MOHAA: {
+ int offset = 4;
+ for (int i = 0; i < value.Length; ++i) {
+ BitConverter.GetBytes(value[i]).CopyTo(data, offset + (i * 4));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public sbyte x {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return (sbyte)data[36];
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.MOHAA: {
+ data[36] = (byte)value;
+ break;
+ }
+ }
+ }
+ }
+
+ public sbyte y {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return (sbyte)data[37];
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.MOHAA: {
+ data[37] = (byte)value;
+ break;
+ }
+ }
+ }
+ }
+
+ public short baseZ {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return BitConverter.ToInt16(data, 38);
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.MOHAA: {
+ bytes.CopyTo(data, 38);
+ break;
+ }
+ }
+ }
+ }
+
+ public ushort texture {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return BitConverter.ToUInt16(data, 40);
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.MOHAA: {
+ bytes.CopyTo(data, 40);
+ break;
+ }
+ }
+ }
+ }
+
+ public short lightmap {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return BitConverter.ToInt16(data, 42);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.MOHAA: {
+ bytes.CopyTo(data, 42);
+ break;
+ }
+ }
+ }
+ }
+
+ public ushort[,] vertexFlags {
+ get {
+ ushort[,] ret = new ushort[2,63];
+ switch (type) {
+ case MapType.MOHAA: {
+ for (int i = 0; i < ret.GetLength(0); ++i) {
+ for (int j = 0; j < ret.GetLength(1); ++j) {
+ ret[i, j] = BitConverter.ToUInt16(data, 52 + (i * 126) + (j * 2));
+ }
+ }
+ break;
+ }
+ }
+ return ret;
+ }
+ set {
+ if (value.GetLength(0) != 2 || value.GetLength(1) != 63) {
+ throw new ArgumentException("VertexFlags array must be size (2, 63) elements.");
+ }
+ for (int i = 0; i < value.GetLength(0); ++i) {
+ for (int j = 0; j < value.GetLength(1); ++j) {
+ BitConverter.GetBytes(value[i, j]).CopyTo(data, 52 + (i * 126) + (j * 2));
+ }
+ }
+ }
+ }
+
+ public byte[,] heightmap {
+ get {
+ byte[,] ret = new byte[9, 9];
+ switch (type) {
+ case MapType.MOHAA: {
+ for (int i = 0; i < ret.GetLength(0); ++i) {
+ for (int j = 0; j < ret.GetLength(1); ++j) {
+ ret[i, j] = data[304 + (i * 9) + j];
+ }
+ }
+ break;
+ }
+ }
+ return ret;
+ }
+ set {
+ if (value.GetLength(0) != 9 || value.GetLength(1) != 9) {
+ throw new ArgumentException("Heightmap array must be size (9, 9) elements.");
+ }
+ for (int i = 0; i < value.GetLength(0); ++i) {
+ for (int j = 0; j < value.GetLength(1); ++j) {
+ data[304 + (i * 9) + j] = value[i, j];
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -27,47 +284,13 @@ namespace LibBSP {
/// The map type.
/// The version of this lump.
/// was null.
- /// This structure is not implemented for the given maptype.
public LODTerrain(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- lightmapCoords = new byte[2];
- textureCoords = new float[8];
- vertexFlags = new short[2][];
- heightmap = new byte[9][];
- switch (type) {
- case MapType.MOHAA: {
- flags = data[0];
- scale = data[1];
- lightmapCoords[0] = data[2];
- lightmapCoords[1] = data[3];
- for (int i = 0; i < 8; ++i) {
- textureCoords[i] = BitConverter.ToSingle(data, 4 + (4 * i));
- }
- x = (sbyte)data[36];
- y = (sbyte)data[37];
- baseZ = BitConverter.ToInt16(data, 38);
- texture = BitConverter.ToUInt16(data, 40);
- lightmap = BitConverter.ToInt16(data, 42);
- for (int i = 0; i < vertexFlags.Length; ++i) {
- vertexFlags[i] = new short[63];
- for (int j = 0; j < vertexFlags[i].Length; ++j) {
- vertexFlags[i][j] = BitConverter.ToInt16(data, 52 + (i * 126) + (j * 2));
- }
- }
- for (int i = 0; i < heightmap.Length; ++i) {
- heightmap[i] = new byte[9];
- for (int j = 0; j < heightmap[i].Length; ++j) {
- heightmap[i][j] = data[304 + (i * 9) + j];
- }
- }
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the LODTerrain class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -95,8 +318,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new LODTerrain(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/BSP/Leaf.cs b/LibBSP/Source/Structs/BSP/Leaf.cs
index e82dfb7..486d9ba 100644
--- a/LibBSP/Source/Structs/BSP/Leaf.cs
+++ b/LibBSP/Source/Structs/BSP/Leaf.cs
@@ -8,12 +8,457 @@ namespace LibBSP {
///
public struct Leaf {
- public int contents { get; private set; }
- [Index("markBrushes")] public int firstMarkBrush { get; private set; }
- [Count("markBrushes")] public int numMarkBrushes { get; private set; }
- [Index("markSurfaces")] public int firstMarkFace { get; private set; }
- [Count("markSurfaces")] public int numMarkFaces { get; private set; }
- public int pvs { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public int contents {
+ get {
+ switch (type) {
+ case MapType.SoF:
+ case MapType.Quake2:
+ case MapType.SiN:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Daikatana:
+ case MapType.Vindictus:
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 0);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.SoF:
+ case MapType.Quake2:
+ case MapType.SiN:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Daikatana:
+ case MapType.Vindictus:
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("markBrushes")] public int firstMarkBrush {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt32(data, 16);
+ }
+ case MapType.Quake2:
+ case MapType.SiN:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Daikatana: {
+ return BitConverter.ToUInt16(data, 24);
+ }
+ case MapType.SoF: {
+ return BitConverter.ToUInt16(data, 26);
+ }
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 40);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 44);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ bytes.CopyTo(data, 16);
+ break;
+ }
+ case MapType.Quake2:
+ case MapType.SiN:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Daikatana: {
+ data[24] = bytes[0];
+ data[25] = bytes[1];
+ break;
+ }
+ case MapType.SoF: {
+ data[26] = bytes[0];
+ data[27] = bytes[1];
+ break;
+ }
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 40);
+ break;
+ }
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 44);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("markBrushes")] public int numMarkBrushes {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt32(data, 20);
+ }
+ case MapType.Quake2:
+ case MapType.SiN:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Daikatana: {
+ return BitConverter.ToUInt16(data, 26);
+ }
+ case MapType.SoF: {
+ return BitConverter.ToUInt16(data, 28);
+ }
+ case MapType.Nightfire:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.Raven: {
+ return BitConverter.ToInt32(data, 44);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 48);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ bytes.CopyTo(data, 20);
+ break;
+ }
+ case MapType.Quake2:
+ case MapType.SiN:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Daikatana: {
+ data[26] = bytes[0];
+ data[27] = bytes[1];
+ break;
+ }
+ case MapType.SoF: {
+ data[28] = bytes[0];
+ data[29] = bytes[1];
+ break;
+ }
+ case MapType.Nightfire:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.Raven: {
+ bytes.CopyTo(data, 44);
+ break;
+ }
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 48);
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("markSurfaces")] public int firstMarkFace {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt32(data, 8);
+ }
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.SiN:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Daikatana: {
+ return BitConverter.ToUInt16(data, 20);
+ }
+ case MapType.SoF: {
+ return BitConverter.ToUInt16(data, 22);
+ }
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 32);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 36);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ bytes.CopyTo(data, 8);
+ break;
+ }
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.SiN:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Daikatana: {
+ data[20] = bytes[0];
+ data[21] = bytes[1];
+ break;
+ }
+ case MapType.SoF: {
+ data[22] = bytes[0];
+ data[23] = bytes[1];
+ break;
+ }
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 32);
+ break;
+ }
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 36);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("markSurfaces")] public int numMarkFaces {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt32(data, 12);
+ }
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.SiN:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Daikatana: {
+ return BitConverter.ToUInt16(data, 22);
+ }
+ case MapType.SoF: {
+ return BitConverter.ToUInt16(data, 24);
+ }
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 36);
+ }
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 40);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ bytes.CopyTo(data, 12);
+ break;
+ }
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.SiN:
+ 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.TacticalInterventionEncrypted:
+ case MapType.DMoMaM:
+ case MapType.Daikatana: {
+ data[22] = bytes[0];
+ data[23] = bytes[1];
+ break;
+ }
+ case MapType.SoF: {
+ data[24] = bytes[0];
+ data[25] = bytes[1];
+ break;
+ }
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.STEF2Demo:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 36);
+ break;
+ }
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 40);
+ break;
+ }
+ }
+ }
+ }
+
+ public int pvs {
+ get {
+ switch (type) {
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 4);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 4);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -22,86 +467,13 @@ namespace LibBSP {
/// 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, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- contents = -1;
- firstMarkBrush = -1;
- numMarkBrushes = -1;
- firstMarkFace = -1;
- numMarkFaces = -1;
- pvs = -1;
- switch (type) {
- case MapType.SoF: {
- contents = BitConverter.ToInt32(data, 0);
- firstMarkFace = BitConverter.ToUInt16(data, 22);
- numMarkFaces = BitConverter.ToUInt16(data, 24);
- firstMarkBrush = BitConverter.ToUInt16(data, 26);
- numMarkBrushes = BitConverter.ToUInt16(data, 28);
- break;
- }
- case MapType.Quake2:
- case MapType.SiN:
- 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.TacticalInterventionEncrypted:
- case MapType.DMoMaM:
- case MapType.Daikatana: {
- contents = BitConverter.ToInt32(data, 0);
- firstMarkBrush = BitConverter.ToUInt16(data, 24);
- numMarkBrushes = BitConverter.ToUInt16(data, 26);
- goto case MapType.Quake;
- }
- case MapType.Quake: {
- firstMarkFace = BitConverter.ToUInt16(data, 20);
- numMarkFaces = BitConverter.ToUInt16(data, 22);
- break;
- }
- case MapType.Vindictus: {
- contents = BitConverter.ToInt32(data, 0);
- firstMarkFace = BitConverter.ToInt32(data, 36);
- numMarkFaces = BitConverter.ToInt32(data, 40);
- firstMarkBrush = BitConverter.ToInt32(data, 44);
- numMarkBrushes = BitConverter.ToInt32(data, 48);
- break;
- }
- case MapType.Nightfire: {
- contents = BitConverter.ToInt32(data, 0);
- pvs = BitConverter.ToInt32(data, 4);
- goto case MapType.Raven;
- }
- case MapType.Quake3:
- case MapType.FAKK:
- case MapType.STEF2Demo:
- case MapType.STEF2:
- case MapType.MOHAA:
- case MapType.Raven: {
- firstMarkFace = BitConverter.ToInt32(data, 32);
- numMarkFaces = BitConverter.ToInt32(data, 36);
- firstMarkBrush = BitConverter.ToInt32(data, 40);
- numMarkBrushes = BitConverter.ToInt32(data, 44);
- break;
- }
- case MapType.CoD: {
- firstMarkFace = BitConverter.ToInt32(data, 8);
- numMarkFaces = BitConverter.ToInt32(data, 12);
- firstMarkBrush = BitConverter.ToInt32(data, 16);
- numMarkBrushes = BitConverter.ToInt32(data, 20);
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the Leaf class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -143,7 +515,8 @@ namespace LibBSP {
structLength = 56;
break;
}
- case MapType.CoD: {
+ case MapType.CoD:
+ case MapType.CoD2: {
structLength = 36;
break;
}
@@ -171,8 +544,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new Leaf(bytes, type, version));
}
@@ -221,6 +594,9 @@ namespace LibBSP {
case MapType.CoD: {
return 21;
}
+ case MapType.CoD2: {
+ return 26;
+ }
default: {
return -1;
}
diff --git a/LibBSP/Source/Structs/BSP/Lumps/DisplacementVertices.cs b/LibBSP/Source/Structs/BSP/Lumps/DisplacementVertices.cs
index acd783a..6e3543c 100644
--- a/LibBSP/Source/Structs/BSP/Lumps/DisplacementVertices.cs
+++ b/LibBSP/Source/Structs/BSP/Lumps/DisplacementVertices.cs
@@ -20,9 +20,9 @@ namespace LibBSP {
throw new ArgumentNullException();
}
int structLength = 20;
- byte[] bytes = new byte[structLength];
int numObjects = data.Length / structLength;
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
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 153e263..e37e18e 100644
--- a/LibBSP/Source/Structs/BSP/Lumps/GameLump.cs
+++ b/LibBSP/Source/Structs/BSP/Lumps/GameLump.cs
@@ -19,27 +19,6 @@ namespace LibBSP {
///
public class GameLump : Dictionary {
- private byte[] _rawData;
- private int _gameLumpOffset;
-
- ///
- /// Byte array representing the raw data read from the BSP for the game lump.
- ///
- public byte[] rawData {
- get {
- return _rawData;
- }
- }
-
- ///
- /// The amount to subtract from all the values to find the offset relative to the start of the Game Lump data. May be 0.
- ///
- public int gameLumpOffset {
- get {
- return _gameLumpOffset;
- }
- }
-
///
/// Creates a new object by parsing a byte array into a Dictionary of objects.
/// These objects contain offsets, lengths and versions of the GameLump lumps.
@@ -53,7 +32,6 @@ namespace LibBSP {
if (data == null) {
throw new ArgumentNullException();
}
- _rawData = data;
int structLength = 0;
switch (type) {
@@ -82,25 +60,25 @@ namespace LibBSP {
int numGameLumps = BitConverter.ToInt32(data, 0);
if (numGameLumps > 0) {
- int headerLength = 4 + (numGameLumps * structLength);
+ int lumpDictionaryOffset = (type == MapType.DMoMaM) ? 8 : 4;
int lowestLumpOffset = int.MaxValue;
for (int i = 0; i < numGameLumps; ++i) {
- int lumpIdent = BitConverter.ToInt32(data, (i * structLength) + 4);
+ int lumpIdent = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset);
int lumpFlags;
int lumpVersion;
int lumpOffset;
int lumpLength;
if (type == MapType.Vindictus) {
- 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);
+ lumpFlags = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 4);
+ lumpVersion = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 8);
+ lumpOffset = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 12);
+ lumpLength = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 16);
} else {
- 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);
+ lumpFlags = BitConverter.ToUInt16(data, (i * structLength) + lumpDictionaryOffset + 4);
+ lumpVersion = BitConverter.ToUInt16(data, (i * structLength) + lumpDictionaryOffset + 6);
+ lumpOffset = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 8);
+ lumpLength = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 12);
}
LumpInfo info = new LumpInfo {
ident = lumpIdent,
@@ -115,9 +93,6 @@ namespace LibBSP {
lowestLumpOffset = info.offset;
}
}
-
- // If the offset values are given relative to the beginning of the lump, this should give 0.
- _gameLumpOffset = lowestLumpOffset - headerLength;
}
}
@@ -159,5 +134,19 @@ namespace LibBSP {
}
}
}
+
+ ///
+ /// Gets the lowest offset used for a Game Lump.
+ ///
+ /// The lowest offset used for a Game Lump, or int.MaxValue if no Game Lumps exist.
+ public int GetLowestLumpOffset() {
+ int lowest = int.MaxValue;
+ foreach (LumpInfo info in Values) {
+ if (info.offset < lowest) {
+ lowest = info.offset;
+ }
+ }
+ return lowest;
+ }
}
}
diff --git a/LibBSP/Source/Structs/BSP/Lumps/StaticProps.cs b/LibBSP/Source/Structs/BSP/Lumps/StaticProps.cs
index be8912d..8961134 100644
--- a/LibBSP/Source/Structs/BSP/Lumps/StaticProps.cs
+++ b/LibBSP/Source/Structs/BSP/Lumps/StaticProps.cs
@@ -43,8 +43,8 @@ namespace LibBSP {
offset += 4;
if (numProps > 0) {
structLength = (data.Length - offset) / numProps;
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numProps; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, offset, bytes, 0, structLength);
Add(new StaticProp(bytes, type, version));
offset += structLength;
diff --git a/LibBSP/Source/Structs/BSP/Lumps/Textures.cs b/LibBSP/Source/Structs/BSP/Lumps/Textures.cs
index a7e1e95..982566d 100644
--- a/LibBSP/Source/Structs/BSP/Lumps/Textures.cs
+++ b/LibBSP/Source/Structs/BSP/Lumps/Textures.cs
@@ -65,11 +65,10 @@ namespace LibBSP {
case MapType.Vindictus:
case MapType.DMoMaM: {
int offset = 0;
- byte[] myBytes;
for (int i = 0; i < data.Length; ++i) {
if (data[i] == (byte)0x00) {
// They are null-terminated strings, of non-constant length (not padded)
- myBytes = new byte[i - offset];
+ byte[] myBytes = new byte[i - offset];
Array.Copy(data, offset, myBytes, 0, i - offset);
Add(new Texture(myBytes, type, version));
offset = i + 1;
@@ -80,8 +79,8 @@ namespace LibBSP {
case MapType.Quake: {
int numElements = BitConverter.ToInt32(data, 0);
structLength = 40;
- byte[] myBytes = new byte[structLength];
for (int i = 0; i < numElements; ++i) {
+ byte[] myBytes = new byte[structLength];
Array.Copy(data, BitConverter.ToInt32(data, (i + 1) * 4), myBytes, 0, structLength);
Add(new Texture(myBytes, type, version));
}
@@ -93,8 +92,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
Add(new Texture(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/BSP/Model.cs b/LibBSP/Source/Structs/BSP/Model.cs
index 5eb0655..a35f288 100644
--- a/LibBSP/Source/Structs/BSP/Model.cs
+++ b/LibBSP/Source/Structs/BSP/Model.cs
@@ -16,15 +16,431 @@ namespace LibBSP {
///
public struct Model {
- public int headNode { get; private set; } // Quake, Half-life, Quake 2, SiN
- [Index("leaves")] public int firstLeaf { get; private set; } // 007 nightfire
- [Count("leaves")] public int numLeaves { get; private set; }
- [Index("brushes")] public int firstBrush { get; private set; } // Quake 3 and derivatives
- [Count("brushes")] public int numBrushes { get; private set; }
- [Index("faces")] public int firstFace { get; private set; } // Quake/GoldSrc
- [Count("faces")] public int numFaces { get; private set; }
- [Index("markSurfaces")] public int firstLeafPatch { get; private set; } // CoD
- [Count("markSurfaces")] public int numLeafPatches { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ [Index("nodes")] public int headNode {
+ get {
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 36);
+ }
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt32(data, 40);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 36);
+ break;
+ }
+ case MapType.DMoMaM: {
+ bytes.CopyTo(data, 40);
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("leaves")] public int firstLeaf {
+ get {
+ switch (type) {
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 40);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 40);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("leaves")] public int numLeaves {
+ get {
+ switch (type) {
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 44);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 44);
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("brushes")] public int firstBrush {
+ get {
+ switch (type) {
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Quake3:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 32);
+ }
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ return BitConverter.ToInt32(data, 40);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Quake3:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 32);
+ break;
+ }
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ bytes.CopyTo(data, 40);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("brushes")] public int numBrushes {
+ get {
+ switch (type) {
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Quake3:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 36);
+ }
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ return BitConverter.ToInt32(data, 44);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Quake3:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 36);
+ break;
+ }
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4: {
+ bytes.CopyTo(data, 44);
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("faces")] public int firstFace {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Quake3:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 24);
+ }
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 40);
+ }
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt32(data, 44);
+ }
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 48);
+ }
+ case MapType.Quake: {
+ return BitConverter.ToInt32(data, 56);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Quake3:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 24);
+ break;
+ }
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 40);
+ break;
+ }
+ case MapType.DMoMaM: {
+ bytes.CopyTo(data, 44);
+ break;
+ }
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 48);
+ break;
+ }
+ case MapType.Quake: {
+ bytes.CopyTo(data, 56);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("faces")] public int numFaces {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Quake3:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 28);
+ }
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 44);
+ }
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt32(data, 48);
+ }
+ case MapType.Nightfire: {
+ return BitConverter.ToInt32(data, 52);
+ }
+ case MapType.Quake: {
+ return BitConverter.ToInt32(data, 60);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Quake3:
+ case MapType.MOHAA:
+ case MapType.Raven:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 28);
+ break;
+ }
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.SiN:
+ case MapType.SoF:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 44);
+ break;
+ }
+ case MapType.DMoMaM: {
+ bytes.CopyTo(data, 48);
+ break;
+ }
+ case MapType.Nightfire: {
+ bytes.CopyTo(data, 52);
+ break;
+ }
+ case MapType.Quake: {
+ bytes.CopyTo(data, 60);
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("markSurfaces")]
+ public int firstLeafPatch {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt32(data, 32);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ bytes.CopyTo(data, 32);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("markSurfaces")] public int numLeafPatches {
+ get {
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt32(data, 36);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD:
+ case MapType.CoD2: {
+ bytes.CopyTo(data, 36);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -33,89 +449,13 @@ namespace LibBSP {
/// 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, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- headNode = -1;
- firstLeaf = -1;
- numLeaves = -1;
- firstBrush = -1;
- numBrushes = -1;
- firstFace = -1;
- numFaces = -1;
- firstLeafPatch = -1;
- numLeafPatches = -1;
- switch (type) {
- case MapType.Quake: {
- headNode = BitConverter.ToInt32(data, 36);
- firstFace = BitConverter.ToInt32(data, 56);
- numFaces = BitConverter.ToInt32(data, 60);
- break;
- }
- case MapType.Quake2:
- case MapType.Daikatana:
- case MapType.SiN:
- case MapType.SoF:
- 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.TacticalInterventionEncrypted:
- case MapType.Vindictus: {
- headNode = BitConverter.ToInt32(data, 36);
- firstFace = BitConverter.ToInt32(data, 40);
- numFaces = BitConverter.ToInt32(data, 44);
- break;
- }
- case MapType.DMoMaM: {
- headNode = BitConverter.ToInt32(data, 40);
- firstFace = BitConverter.ToInt32(data, 44);
- numFaces = BitConverter.ToInt32(data, 48);
- break;
- }
- case MapType.Nightfire: {
- firstLeaf = BitConverter.ToInt32(data, 40);
- numLeaves = BitConverter.ToInt32(data, 44);
- firstFace = BitConverter.ToInt32(data, 48);
- numFaces = BitConverter.ToInt32(data, 52);
- break;
- }
- case MapType.STEF2:
- case MapType.STEF2Demo:
- case MapType.Quake3:
- case MapType.MOHAA:
- case MapType.Raven:
- case MapType.FAKK: {
- firstFace = BitConverter.ToInt32(data, 24);
- numFaces = BitConverter.ToInt32(data, 28);
- firstBrush = BitConverter.ToInt32(data, 32);
- numBrushes = BitConverter.ToInt32(data, 36);
- break;
- }
- case MapType.CoD: {
- firstFace = BitConverter.ToInt32(data, 24);
- numFaces = BitConverter.ToInt32(data, 28);
- firstLeafPatch = BitConverter.ToInt32(data, 32);
- numLeafPatches = BitConverter.ToInt32(data, 36);
- goto case MapType.CoD2;
- }
- case MapType.CoD2:
- case MapType.CoD4: {
- firstBrush = BitConverter.ToInt32(data, 40);
- numBrushes = BitConverter.ToInt32(data, 44);
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the Model class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -181,8 +521,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new Model(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/BSP/Node.cs b/LibBSP/Source/Structs/BSP/Node.cs
index a8419d7..d1cc6f3 100644
--- a/LibBSP/Source/Structs/BSP/Node.cs
+++ b/LibBSP/Source/Structs/BSP/Node.cs
@@ -8,9 +8,174 @@ namespace LibBSP {
///
public struct Node {
- public int plane { get; private set; }
- public int child1 { get; private set; } // Negative values are valid here. However, the child can never be zero,
- public int child2 { get; private set; } // since that would reference the head node causing an infinite loop.
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public int plane {
+ get {
+ return BitConverter.ToInt32(data, 0);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 0);
+ }
+ }
+
+ public int child1 {
+ get {
+ switch (type) {
+ case MapType.Quake: {
+ return BitConverter.ToInt16(data, 4);
+ }
+ case MapType.SiN:
+ case MapType.SoF:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.Nightfire:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt32(data, 4);
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake: {
+ data[4] = bytes[0];
+ data[5] = bytes[1];
+ break;
+ }
+ case MapType.SiN:
+ case MapType.SoF:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.Nightfire:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.CoD:
+ case MapType.CoD2: {
+ bytes.CopyTo(data, 4);
+ break;
+ }
+ }
+ }
+ }
+
+ public int child2 {
+ get {
+ switch (type) {
+ case MapType.Quake: {
+ return BitConverter.ToInt16(data, 6);
+ }
+ case MapType.SiN:
+ case MapType.SoF:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.Nightfire:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.CoD:
+ case MapType.CoD2: {
+ return BitConverter.ToInt32(data, 8);
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake: {
+ data[6] = bytes[0];
+ data[7] = bytes[1];
+ break;
+ }
+ case MapType.SiN:
+ case MapType.SoF:
+ case MapType.Quake2:
+ case MapType.Daikatana:
+ case MapType.Nightfire:
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM:
+ case MapType.STEF2:
+ case MapType.MOHAA:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.FAKK:
+ case MapType.CoD:
+ case MapType.CoD2: {
+ bytes.CopyTo(data, 8);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -19,51 +184,13 @@ namespace LibBSP {
/// 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, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- plane = BitConverter.ToInt32(data, 0); // All formats I've seen use the first 4 bytes as an int, plane index
- switch (type) {
- case MapType.Quake: {
- child1 = BitConverter.ToInt16(data, 4);
- child2 = BitConverter.ToInt16(data, 6);
- break;
- }
- // These all use the first three ints for planenum and children
- case MapType.SiN:
- case MapType.SoF:
- case MapType.Quake2:
- case MapType.Daikatana:
- case MapType.Nightfire:
- 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.TacticalInterventionEncrypted:
- case MapType.Vindictus:
- case MapType.DMoMaM:
- case MapType.STEF2:
- case MapType.MOHAA:
- case MapType.STEF2Demo:
- case MapType.Raven:
- case MapType.Quake3:
- case MapType.FAKK:
- case MapType.CoD: {
- child1 = BitConverter.ToInt32(data, 4);
- child2 = BitConverter.ToInt32(data, 8);
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the Node class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -113,6 +240,7 @@ namespace LibBSP {
case MapType.Quake3:
case MapType.FAKK:
case MapType.CoD:
+ case MapType.CoD2:
case MapType.STEF2:
case MapType.STEF2Demo:
case MapType.MOHAA:
@@ -127,8 +255,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new Node(bytes, type, version));
}
@@ -181,6 +309,9 @@ namespace LibBSP {
case MapType.CoD: {
return 20;
}
+ case MapType.CoD2: {
+ return 25;
+ }
default: {
return -1;
}
diff --git a/LibBSP/Source/Structs/BSP/Patch.cs b/LibBSP/Source/Structs/BSP/Patch.cs
index 8797672..7184b44 100644
--- a/LibBSP/Source/Structs/BSP/Patch.cs
+++ b/LibBSP/Source/Structs/BSP/Patch.cs
@@ -18,14 +18,229 @@ namespace LibBSP {
///
public struct Patch {
- public short shader { get; private set; }
- public short type { get; private set; }
- public Vector2d dimensions { get; private set; }
- public int flags { get; private set; }
- [Index("patchVerts")] public int firstVertex { get; private set; }
- [Count("patchVerts")] public int numVertices { get; private set; }
- [Count("patchIndices")] public int numIndices { get; private set; }
- [Index("patchIndices")] public int firstIndex { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public short shader {
+ get {
+ switch (type) {
+ case MapType.CoD: {
+ return BitConverter.ToInt16(data, 0);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD: {
+ bytes.CopyTo(data, 0);
+ break;
+ }
+ }
+ }
+ }
+
+ public short patchType {
+ get {
+ switch (type) {
+ case MapType.CoD: {
+ return BitConverter.ToInt16(data, 2);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD: {
+ bytes.CopyTo(data, 2);
+ break;
+ }
+ }
+ }
+ }
+
+ public Vector2d dimensions {
+ get {
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 0) {
+ return new Vector2d(BitConverter.ToInt16(data, 4), BitConverter.ToInt16(data, 6));
+ } else {
+ return new Vector2d(float.NaN, float.NaN);
+ }
+ }
+ default: {
+ return new Vector2d(float.NaN, float.NaN);
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 0) {
+ BitConverter.GetBytes((short)value.x).CopyTo(data, 4);
+ BitConverter.GetBytes((short)value.y).CopyTo(data, 6);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public int flags {
+ get {
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 0) {
+ return BitConverter.ToInt32(data, 8);
+ } else {
+ return -1;
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 0) {
+ bytes.CopyTo(data, 8);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("patchVerts")] public int firstVertex {
+ get {
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 0) {
+ return BitConverter.ToInt32(data, 12);
+ } else if (patchType == 1) {
+ return BitConverter.ToInt32(data, 8);
+ } else {
+ return -1;
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 0) {
+ bytes.CopyTo(data, 12);
+ } else if (patchType == 1) {
+ bytes.CopyTo(data, 8);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("patchVerts")] public int numVertices {
+ get {
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 0) {
+ return BitConverter.ToInt16(data, 4) * BitConverter.ToInt16(data, 6);
+ } else if (patchType == 1) {
+ return BitConverter.ToInt16(data, 4);
+ } else {
+ return -1;
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 1) {
+ data[4] = bytes[0];
+ data[5] = bytes[1];
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("patchIndices")] public int numIndices {
+ get {
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 1) {
+ return BitConverter.ToInt16(data, 6);
+ } else {
+ return -1;
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 1) {
+ data[6] = bytes[0];
+ data[7] = bytes[1];
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("patchIndices")] public int firstIndex {
+ get {
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 1) {
+ return BitConverter.ToInt32(data, 12);
+ } else {
+ return -1;
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.CoD: {
+ if (patchType == 1) {
+ bytes.CopyTo(data, 12);
+ }
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -34,34 +249,13 @@ namespace LibBSP {
/// The map type.
/// The version of this lump.
/// was null.
- /// This structure is not implemented for the given maptype.
public Patch(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- switch (type) {
- case MapType.CoD: {
- shader = BitConverter.ToInt16(data, 0);
- this.type = BitConverter.ToInt16(data, 2);
- if (this.type == 0) { // Patch
- short x = BitConverter.ToInt16(data, 4);
- short y = BitConverter.ToInt16(data, 6);
- dimensions = new Vector2d(x, y);
- flags = BitConverter.ToInt32(data, 8);
- firstVertex = BitConverter.ToInt32(data, 12);
- numVertices = x * y;
- } else if (this.type == 1) { // Terrain
- numVertices = BitConverter.ToInt16(data, 4);
- numIndices = BitConverter.ToInt16(data, 6);
- firstVertex = BitConverter.ToInt32(data, 8);
- firstIndex = BitConverter.ToInt32(data, 12);
- }
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the Patch class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -89,8 +283,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new Patch(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/BSP/StaticModel.cs b/LibBSP/Source/Structs/BSP/StaticModel.cs
index a81baab..8707d6c 100644
--- a/LibBSP/Source/Structs/BSP/StaticModel.cs
+++ b/LibBSP/Source/Structs/BSP/StaticModel.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Text;
#if UNITY
using UnityEngine;
#endif
@@ -18,12 +19,142 @@ namespace LibBSP {
///
public struct StaticModel {
- public string name { get; private set; }
- public Vector3d origin { get; private set; }
- public Vector3d angles { get; private set; }
- public float scale { get; private set; }
- [Index("vertices")] public int firstVertex { get; private set; }
- [Count("vertices")] public short numVertices { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public string name {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return data.ToNullTerminatedString(0, 128);
+ }
+ default: {
+ return null;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.MOHAA: {
+ for (int i = 0; i < 128; ++i) {
+ data[i] = 0;
+ }
+ byte[] strBytes = Encoding.ASCII.GetBytes(value);
+ Array.Copy(strBytes, 0, data, 0, Math.Min(strBytes.Length, 127));
+ break;
+ }
+ }
+ }
+ }
+
+ public Vector3d origin {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return new Vector3d(BitConverter.ToSingle(data, 128), BitConverter.ToSingle(data, 132), BitConverter.ToSingle(data, 136));
+ }
+ default: {
+ return new Vector3d(float.NaN, float.NaN, float.NaN);
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.MOHAA: {
+ value.GetBytes().CopyTo(data, 128);
+ break;
+ }
+ }
+ }
+ }
+
+ public Vector3d angles {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return new Vector3d(BitConverter.ToSingle(data, 140), BitConverter.ToSingle(data, 144), BitConverter.ToSingle(data, 148));
+ }
+ default: {
+ return new Vector3d(float.NaN, float.NaN, float.NaN);
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.MOHAA: {
+ value.GetBytes().CopyTo(data, 140);
+ break;
+ }
+ }
+ }
+ }
+
+ public float scale {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return BitConverter.ToSingle(data, 152);
+ }
+ default: {
+ return float.NaN;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.MOHAA: {
+ bytes.CopyTo(data, 152);
+ break;
+ }
+ }
+ }
+ }
+
+ [Index("vertices")] public int firstVertex {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return BitConverter.ToInt32(data, 156);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.MOHAA: {
+ bytes.CopyTo(data, 156);
+ break;
+ }
+ }
+ }
+ }
+
+ [Count("vertices")] public short numVertices {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return BitConverter.ToInt16(data, 160);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.MOHAA: {
+ bytes.CopyTo(data, 160);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -32,31 +163,13 @@ namespace LibBSP {
/// The map type.
/// The version of static prop lump this object is a member of.
/// was null.
- /// This structure is not implemented for the given maptype.
public StaticModel(byte[] data, MapType type, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- name = "";
- origin = Vector3d.zero;
- angles = Vector3d.zero;
- scale = 0;
- switch (type) {
- case MapType.MOHAA: {
- byte[] nameBytes = new byte[128];
- Array.Copy(data, 0, nameBytes, 0, 128);
- name = nameBytes.ToNullTerminatedString();
- origin = new Vector3d(BitConverter.ToSingle(data, 128), BitConverter.ToSingle(data, 132), BitConverter.ToSingle(data, 136));
- angles = new Vector3d(BitConverter.ToSingle(data, 140), BitConverter.ToSingle(data, 144), BitConverter.ToSingle(data, 148));
- scale = BitConverter.ToSingle(data, 152);
- firstVertex = BitConverter.ToInt32(data, 156);
- numVertices = BitConverter.ToInt16(data, 160);
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the StaticModel class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -84,8 +197,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new StaticModel(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/BSP/StaticProp.cs b/LibBSP/Source/Structs/BSP/StaticProp.cs
index 74e423a..401bfc8 100644
--- a/LibBSP/Source/Structs/BSP/StaticProp.cs
+++ b/LibBSP/Source/Structs/BSP/StaticProp.cs
@@ -3,13 +3,17 @@
#endif
using System;
+using System.Text;
#if UNITY
using UnityEngine;
#endif
namespace LibBSP {
#if UNITY
+ using Color = Color32;
using Vector3d = Vector3;
+#else
+ using Color = System.Drawing.Color;
#endif
///
@@ -17,16 +21,1488 @@ namespace LibBSP {
///
public struct StaticProp {
- public Vector3d origin { get; private set; }
- public Vector3d angles { get; private set; }
- public short dictionaryEntry { get; private set; }
- public byte solidity { get; private set; }
- public byte flags { get; private set; }
- public int skin { get; private set; }
- public float minFadeDist { get; private set; }
- public float maxFadeDist { get; private set; }
- public float forcedFadeScale { get; private set; }
- public string targetname { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public Vector3d origin {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ return new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
+ }
+ default: {
+ return new Vector3d(float.NaN, float.NaN, float.NaN);
+ }
+ }
+ }
+ default: {
+ return new Vector3d(float.NaN, float.NaN, float.NaN);
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ value.GetBytes().CopyTo(data, 0);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public Vector3d angles {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ return new Vector3d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 16), BitConverter.ToSingle(data, 20));
+ }
+ default: {
+ return new Vector3d(float.NaN, float.NaN, float.NaN);
+ }
+ }
+ }
+ default: {
+ return new Vector3d(float.NaN, float.NaN, float.NaN);
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ value.GetBytes().CopyTo(data, 12);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public short dictionaryEntry {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ return BitConverter.ToInt16(data, 24);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ bytes.CopyTo(data, 24);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public short firstLeaf {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ return BitConverter.ToInt16(data, 26);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ bytes.CopyTo(data, 26);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public short numLeafs {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ return BitConverter.ToInt16(data, 28);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ bytes.CopyTo(data, 28);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public byte solidity {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ return data[30];
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ data[30] = value;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public byte flags {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ return data[31];
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11: {
+ data[31] = value;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public int skin {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ return BitConverter.ToInt32(data, 32);
+ }
+ case 9: {
+ if (data.Length == 76) {
+ return BitConverter.ToInt32(data, 36);
+ } else {
+ return BitConverter.ToInt32(data, 32);
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ bytes.CopyTo(data, 32);
+ break;
+ }
+ case 9: {
+ if (data.Length == 76) {
+ bytes.CopyTo(data, 36);
+ } else {
+ bytes.CopyTo(data, 32);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public float minFadeDist {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ return BitConverter.ToSingle(data, 36);
+ }
+ case 9: {
+ if (data.Length == 76) {
+ return BitConverter.ToSingle(data, 40);
+ } else {
+ return BitConverter.ToSingle(data, 36);
+ }
+ }
+ default: {
+ return float.NaN;
+ }
+ }
+ }
+ default: {
+ return float.NaN;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ bytes.CopyTo(data, 36);
+ break;
+ }
+ case 9: {
+ if (data.Length == 76) {
+ bytes.CopyTo(data, 40);
+ } else {
+ bytes.CopyTo(data, 36);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public float maxFadeDist {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ return BitConverter.ToSingle(data, 40);
+ }
+ case 9: {
+ if (data.Length == 76) {
+ return BitConverter.ToInt32(data, 44);
+ } else {
+ return BitConverter.ToInt32(data, 40);
+ }
+ }
+ default: {
+ return float.NaN;
+ }
+ }
+ }
+ default: {
+ return float.NaN;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ bytes.CopyTo(data, 40);
+ break;
+ }
+ case 9: {
+ if (data.Length == 76) {
+ bytes.CopyTo(data, 36);
+ } else {
+ bytes.CopyTo(data, 32);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public Vector3d lightingOrigin {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ return new Vector3d(BitConverter.ToSingle(data, 44), BitConverter.ToSingle(data, 48), BitConverter.ToSingle(data, 52));
+ }
+ case 9: {
+ if (data.Length == 76) {
+ return new Vector3d(BitConverter.ToSingle(data, 48), BitConverter.ToSingle(data, 52), BitConverter.ToSingle(data, 56));
+ } else {
+ return new Vector3d(BitConverter.ToSingle(data, 44), BitConverter.ToSingle(data, 48), BitConverter.ToSingle(data, 52));
+ }
+ }
+ default: {
+ return new Vector3d(float.NaN, float.NaN, float.NaN);
+ }
+ }
+ }
+ default: {
+ return new Vector3d(float.NaN, float.NaN, float.NaN);
+ }
+ }
+ }
+ set {
+ byte[] bytes = value.GetBytes();
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ bytes.CopyTo(data, 44);
+ break;
+ }
+ case 9: {
+ if (data.Length == 76) {
+ value.GetBytes().CopyTo(data, 48);
+ } else {
+ value.GetBytes().CopyTo(data, 44);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public float forcedFadeScale {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ return BitConverter.ToSingle(data, 56);
+ }
+ case 9: {
+ if (data.Length == 76) {
+ return BitConverter.ToSingle(data, 60);
+ } else {
+ return BitConverter.ToSingle(data, 56);
+ }
+ }
+ default: {
+ return float.NaN;
+ }
+ }
+ }
+ default: {
+ return float.NaN;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ bytes.CopyTo(data, 56);
+ break;
+ }
+ case 9: {
+ if (data.Length == 76) {
+ bytes.CopyTo(data, 60);
+ } else {
+ bytes.CopyTo(data, 56);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public short minDXLevel {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted: {
+ switch (version) {
+ case 6:
+ case 7: {
+ return BitConverter.ToInt16(data, 60);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted: {
+ switch (version) {
+ case 6:
+ case 7: {
+ bytes.CopyTo(data, 60);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public short maxDXLevel {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted: {
+ switch (version) {
+ case 6:
+ case 7: {
+ return BitConverter.ToInt16(data, 62);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted: {
+ switch (version) {
+ case 6:
+ case 7: {
+ bytes.CopyTo(data, 62);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public byte minCPULevel {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 8:
+ case 10:
+ case 11: {
+ return data[60];
+ }
+ case 9: {
+ if (data.Length == 76) {
+ return data[64];
+ } else {
+ return data[60];
+ }
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 8:
+ case 10:
+ case 11: {
+ data[60] = value;
+ break;
+ }
+ case 9: {
+ if (data.Length == 76) {
+ data[64] = value;
+ } else {
+ data[60] = value;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public byte maxCPULevel {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 8:
+ case 10:
+ case 11: {
+ return data[61];
+ }
+ case 9: {
+ if (data.Length == 76) {
+ return data[65];
+ } else {
+ return data[61];
+ }
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 8:
+ case 10:
+ case 11: {
+ data[61] = value;
+ break;
+ }
+ case 9: {
+ if (data.Length == 76) {
+ data[65] = value;
+ } else {
+ data[61] = value;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public byte minGPULevel {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 8:
+ case 10:
+ case 11: {
+ return data[62];
+ }
+ case 9: {
+ if (data.Length == 76) {
+ return data[66];
+ } else {
+ return data[62];
+ }
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 8:
+ case 10:
+ case 11: {
+ data[62] = value;
+ break;
+ }
+ case 9: {
+ if (data.Length == 76) {
+ data[66] = value;
+ } else {
+ data[62] = value;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public byte maxGPULevel {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 8:
+ case 10:
+ case 11: {
+ return data[63];
+ }
+ case 9: {
+ if (data.Length == 76) {
+ return data[67];
+ } else {
+ return data[63];
+ }
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 8:
+ case 10:
+ case 11: {
+ data[63] = value;
+ break;
+ }
+ case 9: {
+ if (data.Length == 76) {
+ data[67] = value;
+ } else {
+ data[63] = value;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public Color diffuseModulaton {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ return ColorExtensions.FromArgb(data[67], data[64], data[65], data[66]);
+ }
+ case 9: {
+ if (data.Length == 76) {
+ return ColorExtensions.FromArgb(data[72], data[69], data[70], data[71]);
+ } else {
+ return ColorExtensions.FromArgb(data[67], data[64], data[65], data[66]);
+ }
+ }
+ default: {
+ return ColorExtensions.FromArgb(255, 255, 255, 255);
+ }
+ }
+ }
+ default: {
+ return ColorExtensions.FromArgb(255, 255, 255, 255);
+ }
+ }
+ }
+ set {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 7:
+ case 8:
+ case 10:
+ case 11: {
+ value.GetBytes().CopyTo(data, 64);
+ break;
+ }
+ case 9: {
+ if (data.Length == 76) {
+ value.GetBytes().CopyTo(data, 69);
+ } else {
+ value.GetBytes().CopyTo(data, 64);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public float scale {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 11: {
+ return BitConverter.ToSingle(data, 76);
+ }
+ default: {
+ return float.NaN;
+ }
+ }
+ }
+ default: {
+ return float.NaN;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ switch (version) {
+ case 11: {
+ bytes.CopyTo(data, 76);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public string targetname {
+ get {
+ switch (type) {
+ case MapType.Source20: {
+ switch (version) {
+ case 5:
+ case 6: {
+ if (data.Length > 128) {
+ return data.ToNullTerminatedString(data.Length - 128, 128);
+ }
+ return null;
+ }
+ default: {
+ return null;
+ }
+ }
+ }
+ default: {
+ return null;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.Source20: {
+ switch (version) {
+ case 5:
+ case 6: {
+ if (data.Length > 128) {
+ for (int i = 0; i < 128; ++i) {
+ data[data.Length - i - 1] = 0;
+ }
+ byte[] strBytes = Encoding.ASCII.GetBytes(value);
+ Array.Copy(strBytes, 0, data, data.Length - 128, Math.Min(strBytes.Length, 127));
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -35,73 +1511,13 @@ namespace LibBSP {
/// The map type.
/// 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 = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- origin = Vector3d.zero;
- angles = Vector3d.zero;
- dictionaryEntry = 0;
- solidity = 0;
- flags = 0;
- skin = 0;
- minFadeDist = 0;
- maxFadeDist = 0;
- forcedFadeScale = 1;
- targetname = null;
- switch (type) {
- 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.TacticalInterventionEncrypted:
- case MapType.Vindictus:
- case MapType.DMoMaM: {
- switch (version) {
- case 5: {
- if (data.Length == 188) {
- // This is only for The Ship or Bloody Good Time.
- byte[] targetnameBytes = new byte[128];
- Array.Copy(data, 60, targetnameBytes, 0, 128);
- targetname = targetnameBytes.ToNullTerminatedString();
- if (targetname.Length == 0) {
- targetname = null;
- }
- }
- goto case 6;
- }
- case 6:
- case 7:
- case 8:
- case 9:
- case 10: {
- forcedFadeScale = BitConverter.ToSingle(data, 56);
- goto case 4;
- }
- case 4: {
- origin = new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
- angles = new Vector3d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 16), BitConverter.ToSingle(data, 20));
- dictionaryEntry = BitConverter.ToInt16(data, 24);
- solidity = data[30];
- flags = data[31];
- skin = BitConverter.ToInt32(data, 32);
- minFadeDist = BitConverter.ToSingle(data, 36);
- maxFadeDist = BitConverter.ToSingle(data, 40);
- break;
- }
- }
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the SourceStaticProp class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
diff --git a/LibBSP/Source/Structs/BSP/Texture.cs b/LibBSP/Source/Structs/BSP/Texture.cs
index 66f5019..b95ff88 100644
--- a/LibBSP/Source/Structs/BSP/Texture.cs
+++ b/LibBSP/Source/Structs/BSP/Texture.cs
@@ -3,6 +3,7 @@
#endif
using System;
+using System.Text;
#if UNITY
using UnityEngine;
#endif
@@ -25,11 +26,265 @@ namespace LibBSP {
///
public struct Texture {
- public string name { get; private set; }
- public string mask { get; private set; } // Only used by MoHAA, "ignore" means it's unused
- public int flags { get; private set; }
- public int contents { get; private set; }
- public TextureInfo texAxes { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public string name {
+ get {
+ switch (type) {
+ case MapType.Quake: {
+ return data.ToNullTerminatedString(0, 16);
+ }
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4:
+ case MapType.FAKK:
+ case MapType.Nightfire: {
+ return data.ToNullTerminatedString(0, 64);
+ }
+ case MapType.Quake2:
+ case MapType.SoF:
+ case MapType.Daikatana: {
+ return data.ToNullTerminatedString(40, 32);
+ }
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ return data.ToRawString();
+ }
+ case MapType.SiN: {
+ return data.ToNullTerminatedString(36, 64);
+ }
+ default: {
+ return null;
+ }
+ }
+ }
+ set {
+ byte[] bytes = Encoding.ASCII.GetBytes(value);
+ switch (type) {
+ case MapType.Quake: {
+ for (int i = 0; i < 16; ++i) {
+ data[i] = 0;
+ }
+ Array.Copy(bytes, 0, data, 0, Math.Min(bytes.Length, 15));
+ break;
+ }
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4:
+ case MapType.FAKK:
+ case MapType.Nightfire: {
+ for (int i = 0; i < 64; ++i) {
+ data[i] = 0;
+ }
+ Array.Copy(bytes, 0, data, 0, Math.Min(bytes.Length, 63));
+ break;
+ }
+ case MapType.Quake2:
+ case MapType.SoF:
+ case MapType.Daikatana: {
+ for (int i = 0; i < 32; ++i) {
+ data[i + 40] = 0;
+ }
+ Array.Copy(bytes, 0, data, 40, Math.Min(bytes.Length, 31));
+ break;
+ }
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus:
+ case MapType.DMoMaM: {
+ data = bytes;
+ break;
+ }
+ case MapType.SiN: {
+ for (int i = 0; i < 64; ++i) {
+ data[i + 36] = 0;
+ }
+ Array.Copy(bytes, 0, data, 36, Math.Min(bytes.Length, 63));
+ break;
+ }
+ }
+ }
+ }
+
+ public string mask {
+ get {
+ switch (type) {
+ case MapType.MOHAA: {
+ return data.ToNullTerminatedString(76, 64);
+ }
+ default: {
+ return null;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.MOHAA: {
+ for (int i = 0; i < 64; ++i) {
+ data[i + 76] = 0;
+ }
+ byte[] strBytes = Encoding.ASCII.GetBytes(value);
+ Array.Copy(strBytes, 0, data, 76, Math.Min(strBytes.Length, 63));
+ break;
+ }
+ }
+ }
+ }
+
+ public int flags {
+ get {
+ switch (type) {
+ case MapType.Quake2:
+ case MapType.SoF:
+ case MapType.Daikatana:
+ case MapType.SiN: {
+ return BitConverter.ToInt32(data, 32);
+ }
+ case MapType.MOHAA:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4:
+ case MapType.FAKK: {
+ return BitConverter.ToInt32(data, 64);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.Quake2:
+ case MapType.SoF:
+ case MapType.Daikatana:
+ case MapType.SiN: {
+ bytes.CopyTo(data, 32);
+ break;
+ }
+ case MapType.MOHAA:
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4:
+ case MapType.FAKK: {
+ bytes.CopyTo(data, 64);
+ break;
+ }
+ }
+ }
+ }
+
+ public int contents {
+ get {
+ switch (type) {
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4:
+ case MapType.FAKK:
+ case MapType.MOHAA: {
+ return BitConverter.ToInt32(data, 68);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case MapType.STEF2:
+ case MapType.STEF2Demo:
+ case MapType.Raven:
+ case MapType.Quake3:
+ case MapType.CoD:
+ case MapType.CoD2:
+ case MapType.CoD4:
+ case MapType.FAKK:
+ case MapType.MOHAA: {
+ bytes.CopyTo(data, 68);
+ break;
+ }
+ }
+ }
+ }
+
+ public TextureInfo texAxes {
+ get {
+ switch (type) {
+ case MapType.Quake2:
+ case MapType.SoF:
+ case MapType.Daikatana:
+ case MapType.SiN: {
+ return new TextureInfo(new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8)),
+ new Vector3d(BitConverter.ToSingle(data, 16), BitConverter.ToSingle(data, 20), BitConverter.ToSingle(data, 24)),
+ new Vector2d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 28)),
+ Vector2d.one,
+ -1, -1, 0);
+ }
+ default: {
+ return null;
+ }
+ }
+ }
+ set {
+ switch (type) {
+ case MapType.Quake2:
+ case MapType.SoF:
+ case MapType.Daikatana:
+ case MapType.SiN: {
+ byte[] bytes = value.uAxis.GetBytes();
+ bytes.CopyTo(data, 0);
+ bytes = value.vAxis.GetBytes();
+ bytes.CopyTo(data, 16);
+ bytes = BitConverter.GetBytes(value.translation.x);
+ bytes.CopyTo(data, 12);
+ bytes = BitConverter.GetBytes(value.translation.y);
+ bytes.CopyTo(data, 28);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -38,79 +293,13 @@ namespace LibBSP {
/// 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, int version = 0) : this() {
if (data == null) {
throw new ArgumentNullException();
}
- name = "";
- mask = "ignore";
- flags = 0;
- contents = 0;
- switch (type) {
- case MapType.Quake:
- case MapType.Nightfire: {
- name = data.ToNullTerminatedString();
- break;
- }
- case MapType.Quake2:
- case MapType.SoF:
- case MapType.Daikatana: {
- texAxes = new TextureInfo(new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8)),
- new Vector3d(BitConverter.ToSingle(data, 16), BitConverter.ToSingle(data, 20), BitConverter.ToSingle(data, 24)),
- new Vector2d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 28)),
- Vector2d.one,
- -1, -1, 0);
- flags = BitConverter.ToInt32(data, 32);
- name = data.ToNullTerminatedString(40, 32);
- break;
- }
- case MapType.MOHAA: {
- mask = data.ToNullTerminatedString(76, 64);
- goto case MapType.STEF2;
- }
- case MapType.STEF2:
- case MapType.STEF2Demo:
- case MapType.Raven:
- case MapType.Quake3:
- case MapType.CoD:
- case MapType.CoD2:
- case MapType.CoD4:
- case MapType.FAKK: {
- name = data.ToNullTerminatedString(0, 64);
- flags = BitConverter.ToInt32(data, 64);
- contents = BitConverter.ToInt32(data, 68);
- break;
- }
- 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.TacticalInterventionEncrypted:
- case MapType.Vindictus:
- case MapType.DMoMaM: {
- name = data.ToRawString();
- break;
- }
- case MapType.SiN: {
- texAxes = new TextureInfo(new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8)),
- new Vector3d(BitConverter.ToSingle(data, 16), BitConverter.ToSingle(data, 20), BitConverter.ToSingle(data, 24)),
- new Vector2d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 28)),
- Vector2d.one,
- -1, -1, 0);
- flags = BitConverter.ToInt32(data, 32);
- name = data.ToNullTerminatedString(36, 64);
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the Texture class.");
- }
- }
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
diff --git a/LibBSP/Source/Structs/BSP/TextureData.cs b/LibBSP/Source/Structs/BSP/TextureData.cs
index 5f933d2..5eb9bc7 100644
--- a/LibBSP/Source/Structs/BSP/TextureData.cs
+++ b/LibBSP/Source/Structs/BSP/TextureData.cs
@@ -18,12 +18,63 @@ namespace LibBSP {
///
public struct TextureData {
- public Vector3d reflectivity { get; private set; }
- public int stringTableIndex { get; private set; }
- public int width { get; private set; }
- public int height { get; private set; }
- public int view_width { get; private set; }
- public int view_height { get; private set; }
+ public byte[] data;
+ public MapType type;
+ public int version;
+
+ public Vector3d reflectivity {
+ get {
+ return new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
+ }
+ set {
+ value.GetBytes().CopyTo(data, 0);
+ }
+ }
+
+ public int stringTableIndex {
+ get {
+ return BitConverter.ToInt32(data, 12);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 12);
+ }
+ }
+
+ public int width {
+ get {
+ return BitConverter.ToInt32(data, 16);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 16);
+ }
+ }
+
+ public int height {
+ get {
+ return BitConverter.ToInt32(data, 20);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 20);
+ }
+ }
+
+ public int view_width {
+ get {
+ return BitConverter.ToInt32(data, 24);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 24);
+ }
+ }
+
+ public int view_height {
+ get {
+ return BitConverter.ToInt32(data, 28);
+ }
+ set {
+ BitConverter.GetBytes(value).CopyTo(data, 28);
+ }
+ }
///
/// Creates a new object from a byte array.
@@ -36,12 +87,9 @@ namespace LibBSP {
if (data == null) {
throw new ArgumentNullException();
}
- reflectivity = new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
- stringTableIndex = BitConverter.ToInt32(data, 12);
- width = BitConverter.ToInt32(data, 16);
- height = BitConverter.ToInt32(data, 20);
- view_width = BitConverter.ToInt32(data, 24);
- view_height = BitConverter.ToInt32(data, 28);
+ this.data = data;
+ this.type = type;
+ this.version = version;
}
///
@@ -59,8 +107,8 @@ namespace LibBSP {
int structLength = 32;
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; i++) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new TextureData(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/Common/Entity.cs b/LibBSP/Source/Structs/Common/Entity.cs
index e435990..0d7091d 100644
--- a/LibBSP/Source/Structs/Common/Entity.cs
+++ b/LibBSP/Source/Structs/Common/Entity.cs
@@ -420,7 +420,7 @@ namespace LibBSP {
///
/// Clears the bits in "spawnflags" which are set in .
- /// Equivalent to spawnflags = ( ^ 0xFFFFFFFF) & spawnflags.
+ /// Equivalent to spawnflags = ( ^ 0xFFFFFFFF) & spawnflags.
///
/// Bitmask of bits to clear.
public void ClearSpawnflags(uint bits) {
@@ -524,9 +524,9 @@ namespace LibBSP {
#region ISerializable
///
/// Implements the ISerializable interface and returns the data needed
- /// to serialize the instance.
+ /// to serialize the instance.
///
- /// A SerializationInfo object that contains the information required to serialize the instance.
+ /// A SerializationInfo object that contains the information required to serialize the instance.
/// A StreamingContext structure that contains the source and destination of the serialized stream associated with the instance.
public override void GetObjectData(SerializationInfo info, StreamingContext context) {
base.GetObjectData(info, context);
diff --git a/LibBSP/Source/Structs/Common/Lumps/NumList.cs b/LibBSP/Source/Structs/Common/Lumps/NumList.cs
index 04676e5..47bc5b9 100644
--- a/LibBSP/Source/Structs/Common/Lumps/NumList.cs
+++ b/LibBSP/Source/Structs/Common/Lumps/NumList.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Generic;
namespace LibBSP {
@@ -6,8 +7,11 @@ namespace LibBSP {
///
/// List class for numbers. Can handle any integer data type except ulong.
///
- public class NumList : List {
+ public class NumList : IList, ICollection, IEnumerable, IList, ICollection, IEnumerable {
+ ///
+ /// Enum of the types that may be used in this class.
+ ///
public enum DataType : int {
Invalid = 0,
SByte = 1,
@@ -19,6 +23,7 @@ namespace LibBSP {
Int64 = 7,
}
+ public byte[] data;
public DataType type { get; private set; }
///
@@ -27,61 +32,21 @@ namespace LibBSP {
/// byte array to parse.
/// The type of number to store.
/// was null.
- /// was not a member of the DataType enum.
public NumList(byte[] data, DataType type) {
if (data == null) {
throw new ArgumentNullException();
}
+ this.data = data;
+ this.type = type;
+ }
+
+ ///
+ /// Creates an empty object.
+ ///
+ /// The type of number to store.
+ public NumList(DataType type) {
+ this.data = new byte[0];
this.type = type;
- switch (type) {
- case DataType.SByte: {
- unchecked {
- for (int i = 0; i < data.Length; ++i) {
- Add((long)((sbyte)data[i]));
- }
- }
- break;
- }
- case DataType.Byte: {
- for (int i = 0; i < data.Length; ++i) {
- Add((long)(data[i]));
- }
- break;
- }
- case DataType.Int16: {
- for (int i = 0; i < data.Length / 2; ++i) {
- Add((long)BitConverter.ToInt16(data, i * 2));
- }
- break;
- }
- case DataType.UInt16: {
- for (int i = 0; i < data.Length / 2; ++i) {
- Add((long)BitConverter.ToUInt16(data, i * 2));
- }
- break;
- }
- case DataType.Int32: {
- for (int i = 0; i < data.Length / 4; ++i) {
- Add((long)BitConverter.ToInt32(data, i * 4));
- }
- break;
- }
- case DataType.UInt32: {
- for (int i = 0; i < data.Length / 4; ++i) {
- Add((long)BitConverter.ToUInt32(data, i * 4));
- }
- break;
- }
- case DataType.Int64: {
- for (int i = 0; i < data.Length / 8; ++i) {
- Add(BitConverter.ToInt64(data, i * 8));
- }
- break;
- }
- default: {
- throw new ArgumentException(type + " isn't a member of the DataType enum.");
- }
- }
}
///
@@ -94,6 +59,34 @@ namespace LibBSP {
return new NumList(data, type);
}
+ ///
+ /// Gets the length, in bytes, of the numerical primitive used by this instance of this class.
+ ///
+ public int StructLength {
+ get {
+ switch (type) {
+ case DataType.Byte:
+ case DataType.SByte: {
+ return 1;
+ }
+ case DataType.UInt16:
+ case DataType.Int16: {
+ return 2;
+ }
+ case DataType.UInt32:
+ case DataType.Int32: {
+ return 4;
+ }
+ case DataType.Int64: {
+ return 8;
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ }
+
#region IndicesForLumps
///
/// Gets the index for the Mark Surfaces lump in the BSP file for a specific map format, and the type of data the format uses.
@@ -248,6 +241,10 @@ namespace LibBSP {
dataType = DataType.UInt32;
return 22;
}
+ case MapType.CoD2: {
+ dataType = DataType.UInt32;
+ return 27;
+ }
}
dataType = DataType.Invalid;
return -1;
@@ -279,6 +276,10 @@ namespace LibBSP {
dataType = DataType.UInt16;
return 8;
}
+ case MapType.CoD2: {
+ dataType = DataType.UInt16;
+ return 9;
+ }
case MapType.Raven:
case MapType.Quake3: {
dataType = DataType.UInt32;
@@ -362,5 +363,228 @@ namespace LibBSP {
return -1;
}
#endregion
+
+ #region ICollection
+ public void Add(long value) {
+ byte[] temp = new byte[data.Length + StructLength];
+ Array.Copy(data, 0, temp, 0, data.Length);
+ byte[] bytes = BitConverter.GetBytes(value);
+ Array.Copy(bytes, 0, temp, data.Length, StructLength);
+ data = temp;
+ }
+
+ public void Clear() {
+ data = new byte[0];
+ }
+
+ public bool Contains(long value) {
+ foreach (long curr in this) {
+ if (curr == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void CopyTo(long[] array, int arrayIndex) {
+ for (int i = 0; i < Count; ++i) {
+ array[i + arrayIndex] = this[i];
+ }
+ }
+
+ void ICollection.CopyTo(Array array, int arrayIndex) {
+ for (int i = 0; i < Count; ++i) {
+ array.SetValue(this[i], i + arrayIndex);
+ }
+ }
+
+ public bool Remove(long value) {
+ for (int i = 0; i < Count; ++i) {
+ if (this[i] == value) {
+ RemoveAt(i);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public int Count {
+ get {
+ return data.Length / StructLength;
+ }
+ }
+
+ public bool IsReadOnly {
+ get {
+ return false;
+ }
+ }
+
+ public object SyncRoot {
+ get {
+ return data.SyncRoot;
+ }
+ }
+
+ public bool IsSynchronized {
+ get { return data.IsSynchronized; }
+ }
+ #endregion
+
+ #region IEnumerable
+ public IEnumerator GetEnumerator() {
+ for (int i = 0; i < Count; ++i) {
+ yield return this[i];
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() {
+ for (int i = 0; i < Count; ++i) {
+ yield return this[i];
+ }
+ }
+ #endregion
+
+ #region IList
+ public int Add(object obj) {
+ if (obj is byte || obj is sbyte || obj is short || obj is ushort || obj is int || obj is uint || obj is long) {
+ Add((long)obj);
+ return Count - 1;
+ }
+
+ return -1;
+ }
+
+ public bool Contains(object obj) {
+ if (obj is byte || obj is sbyte || obj is short || obj is ushort || obj is int || obj is uint || obj is long) {
+ return Contains((long)obj);
+ }
+
+ return false;
+ }
+
+ public int IndexOf(object obj) {
+ if (obj is byte || obj is sbyte || obj is short || obj is ushort || obj is int || obj is uint || obj is long) {
+ return IndexOf((long)obj);
+ }
+
+ return -1;
+ }
+
+ public void Insert(int index, object obj) {
+ if (obj is byte || obj is sbyte || obj is short || obj is ushort || obj is int || obj is uint || obj is long) {
+ Insert(index, (long)obj);
+ }
+ }
+
+ public void Remove(object obj) {
+ if (obj is byte || obj is sbyte || obj is short || obj is ushort || obj is int || obj is uint || obj is long) {
+ Remove((long)obj);
+ }
+ }
+
+ public int IndexOf(long value) {
+ for (int i = 0; i < Count; ++i) {
+ if (this[i] == value) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ object IList.this[int index] {
+ get {
+ return this[index];
+ }
+ set {
+ if (value is byte || value is sbyte || value is short || value is ushort || value is int || value is uint || value is long) {
+ this[index] = (long)value;
+ }
+ }
+ }
+
+ public bool IsFixedSize {
+ get {
+ return false;
+ }
+ }
+
+ public void Insert(int index, long value) {
+ byte[] temp = new byte[data.Length + StructLength];
+ Array.Copy(data, 0, temp, 0, StructLength * index);
+ byte[] bytes = BitConverter.GetBytes(value);
+ Array.Copy(bytes, 0, temp, StructLength * index, StructLength);
+ Array.Copy(data, StructLength * index, temp, StructLength * (index + 1), data.Length - StructLength * index);
+ data = temp;
+ }
+
+ public void RemoveAt(int index) {
+ byte[] temp = new byte[data.Length - StructLength];
+ Array.Copy(data, 0, temp, 0, StructLength * index);
+ Array.Copy(data, StructLength * (index + 1), temp, StructLength * index, data.Length - (StructLength * (index + 1)));
+ data = temp;
+ }
+
+ public long this[int index] {
+ get {
+ switch (type) {
+ case DataType.SByte: {
+ return (sbyte)data[index];
+ }
+ case DataType.Byte: {
+ return data[index];
+ }
+ case DataType.Int16: {
+ return BitConverter.ToInt16(data, index * 2);
+ }
+ case DataType.UInt16: {
+ return BitConverter.ToUInt16(data, index * 2);
+ }
+ case DataType.Int32: {
+ return BitConverter.ToInt32(data, index * 4);
+ }
+ case DataType.UInt32: {
+ return BitConverter.ToUInt32(data, index * 4);
+ }
+ case DataType.Int64: {
+ return BitConverter.ToInt64(data, index * 8);
+ }
+ default: {
+ return 0;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ case DataType.SByte:
+ case DataType.Byte: {
+ data[index] = bytes[0];
+ break;
+ }
+ case DataType.Int16:
+ case DataType.UInt16: {
+ data[index * 2] = bytes[0];
+ data[(index * 2) + 1] = bytes[1];
+ break;
+ }
+ case DataType.Int32:
+ case DataType.UInt32: {
+ data[index * 4] = bytes[0];
+ data[(index * 4) + 1] = bytes[1];
+ data[(index * 4) + 2] = bytes[2];
+ data[(index * 4) + 3] = bytes[3];
+ break;
+ }
+ case DataType.Int64: {
+ bytes.CopyTo(data, index * 8);
+ break;
+ }
+ }
+ }
+ }
+ #endregion
}
}
diff --git a/LibBSP/Source/Structs/Common/TextureInfo.cs b/LibBSP/Source/Structs/Common/TextureInfo.cs
index dcc062b..5fce0a2 100644
--- a/LibBSP/Source/Structs/Common/TextureInfo.cs
+++ b/LibBSP/Source/Structs/Common/TextureInfo.cs
@@ -21,36 +21,169 @@ namespace LibBSP {
///
[Serializable] public class TextureInfo {
- public const int S = 0;
- public const int T = 1;
- ///
- /// Array of base texture axes. When referenced properly, provides a good default texture axis for any given plane.
- ///
- public static readonly Vector3d[] baseAxes = new Vector3d[] {
- new Vector3d(0, 0, 1), new Vector3d(1, 0, 0), new Vector3d(0, -1, 0),
- new Vector3d(0, 0, -1), new Vector3d(1, 0, 0), new Vector3d(0, -1, 0),
- new Vector3d(1, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, -1),
- new Vector3d(-1, 0, 0), new Vector3d(0, 1, 0), new Vector3d(0, 0, -1),
- new Vector3d(0, 1, 0), new Vector3d(1, 0, 0), new Vector3d(0, 0, -1),
- new Vector3d(0, -1, 0), new Vector3d(1, 0, 0), new Vector3d(0, 0, -1)
- };
+ public byte[] data;
+ public MapType type;
+ public int version;
- public Vector3d[] axes;
- public Vector2d translation;
- public Vector2d scale;
- public int flags;
- public int texture;
- public double rotation;
+ // No BSP format uses these so they are fields.
+ public Vector2d scale = Vector2d.one;
+ public double rotation = 0;
+
+ public Vector3d uAxis {
+ get {
+ return new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
+ }
+ set {
+ value.GetBytes().CopyTo(data, 0);
+ }
+ }
+
+ public Vector3d vAxis {
+ get {
+ return new Vector3d(BitConverter.ToSingle(data, 16), BitConverter.ToSingle(data, 20), BitConverter.ToSingle(data, 24));
+ }
+ set {
+ value.GetBytes().CopyTo(data, 16);
+ }
+ }
+
+ public Vector2d translation {
+ get {
+ return new Vector2d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 28));
+ }
+ set {
+ BitConverter.GetBytes((float)value.x).CopyTo(data, 12);
+ BitConverter.GetBytes((float)value.y).CopyTo(data, 28);
+ }
+ }
+
+ public int flags {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 64);
+ }
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt32(data, 88);
+ }
+ case MapType.Quake: {
+ return BitConverter.ToInt32(data, 36);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 64);
+ break;
+ }
+ case MapType.DMoMaM: {
+ bytes.CopyTo(data, 88);
+ break;
+ }
+ case MapType.Quake: {
+ bytes.CopyTo(data, 36);
+ break;
+ }
+ }
+ }
+ }
+
+ public int texture {
+ get {
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus: {
+ return BitConverter.ToInt32(data, 68);
+ }
+ case MapType.DMoMaM: {
+ return BitConverter.ToInt32(data, 92);
+ }
+ case MapType.Quake: {
+ return BitConverter.ToInt32(data, 32);
+ }
+ default: {
+ return -1;
+ }
+ }
+ }
+ set {
+ byte[] bytes = BitConverter.GetBytes(value);
+ switch (type) {
+ 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.TacticalInterventionEncrypted:
+ case MapType.Vindictus: {
+ bytes.CopyTo(data, 68);
+ break;
+ }
+ case MapType.DMoMaM: {
+ bytes.CopyTo(data, 92);
+ break;
+ }
+ case MapType.Quake: {
+ bytes.CopyTo(data, 32);
+ break;
+ }
+ }
+ }
+ }
///
/// Creates a new object with sensible defaults.
///
public TextureInfo() {
- axes = new Vector3d[2];
+ data = new byte[40];
+ type = MapType.Quake;
+ version = 0;
+
+ uAxis = Vector3d.zero;
+ vAxis = Vector3d.zero;
translation = Vector2d.zero;
- scale = Vector2d.one;
flags = 0;
- texture = 0;
+ texture = -1;
+
+ scale = Vector2d.one;
rotation = 0;
}
@@ -61,70 +194,35 @@ namespace LibBSP {
/// 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, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
- texture = -1;
- flags = -1;
- axes = new Vector3d[2];
- translation = new Vector2d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 28));
- axes[S] = new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
- axes[T] = new Vector3d(BitConverter.ToSingle(data, 16), BitConverter.ToSingle(data, 20), BitConverter.ToSingle(data, 24));
- // Texture scaling information is compiled into the axes by changing their length.
+ this.data = data;
+ this.type = type;
+ this.version = version;
+
scale = Vector2d.one;
rotation = 0;
- switch (type) {
- // Excluded engines: Quake 2-based, Quake 3-based
- 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.TacticalInterventionEncrypted:
- case MapType.Vindictus: {
- texture = BitConverter.ToInt32(data, 68);
- flags = BitConverter.ToInt32(data, 64);
- break;
- }
- case MapType.DMoMaM: {
- texture = BitConverter.ToInt32(data, 92);
- flags = BitConverter.ToInt32(data, 88);
- break;
- }
- case MapType.Quake: {
- texture = BitConverter.ToInt32(data, 32);
- flags = BitConverter.ToInt32(data, 36);
- break;
- }
- case MapType.Nightfire: {
- break;
- }
- default: {
- throw new ArgumentException("Map type " + type + " isn't supported by the TextureInfo class.");
- }
- }
}
///
/// Creates a new object using the passed data.
///
- /// The S texture axis.
- /// The T texture axis.
+ /// The U texture axis.
+ /// The V texture axis.
/// Texture translation along both axes (in pixels).
/// Texture scale along both axes.
/// The flags for this .
/// Index into the texture list for the texture this uses.
/// Rotation of the texutre axes.
- public TextureInfo(Vector3d s, Vector3d t, Vector2d translation, Vector2d scale, int flags, int texture, double rotation) {
- axes = new Vector3d[2];
- axes[S] = s;
- axes[T] = t;
+ public TextureInfo(Vector3d u, Vector3d v, Vector2d translation, Vector2d scale, int flags, int texture, double rotation) {
+ data = new byte[40];
+ type = MapType.Quake;
+ version = 0;
+
+ uAxis = u;
+ vAxis = v;
this.translation = translation;
this.scale = scale;
this.flags = flags;
@@ -138,19 +236,10 @@ namespace LibBSP {
/// of the surface.
/// The best matching texture axes for the given .
public static Vector3d[] TextureAxisFromPlane(Plane p) {
- int bestaxis = 0;
- double best = 0; // "Best" dot product so far
- for (int i = 0; i < 6; ++i) {
- // For all possible axes, positive and negative
- double dot = Vector3d.Dot(p.normal, new Vector3d(baseAxes[i * 3][0], baseAxes[i * 3][1], baseAxes[i * 3][2]));
- if (dot > best) {
- best = dot;
- bestaxis = i;
- }
- }
+ int bestaxis = p.BestAxis();
Vector3d[] newAxes = new Vector3d[2];
- newAxes[0] = new Vector3d(baseAxes[bestaxis * 3 + 1][0], baseAxes[bestaxis * 3 + 1][1], baseAxes[bestaxis * 3 + 1][2]);
- newAxes[1] = new Vector3d(baseAxes[bestaxis * 3 + 2][0], baseAxes[bestaxis * 3 + 2][1], baseAxes[bestaxis * 3 + 2][2]);
+ newAxes[0] = PlaneExtensions.baseAxes[bestaxis * 3 + 1];
+ newAxes[1] = PlaneExtensions.baseAxes[bestaxis * 3 + 2];
return newAxes;
}
@@ -201,8 +290,8 @@ namespace LibBSP {
}
int numObjects = data.Length / structLength;
List lump = new List(numObjects);
- byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
+ byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
lump.Add(new TextureInfo(bytes, type, version));
}
diff --git a/LibBSP/Source/Structs/MAP/MAPBrushSide.cs b/LibBSP/Source/Structs/MAP/MAPBrushSide.cs
index ee1e894..e57dd4d 100644
--- a/LibBSP/Source/Structs/MAP/MAPBrushSide.cs
+++ b/LibBSP/Source/Structs/MAP/MAPBrushSide.cs
@@ -124,7 +124,7 @@ namespace LibBSP {
string[] split = tokens[1].SplitUnlessBetweenDelimiters(' ', '[', ']', StringSplitOptions.RemoveEmptyEntries);
textureInfo.scale = new Vector2d(float.Parse(split[1], _format), textureInfo.scale.y);
split = split[0].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
- textureInfo.axes[0] = new Vector3d(float.Parse(split[0], _format), float.Parse(split[1], _format), float.Parse(split[2], _format));
+ textureInfo.uAxis = new Vector3d(float.Parse(split[0], _format), float.Parse(split[1], _format), float.Parse(split[2], _format));
textureInfo.translation = new Vector2d(float.Parse(split[3], _format), textureInfo.translation.y);
break;
}
@@ -132,7 +132,7 @@ namespace LibBSP {
string[] split = tokens[1].SplitUnlessBetweenDelimiters(' ', '[', ']', StringSplitOptions.RemoveEmptyEntries);
textureInfo.scale = new Vector2d(textureInfo.scale.x, float.Parse(split[1], _format));
split = split[0].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
- textureInfo.axes[1] = new Vector3d(float.Parse(split[0], _format), float.Parse(split[1], _format), float.Parse(split[2], _format));
+ textureInfo.vAxis = new Vector3d(float.Parse(split[0], _format), float.Parse(split[1], _format), float.Parse(split[2], _format));
textureInfo.translation = new Vector2d(textureInfo.translation.x, float.Parse(split[3], _format));
break;
}