private Tag LoadTag(string path) { int index = LocateTagByID(inverseDictionary[path]); Tag tag = new Tag(tags[index].Type); Bsp bsp = null; string[] stringArray = strings.ToArray(); switch (tags[index].Type) { case StructureBsp: bsp = GetBsp(tags[index].Identifier); map.Position = bsp.BspOffset; tag.ReadData(reader, shared, bsp.Magic - bsp.BspHeaderOffset, dictionary, stringArray, coconuts, globals, path); break; case StructureLightmap: bsp = GetBsp(tags[index].Identifier); map.Position = bsp.LightmapOffset; tag.ReadData(reader, shared, bsp.Magic - bsp.BspHeaderOffset, dictionary, stringArray, coconuts, globals, path); break; default: map.Position = unchecked (tags[index].Offset - magic); tag.ReadData(reader, shared, magic, dictionary, stringArray, coconuts, globals, path); break; } return(tag); }
/// <summary> /// Returns true if Order instances are equal /// </summary> /// <param name="other">Instance of Order to be compared</param> /// <returns>Boolean</returns> public bool Equals(Order other) { // credit: http://stackoverflow.com/a/10454552/677735 if (other == null) { return(false); } return((Side == other.Side || Side != null && Side.Equals(other.Side)) && (Sv == other.Sv || Sv != null && Sv.Equals(other.Sv)) && (Pt == other.Pt || Pt != null && Pt.Equals(other.Pt)) && (Ot == other.Ot || Ot != null && Ot.Equals(other.Ot)) && (P == other.P || P != null && P.Equals(other.P)) && (Sc == other.Sc || Sc != null && Sc.Equals(other.Sc)) && (Rc == other.Rc || Rc != null && Rc.Equals(other.Rc)) && (S == other.S || S != null && S.Equals(other.S)) && (Pd == other.Pd || Pd != null && Pd.Equals(other.Pd)) && (Rac == other.Rac || Rac != null && Rac.Equals(other.Rac)) && (Md == other.Md || Md != null && Md.Equals(other.Md)) && (Sl == other.Sl || Sl != null && Sl.Equals(other.Sl)) && (Avp == other.Avp || Avp != null && Avp.Equals(other.Avp)) && (Sm == other.Sm || Sm != null && Sm.Equals(other.Sm)) && (Id == other.Id || Id != null && Id.Equals(other.Id)) && (Bsp == other.Bsp || Bsp != null && Bsp.Equals(other.Bsp)) && (Status == other.Status || Status != null && Status.Equals(other.Status)) && (Sr == other.Sr || Sr != null && Sr.Equals(other.Sr)) && (Cd == other.Cd || Cd != null && Cd.Equals(other.Cd))); }
/// <summary> /// 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="bsp">The <see cref="BSP.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> /// 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="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) : base(bsp, lumpInfo) { if (data == null || bsp == null) { throw new ArgumentNullException(); } if (data.Length > 0) { int offset = 0; ModelDictionary = new string[BitConverter.ToInt32(data, 0)]; offset += 4; for (int i = 0; i < ModelDictionary.Length; ++i) { ModelDictionary[i] = data.ToNullTerminatedString(offset, 128); offset += 128; } LeafIndices = new short[BitConverter.ToInt32(data, offset)]; offset += 4; for (int i = 0; i < LeafIndices.Length; ++i) { LeafIndices[i] = BitConverter.ToInt16(data, offset); offset += 2; } 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 (lumpInfo.version == 12) // So far only Titanfall { offset += 12; } else { offset += 4; } if (numProps > 0) { structLength = (data.Length - offset) / numProps; for (int i = 0; i < numProps; ++i) { byte[] bytes = new byte[structLength]; Array.Copy(data, offset, bytes, 0, structLength); Add(new StaticProp(bytes, this)); offset += structLength; } } } else { ModelDictionary = new string[0]; } }
/// <summary> /// Creates a new <see cref="NumList"/> object from a <c>byte</c> array. /// </summary> /// <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, Bsp bsp = null, LumpInfo lumpInfo = default) { if (data == null) { throw new ArgumentNullException(); } Bsp = bsp; LumpInfo = lumpInfo; this.data = data; Type = type; }
// TODO: Also create a wadmaker.config file, if the wad contained fonts or simple images (mipmap textures are the default behavior, so those don't need a config, // unless the user wants to create a wad file and wants different settings for those images such as different dithering, etc.) static void ExtractTextures(string inputFilePath, string outputDirectory, bool extractMipmaps, bool overwriteExistingFiles) { var stopwatch = Stopwatch.StartNew(); var imageFilesCreated = 0; var textures = new List <Texture>(); if (inputFilePath.EndsWith(".bsp")) { textures = Bsp.GetEmbeddedTextures(inputFilePath); } else { textures = Wad.Load(inputFilePath).Textures; } CreateDirectory(outputDirectory); var isDecalsWad = Path.GetFileName(inputFilePath).ToLowerInvariant() == "decals.wad"; foreach (var texture in textures) { var maxMipmap = extractMipmaps ? 4 : 1; for (int mipmap = 0; mipmap < maxMipmap; mipmap++) { try { var filePath = Path.Combine(outputDirectory, texture.Name + $"{(mipmap > 0 ? ".mipmap" + mipmap : "")}.png"); if (!overwriteExistingFiles && File.Exists(filePath)) { Log($"WARNING: {filePath} already exist. Skipping texture."); continue; } using (var image = isDecalsWad ? DecalTextureToImage(texture, mipmap) : TextureToImage(texture, mipmap)) { image.SaveAsPng(filePath); imageFilesCreated += 1; } } catch (Exception ex) { Log($"ERROR: failed to extract '{texture.Name}'{(mipmap > 0 ? $" (mipmap {mipmap})" : "")}: {ex.GetType().Name}: '{ex.Message}'."); } } } Log($"Extracted {imageFilesCreated} images from {textures.Count} textures from {inputFilePath} to {outputDirectory}, in {stopwatch.Elapsed.TotalSeconds:0.000} seconds."); }
static void RemoveEmbeddedTextures(string bspFilePath, string outputFilePath) { var stopwatch = Stopwatch.StartNew(); if (!bspFilePath.EndsWith(".bsp")) { throw new ArgumentException("Removing embedded textures requires a .bsp file."); } Log($"Removing embedded textures from '{bspFilePath}' and saving the result to '{outputFilePath}'."); var removedTextureCount = Bsp.RemoveEmbeddedTextures(bspFilePath, outputFilePath); Log($"Removed {removedTextureCount} embedded textures from {bspFilePath} in {stopwatch.Elapsed.TotalSeconds:0.000} seconds."); }
/// <summary> /// Returns true if RunnerDefinition instances are equal /// </summary> /// <param name="other">Instance of RunnerDefinition to be compared</param> /// <returns>Boolean</returns> public bool Equals(RunnerDefinition other) { // credit: http://stackoverflow.com/a/10454552/677735 if (other == null) { return(false); } return((SortPriority == other.SortPriority || SortPriority != null && SortPriority.Equals(other.SortPriority)) && (RemovalDate == other.RemovalDate || RemovalDate != null && RemovalDate.Equals(other.RemovalDate)) && (Id == other.Id || Id != null && Id.Equals(other.Id)) && (Hc == other.Hc || Hc != null && Hc.Equals(other.Hc)) && (AdjustmentFactor == other.AdjustmentFactor || AdjustmentFactor != null && AdjustmentFactor.Equals(other.AdjustmentFactor)) && (Bsp == other.Bsp || Bsp != null && Bsp.Equals(other.Bsp)) && (Status == other.Status || Status != null && Status.Equals(other.Status))); }
public override void OnInspectorGUI() { Bsp myTarget = (Bsp)target; if (GUILayout.Button("Generate")) { myTarget.Generate(); } if (GUILayout.Button("Clear")) { myTarget.Clear(); } DrawDefaultInspector(); }
/// <summary> /// Gets the hash code /// </summary> /// <returns>Hash code</returns> public override int GetHashCode() { // credit: http://stackoverflow.com/a/263416/677735 unchecked // Overflow is fine, just wrap { var hash = 41; // Suitable nullity checks etc, of course :) if (SortPriority != null) { hash = hash * 59 + SortPriority.GetHashCode(); } if (RemovalDate != null) { hash = hash * 59 + RemovalDate.GetHashCode(); } if (Id != null) { hash = hash * 59 + Id.GetHashCode(); } if (Hc != null) { hash = hash * 59 + Hc.GetHashCode(); } if (AdjustmentFactor != null) { hash = hash * 59 + AdjustmentFactor.GetHashCode(); } if (Bsp != null) { hash = hash * 59 + Bsp.GetHashCode(); } if (Status != null) { hash = hash * 59 + Status.GetHashCode(); } return(hash); } }
/// <summary> /// 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="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> /// <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 Lump <Vertex> LumpFactory(byte[] data, Bsp bsp, LumpInfo lumpInfo) { if (data == null) { throw new ArgumentNullException(); } int structLength = GetStructLength(bsp.Version, lumpInfo.version); int numObjects = data.Length / structLength; 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, bsp.Version, lumpInfo.version)); } return(lump); }
/// <summary> /// 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="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 Lump <Plane> LumpFactory(byte[] data, Bsp bsp, LumpInfo lumpInfo) { if (data == null) { throw new ArgumentNullException(); } int structLength = GetStructLength(bsp.Version, lumpInfo.version); int numObjects = data.Length / structLength; Lump <Plane> lump = new Lump <Plane>(numObjects, bsp, lumpInfo); for (int i = 0; i < numObjects; ++i) { Vector3 normal = new Vector3(BitConverter.ToSingle(data, structLength * i), BitConverter.ToSingle(data, (structLength * i) + 4), BitConverter.ToSingle(data, (structLength * i) + 8)); float distance = BitConverter.ToSingle(data, (structLength * i) + 12); lump.Add(new Plane(normal, distance)); } return(lump); }
/// <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.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) : 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), bytes, this)); } }
public override string ToString() { return(EventId.ToString() + "," + MarketId.ToString() + "," + (MeetingDate > DateTime.MinValue ? MeetingDate.ToString("yyyy-MM-dd") : @"\N") + "," + DayOfWeek.ToString() + "," + CountryCode.ToString() + "," + Track.ToString() + "," + (RaceTime > DateTime.MinValue ? RaceTime.ToString("yyyy-MM-dd HH:mm:ss") : @"\N") + "," + (OffTime > DateTime.MinValue ? OffTime.ToString("yyyy-MM-dd HH:mm:ss") : @"\N") + "," + MarketName.ToString() + "," + Entries.ToString() + "," + Runners.ToString() + "," + SelectionId.ToString() + "," + SelectionName.ToString() + "," + (Bsp > 1 ? Bsp.ToString() : @"\N") + "," + (NonRunner ? "1" : "0") + "," + (RemovalTime > DateTime.MinValue ? RemovalTime.ToString("yyyy-MM-dd HH:mm:ss") : @"\N") + "," + (NonRunner ? ReductionFactor.ToString() : @"\N") ); }
private void LoadTextures(SceneContext sc, Bitmap lightmap) { var textures = new List <Veldrid.Texture>(); var inBsp = _texture.NumMips > 0; var tex = _texture.NumMips > 0 ? _texture : Environment.Wads.Get(_texture.Name); _currentTextureIndex = 0; if (tex != null) { // Try and load animated textures if (tex.Value.Name.Length > 2 && tex.Value.Name[0] == '+') { // Animated textures can be 0-9 or A-J var c = tex.Value.Name[1] >= '0' && tex.Value.Name[1] <= '9' ? '0' : tex.Value.Name[1] >= 'A' && tex.Value.Name[1] <= 'J' ? 'A' : '\0'; if (c == '\0') { // + texture doesn't follow proper naming standards textures.Add(sc.ResourceCache.GetTexture2D(tex.Value)); } else { // Animated texture, load all the variants var name = tex.Value.Name.Substring(2); for (var i = c; i < c + 10; i++) { var frame = "+" + i + name; if (string.Equals(frame, _texture.Name, StringComparison.InvariantCultureIgnoreCase)) { _currentTextureIndex = i - c; } tex = inBsp ? Bsp.GetTexture(frame) : Environment.Wads.Get(frame); if (tex.HasValue) { textures.Add(sc.ResourceCache.GetTexture2D(tex.Value)); } } } } else { textures.Add(sc.ResourceCache.GetTexture2D(tex.Value)); } } else { textures.Add(sc.ResourceCache.GetPinkTexture()); } var lightmapTexture = sc.ResourceCache.GetTexture2D(lightmap); var lightmapTextureView = sc.ResourceCache.GetTextureView(lightmapTexture); if (!textures.Any()) { textures.Add(sc.ResourceCache.GetPinkTexture()); } foreach (var t in textures) { var tv = sc.ResourceCache.GetTextureView(t); _textureResources.Add(sc.ResourceCache.GetTextureResourceSet(tv, lightmapTextureView)); } }
/// <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) : base(capacity) { 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) : base(items) { Bsp = bsp; LumpInfo = lumpInfo; }
/// <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) { Bsp = bsp; LumpInfo = 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) : base(capacity, bsp, lumpInfo) { }
/// <summary> /// Gets the hash code /// </summary> /// <returns>Hash code</returns> public override int GetHashCode() { // credit: http://stackoverflow.com/a/263416/677735 unchecked // Overflow is fine, just wrap { var hash = 41; // Suitable nullity checks etc, of course :) if (Side != null) { hash = hash * 59 + Side.GetHashCode(); } if (Sv != null) { hash = hash * 59 + Sv.GetHashCode(); } if (Pt != null) { hash = hash * 59 + Pt.GetHashCode(); } if (Ot != null) { hash = hash * 59 + Ot.GetHashCode(); } if (P != null) { hash = hash * 59 + P.GetHashCode(); } if (Sc != null) { hash = hash * 59 + Sc.GetHashCode(); } if (Rc != null) { hash = hash * 59 + Rc.GetHashCode(); } if (S != null) { hash = hash * 59 + S.GetHashCode(); } if (Pd != null) { hash = hash * 59 + Pd.GetHashCode(); } if (Rac != null) { hash = hash * 59 + Rac.GetHashCode(); } if (Md != null) { hash = hash * 59 + Md.GetHashCode(); } if (Sl != null) { hash = hash * 59 + Sl.GetHashCode(); } if (Avp != null) { hash = hash * 59 + Avp.GetHashCode(); } if (Sm != null) { hash = hash * 59 + Sm.GetHashCode(); } if (Id != null) { hash = hash * 59 + Id.GetHashCode(); } if (Bsp != null) { hash = hash * 59 + Bsp.GetHashCode(); } if (Status != null) { hash = hash * 59 + Status.GetHashCode(); } if (Sr != null) { hash = hash * 59 + Sr.GetHashCode(); } if (Cd != null) { hash = hash * 59 + Cd.GetHashCode(); } return(hash); } }
/// <summary> /// Initializes a new <see cref="Entities"/> 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 Entities(Bsp bsp = null, LumpInfo lumpInfo = default) : base(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> /// <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) : base(initialCapacity, bsp, lumpInfo) { }
/// <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> /// <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) : base(entities, bsp, lumpInfo) { }
/// <summary> /// Creates a new <see cref="NumList"/> object from a <c>byte</c> array and returns it. /// </summary> /// <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, Bsp bsp = null, LumpInfo lumpInfo = default) { return(new NumList(data, type, 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) : base(bsp, lumpInfo) { if (data == null || bsp == null) { throw new ArgumentNullException(); } switch (bsp.Version) { case MapType.Nightfire: { structLength = 64; break; } case MapType.Quake3: case MapType.Raven: case MapType.CoD: case MapType.CoD2: case MapType.CoD4: { structLength = 72; break; } case MapType.Quake2: case MapType.Daikatana: case MapType.SoF: case MapType.Stef2: case MapType.Stef2Demo: case MapType.Fakk: { structLength = 76; break; } case MapType.Mohaa: { structLength = 140; break; } case MapType.SiN: { structLength = 180; break; } case MapType.Source17: case MapType.Source18: case MapType.Source19: case MapType.Source20: case MapType.Source21: case MapType.Source22: case MapType.Source23: case MapType.Source27: case MapType.L4D2: case MapType.TacticalInterventionEncrypted: case MapType.Vindictus: case MapType.DMoMaM: { int offset = 0; for (int i = 0; i < data.Length; ++i) { if (data[i] == 0x00) { // 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, this)); offset = i + 1; } } return; } case MapType.Quake: { int numElements = BitConverter.ToInt32(data, 0); structLength = 40; 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, this)); } return; } default: { throw new ArgumentException("Lump object Texture does not exist in map type " + bsp.Version + " or has not been implemented."); } } 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 Texture(bytes, this)); } }
public void Load(string file) { filename = file; string directory = Path.GetDirectoryName(file) + '\\'; #region open maps shared = new SharedMaps(new FileStream(directory + MainMenu, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), new FileStream(directory + Shared, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), new FileStream(directory + SinglePlayerShared, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); map = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); reader = new BinaryReader(map); writer = new BinaryWriter(map); #endregion #region header and index header = Reinterpret.Memory <MapHeader>(reader.ReadBytes(Marshal.SizeOf(typeof(MapHeader)))); map.Position = header.IndexOffset; index = Reinterpret.Memory <IndexHeader>(reader.ReadBytes(Marshal.SizeOf(typeof(IndexHeader)))); magic = (index.MagicConstant - header.IndexOffset - Marshal.SizeOf(typeof(IndexHeader))) + (header.AllExceptRawLength - header.IndexAndMetaLength - header.IndexLength); // each "TagType" is three dwords map.Position += 12 * index.TagTypeCount; tags = new List <IndexElement>(index.TagCount); for (int i = 0; i < index.TagCount; i++) { tags.Add(Reinterpret.Memory <IndexElement>(reader.ReadBytes(Marshal.SizeOf(typeof(IndexElement))))); } #endregion #region bsps int bspCount = 0; int bspOffset = 0; if (header.HeadSignature == HeadSignature) { map.Position = 528 + unchecked (tags[LocateTagByID(index.ScenarioIdentifier)].Offset - magic); bspCount = reader.ReadInt32(); bspOffset = unchecked (reader.ReadInt32() - magic); bsps = new Bsp[bspCount]; for (int i = 0; i < bspCount; i++) { bsps[i] = new Bsp(); map.Position = bsps[i].LocationInScenario = bspOffset + 68 * i; bsps[i].BspHeaderOffset = reader.ReadInt32(); int totalBspSize = reader.ReadInt32(); bsps[i].Magic = reader.ReadInt32(); map.Position += 8; bsps[i].BspID = reader.ReadInt32(); map.Position += 4; bsps[i].LightmapID = reader.ReadInt32(); /* * HEADER FORMAT * total size * pointer to bsp location * pointer to lightmap location * 'sbsp' */ map.Position = bsps[i].BspHeaderOffset; int inHeaderBspSize = reader.ReadInt32(); int inHeaderBspOffset = reader.ReadInt32(); int lightmapOffset = reader.ReadInt32(); bsps[i].BspOffset = (inHeaderBspOffset - bsps[i].Magic) + bsps[i].BspHeaderOffset; if (bsps[i].LightmapID == -1) { bsps[i].BspSize = inHeaderBspSize; } else { bsps[i].LightmapOffset = unchecked (lightmapOffset - bsps[i].Magic) + bsps[i].BspHeaderOffset; bsps[i].BspSize = bsps[i].LightmapOffset - bsps[i].BspOffset; bsps[i].LightmapSize = totalBspSize - bsps[i].BspSize; } } } #endregion #region strings strings = new List <string>(header.StringIdCount); map.Position = header.StringIdTableOffset; for (int i = 0; i < header.StringIdCount; i++) { strings.Add(String.Empty); while (true) { byte character = reader.ReadByte(); if (character == 0) { break; } else { strings[i] += Convert.ToChar(character); } } } string[] stringArray = strings.ToArray(); #endregion #region names map.Position = header.NameTableOffset; names = new List <string>(header.NameTableCount); dictionary = new Dictionary <int, string>(header.NameTableCount); inverseDictionary = new Dictionary <string, int>(header.NameTableCount); for (int i = 0; i < header.NameTableCount; i++) { names.Add(String.Empty); while (true) { byte character = reader.ReadByte(); if (character == 0) { break; } else { names[i] += Convert.ToChar(character); } } string dictionaryName = names[i] + '.' + Singleton <ClassManager> .Instance.GetClassByID(tags[i].Type).Name; dictionary.Add(tags[i].Identifier, dictionaryName); inverseDictionary.Add(dictionaryName, tags[i].Identifier); } #endregion #region globals and coconuts if (header.HeadSignature == HeadSignature) { map.Position = unchecked (tags[LocateTagByID(index.GlobalsIdentifier)].Offset - magic); globals = new Globals(reader); map.Position = unchecked (tags[index.TagCount - 1].Offset - magic); coconuts = new Coconuts(reader, shared, magic, stringArray); } #endregion #region composition if (header.HeadSignature == HeadSignature) { for (int i = 0; i < index.TagCount; i++) { int result; switch (tags[i].Type) { case Animation: map.Position = unchecked (tags[i].Offset - magic); result = Tag.GetFirstInternalResourceOffset(reader, Animation, magic); if (result != -1) { if (result < animationStart || animationStart == -1) { animationStart = result; } } break; case Decorators: map.Position = unchecked (tags[i].Offset - magic); result = Tag.GetFirstInternalResourceOffset(reader, Decorators, magic); if (result != -1) { if (result < decoratorStart || decoratorStart == -1) { decoratorStart = result; } } break; case ParticleModel: map.Position = unchecked (tags[i].Offset - magic); result = Tag.GetFirstInternalResourceOffset(reader, ParticleModel, magic); if (result != -1) { if (result < particleModelStart || particleModelStart == -1) { particleModelStart = result; } } break; case WeatherSystem: map.Position = unchecked (tags[i].Offset - magic); result = Tag.GetFirstInternalResourceOffset(reader, WeatherSystem, magic); if (result != -1) { if (result < weatherStart || weatherStart == -1) { weatherStart = result; } } break; case RenderModel: map.Position = unchecked (tags[i].Offset - magic); result = Tag.GetFirstInternalResourceOffset(reader, RenderModel, magic); if (result != -1) { if (result < modelStart || modelStart == -1) { modelStart = result; } } break; } } // this is (should be anyways) constant soundStart = Marshal.SizeOf(typeof(MapHeader)); // this is a calculated value bitmapStart = header.CrazyDataOffset + header.CrazyDataSize; for (int i = 0; i < bspCount; i++) { Bsp bsp = bsps[i]; if (bsp.BspOffset < bspMetaStart || bspMetaStart == -1) { bspMetaStart = bsp.BspHeaderOffset; } else if (bsp.LightmapOffset < bspMetaStart || bspMetaStart == -1) { bspMetaStart = bsp.BspHeaderOffset; } int result; if (bsp.BspID != -1) { reader.BaseStream.Position = bsp.BspOffset; result = Tag.GetFirstInternalResourceOffset(reader, StructureBsp, bsp.Magic - bsp.BspHeaderOffset); if (result != -1) { if (result < bspRawStart || bspRawStart == -1 && result != -1) { bspRawStart = result; } } } if (bsp.LightmapID != -1) { reader.BaseStream.Position = bsp.LightmapOffset; result = Tag.GetFirstInternalResourceOffset(reader, StructureLightmap, bsp.Magic - bsp.BspHeaderOffset); if (result != -1) { if (result < bspRawStart || bspRawStart == -1) { bspRawStart = result; } } } } foreach (Coconuts.ExtraInfo extraInfo in coconuts.ExtraInfos) { if (extraInfo.ResourceBlock.RawSize > 0) { uint encoded = Conversion.ToUInt(extraInfo.ResourceBlock.RawOffset); if ((encoded & 0xc0000000) == 0) { if (extraInfo.ResourceBlock.RawOffset < coconutsModelStart || coconutsModelStart == -1) { coconutsModelStart = extraInfo.ResourceBlock.RawOffset; } } } } if (bspMetaStart < 0) { bspMetaStart = header.StringIdPaddedOffset; } if (animationStart < 0) { animationStart = bspMetaStart; } if (coconutsModelStart < 0) { coconutsModelStart = animationStart; } if (particleModelStart < 0) { particleModelStart = coconutsModelStart; } if (decoratorStart < 0) { decoratorStart = particleModelStart; } if (weatherStart < 0) { weatherStart = decoratorStart; } if (bspRawStart < 0) { bspRawStart = weatherStart; } if (modelStart < 0) { modelStart = bspRawStart; } // these are all duplicates stringPaddedStart = header.StringIdPaddedOffset; stringIndexStart = header.StringIdIndexOffset; stringTableStart = header.StringIdTableOffset; nameTableStart = header.NameTableOffset; nameIndexStart = header.NameIndexOffset; crazyStart = header.CrazyDataOffset; // this can be calculated a multitude of ways unicodeStart = header.NameIndexOffset + header.NameTableCount * sizeof(int); } #endregion valid = true; }
void SetupScene() // initialise le niveau { dijkstra = FindObjectOfType <Disjskra>(); bspScript = FindObjectOfType <Bsp>(); }
/// <summary> /// Creates an empty <see cref="Textures"/> 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 Textures(Bsp bsp = null, LumpInfo lumpInfo = default) : base(bsp, lumpInfo) { }
/// <summary> /// 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="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) : 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 map maker used { and } within a value. bool inQuotes = false; int braceCount = 0; // The current character being read in the file. This is necessary because // we need to know exactly when the { and } characters occur and capture // all text between them. char currentChar; // This will be the resulting entity, fed into Entity.FromString StringBuilder current = new StringBuilder(); for (int offset = 0; offset < data.Length; ++offset) { currentChar = (char)data[offset]; if (currentChar == '\"') { if (offset == 0) { inQuotes = !inQuotes; } else if ((char)data[offset - 1] != '\\') { // Allow for escape-sequenced quotes to not affect the state machine, but only if the quote isn't at the end of a line. // Some Source engine entities use escape sequence quotes in values, but MoHAA has a map with an obvious erroneous backslash before a quote at the end of a line. if (inQuotes && (offset + 1 >= data.Length || (char)data[offset + 1] == '\n' || (char)data[offset + 1] == '\r')) { inQuotes = false; } } else { inQuotes = !inQuotes; } } if (!inQuotes) { if (currentChar == '{') { // Occasionally, texture paths have been known to contain { or }. Since these aren't always contained // in quotes, we must be a little more precise about how we want to select our delimiters. // As a general rule, though, making sure we're not in quotes is still very effective at error prevention. 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) { current.Append(currentChar); } if (!inQuotes) { if (currentChar == '}') { 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) { Entity entity = new Entity(this); entity.ParseString(current.ToString()); Add(entity); // Reset StringBuilder current.Length = 0; } } } } } if (braceCount != 0) { throw new ArgumentException( $"Brace mismatch when parsing entities! Entity: {Count} Brace level: {braceCount}"); } }
/// <summary> /// Creates a new <see cref="Textures"/> 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"/> 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) : base(items, bsp, lumpInfo) { }