Exemple #1
0
        /// <summary>
        /// Update the Saveability of every MapObject in this map, setting
        /// instance entities to be Saveability.Children.
        /// </summary>
        /// <param name="map"></param>
        /// <returns>A copy of the input Map with its MapObjects' Saveability
        /// updated, in preparation for writing to disk as a string.</returns>
        public override Map Collapse()
        {
            var collapsed = new QuakeMap(this);

            collapsed.MapObjects.Clear();

            int worldspawnIndex = MapObjects.FindIndex(o => o.Definition.ClassName == "worldspawn");

            MapObject worldspawn = MapObjects[worldspawnIndex];

            collapsed.MapObjects.Add(worldspawn);

            for (int i = 0; i < MapObjects.Count; i++)
            {
                if (i != worldspawnIndex)
                {
                    List <MapObject> collapsedObject = MapObjects[i].Collapse();

                    foreach (MapObject co in collapsedObject)
                    {
                        if (co.Definition.ClassName == "worldspawn")
                        {
                            worldspawn.Renderables.AddRange(co.Renderables);
                        }
                        else
                        {
                            collapsed.MapObjects.Add(co);
                        }
                    }
                }
            }

            return(collapsed);
        }
Exemple #2
0
        public string ToString(QuakeSideFormat format)
        {
            var sb = new StringBuilder();

            // First build the final worldspawn.
            int       worldspawnIndex = MapObjects.FindIndex(o => o.Definition.ClassName == "worldspawn");
            MapObject worldspawn      = MapObjects[worldspawnIndex];

            foreach (MapObject mo in AllObjects)
            {
                // Only copy solids to worldspawn if that's all this entity
                // is set to save, otherwise let it get handled later.
                if (mo.Saveability == Saveability.Solids)
                {
                    worldspawn.Renderables.AddRange(mo.Renderables);
                }
            }

            sb.AppendLine(new QuakeBlock(worldspawn).ToString(format));

            for (int i = 0; i < MapObjects.Count; i++)
            {
                if (i == worldspawnIndex)
                {
                    continue;
                }

                MapObject mo = MapObjects[i];

                // Avoid saving a null character to the output.
                if (mo.Saveability == Saveability.None)
                {
                    continue;
                }

                sb.AppendLine(new QuakeBlock(mo).ToString(format));
            }

            return(sb.ToString());
        }
Exemple #3
0
        public override Map Parse()
        {
            string oldCwd = Directory.GetCurrentDirectory();

            Directory.SetCurrentDirectory(Path.GetDirectoryName(AbsolutePath ?? oldCwd));

            OnProgressUpdated(this, new ProgressEventArgs(0, "Cleaning up raw input..."));

            // FIXME: Only strip leading tabs! Or just tabs not within a key or value?
            string stripped = Raw
                              .Replace("\r", String.Empty)
                              .Replace("\n", String.Empty)
                              .Replace("\t", String.Empty);

            // Modern Quake sourceports allow for transparency in textures,
            // indicated by an open curly brace in the texture name. Any open
            // curly brace that's actually a delimiter will be followed by an
            // open parenthesis or one or more whitespace characters. Texture
            // names will instead have ordinary text characters after the brace.
            List <string> split = stripped.SplitAndKeepDelimiters(
                $"{OpenDelimiter} ",
                $"{OpenDelimiter}(",
                $"{OpenDelimiter}\"",
                CloseDelimiter).ToList();

            split.RemoveAll(s => s.Trim().Length == 0 || s.Trim() == "\"");

            // The regex patterns above include capture groups to retain some
            // delimiters in the output, but they end up in the same item in the
            // list resulting from Split. This ugly loop fixes that.
            int item = 0;

            while (item < split.Count)
            {
                if (split[item] == "{(")
                {
                    split[item]     = "{";
                    split[item + 1] = $"({split[item + 1]}";
                    item++;
                }
                else if (split[item] == "{\"")
                {
                    split[item]     = "{";
                    split[item + 1] = $"\"{split[item + 1]}";
                    item++;
                }
                else
                {
                    item++;
                }
            }

            OnProgressUpdated(this, new ProgressEventArgs(25, "Creating map objects..."));

            int i = 0;

            while (i < split.Count)
            {
                int firstBraceIndex = split.IndexOf("{", i);

                var block = new QuakeBlock(split, firstBraceIndex, Definitions);
                MapObjects.Add(new QuakeMapObject(block, Definitions, Textures));

                i = firstBraceIndex + block.RawLength;
            }

            // First build the final worldspawn.
            int       worldspawnIndex = MapObjects.FindIndex(o => o.Definition.ClassName == "worldspawn");
            MapObject worldspawn      = MapObjects[worldspawnIndex];

            foreach (MapObject mo in AllObjects)
            {
                Aabb += mo.Aabb;
            }

            FixUp();

            Directory.SetCurrentDirectory(oldCwd);

            return(this);
        }