Refactors to reuse some commonly used code. This changes a lot.

Refactor everything to use a base ILump interface, and a Lump class implementing it to use in place of regular List.
Refactor lump structures to use an ILumpObject interface. Eventually Lump<T> will enforce T is ILumpObject, there are some other things to do first.
Use Path class to simplify some code in BSP.
This commit is contained in:
wfowler
2019-07-16 02:55:07 -06:00
parent 43ebf69f01
commit 864a6dab6b
33 changed files with 2449 additions and 1627 deletions

View File

@@ -74,6 +74,9 @@
<Compile Include="Source\Structs\BSP\StaticModel.cs" />
<Compile Include="Source\Structs\BSP\StaticProp.cs" />
<Compile Include="Source\Structs\BSP\TextureData.cs" />
<Compile Include="Source\Structs\Common\ILumpObject.cs" />
<Compile Include="Source\Structs\Common\Lumps\ILump.cs" />
<Compile Include="Source\Structs\Common\Lumps\Lump.cs" />
<Compile Include="Source\Structs\Common\TextureInfo.cs" />
<Compile Include="Source\Structs\BSP\Texture.cs" />
<Compile Include="Source\Structs\Common\Entity.cs" />

View File

@@ -329,22 +329,22 @@ namespace LibBSP {
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="Plane"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{Plane}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="Plane"/> objects.</returns>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{Plane}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was null.</exception>
/// <remarks>This function goes here since it can't go into Unity's Plane class, and so can't depend
/// on having a constructor taking a byte array.</remarks>
public static List<Plane> LumpFactory(byte[] data, MapType type, int version = 0) {
public static Lump<Plane> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = GetStructLength(type, version);
int structLength = GetStructLength(bsp.version, lumpInfo.version);
int numObjects = data.Length / structLength;
List<Plane> lump = new List<Plane>(numObjects);
Lump<Plane> lump = new Lump<Plane>(numObjects, bsp, lumpInfo);
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);

View File

@@ -190,27 +190,26 @@ namespace LibBSP {
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="Vertex"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{Vertex}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="Vertex"/> objects.</returns>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{Vertex}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
/// <remarks>This function goes here since it can't be in Unity's <c>UIVertex</c> class, and so I can't
/// depend on having a constructor taking a byte array.</remarks>
public static List<Vertex> LumpFactory(byte[] data, MapType type, int version = 0) {
public static Lump<Vertex> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = GetStructLength(type, version);
int structLength = GetStructLength(bsp.version, lumpInfo.version);
int numObjects = data.Length / structLength;
List<Vertex> lump = new List<Vertex>(numObjects);
Lump<Vertex> lump = new Lump<Vertex>(numObjects, bsp, lumpInfo);
byte[] bytes = new byte[structLength];
for (int i = 0; i < numObjects; ++i) {
Array.Copy(data, i * structLength, bytes, 0, structLength);
lump.Add(CreateVertex(bytes, type, version));
lump.Add(CreateVertex(bytes, bsp.version, lumpInfo.version));
}
return lump;
}

View File

@@ -59,9 +59,9 @@ namespace LibBSP {
}
/// <summary>
/// Class containing basic information for a lump in a BSP file.
/// Struct containing basic information for a lump in a BSP file.
/// </summary>
public class LumpInfo {
public struct LumpInfo {
public int ident;
public int flags;
public int version;
@@ -81,41 +81,41 @@ namespace LibBSP {
// Map structures
// Quake 1/GoldSrc
private Entities _entities;
private List<Plane> _planes;
private Lump<Plane> _planes;
private Textures _textures;
private List<Vertex> _vertices;
private List<Node> _nodes;
private List<TextureInfo> _texInfo;
private List<Face> _faces;
private List<Leaf> _leaves;
private Lump<Vertex> _vertices;
private Lump<Node> _nodes;
private Lump<TextureInfo> _texInfo;
private Lump<Face> _faces;
private Lump<Leaf> _leaves;
private NumList _markSurfaces;
private List<Edge> _edges;
private Lump<Edge> _edges;
private NumList _surfEdges;
private List<Model> _models;
private Lump<Model> _models;
// public byte[] pvs;
// Quake 2
private List<Brush> _brushes;
private List<BrushSide> _brushSides;
private Lump<Brush> _brushes;
private Lump<BrushSide> _brushSides;
private NumList _markBrushes;
// MoHAA
private List<LODTerrain> _lodTerrains;
private List<StaticModel> _staticModels;
private Lump<LODTerrain> _lodTerrains;
private Lump<StaticModel> _staticModels;
// CoD
private List<Patch> _patches;
private List<Vertex> _patchVerts;
private Lump<Patch> _patches;
private Lump<Vertex> _patchVerts;
private NumList _patchIndices;
// Nightfire
private Textures _materials;
private NumList _indices;
// Source
private List<Face> _originalFaces;
private Lump<Face> _originalFaces;
private NumList _texTable;
private List<TextureData> _texDatas;
private List<DisplacementInfo> _dispInfos;
private Lump<TextureData> _texDatas;
private Lump<DisplacementInfo> _dispInfos;
private DisplacementVertices _dispVerts;
private NumList _displacementTriangles;
// public SourceOverlays overlays;
private List<Cubemap> _cubemaps;
private Lump<Cubemap> _cubemaps;
private GameLump _gameLump;
private StaticProps _staticProps;
@@ -152,7 +152,7 @@ namespace LibBSP {
if (_entities == null) {
int index = Entity.GetIndexForLump(version);
if (index >= 0) {
_entities = Entity.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_entities = Entity.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _entities;
@@ -160,14 +160,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Plane"/> objects in the BSP file, if available.
/// A <see cref="Lump{Plane}"/> of <see cref="Plane"/> objects in the BSP file, if available.
/// </summary>
public List<Plane> planes {
public Lump<Plane> planes {
get {
if (_planes == null) {
int index = PlaneExtensions.GetIndexForLump(version);
if (index >= 0) {
_planes = PlaneExtensions.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_planes = PlaneExtensions.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _planes;
@@ -182,7 +182,7 @@ namespace LibBSP {
if (_textures == null) {
int index = Texture.GetIndexForLump(version);
if (index >= 0) {
_textures = Texture.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_textures = Texture.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _textures;
@@ -190,14 +190,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Vertex"/> objects in the BSP file representing the vertices of the BSP, if available.
/// A <see cref="Lump{Vertex}"/> of <see cref="Vertex"/> objects in the BSP file representing the vertices of the BSP, if available.
/// </summary>
public List<Vertex> vertices {
public Lump<Vertex> vertices {
get {
if (_vertices == null) {
int index = VertexExtensions.GetIndexForLump(version);
if (index >= 0) {
_vertices = VertexExtensions.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_vertices = VertexExtensions.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _vertices;
@@ -205,14 +205,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Node"/> objects in the BSP file, if available.
/// A <see cref="Lump{Node}"/> of <see cref="Node"/> objects in the BSP file, if available.
/// </summary>
public List<Node> nodes {
public Lump<Node> nodes {
get {
if (_nodes == null) {
int index = Node.GetIndexForLump(version);
if (index >= 0) {
_nodes = Node.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_nodes = Node.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _nodes;
@@ -220,14 +220,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="TextureInfo"/> objects in the BSP file, if available.
/// A <see cref="Lump{TextureInfo}"/> of <see cref="TextureInfo"/> objects in the BSP file, if available.
/// </summary>
public List<TextureInfo> texInfo {
public Lump<TextureInfo> texInfo {
get {
if (_texInfo == null) {
int index = TextureInfo.GetIndexForLump(version);
if (index >= 0) {
_texInfo = TextureInfo.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_texInfo = TextureInfo.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _texInfo;
@@ -235,14 +235,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Face"/> objects in the BSP file, if available.
/// A <see cref="Lump{Face}"/> of <see cref="Face"/> objects in the BSP file, if available.
/// </summary>
public List<Face> faces {
public Lump<Face> faces {
get {
if (_faces == null) {
int index = Face.GetIndexForLump(version);
if (index >= 0) {
_faces = Face.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_faces = Face.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _faces;
@@ -250,14 +250,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Leaf"/> objects in the BSP file, if available.
/// A <see cref="Lump{Leaf}"/> of <see cref="Leaf"/> objects in the BSP file, if available.
/// </summary>
public List<Leaf> leaves {
public Lump<Leaf> leaves {
get {
if (_leaves == null) {
int index = Leaf.GetIndexForLump(version);
if (index >= 0) {
_leaves = Leaf.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_leaves = Leaf.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _leaves;
@@ -265,14 +265,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Edge"/> objects in the BSP file, if available.
/// A <see cref="Lump{Edge}"/> of <see cref="Edge"/> objects in the BSP file, if available.
/// </summary>
public List<Edge> edges {
public Lump<Edge> edges {
get {
if (_edges == null) {
int index = Edge.GetIndexForLump(version);
if (index >= 0) {
_edges = Edge.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_edges = Edge.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _edges;
@@ -280,14 +280,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Model"/> objects in the BSP file, if available.
/// A <see cref="Lump{Model}"/> of <see cref="Model"/> objects in the BSP file, if available.
/// </summary>
public List<Model> models {
public Lump<Model> models {
get {
if (_models == null) {
int index = Model.GetIndexForLump(version);
if (index >= 0) {
_models = Model.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_models = Model.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _models;
@@ -295,14 +295,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Brush"/> objects in the BSP file, if available.
/// A <see cref="Lump{Brush}"/> of <see cref="Brush"/> objects in the BSP file, if available.
/// </summary>
public List<Brush> brushes {
public Lump<Brush> brushes {
get {
if (_brushes == null) {
int index = Brush.GetIndexForLump(version);
if (index >= 0) {
_brushes = Brush.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_brushes = Brush.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _brushes;
@@ -310,14 +310,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="BrushSide"/> objects in the BSP file, if available.
/// A <see cref="Lump{BrushSide}"/> of <see cref="BrushSide"/> objects in the BSP file, if available.
/// </summary>
public List<BrushSide> brushSides {
public Lump<BrushSide> brushSides {
get {
if (_brushSides == null) {
int index = BrushSide.GetIndexForLump(version);
if (index >= 0) {
_brushSides = BrushSide.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_brushSides = BrushSide.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _brushSides;
@@ -325,14 +325,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Texture"/> objects in the BSP file representing Materials (shaders), if available.
/// A <see cref="Textures"/> object representing Materials (shaders), if available.
/// </summary>
public Textures materials {
get {
if (_materials == null) {
int index = Texture.GetIndexForMaterialLump(version);
if (index >= 0) {
_materials = Texture.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_materials = Texture.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _materials;
@@ -340,14 +340,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Face"/> objects in the BSP file representing the Original Faces, if available.
/// A <see cref="Lump{Face}"/> of <see cref="Face"/> objects in the BSP file representing the Original Faces, if available.
/// </summary>
public List<Face> originalFaces {
public Lump<Face> originalFaces {
get {
if (_originalFaces == null) {
int index = Face.GetIndexForOriginalFacesLump(version);
if (index >= 0) {
_originalFaces = Face.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_originalFaces = Face.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _originalFaces;
@@ -355,14 +355,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="TextureData"/> objects in the BSP file, if available.
/// A <see cref="Lump{TextureData}"/> of <see cref="TextureData"/> objects in the BSP file, if available.
/// </summary>
public List<TextureData> texDatas {
public Lump<TextureData> texDatas {
get {
if (_texDatas == null) {
int index = TextureData.GetIndexForLump(version);
if (index >= 0) {
_texDatas = TextureData.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_texDatas = TextureData.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _texDatas;
@@ -370,14 +370,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="DisplacementInfo"/> objects in the BSP file, if available.
/// A <see cref="Lump{DisplacementInfo}"/> of <see cref="DisplacementInfo"/> objects in the BSP file, if available.
/// </summary>
public List<DisplacementInfo> dispInfos {
public Lump<DisplacementInfo> dispInfos {
get {
if (_dispInfos == null) {
int index = DisplacementInfo.GetIndexForLump(version);
if (index >= 0) {
_dispInfos = DisplacementInfo.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_dispInfos = DisplacementInfo.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _dispInfos;
@@ -392,7 +392,7 @@ namespace LibBSP {
if (_dispVerts == null) {
int index = DisplacementVertex.GetIndexForLump(version);
if (index >= 0) {
_dispVerts = DisplacementVertex.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_dispVerts = DisplacementVertex.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _dispVerts;
@@ -400,14 +400,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Cubemap"/> objects in the BSP file, if available.
/// A <see cref="Lump{Cubemap}"/> of <see cref="Cubemap"/> objects in the BSP file, if available.
/// </summary>
public List<Cubemap> cubemaps {
public Lump<Cubemap> cubemaps {
get {
if (_cubemaps == null) {
int index = Cubemap.GetIndexForLump(version);
if (index >= 0) {
_cubemaps = Cubemap.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_cubemaps = Cubemap.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _cubemaps;
@@ -423,7 +423,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForMarkSurfacesLump(version, out type);
if (index >= 0) {
_markSurfaces = NumList.LumpFactory(reader.ReadLump(this[index]), type);
_markSurfaces = NumList.LumpFactory(reader.ReadLump(this[index]), type, this, this[index]);
}
}
return _markSurfaces;
@@ -439,7 +439,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForSurfEdgesLump(version, out type);
if (index >= 0) {
_surfEdges = NumList.LumpFactory(reader.ReadLump(this[index]), type);
_surfEdges = NumList.LumpFactory(reader.ReadLump(this[index]), type, this, this[index]);
}
}
return _surfEdges;
@@ -455,7 +455,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForMarkBrushesLump(version, out type);
if (index >= 0) {
_markBrushes = NumList.LumpFactory(reader.ReadLump(this[index]), type);
_markBrushes = NumList.LumpFactory(reader.ReadLump(this[index]), type, this, this[index]);
}
}
return _markBrushes;
@@ -463,14 +463,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="StaticModel"/> objects in the BSP file, if available.
/// A <see cref="Lump{StaticModel}"/> of <see cref="StaticModel"/> objects in the BSP file, if available.
/// </summary>
public List<StaticModel> staticModels {
public Lump<StaticModel> staticModels {
get {
if (_staticModels == null) {
int index = StaticModel.GetIndexForLump(version);
if (index >= 0) {
_staticModels = StaticModel.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_staticModels = StaticModel.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _staticModels;
@@ -478,14 +478,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="LODTerrain"/> objects in the BSP file, if available.
/// A <see cref="Lump{LODTerrain}"/> of <see cref="LODTerrain"/> objects in the BSP file, if available.
/// </summary>
public List<LODTerrain> lodTerrains {
public Lump<LODTerrain> lodTerrains {
get {
if (_lodTerrains == null) {
int index = LODTerrain.GetIndexForLump(version);
if (index >= 0) {
_lodTerrains = LODTerrain.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_lodTerrains = LODTerrain.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _lodTerrains;
@@ -493,14 +493,14 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Patch"/> objects in the BSP file, if available.
/// A <see cref="Lump{Patch}"/> of <see cref="Patch"/> objects in the BSP file, if available.
/// </summary>
public List<Patch> patches {
public Lump<Patch> patches {
get {
if (_patches == null) {
int index = Patch.GetIndexForLump(version);
if (index >= 0) {
_patches = Patch.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_patches = Patch.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _patches;
@@ -508,14 +508,17 @@ namespace LibBSP {
}
/// <summary>
/// A <c>List</c> of <see cref="Vertex"/> objects in the BSP file representing the patch vertices of the BSP, if available.
/// A <see cref="Lump{Vertex}"/> of <see cref="Vertex"/> objects in the BSP file representing the patch vertices of the BSP, if available.
/// </summary>
public List<Vertex> patchVerts {
public Lump<Vertex> patchVerts {
get {
if (_patchVerts == null) {
int index = VertexExtensions.GetIndexForPatchVertsLump(version);
if (index >= 0) {
_patchVerts = VertexExtensions.LumpFactory(reader.ReadLump(this[index]), version, 1);
// Hax: CoD maps will read Vertex lump with version 1 as simply Vector3s rather than vertices.
LumpInfo lumpInfo = this[index];
lumpInfo.version = 1;
_patchVerts = VertexExtensions.LumpFactory(reader.ReadLump(this[index]), this, lumpInfo);
}
}
return _patchVerts;
@@ -531,7 +534,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForPatchIndicesLump(version, out type);
if (index >= 0) {
_patchIndices = NumList.LumpFactory(reader.ReadLump(this[index]), type);
_patchIndices = NumList.LumpFactory(reader.ReadLump(this[index]), type, this, this[index]);
}
}
return _patchIndices;
@@ -547,7 +550,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForIndicesLump(version, out type);
if (index >= 0) {
_indices = NumList.LumpFactory(reader.ReadLump(this[index]), type);
_indices = NumList.LumpFactory(reader.ReadLump(this[index]), type, this, this[index]);
}
}
return _indices;
@@ -563,7 +566,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForTexTableLump(version, out type);
if (index >= 0) {
_texTable = NumList.LumpFactory(reader.ReadLump(this[index]), type);
_texTable = NumList.LumpFactory(reader.ReadLump(this[index]), type, this, this[index]);
}
}
return _texTable;
@@ -579,7 +582,7 @@ namespace LibBSP {
NumList.DataType type;
int index = NumList.GetIndexForDisplacementTrianglesLump(version, out type);
if (index >= 0) {
_displacementTriangles = NumList.LumpFactory(reader.ReadLump(this[index]), type);
_displacementTriangles = NumList.LumpFactory(reader.ReadLump(this[index]), type, this, this[index]);
}
}
return _displacementTriangles;
@@ -594,7 +597,7 @@ namespace LibBSP {
if (_gameLump == null) {
int index = GameLump.GetIndexForLump(version);
if (index >= 0) {
_gameLump = GameLump.LumpFactory(reader.ReadLump(this[index]), version, this[index].version);
_gameLump = GameLump.LumpFactory(reader.ReadLump(this[index]), this, this[index]);
}
}
return _gameLump;
@@ -622,7 +625,7 @@ namespace LibBSP {
} else {
thisLump = reader.ReadLump(info);
}
_staticProps = StaticProp.LumpFactory(thisLump, version, info.version);
_staticProps = StaticProp.LumpFactory(thisLump, this, info);
}
}
return _staticProps;
@@ -639,16 +642,7 @@ namespace LibBSP {
/// </summary>
public string MapName {
get {
int i;
for (i = 0; i < filePath.Length; ++i) {
if (filePath[filePath.Length - 1 - i] == '\\') {
break;
}
if (filePath[filePath.Length - 1 - i] == '/') {
break;
}
}
return filePath.Substring(filePath.Length - i, (filePath.Length) - (filePath.Length - i));
return Path.GetFileName(filePath);
}
}
@@ -657,14 +651,7 @@ namespace LibBSP {
/// </summary>
public string MapNameNoExtension {
get {
string name = MapName;
int i;
for (i = 0; i < name.Length; ++i) {
if (name[name.Length - 1 - i] == '.') {
break;
}
}
return name.Substring(0, (name.Length - 1 - i) - (0));
return Path.GetFileNameWithoutExtension(filePath);
}
}
@@ -673,16 +660,7 @@ namespace LibBSP {
/// </summary>
public string Folder {
get {
int i;
for (i = 0; i < filePath.Length; ++i) {
if (filePath[filePath.Length - 1 - i] == '\\') {
break;
}
if (filePath[filePath.Length - 1 - i] == '/') {
break;
}
}
return filePath.Substring(0, (filePath.Length - i) - (0));
return Path.GetDirectoryName(filePath);
}
}

View File

@@ -1,20 +1,51 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
/// <summary>
/// Holds the data used by the brush structures of all formats of BSP.
/// </summary>
public struct Brush {
public struct Brush : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
[Index("brushSides")] public int firstSide {
get {
switch (type) {
switch (MapType) {
case MapType.Quake2:
case MapType.Daikatana:
case MapType.SiN:
@@ -36,11 +67,11 @@ namespace LibBSP {
case MapType.Raven:
case MapType.Quake3:
case MapType.FAKK: {
return BitConverter.ToInt32(data, 0);
return BitConverter.ToInt32(Data, 0);
}
case MapType.Nightfire:
case MapType.STEF2: {
return BitConverter.ToInt32(data, 4);
return BitConverter.ToInt32(Data, 4);
}
default: {
return -1;
@@ -49,7 +80,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Quake2:
case MapType.Daikatana:
case MapType.SiN:
@@ -71,12 +102,12 @@ namespace LibBSP {
case MapType.Raven:
case MapType.Quake3:
case MapType.FAKK: {
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
break;
}
case MapType.Nightfire:
case MapType.STEF2: {
bytes.CopyTo(data, 4);
bytes.CopyTo(Data, 4);
break;
}
}
@@ -85,14 +116,14 @@ namespace LibBSP {
[Count("brushSides")] public int numSides {
get {
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
return BitConverter.ToInt16(data, 0);
return BitConverter.ToInt16(Data, 0);
}
case MapType.STEF2: {
return BitConverter.ToInt32(data, 0);
return BitConverter.ToInt32(Data, 0);
}
case MapType.Quake2:
case MapType.Daikatana:
@@ -115,10 +146,10 @@ namespace LibBSP {
case MapType.Raven:
case MapType.Quake3:
case MapType.FAKK: {
return BitConverter.ToInt32(data, 4);
return BitConverter.ToInt32(Data, 4);
}
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 8);
return BitConverter.ToInt32(Data, 8);
}
default: {
return -1;
@@ -127,16 +158,16 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
data[0] = bytes[0];
data[1] = bytes[1];
Data[0] = bytes[0];
Data[1] = bytes[1];
break;
}
case MapType.STEF2: {
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
break;
}
case MapType.Quake2:
@@ -160,11 +191,11 @@ namespace LibBSP {
case MapType.Raven:
case MapType.Quake3:
case MapType.FAKK: {
bytes.CopyTo(data, 4);
bytes.CopyTo(Data, 4);
break;
}
case MapType.Nightfire: {
bytes.CopyTo(data, 8);
bytes.CopyTo(Data, 8);
break;
}
}
@@ -173,11 +204,11 @@ namespace LibBSP {
public int texture {
get {
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
return BitConverter.ToInt16(data, 2);
return BitConverter.ToInt16(Data, 2);
}
case MapType.MOHAA:
case MapType.STEF2Demo:
@@ -185,7 +216,7 @@ namespace LibBSP {
case MapType.Quake3:
case MapType.FAKK:
case MapType.STEF2: {
return BitConverter.ToInt32(data, 8);
return BitConverter.ToInt32(Data, 8);
}
default: {
return -1;
@@ -194,11 +225,11 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
bytes.CopyTo(data, 2);
bytes.CopyTo(Data, 2);
break;
}
case MapType.MOHAA:
@@ -207,7 +238,7 @@ namespace LibBSP {
case MapType.Quake3:
case MapType.FAKK:
case MapType.STEF2: {
bytes.CopyTo(data, 8);
bytes.CopyTo(Data, 8);
break;
}
}
@@ -216,9 +247,9 @@ namespace LibBSP {
public int contents {
get {
switch (type) {
switch (MapType) {
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 0);
return BitConverter.ToInt32(Data, 0);
}
case MapType.Quake2:
case MapType.Daikatana:
@@ -236,7 +267,7 @@ namespace LibBSP {
case MapType.Vindictus:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
return BitConverter.ToInt32(data, 8);
return BitConverter.ToInt32(Data, 8);
}
default: {
return -1;
@@ -245,9 +276,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Nightfire: {
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
break;
}
case MapType.Quake2:
@@ -266,7 +297,7 @@ namespace LibBSP {
case MapType.Vindictus:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
bytes.CopyTo(data, 8);
bytes.CopyTo(Data, 8);
break;
}
}
@@ -277,33 +308,42 @@ namespace LibBSP {
/// Creates a new <see cref="Brush"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <param name="parent">The <see cref="ILump"/> this <see cref="Brush"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public Brush(byte[] data, MapType type, int version = 0) : this() {
public Brush(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="Brush"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{Brush}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="Brush"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<Brush> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{Brush}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<Brush> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<Brush>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.Quake2:
case MapType.Daikatana:
case MapType.SiN:
@@ -327,27 +367,17 @@ namespace LibBSP {
case MapType.Raven:
case MapType.Quake3:
case MapType.FAKK: {
structLength = 12;
break;
return 12;
}
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
structLength = 4;
break;
return 4;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the Brush lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<Brush> lump = new List<Brush>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -1,20 +1,51 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
/// <summary>
/// Holds the data used by the brush side structures of all formats of BSP.
/// </summary>
public struct BrushSide {
public struct BrushSide : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public int plane {
get {
switch (type) {
switch (MapType) {
case MapType.SiN:
case MapType.Quake2:
case MapType.Daikatana:
@@ -30,7 +61,7 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
return BitConverter.ToUInt16(data, 0);
return BitConverter.ToUInt16(Data, 0);
}
case MapType.Raven:
case MapType.CoD:
@@ -41,11 +72,11 @@ namespace LibBSP {
case MapType.STEF2Demo:
case MapType.MOHAA:
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 0);
return BitConverter.ToInt32(Data, 0);
}
case MapType.STEF2:
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 4);
return BitConverter.ToInt32(Data, 4);
}
default: {
return -1;
@@ -54,7 +85,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.SiN:
case MapType.Quake2:
case MapType.Daikatana:
@@ -70,8 +101,8 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
data[0] = bytes[0];
data[1] = bytes[1];
Data[0] = bytes[0];
Data[1] = bytes[1];
break;
}
case MapType.Raven:
@@ -83,12 +114,12 @@ namespace LibBSP {
case MapType.STEF2Demo:
case MapType.MOHAA:
case MapType.Vindictus: {
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
break;
}
case MapType.STEF2:
case MapType.Nightfire: {
bytes.CopyTo(data, 4);
bytes.CopyTo(Data, 4);
break;
}
}
@@ -97,11 +128,11 @@ namespace LibBSP {
public float dist {
get {
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
return BitConverter.ToSingle(data, 0);
return BitConverter.ToSingle(Data, 0);
}
default: {
return float.NaN;
@@ -110,11 +141,11 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
break;
}
}
@@ -123,9 +154,9 @@ namespace LibBSP {
public int texture {
get {
switch (type) {
switch (MapType) {
case MapType.STEF2: {
return BitConverter.ToInt32(data, 0);
return BitConverter.ToInt32(Data, 0);
}
case MapType.SiN:
case MapType.Quake2:
@@ -142,7 +173,7 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
return BitConverter.ToInt16(data, 2);
return BitConverter.ToInt16(Data, 2);
}
case MapType.Vindictus:
case MapType.CoD:
@@ -153,7 +184,7 @@ namespace LibBSP {
case MapType.STEF2Demo:
case MapType.MOHAA:
case MapType.Raven: {
return BitConverter.ToInt32(data, 4);
return BitConverter.ToInt32(Data, 4);
}
default: {
return -1;
@@ -162,9 +193,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.STEF2: {
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
break;
}
case MapType.SiN:
@@ -182,8 +213,8 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
data[2] = bytes[0];
data[3] = bytes[1];
Data[2] = bytes[0];
Data[3] = bytes[1];
break;
}
case MapType.Vindictus:
@@ -195,7 +226,7 @@ namespace LibBSP {
case MapType.STEF2Demo:
case MapType.MOHAA:
case MapType.Raven: {
bytes.CopyTo(data, 4);
bytes.CopyTo(Data, 4);
break;
}
}
@@ -204,12 +235,12 @@ namespace LibBSP {
public int face {
get {
switch (type) {
switch (MapType) {
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 0);
return BitConverter.ToInt32(Data, 0);
}
case MapType.Raven: {
return BitConverter.ToInt32(data, 8);
return BitConverter.ToInt32(Data, 8);
}
default: {
return -1;
@@ -218,13 +249,13 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Nightfire: {
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
break;
}
case MapType.Raven: {
bytes.CopyTo(data, 8);
bytes.CopyTo(Data, 8);
break;
}
}
@@ -233,7 +264,7 @@ namespace LibBSP {
public int displacement {
get {
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -245,10 +276,10 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
return BitConverter.ToInt16(data, 4);
return BitConverter.ToInt16(Data, 4);
}
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 8);
return BitConverter.ToInt32(Data, 8);
}
default: {
return -1;
@@ -257,7 +288,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -269,12 +300,12 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
data[4] = bytes[0];
data[5] = bytes[1];
Data[4] = bytes[0];
Data[5] = bytes[1];
break;
}
case MapType.Vindictus: {
bytes.CopyTo(data, 8);
bytes.CopyTo(Data, 8);
break;
}
}
@@ -283,7 +314,7 @@ namespace LibBSP {
public bool bevel {
get {
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -295,10 +326,10 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
return data[6] > 0;
return Data[6] > 0;
}
case MapType.Vindictus: {
return data[12] > 0;
return Data[12] > 0;
}
default: {
return false;
@@ -306,7 +337,7 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -318,11 +349,11 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
data[6] = (byte)(value ? 1 : 0);
Data[6] = (byte)(value ? 1 : 0);
break;
}
case MapType.Vindictus: {
data[12] = (byte)(value ? 1 : 0);
Data[12] = (byte)(value ? 1 : 0);
break;
}
}
@@ -331,7 +362,7 @@ namespace LibBSP {
public bool thin {
get {
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -343,7 +374,7 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
return data[7] > 0;
return Data[7] > 0;
}
default: {
return false;
@@ -351,7 +382,7 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -363,7 +394,7 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
data[7] = (byte)(value ? 1 : 0);
Data[7] = (byte)(value ? 1 : 0);
break;
}
}
@@ -374,38 +405,46 @@ namespace LibBSP {
/// Creates a new <see cref="BrushSide"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public BrushSide(byte[] data, MapType type, int version = 0) : this() {
/// <param name="parent">The <see cref="ILump"/> this <see cref="BrushSide"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public BrushSide(byte[] data, ILump parent) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{BrushSide}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{BrushSide}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<BrushSide> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
return new Lump<BrushSide>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="BrushSide"/> objects.
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="BrushSide"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<BrushSide> LumpFactory(byte[] data, MapType type, int version = 0) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType type, int version = 0) {
switch (type) {
case MapType.Quake2:
case MapType.Daikatana:
case MapType.SoF: {
structLength = 4;
break;
return 4;
}
case MapType.CoD:
case MapType.CoD2:
@@ -427,30 +466,19 @@ namespace LibBSP {
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM:
case MapType.FAKK: {
structLength = 8;
break;
return 8;
}
case MapType.MOHAA:
case MapType.Raven: {
structLength = 12;
break;
return 12;
}
case MapType.Vindictus: {
structLength = 16;
break;
return 16;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the BrushSide lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + type + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<BrushSide> lump = new List<BrushSide>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
#if UNITY
@@ -15,15 +16,45 @@ namespace LibBSP {
/// <summary>
/// Holds all data for a Cubemap from Source engine.
/// </summary>
public struct Cubemap {
public struct Cubemap : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public Vector3d origin {
get {
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -36,7 +67,7 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.Vindictus:
case MapType.DMoMaM: {
return new Vector3d(BitConverter.ToInt32(data, 0), BitConverter.ToInt32(data, 4), BitConverter.ToInt32(data, 8));
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);
@@ -44,7 +75,7 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -57,7 +88,7 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.Vindictus:
case MapType.DMoMaM: {
value.GetBytes().CopyTo(data, 0);
value.GetBytes().CopyTo(Data, 0);
break;
}
}
@@ -66,7 +97,7 @@ namespace LibBSP {
public int size {
get {
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -79,7 +110,7 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.Vindictus:
case MapType.DMoMaM: {
return BitConverter.ToInt32(data, 12);
return BitConverter.ToInt32(Data, 12);
}
default: {
return -1;
@@ -88,7 +119,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -101,7 +132,7 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.Vindictus:
case MapType.DMoMaM: {
bytes.CopyTo(data, 12);
bytes.CopyTo(Data, 12);
break;
}
}
@@ -112,33 +143,42 @@ namespace LibBSP {
/// Creates a new <see cref="Cubemap"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public Cubemap(byte[] data, MapType type, int version = 0) : this() {
/// <param name="parent">The <see cref="ILump"/> this <see cref="Cubemap"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public Cubemap(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="Cubemap"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{Cubemap}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="Cubemap"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<Cubemap> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{Cubemap}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<Cubemap> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<Cubemap>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -151,21 +191,12 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.Vindictus:
case MapType.DMoMaM: {
structLength = 16;
break;
return 16;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the SourceCubemap lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<Cubemap> lump = new List<Cubemap>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
#if UNITY
@@ -15,99 +16,129 @@ namespace LibBSP {
/// <summary>
/// Holds all data for a Displacement from Source engine.
/// </summary>
public struct DisplacementInfo {
public struct DisplacementInfo : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public Vector3d startPosition {
get {
return new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
return new Vector3d(BitConverter.ToSingle(Data, 0), BitConverter.ToSingle(Data, 4), BitConverter.ToSingle(Data, 8));
}
set {
value.GetBytes().CopyTo(data, 0);
value.GetBytes().CopyTo(Data, 0);
}
}
public int dispVertStart {
get {
return BitConverter.ToInt32(data, 12);
return BitConverter.ToInt32(Data, 12);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 12);
BitConverter.GetBytes(value).CopyTo(Data, 12);
}
}
public int dispTriStart {
get {
return BitConverter.ToInt32(data, 16);
return BitConverter.ToInt32(Data, 16);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 16);
BitConverter.GetBytes(value).CopyTo(Data, 16);
}
}
public int power {
get {
return BitConverter.ToInt32(data, 20);
return BitConverter.ToInt32(Data, 20);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 20);
BitConverter.GetBytes(value).CopyTo(Data, 20);
}
}
public int minTess {
get {
return BitConverter.ToInt32(data, 24);
return BitConverter.ToInt32(Data, 24);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 24);
BitConverter.GetBytes(value).CopyTo(Data, 24);
}
}
public float smoothingAngle {
get {
return BitConverter.ToSingle(data, 28);
return BitConverter.ToSingle(Data, 28);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 28);
BitConverter.GetBytes(value).CopyTo(Data, 28);
}
}
public int contents {
get {
return BitConverter.ToInt32(data, 32);
return BitConverter.ToInt32(Data, 32);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 32);
BitConverter.GetBytes(value).CopyTo(Data, 32);
}
}
public ushort mapFace {
get {
return BitConverter.ToUInt16(data, 36);
return BitConverter.ToUInt16(Data, 36);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 36);
BitConverter.GetBytes(value).CopyTo(Data, 36);
}
}
public int lightmapAlphaStart {
get {
return BitConverter.ToInt32(data, 38);
return BitConverter.ToInt32(Data, 38);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 38);
BitConverter.GetBytes(value).CopyTo(Data, 38);
}
}
public int lightmapSamplePositionStart {
get {
return BitConverter.ToInt32(data, 42);
return BitConverter.ToInt32(Data, 42);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 42);
BitConverter.GetBytes(value).CopyTo(Data, 42);
}
}
@@ -115,7 +146,7 @@ namespace LibBSP {
get {
uint[] allowedVerts = new uint[10];
int offset = -1;
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -143,7 +174,7 @@ namespace LibBSP {
}
if (offset >= 0) {
for (int i = 0; i < 10; ++i) {
allowedVerts[i] = BitConverter.ToUInt32(data, offset + (i * 4));
allowedVerts[i] = BitConverter.ToUInt32(Data, offset + (i * 4));
}
}
return allowedVerts;
@@ -153,7 +184,7 @@ namespace LibBSP {
throw new ArgumentException("AllowedVerts array must have 10 elements.");
}
int offset = -1;
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -181,7 +212,7 @@ namespace LibBSP {
}
if (offset >= 0) {
for (int i = 0; i < value.Length; ++i) {
BitConverter.GetBytes(value[i]).CopyTo(data, offset + (i * 4));
BitConverter.GetBytes(value[i]).CopyTo(Data, offset + (i * 4));
}
}
}
@@ -191,33 +222,42 @@ namespace LibBSP {
/// Creates a new <see cref="DisplacementInfo"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public DisplacementInfo(byte[] data, MapType type, int version = 0) : this() {
/// <param name="parent">The <see cref="ILump"/> this <see cref="DisplacementInfo"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public DisplacementInfo(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="DisplacementInfo"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{DisplacementInfo}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="DisplacementInfo"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<DisplacementInfo> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{DisplacementInfo}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<DisplacementInfo> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<DisplacementInfo>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -227,33 +267,21 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
structLength = 176;
break;
return 176;
}
case MapType.Source22: {
structLength = 180;
break;
return 180;
}
case MapType.Source23: {
structLength = 184;
break;
return 184;
}
case MapType.Vindictus: {
structLength = 232;
break;
return 232;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the SourceDispInfo lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<DisplacementInfo> lump = new List<DisplacementInfo>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -3,6 +3,7 @@
#endif
using System;
using System.Reflection;
namespace LibBSP {
#if UNITY
@@ -14,21 +15,51 @@ namespace LibBSP {
/// <summary>
/// Holds all the data for a displacement in a Source map.
/// </summary>
public struct DisplacementVertex {
public struct DisplacementVertex : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
/// <summary>
/// The normalized vector direction this vertex points from "flat".
/// </summary>
public Vector3d normal {
get {
return new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
return new Vector3d(BitConverter.ToSingle(Data, 0), BitConverter.ToSingle(Data, 4), BitConverter.ToSingle(Data, 8));
}
set {
value.GetBytes().CopyTo(data, 0);
value.GetBytes().CopyTo(Data, 0);
}
}
@@ -37,10 +68,10 @@ namespace LibBSP {
/// </summary>
public float dist {
get {
return BitConverter.ToSingle(data, 12);
return BitConverter.ToSingle(Data, 12);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 12);
BitConverter.GetBytes(value).CopyTo(Data, 12);
}
}
@@ -49,10 +80,10 @@ namespace LibBSP {
/// </summary>
public float alpha {
get {
return BitConverter.ToSingle(data, 16);
return BitConverter.ToSingle(Data, 16);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 16);
BitConverter.GetBytes(value).CopyTo(Data, 16);
}
}
@@ -60,31 +91,60 @@ namespace LibBSP {
/// Creates a new <see cref="DisplacementVertex"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <param name="parent">The <see cref="ILump"/> this <see cref="DisplacementVertex"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public DisplacementVertex(byte[] data, MapType type, int version = 0) : this() {
public DisplacementVertex(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <see cref="DisplacementVertices"/> object.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="DisplacementVertices"/> object.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public static DisplacementVertices LumpFactory(byte[] data, MapType type, int version = 0) {
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static DisplacementVertices LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
return new DisplacementVertices(data, type, version);
return new DisplacementVertices(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.Vindictus:
case MapType.TacticalInterventionEncrypted:
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: {
return 20;
}
default: {
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
}
/// <summary>

View File

@@ -1,20 +1,51 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
/// <summary>
/// Holds all the data for an edge in a BSP map.
/// </summary>
public struct Edge {
public struct Edge : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public int firstVertex {
get {
switch (type) {
switch (MapType) {
case MapType.Quake:
case MapType.SiN:
case MapType.Daikatana:
@@ -31,10 +62,10 @@ namespace LibBSP {
case MapType.DMoMaM:
case MapType.Quake2:
case MapType.SoF: {
return BitConverter.ToUInt16(data, 0);
return BitConverter.ToUInt16(Data, 0);
}
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 0);
return BitConverter.ToInt32(Data, 0);
}
default: {
return -1;
@@ -43,7 +74,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Quake:
case MapType.SiN:
case MapType.Daikatana:
@@ -60,12 +91,12 @@ namespace LibBSP {
case MapType.DMoMaM:
case MapType.Quake2:
case MapType.SoF: {
data[0] = bytes[0];
data[1] = bytes[1];
Data[0] = bytes[0];
Data[1] = bytes[1];
break;
}
case MapType.Vindictus: {
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
break;
}
}
@@ -74,7 +105,7 @@ namespace LibBSP {
public int secondVertex {
get {
switch (type) {
switch (MapType) {
case MapType.Quake:
case MapType.SiN:
case MapType.Daikatana:
@@ -91,10 +122,10 @@ namespace LibBSP {
case MapType.DMoMaM:
case MapType.Quake2:
case MapType.SoF: {
return BitConverter.ToUInt16(data, 2);
return BitConverter.ToUInt16(Data, 2);
}
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 4);
return BitConverter.ToInt32(Data, 4);
}
default: {
return -1;
@@ -103,7 +134,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Quake:
case MapType.SiN:
case MapType.Daikatana:
@@ -120,12 +151,12 @@ namespace LibBSP {
case MapType.DMoMaM:
case MapType.Quake2:
case MapType.SoF: {
data[2] = bytes[0];
data[3] = bytes[1];
Data[2] = bytes[0];
Data[3] = bytes[1];
break;
}
case MapType.Vindictus: {
BitConverter.GetBytes(value).CopyTo(data, 4);
BitConverter.GetBytes(value).CopyTo(Data, 4);
break;
}
}
@@ -136,33 +167,42 @@ namespace LibBSP {
/// Creates a new <see cref="Edge"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <param name="parent">The <see cref="ILump"/> this <see cref="Edge"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public Edge(byte[] data, MapType type, int version = 0) : this() {
public Edge(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="Edge"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{Edge}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="Edge"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was null.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<Edge> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{Edge}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<Edge> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<Edge>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.Quake:
case MapType.SiN:
case MapType.Daikatana:
@@ -179,25 +219,15 @@ namespace LibBSP {
case MapType.DMoMaM:
case MapType.Quake2:
case MapType.SoF: {
structLength = 4;
break;
return 4;
}
case MapType.Vindictus: {
structLength = 8;
break;
return 8;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the Edge lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<Edge> lump = new List<Edge>(numObjects);
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));
}
return lump;
}
/// <summary>

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +1,53 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
/// <summary>
/// Holds the data for a terrain object in MoHAA.
/// </summary>
public struct LODTerrain {
public struct LODTerrain : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public byte flags {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return data[0];
return Data[0];
}
default: {
return 0;
@@ -24,9 +55,9 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
data[0] = value;
Data[0] = value;
break;
}
}
@@ -35,9 +66,9 @@ namespace LibBSP {
public byte scale {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return data[1];
return Data[1];
}
default: {
return 0;
@@ -45,9 +76,9 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
data[1] = value;
Data[1] = value;
break;
}
}
@@ -56,9 +87,9 @@ namespace LibBSP {
public byte[] lightmapCoords {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return new byte[] { data[2], data[3] };
return new byte[] { Data[2], Data[3] };
}
default: {
return null;
@@ -69,10 +100,10 @@ namespace LibBSP {
if (value.Length != 2) {
throw new ArgumentException("LightmapCoords array must have 2 elements.");
}
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
data[2] = value[0];
data[3] = value[1];
Data[2] = value[0];
Data[3] = value[1];
break;
}
}
@@ -81,17 +112,17 @@ namespace LibBSP {
public float[] textureCoords {
get {
switch (type) {
switch (MapType) {
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),
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: {
@@ -103,11 +134,11 @@ namespace LibBSP {
if (value.Length != 8) {
throw new ArgumentException("TextureCoords array must have 8 elements.");
}
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
int offset = 4;
for (int i = 0; i < value.Length; ++i) {
BitConverter.GetBytes(value[i]).CopyTo(data, offset + (i * 4));
BitConverter.GetBytes(value[i]).CopyTo(Data, offset + (i * 4));
}
break;
}
@@ -117,9 +148,9 @@ namespace LibBSP {
public sbyte x {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return (sbyte)data[36];
return (sbyte)Data[36];
}
default: {
return 0;
@@ -127,9 +158,9 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
data[36] = (byte)value;
Data[36] = (byte)value;
break;
}
}
@@ -138,9 +169,9 @@ namespace LibBSP {
public sbyte y {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return (sbyte)data[37];
return (sbyte)Data[37];
}
default: {
return 0;
@@ -148,9 +179,9 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
data[37] = (byte)value;
Data[37] = (byte)value;
break;
}
}
@@ -159,9 +190,9 @@ namespace LibBSP {
public short baseZ {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return BitConverter.ToInt16(data, 38);
return BitConverter.ToInt16(Data, 38);
}
default: {
return 0;
@@ -170,9 +201,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
bytes.CopyTo(data, 38);
bytes.CopyTo(Data, 38);
break;
}
}
@@ -181,9 +212,9 @@ namespace LibBSP {
public ushort texture {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return BitConverter.ToUInt16(data, 40);
return BitConverter.ToUInt16(Data, 40);
}
default: {
return 0;
@@ -192,9 +223,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
bytes.CopyTo(data, 40);
bytes.CopyTo(Data, 40);
break;
}
}
@@ -203,9 +234,9 @@ namespace LibBSP {
public short lightmap {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return BitConverter.ToInt16(data, 42);
return BitConverter.ToInt16(Data, 42);
}
default: {
return -1;
@@ -214,9 +245,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
bytes.CopyTo(data, 42);
bytes.CopyTo(Data, 42);
break;
}
}
@@ -226,11 +257,11 @@ namespace LibBSP {
public ushort[,] vertexFlags {
get {
ushort[,] ret = new ushort[2,63];
switch (type) {
switch (MapType) {
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));
ret[i, j] = BitConverter.ToUInt16(Data, 52 + (i * 126) + (j * 2));
}
}
break;
@@ -244,7 +275,7 @@ namespace LibBSP {
}
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));
BitConverter.GetBytes(value[i, j]).CopyTo(Data, 52 + (i * 126) + (j * 2));
}
}
}
@@ -253,11 +284,11 @@ namespace LibBSP {
public byte[,] heightmap {
get {
byte[,] ret = new byte[9, 9];
switch (type) {
switch (MapType) {
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];
ret[i, j] = Data[304 + (i * 9) + j];
}
}
break;
@@ -271,7 +302,7 @@ namespace LibBSP {
}
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];
Data[304 + (i * 9) + j] = value[i, j];
}
}
}
@@ -281,49 +312,49 @@ namespace LibBSP {
/// Creates a new <see cref="LODTerrain"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <param name="parent">The <see cref="ILump"/> this <see cref="LODTerrain"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public LODTerrain(byte[] data, MapType type, int version = 0) : this() {
public LODTerrain(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="LODTerrain"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{LODTerrain}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="LODTerrain"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<LODTerrain> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{LODTerrain}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<LODTerrain> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<LODTerrain>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.MOHAA: {
structLength = 388;
break;
return 388;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the LODTerrain lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<LODTerrain> lump = new List<LODTerrain>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -1,20 +1,51 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
/// <summary>
/// Holds data for a leaf structure in a BSP map.
/// </summary>
public struct Leaf {
public struct Leaf : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public int contents {
get {
switch (type) {
switch (MapType) {
case MapType.SoF:
case MapType.Quake2:
case MapType.SiN:
@@ -32,7 +63,7 @@ namespace LibBSP {
case MapType.Daikatana:
case MapType.Vindictus:
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 0);
return BitConverter.ToInt32(Data, 0);
}
default: {
return -1;
@@ -41,7 +72,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.SoF:
case MapType.Quake2:
case MapType.SiN:
@@ -59,7 +90,7 @@ namespace LibBSP {
case MapType.Daikatana:
case MapType.Vindictus:
case MapType.Nightfire: {
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
break;
}
}
@@ -68,13 +99,13 @@ namespace LibBSP {
[Index("markBrushes")] public int firstMarkBrush {
get {
switch (type) {
switch (MapType) {
case MapType.CoD4: {
return BitConverter.ToInt32(data, 12);
return BitConverter.ToInt32(Data, 12);
}
case MapType.CoD:
case MapType.CoD2: {
return BitConverter.ToInt32(data, 16);
return BitConverter.ToInt32(Data, 16);
}
case MapType.Quake2:
case MapType.SiN:
@@ -90,10 +121,10 @@ namespace LibBSP {
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM:
case MapType.Daikatana: {
return BitConverter.ToUInt16(data, 24);
return BitConverter.ToUInt16(Data, 24);
}
case MapType.SoF: {
return BitConverter.ToUInt16(data, 26);
return BitConverter.ToUInt16(Data, 26);
}
case MapType.Quake3:
case MapType.FAKK:
@@ -102,10 +133,10 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 40);
return BitConverter.ToInt32(Data, 40);
}
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 44);
return BitConverter.ToInt32(Data, 44);
}
default: {
return -1;
@@ -114,14 +145,14 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD4: {
bytes.CopyTo(data, 12);
bytes.CopyTo(Data, 12);
break;
}
case MapType.CoD:
case MapType.CoD2: {
bytes.CopyTo(data, 16);
bytes.CopyTo(Data, 16);
break;
}
case MapType.Quake2:
@@ -138,13 +169,13 @@ namespace LibBSP {
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM:
case MapType.Daikatana: {
data[24] = bytes[0];
data[25] = bytes[1];
Data[24] = bytes[0];
Data[25] = bytes[1];
break;
}
case MapType.SoF: {
data[26] = bytes[0];
data[27] = bytes[1];
Data[26] = bytes[0];
Data[27] = bytes[1];
break;
}
case MapType.Quake3:
@@ -154,11 +185,11 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.Nightfire: {
bytes.CopyTo(data, 40);
bytes.CopyTo(Data, 40);
break;
}
case MapType.Vindictus: {
bytes.CopyTo(data, 44);
bytes.CopyTo(Data, 44);
break;
}
}
@@ -167,13 +198,13 @@ namespace LibBSP {
[Count("markBrushes")] public int numMarkBrushes {
get {
switch (type) {
switch (MapType) {
case MapType.CoD4: {
return BitConverter.ToInt32(data, 16);
return BitConverter.ToInt32(Data, 16);
}
case MapType.CoD:
case MapType.CoD2: {
return BitConverter.ToInt32(data, 20);
return BitConverter.ToInt32(Data, 20);
}
case MapType.Quake2:
case MapType.SiN:
@@ -189,10 +220,10 @@ namespace LibBSP {
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM:
case MapType.Daikatana: {
return BitConverter.ToUInt16(data, 26);
return BitConverter.ToUInt16(Data, 26);
}
case MapType.SoF: {
return BitConverter.ToUInt16(data, 28);
return BitConverter.ToUInt16(Data, 28);
}
case MapType.Nightfire:
case MapType.Quake3:
@@ -201,10 +232,10 @@ namespace LibBSP {
case MapType.STEF2:
case MapType.MOHAA:
case MapType.Raven: {
return BitConverter.ToInt32(data, 44);
return BitConverter.ToInt32(Data, 44);
}
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 48);
return BitConverter.ToInt32(Data, 48);
}
default: {
return -1;
@@ -213,14 +244,14 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD4: {
bytes.CopyTo(data, 16);
bytes.CopyTo(Data, 16);
break;
}
case MapType.CoD:
case MapType.CoD2: {
bytes.CopyTo(data, 20);
bytes.CopyTo(Data, 20);
break;
}
case MapType.Quake2:
@@ -237,13 +268,13 @@ namespace LibBSP {
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM:
case MapType.Daikatana: {
data[26] = bytes[0];
data[27] = bytes[1];
Data[26] = bytes[0];
Data[27] = bytes[1];
break;
}
case MapType.SoF: {
data[28] = bytes[0];
data[29] = bytes[1];
Data[28] = bytes[0];
Data[29] = bytes[1];
break;
}
case MapType.Nightfire:
@@ -253,11 +284,11 @@ namespace LibBSP {
case MapType.STEF2:
case MapType.MOHAA:
case MapType.Raven: {
bytes.CopyTo(data, 44);
bytes.CopyTo(Data, 44);
break;
}
case MapType.Vindictus: {
bytes.CopyTo(data, 48);
bytes.CopyTo(Data, 48);
break;
}
}
@@ -266,10 +297,10 @@ namespace LibBSP {
[Index("markSurfaces")] public int firstMarkFace {
get {
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2: {
return BitConverter.ToInt32(data, 8);
return BitConverter.ToInt32(Data, 8);
}
case MapType.Quake:
case MapType.Quake2:
@@ -286,10 +317,10 @@ namespace LibBSP {
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM:
case MapType.Daikatana: {
return BitConverter.ToUInt16(data, 20);
return BitConverter.ToUInt16(Data, 20);
}
case MapType.SoF: {
return BitConverter.ToUInt16(data, 22);
return BitConverter.ToUInt16(Data, 22);
}
case MapType.Quake3:
case MapType.FAKK:
@@ -298,10 +329,10 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 32);
return BitConverter.ToInt32(Data, 32);
}
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 36);
return BitConverter.ToInt32(Data, 36);
}
default: {
return -1;
@@ -310,10 +341,10 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2: {
bytes.CopyTo(data, 8);
bytes.CopyTo(Data, 8);
break;
}
case MapType.Quake:
@@ -331,13 +362,13 @@ namespace LibBSP {
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM:
case MapType.Daikatana: {
data[20] = bytes[0];
data[21] = bytes[1];
Data[20] = bytes[0];
Data[21] = bytes[1];
break;
}
case MapType.SoF: {
data[22] = bytes[0];
data[23] = bytes[1];
Data[22] = bytes[0];
Data[23] = bytes[1];
break;
}
case MapType.Quake3:
@@ -347,11 +378,11 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.Nightfire: {
bytes.CopyTo(data, 32);
bytes.CopyTo(Data, 32);
break;
}
case MapType.Vindictus: {
bytes.CopyTo(data, 36);
bytes.CopyTo(Data, 36);
break;
}
}
@@ -360,10 +391,10 @@ namespace LibBSP {
[Count("markSurfaces")] public int numMarkFaces {
get {
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2: {
return BitConverter.ToInt32(data, 12);
return BitConverter.ToInt32(Data, 12);
}
case MapType.Quake:
case MapType.Quake2:
@@ -380,10 +411,10 @@ namespace LibBSP {
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM:
case MapType.Daikatana: {
return BitConverter.ToUInt16(data, 22);
return BitConverter.ToUInt16(Data, 22);
}
case MapType.SoF: {
return BitConverter.ToUInt16(data, 24);
return BitConverter.ToUInt16(Data, 24);
}
case MapType.Quake3:
case MapType.FAKK:
@@ -392,10 +423,10 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 36);
return BitConverter.ToInt32(Data, 36);
}
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 40);
return BitConverter.ToInt32(Data, 40);
}
default: {
return -1;
@@ -404,10 +435,10 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2: {
bytes.CopyTo(data, 12);
bytes.CopyTo(Data, 12);
break;
}
case MapType.Quake:
@@ -425,13 +456,13 @@ namespace LibBSP {
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM:
case MapType.Daikatana: {
data[22] = bytes[0];
data[23] = bytes[1];
Data[22] = bytes[0];
Data[23] = bytes[1];
break;
}
case MapType.SoF: {
data[24] = bytes[0];
data[25] = bytes[1];
Data[24] = bytes[0];
Data[25] = bytes[1];
break;
}
case MapType.Quake3:
@@ -441,11 +472,11 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.Nightfire: {
bytes.CopyTo(data, 36);
bytes.CopyTo(Data, 36);
break;
}
case MapType.Vindictus: {
bytes.CopyTo(data, 40);
bytes.CopyTo(Data, 40);
break;
}
}
@@ -454,9 +485,9 @@ namespace LibBSP {
public int pvs {
get {
switch (type) {
switch (MapType) {
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 4);
return BitConverter.ToInt32(Data, 4);
}
default: {
return -1;
@@ -465,9 +496,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Nightfire: {
bytes.CopyTo(data, 4);
bytes.CopyTo(Data, 4);
break;
}
}
@@ -478,42 +509,49 @@ namespace LibBSP {
/// Creates a new <see cref="Leaf"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public Leaf(byte[] data, MapType type, int version = 0) : this() {
/// <param name="parent">The <see cref="ILump"/> this <see cref="Leaf"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public Leaf(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="Leaf"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{Leaf}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="Leaf"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<Leaf> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{Leaf}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<Leaf> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<Leaf>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.CoD4: {
structLength = 24;
break;
return 24;
}
case MapType.Quake:
case MapType.Quake2:
case MapType.SiN: {
structLength = 28;
break;
return 28;
}
case MapType.Source17:
case MapType.Source20:
@@ -526,13 +564,11 @@ namespace LibBSP {
case MapType.SoF:
case MapType.Daikatana:
case MapType.DMoMaM: {
structLength = 32;
break;
return 32;
}
case MapType.CoD:
case MapType.CoD2: {
structLength = 36;
break;
return 36;
}
case MapType.Nightfire:
case MapType.Quake3:
@@ -540,31 +576,20 @@ namespace LibBSP {
case MapType.STEF2Demo:
case MapType.STEF2:
case MapType.Raven: {
structLength = 48;
break;
return 48;
}
case MapType.Source18:
case MapType.Source19:
case MapType.Vindictus: {
structLength = 56;
break;
return 56;
}
case MapType.MOHAA: {
structLength = 64;
break;
return 64;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the Leaf lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<Leaf> lump = new List<Leaf>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -6,27 +6,40 @@ namespace LibBSP {
/// <summary>
/// Class representing a group of <see cref="DisplacementVertex"/> objects. Contains helpful methods to handle Displacement Vertices in the <c>List</c>.
/// </summary>
public class DisplacementVertices : List<DisplacementVertex> {
public class DisplacementVertices : Lump<DisplacementVertex> {
/// <summary>
/// Parses the passed <c>byte</c> array into a <c>List</c> of <see cref="DisplacementVertex"/> objects.
/// Creates an empty <see cref="DisplacementVertices"/> object.
/// </summary>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public DisplacementVertices(BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(bsp, lumpInfo) { }
/// <summary>
/// Creates a new <see cref="DisplacementVertices"/> that contains elements copied from the passed <see cref="IEnumerable{DisplacementVertex}"/>.
/// </summary>
/// <param name="items">The elements to copy into this <c>Lump</c>.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public DisplacementVertices(IEnumerable<DisplacementVertex> items, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(items, bsp, lumpInfo) { }
/// <summary>
/// Creates an empty <see cref="DisplacementVertices"/> object with the specified initial capactiy.
/// </summary>
/// <param name="capacity">The number of elements that can initially be stored.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public DisplacementVertices(int capacity, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(capacity, bsp, lumpInfo) { }
/// <summary>
/// Parses the passed <c>byte</c> array into a <see cref="DisplacementVertices"/> object.
/// </summary>
/// <param name="data">Array of <c>byte</c>s to parse.</param>
/// <param name="type">Format identifier.</param>
/// <param name="version">The version of this lump.</param>
/// <param name="structLength">Number of <c>byte</c>s to copy into the children.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public DisplacementVertices(byte[] data, MapType type, int version = 0) : base(data.Length / 20) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 20;
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));
}
}
public DisplacementVertices(byte[] data, int structLength, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(data, structLength, bsp, lumpInfo) { }
/// <summary>
/// Gets enough vertices from the list for a displacement of power <paramref name="power"/>, starting at <paramref name="first"/>.

View File

@@ -17,24 +17,33 @@ namespace LibBSP {
/// Class containing the identification and information for the various Game Lumps in Source
/// engine BSPs.
/// </summary>
public class GameLump : Dictionary<GameLumpType, LumpInfo> {
public class GameLump : Dictionary<GameLumpType, LumpInfo>, ILump {
/// <summary>
/// Creates a new <see cref="GameLump"/> object by parsing a <c>byte</c> array into a <c>Dictionary</c> of <see cref="LumpInfo"/> objects.
/// These objects contain offsets, lengths and versions of the GameLump lumps.
/// The <see cref="BSP"/> this <see cref="ILump"/> came from.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
public BSP Bsp { get; protected set; }
/// <summary>
/// The <see cref="LumpInfo"/> associated with this <see cref="ILump"/>.
/// </summary>
public LumpInfo LumpInfo { get; protected set; }
/// <summary>
/// Parses the passed <c>byte</c> array into a <see cref="GameLump"/> object.
/// </summary>
/// <param name="data">Array of <c>byte</c>s to parse.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public GameLump(byte[] data, MapType type, int version = 0) {
public GameLump(byte[] data, BSP bsp, LumpInfo lumpInfo = default(LumpInfo)) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
switch (bsp.version) {
case MapType.TacticalInterventionEncrypted:
case MapType.Source17:
case MapType.Source18:
@@ -55,13 +64,13 @@ namespace LibBSP {
break;
}
default: {
throw new ArgumentException("Map type " + type + " doesn't use a Game lump or the lump is unknown.");
throw new ArgumentException("Game lump does not exist in map type " + bsp.version + " or has not been implemented.");
}
}
int numGameLumps = BitConverter.ToInt32(data, 0);
if (numGameLumps > 0) {
int lumpDictionaryOffset = (type == MapType.DMoMaM) ? 8 : 4;
int lumpDictionaryOffset = (bsp.version == MapType.DMoMaM) ? 8 : 4;
int lowestLumpOffset = int.MaxValue;
for (int i = 0; i < numGameLumps; ++i) {
@@ -70,7 +79,7 @@ namespace LibBSP {
int lumpVersion;
int lumpOffset;
int lumpLength;
if (type == MapType.Vindictus) {
if (bsp.version == MapType.Vindictus) {
lumpFlags = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 4);
lumpVersion = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 8);
lumpOffset = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 12);
@@ -98,15 +107,19 @@ namespace LibBSP {
}
/// <summary>
/// Passes a <c>byte</c> array into the constructor for <see cref="GameLump"/>.
/// Factory method to parse a <c>byte</c> array into a <see cref="GameLump"/> object.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A new <see cref="GameLump"/> object.</returns>
/// <remarks>This is only here for consistency with the other lump structures.</remarks>
public static GameLump LumpFactory(byte[] data, MapType type, int version = 0) {
return new GameLump(data, type, version);
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="GameLump"/> object.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static GameLump LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
return new GameLump(data, bsp, lumpInfo);
}
/// <summary>

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Collections.Generic;
namespace LibBSP {
@@ -6,22 +7,53 @@ namespace LibBSP {
/// <summary>
/// List of <see cref="StaticProp"/> objects containing data relevant to Static Props, like the dictionary of actual model paths.
/// </summary>
public class StaticProps : List<StaticProp> {
public class StaticProps : Lump<StaticProp> {
public string[] dictionary { get; private set; }
/// <summary>
/// Parses the passed <c>byte</c> array into a <c>List</c> of <see cref="StaticProp"/> objects.
/// Creates an empty <see cref="StaticProps"/> object.
/// </summary>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public StaticProps(BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(bsp, lumpInfo) {
dictionary = new string[] { };
}
/// <summary>
/// Creates a new <see cref="StaticProps"/> that contains elements copied from the passed <see cref="IEnumerable{StaticProp}"/> and the passed <paramref name="dictionary"/>.
/// </summary>
/// <param name="items">The elements to copy into this <c>Lump</c>.</param>
/// <param name="dictionary">A dictionary of static prop models. This is referenced from <see cref="StaticProp"/> objects.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public StaticProps(IEnumerable<StaticProp> items, IList<string> dictionary, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(items, bsp, lumpInfo) {
this.dictionary = dictionary.ToArray();
}
/// <summary>
/// Creates an empty <see cref="StaticProps"/> object with the specified initial capactiy.
/// </summary>
/// <param name="capacity">The number of elements that can initially be stored.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public StaticProps(int capacity, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(capacity, bsp, lumpInfo) {
dictionary = new string[] { };
}
/// <summary>
/// Parses the passed <c>byte</c> array into a <see cref="StaticProps"/> object.
/// </summary>
/// <param name="data">Array of <c>byte</c>s to parse.</param>
/// <param name="type">Format identifier.</param>
/// <param name="version">Version of static prop lump this is.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public StaticProps(byte[] data, MapType type, int version = 0) {
if (data == null) {
/// <param name="structLength">Number of <c>byte</c>s to copy into the children. Will be recalculated based on BSP format.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> or <paramref name="bsp"/> was <c>null</c>.</exception>
public StaticProps(byte[] data, int structLength, BSP bsp, LumpInfo lumpInfo = default(LumpInfo)) : base(bsp, lumpInfo) {
if (data == null || bsp == null) {
throw new ArgumentNullException();
}
int structLength = 0;
dictionary = new string[0];
if (data.Length > 0) {
int offset = 0;
@@ -33,12 +65,12 @@ namespace LibBSP {
}
int numLeafDefinitions = BitConverter.ToInt32(data, offset);
offset += 4 + (numLeafDefinitions * 2);
if (type == MapType.Vindictus && version == 6) {
if (Bsp.version == MapType.Vindictus && lumpInfo.version == 6) {
int numPropScales = BitConverter.ToInt32(data, offset);
offset += 4 + (numPropScales * 16);
}
int numProps = BitConverter.ToInt32(data, offset);
if (version == 12) { // So far only Titanfall
if (lumpInfo.version == 12) { // So far only Titanfall
offset += 12;
} else {
offset += 4;
@@ -48,7 +80,7 @@ namespace LibBSP {
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));
Add(new StaticProp(bytes, this));
offset += structLength;
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
@@ -7,22 +8,45 @@ namespace LibBSP {
/// <c>List</c>&lt;<see cref="Texture"/>&gt; with some useful methods for manipulating <see cref="Texture"/> objects,
/// especially when handling them as a group.
/// </summary>
public class Textures : List<Texture> {
public class Textures : Lump<Texture> {
/// <summary>
/// Parses a <c>byte</c> array into this <c>List</c> of <see cref="Texture"/> objects.
/// Creates an empty <see cref="Textures"/> object.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public Textures(byte[] data, MapType type, int version = 0) {
if (data == null) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public Textures(BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(bsp, lumpInfo) { }
/// <summary>
/// Creates a new <see cref="Textures"/> that contains elements copied from the passed <see cref="IEnumerable{Texture}"/>.
/// </summary>
/// <param name="items">The elements to copy into this <c>Lump</c>.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public Textures(IEnumerable<Texture> items, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(items, bsp, lumpInfo) { }
/// <summary>
/// Creates an empty <see cref="Textures"/> object with the specified initial capactiy.
/// </summary>
/// <param name="capacity">The number of elements that can initially be stored.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public Textures(int capacity, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(capacity, bsp, lumpInfo) { }
/// <summary>
/// Parses the passed <c>byte</c> array into a <see cref="Textures"/> object.
/// </summary>
/// <param name="data">Array of <c>byte</c>s to parse.</param>
/// <param name="structLength">Number of <c>byte</c>s to copy into the children. Will be recalculated based on BSP format.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> or <paramref name="bsp"/> was <c>null</c>.</exception>
public Textures(byte[] data, int structLength, BSP bsp, LumpInfo lumpInfo = default(LumpInfo)) : base(bsp, lumpInfo) {
if (data == null || bsp == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
switch (bsp.version) {
case MapType.Nightfire: {
structLength = 64;
break;
@@ -70,7 +94,7 @@ namespace LibBSP {
// They are null-terminated strings, of non-constant length (not padded)
byte[] myBytes = new byte[i - offset];
Array.Copy(data, offset, myBytes, 0, i - offset);
Add(new Texture(myBytes, type, version));
Add(new Texture(myBytes, this));
offset = i + 1;
}
}
@@ -82,12 +106,12 @@ namespace LibBSP {
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));
Add(new Texture(myBytes, this));
}
return;
}
default: {
throw new ArgumentException("Map type " + type + " doesn't use a Texture lump or the lump is unknown.");
throw new ArgumentException("Lump object Texture does not exist in map type " + bsp.version + " or has not been implemented.");
}
}
@@ -95,7 +119,7 @@ namespace LibBSP {
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));
Add(new Texture(bytes, this));
}
}

View File

@@ -1,28 +1,51 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
/// <summary>
/// A class containing all data needed for the models lump in any given BSP.
/// </summary>
/// <remarks>
/// In general, we need to use models to find one or more leaves containing the
/// information for the solids described by this model. Some formats do it by
/// referencing a head node to iterate through and find the leaves. Others
/// directly point to a set of leaves, and still others simply directly reference
/// brushes. The ideal format simply points to brush information from here (Quake
/// 3-based engines do), but most of them don't.
/// </remarks>
public struct Model {
public struct Model : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
[Index("nodes")] public int headNode {
get {
switch (type) {
switch (MapType) {
case MapType.Quake:
case MapType.Quake2:
case MapType.Daikatana:
@@ -39,10 +62,10 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 36);
return BitConverter.ToInt32(Data, 36);
}
case MapType.DMoMaM: {
return BitConverter.ToInt32(data, 40);
return BitConverter.ToInt32(Data, 40);
}
default: {
return -1;
@@ -51,7 +74,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Quake:
case MapType.Quake2:
case MapType.Daikatana:
@@ -68,11 +91,11 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
bytes.CopyTo(data, 36);
bytes.CopyTo(Data, 36);
break;
}
case MapType.DMoMaM: {
bytes.CopyTo(data, 40);
bytes.CopyTo(Data, 40);
break;
}
}
@@ -81,9 +104,9 @@ namespace LibBSP {
[Index("leaves")] public int firstLeaf {
get {
switch (type) {
switch (MapType) {
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 40);
return BitConverter.ToInt32(Data, 40);
}
default: {
return -1;
@@ -92,9 +115,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Nightfire: {
bytes.CopyTo(data, 40);
bytes.CopyTo(Data, 40);
break;
}
}
@@ -103,9 +126,9 @@ namespace LibBSP {
[Count("leaves")] public int numLeaves {
get {
switch (type) {
switch (MapType) {
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 44);
return BitConverter.ToInt32(Data, 44);
}
default: {
return -1;
@@ -114,9 +137,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Nightfire: {
bytes.CopyTo(data, 44);
bytes.CopyTo(Data, 44);
break;
}
}
@@ -125,19 +148,19 @@ namespace LibBSP {
[Index("brushes")] public int firstBrush {
get {
switch (type) {
switch (MapType) {
case MapType.STEF2:
case MapType.STEF2Demo:
case MapType.Quake3:
case MapType.MOHAA:
case MapType.Raven:
case MapType.FAKK: {
return BitConverter.ToInt32(data, 32);
return BitConverter.ToInt32(Data, 32);
}
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
return BitConverter.ToInt32(data, 40);
return BitConverter.ToInt32(Data, 40);
}
default: {
return -1;
@@ -146,20 +169,20 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.STEF2:
case MapType.STEF2Demo:
case MapType.Quake3:
case MapType.MOHAA:
case MapType.Raven:
case MapType.FAKK: {
bytes.CopyTo(data, 32);
bytes.CopyTo(Data, 32);
break;
}
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
bytes.CopyTo(data, 40);
bytes.CopyTo(Data, 40);
break;
}
}
@@ -168,19 +191,19 @@ namespace LibBSP {
[Count("brushes")] public int numBrushes {
get {
switch (type) {
switch (MapType) {
case MapType.STEF2:
case MapType.STEF2Demo:
case MapType.Quake3:
case MapType.MOHAA:
case MapType.Raven:
case MapType.FAKK: {
return BitConverter.ToInt32(data, 36);
return BitConverter.ToInt32(Data, 36);
}
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
return BitConverter.ToInt32(data, 44);
return BitConverter.ToInt32(Data, 44);
}
default: {
return -1;
@@ -189,20 +212,20 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.STEF2:
case MapType.STEF2Demo:
case MapType.Quake3:
case MapType.MOHAA:
case MapType.Raven:
case MapType.FAKK: {
bytes.CopyTo(data, 36);
bytes.CopyTo(Data, 36);
break;
}
case MapType.CoD:
case MapType.CoD2:
case MapType.CoD4: {
bytes.CopyTo(data, 44);
bytes.CopyTo(Data, 44);
break;
}
}
@@ -211,9 +234,9 @@ namespace LibBSP {
[Index("faces")] public int firstFace {
get {
switch (type) {
switch (MapType) {
case MapType.CoD4: {
return BitConverter.ToInt16(data, 24);
return BitConverter.ToInt16(Data, 24);
}
case MapType.CoD:
case MapType.CoD2:
@@ -223,7 +246,7 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.FAKK: {
return BitConverter.ToInt32(data, 24);
return BitConverter.ToInt32(Data, 24);
}
case MapType.Quake2:
case MapType.Daikatana:
@@ -240,16 +263,16 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 40);
return BitConverter.ToInt32(Data, 40);
}
case MapType.DMoMaM: {
return BitConverter.ToInt32(data, 44);
return BitConverter.ToInt32(Data, 44);
}
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 48);
return BitConverter.ToInt32(Data, 48);
}
case MapType.Quake: {
return BitConverter.ToInt32(data, 56);
return BitConverter.ToInt32(Data, 56);
}
default: {
return -1;
@@ -258,10 +281,10 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD4: {
data[24] = bytes[0];
data[25] = bytes[1];
Data[24] = bytes[0];
Data[25] = bytes[1];
break;
}
case MapType.CoD:
@@ -272,7 +295,7 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.FAKK: {
bytes.CopyTo(data, 24);
bytes.CopyTo(Data, 24);
break;
}
case MapType.Quake2:
@@ -290,19 +313,19 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
bytes.CopyTo(data, 40);
bytes.CopyTo(Data, 40);
break;
}
case MapType.DMoMaM: {
bytes.CopyTo(data, 44);
bytes.CopyTo(Data, 44);
break;
}
case MapType.Nightfire: {
bytes.CopyTo(data, 48);
bytes.CopyTo(Data, 48);
break;
}
case MapType.Quake: {
bytes.CopyTo(data, 56);
bytes.CopyTo(Data, 56);
break;
}
}
@@ -311,9 +334,9 @@ namespace LibBSP {
[Count("faces")] public int numFaces {
get {
switch (type) {
switch (MapType) {
case MapType.CoD4: {
return BitConverter.ToInt16(data, 28);
return BitConverter.ToInt16(Data, 28);
}
case MapType.CoD:
case MapType.CoD2:
@@ -323,7 +346,7 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.FAKK: {
return BitConverter.ToInt32(data, 28);
return BitConverter.ToInt32(Data, 28);
}
case MapType.Quake2:
case MapType.Daikatana:
@@ -340,16 +363,16 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 44);
return BitConverter.ToInt32(Data, 44);
}
case MapType.DMoMaM: {
return BitConverter.ToInt32(data, 48);
return BitConverter.ToInt32(Data, 48);
}
case MapType.Nightfire: {
return BitConverter.ToInt32(data, 52);
return BitConverter.ToInt32(Data, 52);
}
case MapType.Quake: {
return BitConverter.ToInt32(data, 60);
return BitConverter.ToInt32(Data, 60);
}
default: {
return -1;
@@ -358,10 +381,10 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD4: {
data[28] = bytes[0];
data[29] = bytes[1];
Data[28] = bytes[0];
Data[29] = bytes[1];
break;
}
case MapType.CoD:
@@ -372,7 +395,7 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.FAKK: {
bytes.CopyTo(data, 28);
bytes.CopyTo(Data, 28);
break;
}
case MapType.Quake2:
@@ -390,19 +413,19 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
bytes.CopyTo(data, 44);
bytes.CopyTo(Data, 44);
break;
}
case MapType.DMoMaM: {
bytes.CopyTo(data, 48);
bytes.CopyTo(Data, 48);
break;
}
case MapType.Nightfire: {
bytes.CopyTo(data, 52);
bytes.CopyTo(Data, 52);
break;
}
case MapType.Quake: {
bytes.CopyTo(data, 60);
bytes.CopyTo(Data, 60);
break;
}
}
@@ -412,10 +435,10 @@ namespace LibBSP {
[Index("markSurfaces")]
public int firstLeafPatch {
get {
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2: {
return BitConverter.ToInt32(data, 32);
return BitConverter.ToInt32(Data, 32);
}
default: {
return -1;
@@ -424,10 +447,10 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2: {
bytes.CopyTo(data, 32);
bytes.CopyTo(Data, 32);
break;
}
}
@@ -436,10 +459,10 @@ namespace LibBSP {
[Count("markSurfaces")] public int numLeafPatches {
get {
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2: {
return BitConverter.ToInt32(data, 36);
return BitConverter.ToInt32(Data, 36);
}
default: {
return -1;
@@ -448,10 +471,10 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD:
case MapType.CoD2: {
bytes.CopyTo(data, 36);
bytes.CopyTo(Data, 36);
break;
}
}
@@ -462,36 +485,44 @@ namespace LibBSP {
/// Creates a new <see cref="Model"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <param name="parent">The <see cref="ILump"/> this <see cref="Model"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public Model(byte[] data, MapType type, int version = 0) : this() {
public Model(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="Model"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{Model}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="Model"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<Model> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{Model}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<Model> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<Model>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.Titanfall: {
structLength = 32;
break;
return 32;
}
case MapType.Quake3:
case MapType.Raven:
@@ -499,8 +530,7 @@ namespace LibBSP {
case MapType.STEF2Demo:
case MapType.MOHAA:
case MapType.FAKK: {
structLength = 40;
break;
return 40;
}
case MapType.Quake2:
case MapType.Daikatana:
@@ -520,33 +550,21 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
structLength = 48;
break;
return 48;
}
case MapType.DMoMaM: {
structLength = 52;
break;
return 52;
}
case MapType.Nightfire: {
structLength = 56;
break;
return 56;
}
case MapType.Quake: {
structLength = 64;
break;
return 64;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the Leaf lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<Model> lump = new List<Model>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -1,31 +1,62 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
/// <summary>
/// Contains all data needed for a node in a BSP tree.
/// </summary>
public struct Node {
public struct Node : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public int plane {
get {
return BitConverter.ToInt32(data, 0);
return BitConverter.ToInt32(Data, 0);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 0);
BitConverter.GetBytes(value).CopyTo(Data, 0);
}
}
public int child1 {
get {
switch (type) {
switch (MapType) {
case MapType.Quake: {
return BitConverter.ToInt16(data, 4);
return BitConverter.ToInt16(Data, 4);
}
case MapType.SiN:
case MapType.SoF:
@@ -52,7 +83,7 @@ namespace LibBSP {
case MapType.FAKK:
case MapType.CoD:
case MapType.CoD2: {
return BitConverter.ToInt32(data, 4);
return BitConverter.ToInt32(Data, 4);
}
default: {
return 0;
@@ -61,10 +92,10 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Quake: {
data[4] = bytes[0];
data[5] = bytes[1];
Data[4] = bytes[0];
Data[5] = bytes[1];
break;
}
case MapType.SiN:
@@ -92,7 +123,7 @@ namespace LibBSP {
case MapType.FAKK:
case MapType.CoD:
case MapType.CoD2: {
bytes.CopyTo(data, 4);
bytes.CopyTo(Data, 4);
break;
}
}
@@ -101,9 +132,9 @@ namespace LibBSP {
public int child2 {
get {
switch (type) {
switch (MapType) {
case MapType.Quake: {
return BitConverter.ToInt16(data, 6);
return BitConverter.ToInt16(Data, 6);
}
case MapType.SiN:
case MapType.SoF:
@@ -130,7 +161,7 @@ namespace LibBSP {
case MapType.FAKK:
case MapType.CoD:
case MapType.CoD2: {
return BitConverter.ToInt32(data, 8);
return BitConverter.ToInt32(Data, 8);
}
default: {
return 0;
@@ -139,10 +170,10 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Quake: {
data[6] = bytes[0];
data[7] = bytes[1];
Data[6] = bytes[0];
Data[7] = bytes[1];
break;
}
case MapType.SiN:
@@ -170,7 +201,7 @@ namespace LibBSP {
case MapType.FAKK:
case MapType.CoD:
case MapType.CoD2: {
bytes.CopyTo(data, 8);
bytes.CopyTo(Data, 8);
break;
}
}
@@ -181,43 +212,50 @@ namespace LibBSP {
/// Creates a new <see cref="Node"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public Node(byte[] data, MapType type, int version = 0) : this() {
/// <param name="parent">The <see cref="ILump"/> this <see cref="Node"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public Node(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="Node"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{Node}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="Node"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<Node> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{Node}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<Node> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<Node>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.Quake: {
structLength = 24;
break;
return 24;
}
case MapType.Quake2:
case MapType.SiN:
case MapType.SoF:
case MapType.Daikatana: {
structLength = 28;
break;
return 28;
}
case MapType.Source17:
case MapType.Source18:
@@ -230,12 +268,10 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.DMoMaM: {
structLength = 32;
break;
return 32;
}
case MapType.Vindictus: {
structLength = 48;
break;
return 48;
}
case MapType.Quake3:
case MapType.FAKK:
@@ -246,21 +282,12 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Raven:
case MapType.Nightfire: {
structLength = 36;
break;
return 36;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the Node lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<Node> lump = new List<Node>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
#if UNITY
@@ -15,17 +16,47 @@ namespace LibBSP {
/// <summary>
/// Holds the data for a patch in a CoD BSP.
/// </summary>
public struct Patch {
public struct Patch : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public short shader {
get {
switch (type) {
switch (MapType) {
case MapType.CoD: {
return BitConverter.ToInt16(data, 0);
return BitConverter.ToInt16(Data, 0);
}
default: {
return -1;
@@ -34,9 +65,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD: {
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
break;
}
}
@@ -45,9 +76,9 @@ namespace LibBSP {
public short patchType {
get {
switch (type) {
switch (MapType) {
case MapType.CoD: {
return BitConverter.ToInt16(data, 2);
return BitConverter.ToInt16(Data, 2);
}
default: {
return -1;
@@ -56,9 +87,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD: {
bytes.CopyTo(data, 2);
bytes.CopyTo(Data, 2);
break;
}
}
@@ -67,10 +98,10 @@ namespace LibBSP {
public Vector2d dimensions {
get {
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 0) {
return new Vector2d(BitConverter.ToInt16(data, 4), BitConverter.ToInt16(data, 6));
return new Vector2d(BitConverter.ToInt16(Data, 4), BitConverter.ToInt16(Data, 6));
} else {
return new Vector2d(float.NaN, float.NaN);
}
@@ -81,11 +112,11 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 0) {
BitConverter.GetBytes((short)value.x).CopyTo(data, 4);
BitConverter.GetBytes((short)value.y).CopyTo(data, 6);
BitConverter.GetBytes((short)value.x).CopyTo(Data, 4);
BitConverter.GetBytes((short)value.y).CopyTo(Data, 6);
}
break;
}
@@ -95,10 +126,10 @@ namespace LibBSP {
public int flags {
get {
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 0) {
return BitConverter.ToInt32(data, 8);
return BitConverter.ToInt32(Data, 8);
} else {
return -1;
}
@@ -110,10 +141,10 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 0) {
bytes.CopyTo(data, 8);
bytes.CopyTo(Data, 8);
}
break;
}
@@ -123,12 +154,12 @@ namespace LibBSP {
[Index("patchVerts")] public int firstVertex {
get {
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 0) {
return BitConverter.ToInt32(data, 12);
return BitConverter.ToInt32(Data, 12);
} else if (patchType == 1) {
return BitConverter.ToInt32(data, 8);
return BitConverter.ToInt32(Data, 8);
} else {
return -1;
}
@@ -140,12 +171,12 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 0) {
bytes.CopyTo(data, 12);
bytes.CopyTo(Data, 12);
} else if (patchType == 1) {
bytes.CopyTo(data, 8);
bytes.CopyTo(Data, 8);
}
break;
}
@@ -155,12 +186,12 @@ namespace LibBSP {
[Count("patchVerts")] public int numVertices {
get {
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 0) {
return BitConverter.ToInt16(data, 4) * BitConverter.ToInt16(data, 6);
return BitConverter.ToInt16(Data, 4) * BitConverter.ToInt16(Data, 6);
} else if (patchType == 1) {
return BitConverter.ToInt16(data, 4);
return BitConverter.ToInt16(Data, 4);
} else {
return -1;
}
@@ -172,11 +203,11 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 1) {
data[4] = bytes[0];
data[5] = bytes[1];
Data[4] = bytes[0];
Data[5] = bytes[1];
}
break;
}
@@ -186,10 +217,10 @@ namespace LibBSP {
[Count("patchIndices")] public int numIndices {
get {
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 1) {
return BitConverter.ToInt16(data, 6);
return BitConverter.ToInt16(Data, 6);
} else {
return -1;
}
@@ -201,11 +232,11 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 1) {
data[6] = bytes[0];
data[7] = bytes[1];
Data[6] = bytes[0];
Data[7] = bytes[1];
}
break;
}
@@ -215,10 +246,10 @@ namespace LibBSP {
[Index("patchIndices")] public int firstIndex {
get {
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 1) {
return BitConverter.ToInt32(data, 12);
return BitConverter.ToInt32(Data, 12);
} else {
return -1;
}
@@ -230,10 +261,10 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.CoD: {
if (patchType == 1) {
bytes.CopyTo(data, 12);
bytes.CopyTo(Data, 12);
}
break;
}
@@ -245,49 +276,49 @@ namespace LibBSP {
/// Creates a new <see cref="Patch"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <param name="parent">The <see cref="ILump"/> this <see cref="Patch"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public Patch(byte[] data, MapType type, int version = 0) : this() {
public Patch(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="Patch"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{Patch}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="Patch"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<Patch> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{Patch}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<Patch> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<Patch>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.CoD: {
structLength = 16;
break;
return 16;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the Patch lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<Patch> lump = new List<Patch>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace LibBSP {
@@ -16,17 +17,47 @@ namespace LibBSP {
/// <summary>
/// Handles the data needed for a static model object from MoHAA.
/// </summary>
public struct StaticModel {
public struct StaticModel : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public string name {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return data.ToNullTerminatedString(0, 128);
return Data.ToNullTerminatedString(0, 128);
}
default: {
return null;
@@ -34,13 +65,13 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
for (int i = 0; i < 128; ++i) {
data[i] = 0;
Data[i] = 0;
}
byte[] strBytes = Encoding.ASCII.GetBytes(value);
Array.Copy(strBytes, 0, data, 0, Math.Min(strBytes.Length, 127));
Array.Copy(strBytes, 0, Data, 0, Math.Min(strBytes.Length, 127));
break;
}
}
@@ -49,9 +80,9 @@ namespace LibBSP {
public Vector3d origin {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return new Vector3d(BitConverter.ToSingle(data, 128), BitConverter.ToSingle(data, 132), BitConverter.ToSingle(data, 136));
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);
@@ -59,9 +90,9 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
value.GetBytes().CopyTo(data, 128);
value.GetBytes().CopyTo(Data, 128);
break;
}
}
@@ -70,9 +101,9 @@ namespace LibBSP {
public Vector3d angles {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return new Vector3d(BitConverter.ToSingle(data, 140), BitConverter.ToSingle(data, 144), BitConverter.ToSingle(data, 148));
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);
@@ -80,9 +111,9 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
value.GetBytes().CopyTo(data, 140);
value.GetBytes().CopyTo(Data, 140);
break;
}
}
@@ -91,9 +122,9 @@ namespace LibBSP {
public float scale {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return BitConverter.ToSingle(data, 152);
return BitConverter.ToSingle(Data, 152);
}
default: {
return float.NaN;
@@ -102,9 +133,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
bytes.CopyTo(data, 152);
bytes.CopyTo(Data, 152);
break;
}
}
@@ -113,9 +144,9 @@ namespace LibBSP {
[Index("vertices")] public int firstVertex {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return BitConverter.ToInt32(data, 156);
return BitConverter.ToInt32(Data, 156);
}
default: {
return -1;
@@ -124,9 +155,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
bytes.CopyTo(data, 156);
bytes.CopyTo(Data, 156);
break;
}
}
@@ -135,9 +166,9 @@ namespace LibBSP {
[Count("vertices")] public short numVertices {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return BitConverter.ToInt16(data, 160);
return BitConverter.ToInt16(Data, 160);
}
default: {
return -1;
@@ -146,9 +177,9 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
bytes.CopyTo(data, 160);
bytes.CopyTo(Data, 160);
break;
}
}
@@ -159,49 +190,49 @@ namespace LibBSP {
/// Creates a new <see cref="StaticModel"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of static prop lump this object is a member of.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public StaticModel(byte[] data, MapType type, int version = 0) : this() {
/// <param name="parent">The <see cref="ILump"/> this <see cref="StaticModel"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public StaticModel(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="StaticModel"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{StaticModel}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="StaticModel"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<StaticModel> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{StaticModel}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<StaticModel> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<StaticModel>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.MOHAA: {
structLength = 164;
break;
return 164;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the StaticModel lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<StaticModel> lump = new List<StaticModel>(numObjects);
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));
}
return lump;
}
/// <summary>

File diff suppressed because it is too large Load Diff

View File

@@ -24,17 +24,47 @@ namespace LibBSP {
/// For example, Nightfire's texture lump only contains 64-byte null-padded strings, but
/// Quake 2's has texture scaling included.
/// </remarks>
public struct Texture {
public struct Texture : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public string name {
get {
switch (type) {
switch (MapType) {
case MapType.Quake: {
return data.ToNullTerminatedString(0, 16);
return Data.ToNullTerminatedString(0, 16);
}
case MapType.STEF2:
case MapType.STEF2Demo:
@@ -46,12 +76,12 @@ namespace LibBSP {
case MapType.FAKK:
case MapType.MOHAA:
case MapType.Nightfire: {
return data.ToNullTerminatedString(0, 64);
return Data.ToNullTerminatedString(0, 64);
}
case MapType.Quake2:
case MapType.SoF:
case MapType.Daikatana: {
return data.ToNullTerminatedString(40, 32);
return Data.ToNullTerminatedString(40, 32);
}
case MapType.Source17:
case MapType.Source18:
@@ -66,10 +96,10 @@ namespace LibBSP {
case MapType.Vindictus:
case MapType.DMoMaM:
case MapType.Titanfall: {
return data.ToRawString();
return Data.ToRawString();
}
case MapType.SiN: {
return data.ToNullTerminatedString(36, 64);
return Data.ToNullTerminatedString(36, 64);
}
default: {
return null;
@@ -78,12 +108,12 @@ namespace LibBSP {
}
set {
byte[] bytes = Encoding.ASCII.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Quake: {
for (int i = 0; i < 16; ++i) {
data[i] = 0;
Data[i] = 0;
}
Array.Copy(bytes, 0, data, 0, Math.Min(bytes.Length, 15));
Array.Copy(bytes, 0, Data, 0, Math.Min(bytes.Length, 15));
break;
}
case MapType.STEF2:
@@ -97,18 +127,18 @@ namespace LibBSP {
case MapType.MOHAA:
case MapType.Nightfire: {
for (int i = 0; i < 64; ++i) {
data[i] = 0;
Data[i] = 0;
}
Array.Copy(bytes, 0, data, 0, Math.Min(bytes.Length, 63));
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;
Data[i + 40] = 0;
}
Array.Copy(bytes, 0, data, 40, Math.Min(bytes.Length, 31));
Array.Copy(bytes, 0, Data, 40, Math.Min(bytes.Length, 31));
break;
}
case MapType.Source17:
@@ -124,14 +154,14 @@ namespace LibBSP {
case MapType.Vindictus:
case MapType.DMoMaM:
case MapType.Titanfall: {
data = bytes;
Data = bytes;
break;
}
case MapType.SiN: {
for (int i = 0; i < 64; ++i) {
data[i + 36] = 0;
Data[i + 36] = 0;
}
Array.Copy(bytes, 0, data, 36, Math.Min(bytes.Length, 63));
Array.Copy(bytes, 0, Data, 36, Math.Min(bytes.Length, 63));
break;
}
}
@@ -140,9 +170,9 @@ namespace LibBSP {
public string mask {
get {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
return data.ToNullTerminatedString(76, 64);
return Data.ToNullTerminatedString(76, 64);
}
default: {
return null;
@@ -150,13 +180,13 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.MOHAA: {
for (int i = 0; i < 64; ++i) {
data[i + 76] = 0;
Data[i + 76] = 0;
}
byte[] strBytes = Encoding.ASCII.GetBytes(value);
Array.Copy(strBytes, 0, data, 76, Math.Min(strBytes.Length, 63));
Array.Copy(strBytes, 0, Data, 76, Math.Min(strBytes.Length, 63));
break;
}
}
@@ -165,12 +195,12 @@ namespace LibBSP {
public int flags {
get {
switch (type) {
switch (MapType) {
case MapType.Quake2:
case MapType.SoF:
case MapType.Daikatana:
case MapType.SiN: {
return BitConverter.ToInt32(data, 32);
return BitConverter.ToInt32(Data, 32);
}
case MapType.MOHAA:
case MapType.STEF2:
@@ -181,7 +211,7 @@ namespace LibBSP {
case MapType.CoD2:
case MapType.CoD4:
case MapType.FAKK: {
return BitConverter.ToInt32(data, 64);
return BitConverter.ToInt32(Data, 64);
}
default: {
return -1;
@@ -190,12 +220,12 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Quake2:
case MapType.SoF:
case MapType.Daikatana:
case MapType.SiN: {
bytes.CopyTo(data, 32);
bytes.CopyTo(Data, 32);
break;
}
case MapType.MOHAA:
@@ -207,7 +237,7 @@ namespace LibBSP {
case MapType.CoD2:
case MapType.CoD4:
case MapType.FAKK: {
bytes.CopyTo(data, 64);
bytes.CopyTo(Data, 64);
break;
}
}
@@ -216,7 +246,7 @@ namespace LibBSP {
public int contents {
get {
switch (type) {
switch (MapType) {
case MapType.STEF2:
case MapType.STEF2Demo:
case MapType.Raven:
@@ -226,7 +256,7 @@ namespace LibBSP {
case MapType.CoD4:
case MapType.FAKK:
case MapType.MOHAA: {
return BitConverter.ToInt32(data, 68);
return BitConverter.ToInt32(Data, 68);
}
default: {
return -1;
@@ -235,7 +265,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.STEF2:
case MapType.STEF2Demo:
case MapType.Raven:
@@ -245,7 +275,7 @@ namespace LibBSP {
case MapType.CoD4:
case MapType.FAKK:
case MapType.MOHAA: {
bytes.CopyTo(data, 68);
bytes.CopyTo(Data, 68);
break;
}
}
@@ -254,14 +284,14 @@ namespace LibBSP {
public TextureInfo texAxes {
get {
switch (type) {
switch (MapType) {
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)),
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)),
new Vector2d(1, 1),
-1, -1, 0);
}
@@ -271,19 +301,19 @@ namespace LibBSP {
}
}
set {
switch (type) {
switch (MapType) {
case MapType.Quake2:
case MapType.SoF:
case MapType.Daikatana:
case MapType.SiN: {
byte[] bytes = value.uAxis.GetBytes();
bytes.CopyTo(data, 0);
bytes.CopyTo(Data, 0);
bytes = value.vAxis.GetBytes();
bytes.CopyTo(data, 16);
bytes.CopyTo(Data, 16);
bytes = BitConverter.GetBytes(value.translation.x);
bytes.CopyTo(data, 12);
bytes.CopyTo(Data, 12);
bytes = BitConverter.GetBytes(value.translation.y);
bytes.CopyTo(data, 28);
bytes.CopyTo(Data, 28);
break;
}
}
@@ -294,27 +324,41 @@ namespace LibBSP {
/// Creates a new <see cref="Texture"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <param name="parent">The <see cref="ILump"/> this <see cref="Texture"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public Texture(byte[] data, MapType type, int version = 0) : this() {
public Texture(byte[] data, ILump parent) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <see cref="Textures"/> object.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Textures"/> object.</returns>
public static Textures LumpFactory(byte[] data, MapType type, int version = 0) {
return new Textures(data, type, version);
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Textures LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
return new Textures(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Depending on format, this is a variable length structure. Return -1. The <see cref="Textures"/> class will handle object creation.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>-1</returns>
public static int GetStructLength(MapType type, int version) {
return -1;
}
/// <summary>

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
#if UNITY
@@ -15,63 +16,93 @@ namespace LibBSP {
/// <summary>
/// Contains all the information for a single Texture Data object.
/// </summary>
public struct TextureData {
public struct TextureData : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public Vector3d reflectivity {
get {
return new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
return new Vector3d(BitConverter.ToSingle(Data, 0), BitConverter.ToSingle(Data, 4), BitConverter.ToSingle(Data, 8));
}
set {
value.GetBytes().CopyTo(data, 0);
value.GetBytes().CopyTo(Data, 0);
}
}
public int stringTableIndex {
get {
return BitConverter.ToInt32(data, 12);
return BitConverter.ToInt32(Data, 12);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 12);
BitConverter.GetBytes(value).CopyTo(Data, 12);
}
}
public int width {
get {
return BitConverter.ToInt32(data, 16);
return BitConverter.ToInt32(Data, 16);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 16);
BitConverter.GetBytes(value).CopyTo(Data, 16);
}
}
public int height {
get {
return BitConverter.ToInt32(data, 20);
return BitConverter.ToInt32(Data, 20);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 20);
BitConverter.GetBytes(value).CopyTo(Data, 20);
}
}
public int view_width {
get {
return BitConverter.ToInt32(data, 24);
return BitConverter.ToInt32(Data, 24);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 24);
BitConverter.GetBytes(value).CopyTo(Data, 24);
}
}
public int view_height {
get {
return BitConverter.ToInt32(data, 28);
return BitConverter.ToInt32(Data, 28);
}
set {
BitConverter.GetBytes(value).CopyTo(data, 28);
BitConverter.GetBytes(value).CopyTo(Data, 28);
}
}
@@ -79,42 +110,63 @@ namespace LibBSP {
/// Creates a new <see cref="TextureData"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public TextureData(byte[] data, MapType type, int version = 0) : this() {
/// <param name="parent">The <see cref="ILump"/> this <see cref="TextureData"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public TextureData(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="TextureData"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{TextureData}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="TextureData"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public static List<TextureData> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{TextureData}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<TextureData> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 32;
if (type == MapType.Titanfall) {
structLength = 36;
return new Lump<TextureData>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.Vindictus:
case MapType.TacticalInterventionEncrypted:
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: {
return 32;
}
case MapType.Titanfall: {
return 36;
}
default: {
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<TextureData> lump = new List<TextureData>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -20,12 +20,53 @@ namespace LibBSP {
/// <summary>
/// Class containing all data for a single <see cref="Entity"/>, including attributes, Source Entity I/O connections and solids.
/// </summary>
[Serializable] public class Entity : Dictionary<string, string>, IComparable, IComparable<Entity>, ISerializable {
[Serializable] public class Entity : Dictionary<string, string>, IComparable, IComparable<Entity>, ISerializable, ILumpObject {
private static IFormatProvider _format = CultureInfo.CreateSpecificCulture("en-US");
public const char ConnectionMemberSeparater = (char)0x1B;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s representing this <see cref="Entity"/>. If this is set, it will parse the bytes as a string.
/// If accessed, will return a <c>byte</c> array of <see cref="ToString"/>.
/// </summary>
public byte[] Data {
get {
return Encoding.ASCII.GetBytes(ToString());
}
set {
ParseString(Encoding.ASCII.GetString(value));
}
}
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
public List<EntityConnection> connections = new List<EntityConnection>();
public List<MAPBrush> brushes = new List<MAPBrush>();
@@ -164,41 +205,67 @@ namespace LibBSP {
/// <param name="data">Array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
public Entity(byte[] data, MapType type, int version = 0) : this(Encoding.ASCII.GetString(data).Split('\n')) { }
public Entity(byte[] data, ILump parent = null) {
Parent = parent;
Data = data;
}
/// <summary>
/// Initializes a new instance of an <see cref="Entity"/> with the given classname.
/// </summary>
/// <param name="className">Classname of the new <see cref="Entity"/>.</param>
public Entity(string className) : base(StringComparer.InvariantCultureIgnoreCase) {
public Entity(string className, ILump parent = null) : this(parent) {
Add("classname", className);
}
/// <summary>
/// Initializes a new instance of an <see cref="Entity"/> object with no initial properties.
/// </summary>
public Entity() : base(StringComparer.InvariantCultureIgnoreCase) { }
public Entity(ILump parent = null) : base(StringComparer.InvariantCultureIgnoreCase) {
Parent = parent;
}
/// <summary>
/// Initializes a new instance of an <see cref="Entity"/> object, copying the attributes, connections and brushes of the passed <see cref="Entity"/>.
/// </summary>
/// <param name="copy">The <see cref="Entity"/> to copy.</param>
public Entity(Entity copy) : base(copy, StringComparer.InvariantCultureIgnoreCase) {
public Entity(Entity copy, ILump parent = null) : base(copy, StringComparer.InvariantCultureIgnoreCase) {
connections = new List<EntityConnection>(copy.connections);
brushes = new List<MAPBrush>(copy.brushes);
Parent = parent;
}
/// <summary>
/// Initializes a new instance of an <see cref="Entity"/>, parsing the given <c>string</c> array into an <see cref="Entity"/> structure.
/// Initializes a new instance of the <see cref="Entity"/> class with serialized data.
/// </summary>
/// <param name="lines">Array of <c>string</c>s representing attributes, patches, brushes, displacements etc. to parse.</param>
public Entity(string[] lines) : base(StringComparer.InvariantCultureIgnoreCase) {
int braceCount = 0;
/// <param name="info">A <c>SerializationInfo</c> object containing the information required to serialize the <see cref="Entity"/>.</param>
/// <param name="context">A <c>StreamingContext</c> structure containing the source and destination of the serialized stream associated with the <see cref="Entity"/>.</param>
protected Entity(SerializationInfo info, StreamingContext context) : base(info, context) {
connections = (List<EntityConnection>)info.GetValue("connections", typeof(List<EntityConnection>));
brushes = (List<MAPBrush>)info.GetValue("brushes", typeof(List<MAPBrush>));
Parent = (ILump)info.GetValue("Parent", typeof(ILump));
}
/// <summary>
/// Parses the <c>string</c> <paramref name="st"/> into this <see cref="Entity"/> object.
/// All data in this <see cref="Entity"/> will be removed and replaced with the newly parsed data.
/// </summary>
/// <remarks>
/// This was necessary since the <see cref="Entity"/>(<c>string</c>) constructor was already used in a different way.
/// </remarks>
/// <param name="st">The string to parse.</param>
public void ParseString(string st) {
Clear();
brushes = new List<MAPBrush>();
connections = new List<EntityConnection>();
string[] lines = st.Split('\n');
int braceCount = 0;
bool inConnections = false;
bool inBrush = false;
List<string> child = new List<string>();
List<string> brushLines = new List<string>();
foreach (string line in lines) {
string current = line.Trim(' ', '\t', '\r');
@@ -206,7 +273,7 @@ namespace LibBSP {
// Cull everything after a "//"
bool inQuotes = false;
for (int i = 0; i < current.Length; ++i) {
if (current[i] == '\"') {
if (i == 0) {
inQuotes = !inQuotes;
@@ -229,8 +296,7 @@ namespace LibBSP {
if (string.IsNullOrEmpty(current)) {
continue;
}
// Perhaps I should not assume these will always be the first thing on the line
if (current[0] == '{') {
// If we're only one brace deep, and we have no prior information, assume a brush
if (braceCount == 1 && !inBrush && !inConnections) {
@@ -243,14 +309,14 @@ namespace LibBSP {
if (braceCount == 1) {
// If we determined we were inside a brush substructure
if (inBrush) {
child.Add(current);
brushes.Add(new MAPBrush(child.ToArray()));
child = new List<string>();
brushLines.Add(current);
brushes.Add(new MAPBrush(brushLines));
brushLines = new List<string>();
}
inBrush = false;
inConnections = false;
} else {
child.Add(current);
brushLines.Add(current);
}
continue;
} else if (current.Length >= 5 && current.Substring(0, 5) == "solid") {
@@ -262,7 +328,7 @@ namespace LibBSP {
}
if (inBrush) {
child.Add(current);
brushLines.Add(current);
continue;
}
@@ -270,29 +336,6 @@ namespace LibBSP {
}
}
/// <summary>
/// Initializes a new instance of the <see cref="Entity"/> class with serialized data.
/// </summary>
/// <param name="info">A <c>SerializationInfo</c> object containing the information required to serialize the <see cref="Entity"/>.</param>
/// <param name="context">A <c>StreamingContext</c> structure containing the source and destination of the serialized stream associated with the <see cref="Entity"/>.</param>
protected Entity(SerializationInfo info, StreamingContext context) : base(info, context) {
connections = (List<EntityConnection>)info.GetValue("connections", typeof(List<EntityConnection>));
brushes = (List<MAPBrush>)info.GetValue("brushes", typeof(List<MAPBrush>));
}
/// <summary>
/// Factory method to create an <see cref="Entity"/> from a <c>string</c> "<paramref name="st"/>" where
/// "<paramref name="st"/>" contains all lines for the entity, including attributes, brushes, etc.
/// </summary>
/// <remarks>
/// This was necessary since the <see cref="Entity(System.String)"/> constructor was already used in a different way.
/// </remarks>
/// <param name="st">The data to parse.</param>
/// <returns>The resulting <see cref="Entity"/> object.</returns>
public static Entity FromString(string st) {
return new Entity(st.Split('\n'));
}
/// <summary>
/// Renames the attribute named "<paramref name="oldName"/>" to "<paramref name="newName"/>". Replaces the old entry if it already exists.
/// </summary>
@@ -380,7 +423,7 @@ namespace LibBSP {
/// <summary>
/// Gets a <c>string</c> representation of this <see cref="Entity"/>.
/// </summary>
/// <returns><c>string</c> representation of this <see cref="Entity"/>.</returns>
/// <returns>A <c>string</c> representation of this <see cref="Entity"/>.</returns>
public override string ToString() {
StringBuilder output = new StringBuilder();
output.Append("{\n");
@@ -549,8 +592,12 @@ namespace LibBSP {
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>An <see cref="Entities"/> object, which is a <c>List</c> of <see cref="Entity"/>s.</returns>
public static Entities LumpFactory(byte[] data, MapType type, int version = 0) {
return new Entities(data, type);
public static Entities LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
return new Entities(data, bsp, lumpInfo);
}
/// <summary>

View File

@@ -0,0 +1,32 @@
using System;
using System.Reflection;
namespace LibBSP {
/// <summary>
/// Interface for an object intended to be stored in an <see cref="ILump"/> object.
/// </summary>
public interface ILumpObject {
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
ILump Parent { get; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
byte[] Data { get; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
MapType MapType { get; }
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
int LumpVersion { get; }
}
}

View File

@@ -8,41 +8,51 @@ namespace LibBSP {
/// <summary>
/// Class representing a group of <see cref="Entity"/> objects. Contains helpful methods to handle Entities in the <c>List</c>.
/// </summary>
[Serializable] public class Entities : List<Entity> {
[Serializable] public class Entities : Lump<Entity> {
/// <summary>
/// Initializes a new instance of an <see cref="Entities"/> object copying a passed <c>IEnumerable</c> of <see cref="Entity"/> objects.
/// </summary>
/// <param name="data">Collection of <see cref="Entity"/> objects to copy.</param>
public Entities(IEnumerable<Entity> data) : base(data) { }
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public Entities(IEnumerable<Entity> entities, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(entities, bsp, lumpInfo) { }
/// <summary>
/// Initializes a new instance of an <see cref="Entities"/> object with a specified initial capacity.
/// </summary>
/// <param name="initialCapacity">Initial capacity of the <c>List</c> of <see cref="Entity"/> objects.</param>
public Entities(int initialCapacity) : base(initialCapacity) { }
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public Entities(int initialCapacity, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(initialCapacity, bsp, lumpInfo) { }
/// <summary>
/// Initializes a new empty <see cref="Entities"/> object.
/// </summary>
public Entities() : base() { }
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public Entities(BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(bsp, lumpInfo) { }
/// <summary>
/// Initializes a new <see cref="Entities"/> object, parsing all the bytes in the passed <paramref name="file"/>.
/// </summary>
/// <remarks>
/// This will not populate Bsp or LumpInfo since a file is being read directly. This should not be used to read a
/// lump file, they should be handled through <see cref="BSPReader"/>. Use this to read raw MAP formats instead.
/// </remarks>
/// <param name="file">The file to read.</param>
/// <param name="type">The <see cref="MapType"/> of the source map.</param>
public Entities(FileInfo file, MapType type) : this(File.ReadAllBytes(file.FullName), type) { }
public Entities(FileInfo file) : this(File.ReadAllBytes(file.FullName)) { }
/// <summary>
/// Initializes a new <see cref="Entities"/> object, and parses the passed <c>byte</c> array into the <c>List</c>.
/// Initializes a new <see cref="Entities"/> object, and parses the passed <c>byte</c> array as a <c>string</c>.
/// </summary>
/// <param name="data"><c>Byte</c>s read from a file.</param>
/// <param name="type">The <see cref="MapType"/> of the source map.</param>
/// <param name="version">The version of this lump.</param>
public Entities(byte[] data, MapType type, int version = 0) : base() {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
public Entities(byte[] data, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(bsp, lumpInfo) {
// Keep track of whether or not we're currently in a set of quotation marks.
// I came across a map where the idiot map maker used { and } within a value. This broke the code before.
// I came across a map where the map maker used { and } within a value.
bool inQuotes = false;
int braceCount = 0;
@@ -90,7 +100,9 @@ namespace LibBSP {
if (offset == 0 || (char)data[offset - 1] == '\n' || (char)data[offset - 1] == '\t' || (char)data[offset - 1] == ' ' || (char)data[offset - 1] == '\r') {
--braceCount;
if (braceCount == 0) {
Add(Entity.FromString(current.ToString()));
Entity entity = new Entity(this);
entity.ParseString(current.ToString());
Add(entity);
// Reset StringBuilder
current.Length = 0;
}
@@ -146,7 +158,7 @@ namespace LibBSP {
/// Gets the first <see cref="Entity"/> with the specified targetname.
/// </summary>
/// <param name="targetname">Targetname attribute to find.</param>
/// <returns>Entity object with the specified targetname.</returns>
/// <returns><see cref="Entity"/> object with the specified targetname.</returns>
public Entity GetWithName(string targetname) {
return Find(entity => { return entity.name.Equals(targetname, StringComparison.InvariantCultureIgnoreCase); });
}

View File

@@ -0,0 +1,19 @@
namespace LibBSP {
/// <summary>
/// Interface for a Lump object.
/// </summary>
public interface ILump {
/// <summary>
/// The <see cref="BSP"/> this <see cref="ILump"/> came from.
/// </summary>
BSP Bsp { get; }
/// <summary>
/// The <see cref="LumpInfo"/> associated with this <see cref="ILump"/>.
/// </summary>
LumpInfo LumpInfo { get; }
}
}

View File

@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
namespace LibBSP {
public class Lump<T> : List<T>, ILump {
/// <summary>
/// The <see cref="BSP"/> this <see cref="ILump"/> came from.
/// </summary>
public BSP Bsp { get; protected set; }
/// <summary>
/// The <see cref="LumpInfo"/> associated with this <see cref="ILump"/>.
/// </summary>
public LumpInfo LumpInfo { get; protected set; }
/// <summary>
/// Creates an empty <c>Lump</c> of <typeparamref name="T"/> objects.
/// </summary>
/// <param name="bsp">The <see cref="BSP"/> which <paramref name="data"/> came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> object for this <c>Lump</c>.</param>
public Lump(BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) {
Bsp = bsp;
LumpInfo = lumpInfo;
}
/// <summary>
/// Creates a new <c>Lump</c> that contains elements copied from the passed <see cref="IEnumerable{T}"/>.
/// </summary>
/// <param name="items">The elements to copy into this <c>Lump</c>.</param>
/// <param name="bsp">The <see cref="BSP"/> which <paramref name="data"/> came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> object for this <c>Lump</c>.</param>
public Lump(IEnumerable<T> items, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(items) {
Bsp = bsp;
LumpInfo = lumpInfo;
}
/// <summary>
/// Creates an empty <c>Lump</c> of <typeparamref name="T"/> objects with the specified initial capactiy.
/// </summary>
/// <param name="capacity">The number of elements that can initially be stored.</param>
/// <param name="bsp">The <see cref="BSP"/> which <paramref name="data"/> came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> object for this <c>Lump</c>.</param>
public Lump(int capacity, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(capacity) {
Bsp = bsp;
LumpInfo = lumpInfo;
}
/// <summary>
/// Parses the passed <c>byte</c> array into a <c>Lump</c> of <typeparamref name="T"/> objects.
/// </summary>
/// <param name="data">Array of <c>byte</c>s to parse.</param>
/// <param name="structLength">Number of <c>byte</c>s to copy into the elements. Negative values indicate a variable length, which is not supported by this constructor.</param>
/// <param name="bsp">The <see cref="BSP"/> which <paramref name="data"/> came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> object for this <c>Lump</c>.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
/// <exception cref="NotSupportedException"><paramref name="structLength"/> is negative.</exception>
public Lump(byte[] data, int structLength, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(data.Length / structLength) {
if (data == null) {
throw new ArgumentNullException();
}
if (structLength <= 0) {
throw new NotSupportedException("Cannot use the base Lump constructor for variable length lumps (structLength was negative). Create a derived class with a new constructor instead.");
}
Bsp = bsp;
LumpInfo = lumpInfo;
for (int i = 0; i < data.Length / structLength; ++i) {
byte[] bytes = new byte[structLength];
Array.Copy(data, (i * structLength), bytes, 0, structLength);
Add((T)Activator.CreateInstance(typeof(T), new object[] { bytes, this }));
}
}
}
}

View File

@@ -7,7 +7,17 @@ namespace LibBSP {
/// <summary>
/// List class for numbers. Can handle any integer data type except <c>ulong</c>.
/// </summary>
public class NumList : IList<long>, ICollection<long>, IEnumerable<long>, IList, ICollection, IEnumerable {
public class NumList : IList<long>, ICollection<long>, IEnumerable<long>, IList, ICollection, IEnumerable, ILump {
/// <summary>
/// The <see cref="BSP"/> this <see cref="ILump"/> came from.
/// </summary>
public BSP Bsp { get; protected set; }
/// <summary>
/// The <see cref="LumpInfo"/> associated with this <see cref="ILump"/>.
/// </summary>
public LumpInfo LumpInfo { get; protected set; }
/// <summary>
/// Enum of the types that may be used in this class.
@@ -32,10 +42,12 @@ namespace LibBSP {
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The type of number to store.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public NumList(byte[] data, DataType type) {
public NumList(byte[] data, DataType type, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) {
if (data == null) {
throw new ArgumentNullException();
}
Bsp = bsp;
LumpInfo = lumpInfo;
this.data = data;
this.type = type;
}
@@ -55,8 +67,8 @@ namespace LibBSP {
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The type of number to store.</param>
/// <returns>The resulting <see cref="NumList"/>.</returns>
public static NumList LumpFactory(byte[] data, DataType type) {
return new NumList(data, type);
public static NumList LumpFactory(byte[] data, DataType type, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) {
return new NumList(data, type, bsp, lumpInfo);
}
/// <summary>

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace LibBSP {
#if UNITY
@@ -21,11 +22,41 @@ namespace LibBSP {
/// Some BSP formats lack this lump (or the information is contained in a
/// different lump) so their cases will be left out.
/// </summary>
[Serializable] public struct TextureInfo {
[Serializable] public struct TextureInfo : ILumpObject {
public byte[] data;
public MapType type;
public int version;
/// <summary>
/// The <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public ILump Parent { get; private set; }
/// <summary>
/// Array of <c>byte</c>s used as the data source for this <see cref="ILumpObject"/>.
/// </summary>
public byte[] Data { get; private set; }
/// <summary>
/// The <see cref="LibBSP.MapType"/> to use to interpret <see cref="Data"/>.
/// </summary>
public MapType MapType {
get {
if (Parent == null || Parent.Bsp == null) {
return MapType.Undefined;
}
return Parent.Bsp.version;
}
}
/// <summary>
/// The version number of the <see cref="ILump"/> this <see cref="ILumpObject"/> came from.
/// </summary>
public int LumpVersion {
get {
if (Parent == null) {
return 0;
}
return Parent.LumpInfo.version;
}
}
// No BSP format uses these so they are fields.
public Vector2d scale;
@@ -33,35 +64,35 @@ namespace LibBSP {
public Vector3d uAxis {
get {
return new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8));
return new Vector3d(BitConverter.ToSingle(Data, 0), BitConverter.ToSingle(Data, 4), BitConverter.ToSingle(Data, 8));
}
set {
value.GetBytes().CopyTo(data, 0);
value.GetBytes().CopyTo(Data, 0);
}
}
public Vector3d vAxis {
get {
return new Vector3d(BitConverter.ToSingle(data, 16), BitConverter.ToSingle(data, 20), BitConverter.ToSingle(data, 24));
return new Vector3d(BitConverter.ToSingle(Data, 16), BitConverter.ToSingle(Data, 20), BitConverter.ToSingle(Data, 24));
}
set {
value.GetBytes().CopyTo(data, 16);
value.GetBytes().CopyTo(Data, 16);
}
}
public Vector2d translation {
get {
return new Vector2d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 28));
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);
BitConverter.GetBytes((float)value.x).CopyTo(Data, 12);
BitConverter.GetBytes((float)value.y).CopyTo(Data, 28);
}
}
public int flags {
get {
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -73,13 +104,14 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 64);
return BitConverter.ToInt32(Data, 64);
}
case MapType.DMoMaM: {
return BitConverter.ToInt32(data, 88);
return BitConverter.ToInt32(Data, 88);
}
case MapType.Quake: {
return BitConverter.ToInt32(data, 36);
case MapType.Quake:
case MapType.Undefined: {
return BitConverter.ToInt32(Data, 36);
}
default: {
return -1;
@@ -88,7 +120,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -100,15 +132,16 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
bytes.CopyTo(data, 64);
bytes.CopyTo(Data, 64);
break;
}
case MapType.DMoMaM: {
bytes.CopyTo(data, 88);
bytes.CopyTo(Data, 88);
break;
}
case MapType.Quake: {
bytes.CopyTo(data, 36);
case MapType.Quake:
case MapType.Undefined: {
bytes.CopyTo(Data, 36);
break;
}
}
@@ -117,7 +150,7 @@ namespace LibBSP {
public int texture {
get {
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -129,13 +162,14 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
return BitConverter.ToInt32(data, 68);
return BitConverter.ToInt32(Data, 68);
}
case MapType.DMoMaM: {
return BitConverter.ToInt32(data, 92);
return BitConverter.ToInt32(Data, 92);
}
case MapType.Quake: {
return BitConverter.ToInt32(data, 32);
case MapType.Quake:
case MapType.Undefined: {
return BitConverter.ToInt32(Data, 32);
}
default: {
return -1;
@@ -144,7 +178,7 @@ namespace LibBSP {
}
set {
byte[] bytes = BitConverter.GetBytes(value);
switch (type) {
switch (MapType) {
case MapType.Source17:
case MapType.Source18:
case MapType.Source19:
@@ -156,15 +190,16 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
bytes.CopyTo(data, 68);
bytes.CopyTo(Data, 68);
break;
}
case MapType.DMoMaM: {
bytes.CopyTo(data, 92);
bytes.CopyTo(Data, 92);
break;
}
case MapType.Quake: {
bytes.CopyTo(data, 32);
case MapType.Quake:
case MapType.Undefined: {
bytes.CopyTo(Data, 32);
break;
}
}
@@ -175,17 +210,15 @@ namespace LibBSP {
/// Creates a new <see cref="TextureInfo"/> object from a <c>byte</c> array.
/// </summary>
/// <param name="data"><c>byte</c> array to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <exception cref="ArgumentNullException"><paramref name="data" /> was <c>null</c>.</exception>
public TextureInfo(byte[] data, MapType type, int version = 0) {
/// <param name="parent">The <see cref="ILump"/> this <see cref="TextureInfo"/> came from.</param>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was <c>null</c>.</exception>
public TextureInfo(byte[] data, ILump parent = null) {
if (data == null) {
throw new ArgumentNullException();
}
this.data = data;
this.type = type;
this.version = version;
Data = data;
Parent = parent;
scale = new Vector2d(1, 1);
rotation = 0;
}
@@ -193,22 +226,21 @@ namespace LibBSP {
/// <summary>
/// Creates a new <see cref="TextureInfo"/> object using the passed data.
/// </summary>
/// <param name="u">The U texture axis.</param>
/// <param name="v">The V texture axis.</param>
/// <param name="uAxis">The U texture axis.</param>
/// <param name="vAxis">The V texture axis.</param>
/// <param name="translation">Texture translation along both axes (in pixels).</param>
/// <param name="scale">Texture scale along both axes.</param>
/// <param name="flags">The flags for this <see cref="TextureInfo"/>.</param>
/// <param name="texture">Index into the texture list for the texture this <see cref="TextureInfo"/> uses.</param>
/// <param name="rotation">Rotation of the texutre axes.</param>
public TextureInfo(Vector3d u, Vector3d v, Vector2d translation, Vector2d scale, int flags, int texture, double rotation) {
this.data = new byte[40];
this.type = MapType.Quake;
this.version = 0;
public TextureInfo(Vector3d uAxis, Vector3d vAxis, Vector2d translation, Vector2d scale, int flags, int texture, double rotation) {
Data = new byte[40];
Parent = null;
this.scale = scale;
this.rotation = rotation;
uAxis = u;
vAxis = v;
this.uAxis = uAxis;
this.vAxis = vAxis;
this.translation = translation;
this.flags = flags;
this.texture = texture;
@@ -228,27 +260,36 @@ namespace LibBSP {
}
/// <summary>
/// Factory method to parse a <c>byte</c> array into a <c>List</c> of <see cref="TextureInfo"/> objects.
/// Factory method to parse a <c>byte</c> array into a <see cref="Lump{TextureInfo}"/>.
/// </summary>
/// <param name="data">The data to parse.</param>
/// <param name="type">The map type.</param>
/// <param name="version">The version of this lump.</param>
/// <returns>A <c>List</c> of <see cref="TextureInfo"/> objects.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> was null.</exception>
/// <exception cref="ArgumentException">This structure is not implemented for the given maptype.</exception>
public static List<TextureInfo> LumpFactory(byte[] data, MapType type, int version = 0) {
/// <param name="bsp">The <see cref="BSP"/> this lump came from.</param>
/// <param name="lumpInfo">The <see cref="LumpInfo"/> associated with this lump.</param>
/// <returns>A <see cref="Lump{TextureInfo}"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="data"/> parameter was <c>null</c>.</exception>
public static Lump<TextureInfo> LumpFactory(byte[] data, BSP bsp, LumpInfo lumpInfo) {
if (data == null) {
throw new ArgumentNullException();
}
int structLength = 0;
switch (type) {
return new Lump<TextureInfo>(data, GetStructLength(bsp.version, lumpInfo.version), bsp, lumpInfo);
}
/// <summary>
/// Gets the length of this struct's data for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.
/// </summary>
/// <param name="mapType">The <see cref="LibBSP.MapType"/> of the BSP.</param>
/// <param name="lumpVersion">The version number for the lump.</param>
/// <returns>The length, in <c>byte</c>s, of this struct.</returns>
/// <exception cref="ArgumentException">This struct is not valid or is not implemented for the given <paramref name="mapType"/> and <paramref name="lumpVersion"/>.</exception>
public static int GetStructLength(MapType mapType, int lumpVersion = 0) {
switch (mapType) {
case MapType.Nightfire: {
structLength = 32;
break;
return 32;
}
case MapType.Quake: {
structLength = 40;
break;
case MapType.Quake:
case MapType.Undefined: {
return 40;
}
case MapType.Source17:
case MapType.Source18:
@@ -261,25 +302,15 @@ namespace LibBSP {
case MapType.L4D2:
case MapType.TacticalInterventionEncrypted:
case MapType.Vindictus: {
structLength = 72;
break;
return 72;
}
case MapType.DMoMaM: {
structLength = 96;
break;
return 96;
}
default: {
throw new ArgumentException("Map type " + type + " isn't supported by the Leaf lump factory.");
throw new ArgumentException("Lump object " + MethodBase.GetCurrentMethod().DeclaringType.Name + " does not exist in map type " + mapType + " or has not been implemented.");
}
}
int numObjects = data.Length / structLength;
List<TextureInfo> lump = new List<TextureInfo>(numObjects);
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));
}
return lump;
}
/// <summary>

View File

@@ -26,13 +26,15 @@ namespace LibBSP {
/// Creates a new <see cref="MAPBrush"/> object using the supplied <c>string</c> array as data.
/// </summary>
/// <param name="lines">Data to parse.</param>
public MAPBrush(string[] lines) {
public MAPBrush(IList<string> lines) {
int braceCount = 0;
bool brushDef3 = false;
bool inPatch = false;
bool inTerrain = false;
List<string> child = new List<string>();
foreach (string line in lines) {
for (int i = 0; i < lines.Count; ++i) {
string line = lines[i];
if (line[0] == '{') {
braceCount++;
if (braceCount == 1 || brushDef3) { continue; }

View File

@@ -116,10 +116,10 @@ namespace LibBSP {
}
binaryReader.Close();
}
return new LumpInfo();
return default(LumpInfo);
}
default: {
return null;
return default(LumpInfo);
}
}
}
@@ -132,7 +132,7 @@ namespace LibBSP {
/// <returns>A <see cref="LumpInfo"/> object containing information about the lump.</returns>
private LumpInfo GetLumpInfoAtOffset(int offset, MapType version) {
if (bspFile.Length < offset + 16) {
return new LumpInfo();
return default(LumpInfo);
}
byte[] input;
using (FileStream stream = new FileStream(bspFile.FullName, FileMode.Open, FileAccess.Read)) {