Exemple #1
0
 /// <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(LumpInfo)) : base(bsp, lumpInfo)
 {
 }
Exemple #2
0
        /// <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(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 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(string.Format("Brace mismatch when parsing entities! Entity: {0} Brace level: {1}", Count, braceCount));
            }
        }
Exemple #3
0
 /// <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(LumpInfo)) : base(entities, bsp, lumpInfo)
 {
 }
Exemple #4
0
 /// <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(LumpInfo)) : base(initialCapacity, bsp, lumpInfo)
 {
 }
Exemple #5
0
 /// <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)
 {
 }
Exemple #6
0
 /// <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.ModelDictionary = dictionary.ToArray();
 }
 /// <summary>
 /// 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)
 {
 }
Exemple #8
0
 /// <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(LumpInfo)) : base(bsp, lumpInfo)
 {
 }
Exemple #9
0
 /// <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;
 }
Exemple #10
0
        /// <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, BSP bsp, LumpInfo lumpInfo = default(LumpInfo))
        {
            if (data == null)
            {
                throw new ArgumentNullException();
            }

            int structLength = 0;

            switch (bsp.version)
            {
            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.L4D2:
            case MapType.Source27:
            case MapType.Titanfall: {
                structLength = 16;
                break;
            }

            case MapType.Vindictus:
            case MapType.DMoMaM: {
                structLength = 20;
                break;
            }

            default: {
                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 = (bsp.version == MapType.DMoMaM) ? 8 : 4;
                int lowestLumpOffset     = int.MaxValue;

                for (int i = 0; i < numGameLumps; ++i)
                {
                    int lumpIdent = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset);
                    int lumpFlags;
                    int lumpVersion;
                    int lumpOffset;
                    int lumpLength;
                    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);
                        lumpLength  = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 16);
                    }
                    else
                    {
                        lumpFlags   = BitConverter.ToUInt16(data, (i * structLength) + lumpDictionaryOffset + 4);
                        lumpVersion = BitConverter.ToUInt16(data, (i * structLength) + lumpDictionaryOffset + 6);
                        lumpOffset  = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 8);
                        lumpLength  = BitConverter.ToInt32(data, (i * structLength) + lumpDictionaryOffset + 12);
                    }
                    LumpInfo info = new LumpInfo {
                        ident   = lumpIdent,
                        flags   = lumpFlags,
                        version = lumpVersion,
                        offset  = lumpOffset,
                        length  = lumpLength,
                    };
                    this[(GameLumpType)info.ident] = info;

                    if (info.offset < lowestLumpOffset)
                    {
                        lowestLumpOffset = info.offset;
                    }
                }
            }
        }
Exemple #11
0
 /// <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;
 }
Exemple #12
0
 /// <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;
 }
Exemple #13
0
 /// <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)
 {
     ModelDictionary = new string[] { };
 }
Exemple #14
0
        /// <summary>
        /// Gets the information for lump "<paramref name="index"/>" for this BSP file when reading it as "<paramref name="version"/>".
        /// </summary>
        /// <param name="index">The numerical index of this lump.</param>
        /// <param name="version">The type of BSP to interpret the file as.</param>
        /// <returns>A <see cref="LumpInfo"/> object containing information about the lump.</returns>
        /// <exception cref="IndexOutOfRangeException">"<paramref name="index"/>" is less than zero, or greater than the number of lumps allowed by "<paramref name="version"/>".</exception>
        public LumpInfo GetLumpInfo(int index, MapType version)
        {
            if (index < 0 || index >= BSP.GetNumLumps(version))
            {
                throw new IndexOutOfRangeException();
            }

            switch (version)
            {
            case MapType.Quake:
            case MapType.Nightfire: {
                return(GetLumpInfoAtOffset(4 + (8 * index), version));
            }

            case MapType.Quake2:
            case MapType.Daikatana:
            case MapType.SiN:
            case MapType.SoF:
            case MapType.Quake3:
            case MapType.Raven:
            case MapType.CoD:
            case MapType.CoD2: {
                return(GetLumpInfoAtOffset(8 + (8 * index), version));
            }

            case MapType.STEF2:
            case MapType.STEF2Demo:
            case MapType.MOHAA:
            case MapType.FAKK: {
                return(GetLumpInfoAtOffset(12 + (8 * index), version));
            }

            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: {
                if (lumpFiles == null)
                {
                    LoadLumpFiles();
                }
                if (lumpFiles.ContainsKey(index))
                {
                    return(lumpFiles[index]);
                }
                return(GetLumpInfoAtOffset(8 + (16 * index), version));
            }

            case MapType.Titanfall: {
                if (lumpFiles == null)
                {
                    LoadLumpFiles();
                }
                if (lumpFiles.ContainsKey(index))
                {
                    return(lumpFiles[index]);
                }
                return(GetLumpInfoAtOffset((16 * (index + 1)), version));
            }

            case MapType.CoD4: {
                using (FileStream stream = new FileStream(bspFile.FullName, FileMode.Open, FileAccess.Read)) {
                    BinaryReader binaryReader = new BinaryReader(stream);
                    stream.Seek(8, SeekOrigin.Begin);
                    int numlumps = binaryReader.ReadInt32();
                    int offset   = (numlumps * 8) + 12;
                    for (int i = 0; i < numlumps; i++)
                    {
                        int id     = binaryReader.ReadInt32();
                        int length = binaryReader.ReadInt32();
                        if (id == index)
                        {
                            return(new LumpInfo()
                                {
                                    offset = offset,
                                    length = length
                                });
                        }
                        else
                        {
                            offset += length;
                            while (offset % 4 != 0)
                            {
                                offset++;
                            }
                        }
                    }
                    binaryReader.Close();
                }
                return(default(LumpInfo));
            }

            default: {
                return(default(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)
 {
 }
Exemple #16
0
 /// <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(LumpInfo))
 {
     return(new NumList(data, type, 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)
 {
 }
Exemple #18
0
 /// <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>
 /// 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="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, int structLength, BSP bsp = null, LumpInfo lumpInfo = default(LumpInfo)) : base(data, structLength, bsp, lumpInfo)
 {
 }
Exemple #20
0
        /// <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();
            }

            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] == (byte)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));
            }
        }
Exemple #21
0
 /// <summary>
 /// 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[] { };
 }