Esempio n. 1
0
 public void Add(T entity)
 {
     if (entity == null)
     {
         throw new ArgumentNullException(nameof(entity));
     }
     if (DbContext != null)
     {
         Entities?.Add(entity);
     }
     // DbContext.SaveChanges();
 }
Esempio n. 2
0
 public void To_String()
 {
     var list = new Entities<Entity>();
     var nestedEntity = new NestedEntity();
     var testEntity = new TestEntity(nestedEntity);
     nestedEntity.Yo = "7";
     testEntity.Zo = "8";
     list.Add(testEntity);
     var builder = new StringBuilder();
     builder.AppendLine("ZO, YO, ");
     builder.AppendLine("8, 7, ");
     Assert.That(list.ToString(), Is.EqualTo(builder.ToString()));
 }
        /// <summary>
        /// 映射数据同步领域上下文范围
        /// </summary>
        /// <typeparam name="LocalEntity">本地实体</typeparam>
        /// <typeparam name="TService">服务器端数据同步服务对象</typeparam>
        static void Mapping <LocalEntity>()
            where LocalEntity : Pharos.Logic.LocalEntity.BaseEntity, new()
        {
            var type = typeof(LocalEntity);
            var key  = type.ToString();

            var titleAttr = Attribute.GetCustomAttribute(type, typeof(ExcelAttribute)) as ExcelAttribute;

            if (titleAttr != null)
            {
                TableNames.Add(key, titleAttr.Title);
            }
            Entities.Add(key, new LocalEntity());
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="SerializableEntityCollection"/> class.
 /// </summary>
 /// <param name="entities">The entities.</param>
 public SerializableEntityCollection(EntityCollection entities) : this()
 {
     foreach (var entity in entities.Entities)
     {
         Entities.Add(new SerializableEntity(entity));
     }
     EntityName                    = entities.EntityName;
     ExtensionData                 = entities.ExtensionData;
     MinActiveRowVersion           = entities.MinActiveRowVersion;
     MoreRecords                   = entities.MoreRecords;
     PagingCookie                  = entities.PagingCookie;
     TotalRecordCount              = entities.TotalRecordCount;
     TotalRecordCountLimitExceeded = entities.TotalRecordCountLimitExceeded;
 }
Esempio n. 5
0
        private void AddEntityToDictionary(Entity entity)
        {
            if (!Entities.ContainsKey(entity.PlayerNumber))
            {
                Entities.Add(entity.PlayerNumber, new Dictionary <EntityType, List <Entity> >());
            }

            if (!Entities[entity.PlayerNumber].ContainsKey(entity.Type))
            {
                Entities[entity.PlayerNumber].Add(entity.Type, new List <Entity>());
            }

            Entities[entity.PlayerNumber][entity.Type].Add(entity);
        }
Esempio n. 6
0
      internal ushort GetPlayerId(string name)
      {
         List<Player> players = new List<Player>(Entities.Values.Where(e => e is Player).Cast<Player>());
         Player player = players.FirstOrDefault(p => p.PlayerName == name);
         if (player == null)
         {
            // create and save new player with given name
            player = new Player(Configuration.World.NewPlayerSpawnPoint, name);
            Entities.Add(player.ID, player);
            Save(false);
         }

         return player.ID;
      }
Esempio n. 7
0
        public Task UpdateAsync(T entity, DateTimeOffset dateTimeOffset)
        {
            var matchingT = Entities.SingleOrDefault(x => x.Id == entity.Id);

            if (matchingT != null)
            {
                Entities.Remove(matchingT);
            }

            Entities.Add(entity);

            EventOccurred(entity);
            return(Task.CompletedTask);
        }
Esempio n. 8
0
        private void SmartDetect(string filename)
        {
            var detector = new FileHelpers.Detection.SmartFormatDetector();
            var formats  = detector.DetectFileFormat(filename);

            foreach (var format in formats)
            {
                Console.WriteLine("Format Detected, confidence:" + format.Confidence + "%");
                var delimited = format.ClassBuilderAsDelimited;

                Console.WriteLine("    Delimiter:" + delimited.Delimiter);
                Console.WriteLine("    Fields:");
                EntityStructure entityData = new EntityStructure();

                string sheetname;
                sheetname                       = FileName;
                entityData.Viewtype             = ViewType.File;
                entityData.DatabaseType         = DataSourceType.Text;
                entityData.DataSourceID         = FileName;
                entityData.DatasourceEntityName = FileName;
                entityData.Caption              = FileName;
                entityData.EntityName           = FileName;
                List <EntityField> Fields = new List <EntityField>();
                int y = 0;
                foreach (var field in delimited.Fields)
                {
                    Console.WriteLine("        " + field.FieldName + ": " + field.FieldType);


                    EntityField f = new EntityField();


                    //  f.tablename = sheetname;
                    f.fieldname = field.FieldName;
                    f.fieldtype = field.FieldType.ToString();
                    f.ValueRetrievedFromParent = false;
                    f.EntityName = sheetname;
                    f.FieldIndex = y;
                    Fields.Add(f);
                    y += 1;
                }

                entityData.Fields = new List <EntityField>();
                entityData.Fields.AddRange(Fields);
                Entities.Clear();
                EntitiesNames.Clear();
                EntitiesNames.Add(filename);
                Entities.Add(entityData);
            }
        }
Esempio n. 9
0
        public int Insert(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException();
            }

            Entities.Add(entity);
            //_context.Set<T>().Add(entity);

            var id = _context.SaveChanges();

            return(id);
        }
Esempio n. 10
0
        private Entities GetListInRecurit(SqlDataReader reader)
        {
            Major    major;
            Entities entities = new Entities();

            while (reader.Read())
            {
                major           = new Major();
                major.MajorId   = reader.GetInt32(0);
                major.MajorName = reader.GetString(1);
                entities.Add(major);
            }
            return(entities);
        }
Esempio n. 11
0
        /// <summary>
        /// Insert entities as async
        /// </summary>
        /// <param name="entities">Entities</param>
        public virtual async Task InsertAsync(IEnumerable <T> entities)
        {
            if (entities == null)
            {
                throw new ArgumentNullException("entities");
            }

            foreach (var entity in entities)
            {
                Entities.Add(entity);
            }

            await _context.SaveChangesAsync();
        }
Esempio n. 12
0
        /// <summary>
        /// tracks entity of type <typeparamref name="TEntity"/> in the context. Creates a new
        /// <see cref="ExcelEntityBuilder{TEntity}"/> and calls the passed configuration method
        /// </summary>
        /// <typeparam name="TEntity">type of the domain object</typeparam>
        /// <param name="buildAction">gets called by this method and contains the builder configuration</param>
        public virtual void Entity <TEntity>(Action <ExcelEntityBuilder <TEntity> > buildAction)
            where TEntity : class
        {
            var entityBuilder = new ExcelEntityBuilder <TEntity>();

            try {
                Entities.Add(typeof(TEntity), entityBuilder);
            }
            catch (ArgumentException e) {
                throw new ArgumentException($"The type '{typeof(TEntity)}' was already configured as a mapped entity in the excel context.");
            }

            buildAction(entityBuilder);
        }
Esempio n. 13
0
        public void Create(CiudadViewModel obj)
        {
            var entity = new Ciudade();

            entity.Codigo         = obj.Codigo;
            entity.Nombre         = obj.NombreCiudad;
            entity.Iddepartamento = obj.IdDepartamento;
            entity.Fechacreacion  = DateTime.Now;


            entities.Add(entity);
            entities.SaveChanges();
            obj.Id = entity.Id;
        }
        private void Attack(Planet p)
        {
            int shipsToAttack = p.Health > GameState.Ships ? GameState.Ships : p.Health;

            GameState.Ships -= shipsToAttack;

            HomePlanet hp = Entities.OfType <HomePlanet>().First();

            for (int i = 0; i < shipsToAttack; i++)
            {
                Raylib.PlaySound(AssetManager.GetSound("shipLaunch"));
                Entities.Add(new Ship(hp.Pos, p));
            }
        }
Esempio n. 15
0
 public RouteTestContext()
     : base()
 {
     Entities.Add(new Route(NextID, "Route 66"));
     Entities.Add(new Route(NextID, "Stairway to Heaven"));
     Entities.Add(new Route(NextID, "Bart Verminken met Bacon"));
     Entities.Add(new Route(NextID, ""));
     Entities.Add(new Route(NextID, ""));
     Entities.Add(new Route(NextID, ""));
     Entities.Add(new Route(NextID, ""));
     Entities.Add(new Route(NextID, ""));
     Entities.Add(new Route(NextID, ""));
     Entities.Add(new Route(NextID, ""));
 }
        public async Task <T> CreateAsync(T entity)
        {
            ValidateAndThrow(entity);
            AddDefaultValue(ref entity);
            Entities.Add(entity);

            var effectedCount = await _context.SaveChangesAsync();

            if (effectedCount == 0)
            {
                return(null);
            }
            return(entity);
        }
Esempio n. 17
0
 private void doSpawnEvent(SpawnEvent e)
 {
     Entities.Add(e.Entity);
     e.Entity.GameEngineEventHandler += (sender, args) => OnGameEngineEvent(sender, args);
     if (e.Entity is Ship)
     {
         (e.Entity as Ship).gameState = this;
         (e.Entity as Ship).FlavourTextEventHandler += OnFlavourText;
     }
     e.Entity.Position    = e.Position;
     e.Entity.Velocity    = e.Velocity;
     e.Entity.Orientation = e.Orientation;
     _physicsEngine.Register(e.Entity);
 }
Esempio n. 18
0
        /// <summary>
        /// Insert entities
        /// </summary>
        /// <param name="entities">Entities</param>
        public virtual void Insert(IEnumerable <T> entities)
        {
            if (entities == null)
            {
                throw new ArgumentNullException(nameof(entities));
            }

            foreach (var entity in entities)
            {
                Entities.Add(entity);
            }

            _context.SaveChanges();
        }
        internal int Save(EventoViewModel obj)
        {
            var entity = new Evento();

            if (obj.Id > 0)
            {
                entity = entities.Eventos.Where(e => e.Id == obj.Id).FirstOrDefault();
            }
            entity.Nombre            = obj.Nombre;
            entity.Multifuncion      = obj.Funciones.Count > 0;
            entity.CantidadFunciones = obj.Funciones.Count;
            entity.FechaInicial      = obj.FechaInicial;
            entity.FechaFinal        = obj.FechaFinal;
            entity.Empresario_id     = obj.Empresario_id;
            entity.Foto                   = obj.Foto;
            entity.Descripcion            = obj.Descripcion;
            entity.EdadMinima             = obj.EdadMinima;
            entity.EventoPublico          = obj.EventoPublico == "Sí";
            entity.TipoRecaudo_id         = obj.TipoRecaudo_id;
            entity.EntradasxPedidoOcompra = obj.EntradasxPedidoOcompra;
            entity.EntradasxUsuario       = obj.EntradasxUsuario;
            entity.AplicaServicio         = obj.AplicaServicio == "Sí";
            entity.CantidadDiasValides    = obj.CantidadFunciones;
            entity.AforoTotal             = obj.AforoTotal;
            entity.Estado                 = obj.Estado.ToString();
            entity.UrlVideo               = obj.UrlVideo;
            entity.StagesByMap            = obj.StagesByMap;

            if (obj.Id <= 0)
            {
                entity.FechaCreacion = DateTime.Now;
                entities.Add(entity);
            }
            entities.SaveChanges();
            obj.Id = entity.Id;
            return(obj.Id);
        }
        public string Create(List <PreguntaViewModel> obj, int idEvento)
        {
            var mensaje = "";

            try
            {
                foreach (var item in obj)
                {
                    var entityPregunta = new PreguntasEvento();
                    entityPregunta.IdEvento       = idEvento;
                    entityPregunta.NumeroPregunta = item.NumeroPregunta;
                    entityPregunta.TextoPregunta  = item.TextoPregunta;
                    entityPregunta.TipoRespuesta  = item.TipoRespuesta;
                    entities.Add(entityPregunta);
                    entities.SaveChanges();
                    var id = entityPregunta.Id;

                    foreach (var itemOpciones in item.Opciones)
                    {
                        var entityOpciones = new OpcionesPreguntaEvento();
                        entityOpciones.IdPregunta   = id;
                        entityOpciones.NumeroOpcion = itemOpciones.NumeroOpcion;
                        entityOpciones.TextoOpcion  = itemOpciones.TextoOpcion;
                        entities.Add(entityOpciones);
                        entities.SaveChanges();
                    }
                }

                mensaje = "OK";
            }
            catch (Exception ex)
            {
                mensaje = ex.Source + ex.Message;
            }

            return(mensaje);
        }
Esempio n. 21
0
        public override void DrawBackground()
        {
            List <Entity> NewEntities = viewPort.Render();

            foreach (Entity e in NewEntities)
            {
                Entity c = null;

                switch (e.Name)
                {
                case "ground": c = new Characters.Ground(this.gameObject); break;

                case "brick": c = new Characters.Brick(this.gameObject); break;

                case "pipeleftup": c = new Characters.Pipeleftup(this.gameObject); break;

                case "piperightup": c = new Characters.Piperightup(this.gameObject); break;

                case "pipeleft": c = new Characters.Pipeleft(this.gameObject); break;

                case "piperight": c = new Characters.Piperight(this.gameObject); break;

                case "coinbox": c = new Characters.CoinBox(this.gameObject); break;

                case "emptycoinbox": c = new Characters.EmptyCoinBox(this.gameObject); break;

                case "coinbounce": c = new Characters.CoinBounce(this.gameObject); break;

                case "block": c = new Characters.Block(this.gameObject); break;

                case "goomba": c = new Characters.Goomba(this.gameObject); break;

                case "koopatroopa": c = new Characters.KoopaTroopa(this.gameObject); break;
                }

                c.X             = e.X;
                c.Y             = e.Y;
                c.OriginTileCol = e.OriginTileCol;
                c.OriginTileRow = e.OriginTileRow;

                var xx = Entities.Where(x => x.OriginTileRow == c.OriginTileRow && x.OriginTileCol == c.OriginTileCol);
                if (xx.Count() == 0)
                {
                    Entities.Add(c);
                }
            }

            NewEntities.Clear();
        }
Esempio n. 22
0
        /// <summary>
        /// Insert
        /// </summary>
        /// <param name="entity">Entity object</param>
        public void Insert(T entity)
        {
            try
            {
                if (entity == null)
                {
                    throw new ArgumentNullException("entity");
                }

                OpenConnection();

                Entities.Add(entity);
                DbContext.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                foreach (DbEntityValidationResult item in dbEx.EntityValidationErrors)
                {
                    // Get entry

                    DbEntityEntry entry = item.Entry;
                    switch (entry.State)
                    {
                    case EntityState.Added:
                        entry.State = EntityState.Detached;
                        break;

                    case EntityState.Modified:
                        entry.CurrentValues.SetValues(entry.OriginalValues);
                        entry.State = EntityState.Unchanged;
                        break;

                    case EntityState.Deleted:
                        entry.State = EntityState.Unchanged;
                        break;
                    }
                }

                var msg = dbEx.EntityValidationErrors
                          .SelectMany(validationErrors => validationErrors.ValidationErrors)
                          .Aggregate(string.Empty, (current, validationError) => current
                                     + (string.Format("Property: {0} Error: {1}",
                                                      validationError.PropertyName, validationError.ErrorMessage)
                                        + Environment.NewLine));

                var fail = new Exception(msg, dbEx);
                throw fail;
            }
        }
        public void Create(MonedaViewModel obj)
        {
            var entity = new Tipomoneda();

            entity.Nombre    = obj.Nombre;
            entity.Codigo    = obj.Codigo;
            entity.Simbolo   = obj.Simbolo;
            entity.Decimales = obj.Decimales;

            entity.Fechacreacion = DateTime.Now;

            entities.Add(entity);
            entities.SaveChanges();
            obj.Id = entity.Id;
        }
Esempio n. 24
0
        public void To_String()
        {
            var list         = new Entities <Entity>();
            var nestedEntity = new NestedEntity();
            var testEntity   = new TestEntity(nestedEntity);

            nestedEntity.Yo = "7";
            testEntity.Zo   = "8";
            list.Add(testEntity);
            var builder = new StringBuilder();

            builder.AppendLine("ZO, YO, ");
            builder.AppendLine("8, 7, ");
            Assert.AreEqual(builder.ToString(), list.ToString());
        }
        public ClassEntity RegisterClass(ClassType type, string className, TypeDefinition typeDefinition, NamespaceEntity namespaceEntity)
        {
            var namespaceQualifiedId = namespaceEntity.GetNamespaceQualifiedId(className);

            if (Entities.Any(e => e.NamespaceQualifiedId.Equals(namespaceQualifiedId)))
            {
                throw new InvalidOperationException($"Class entity with id '{namespaceQualifiedId}' already exists.");
            }

            var entity = new ClassEntity(type, className, namespaceQualifiedId, typeDefinition, namespaceEntity);

            Entities.Add(entity);

            return(entity);
        }
Esempio n. 26
0
        private Entities GetList(SqlDataReader reader)
        {
            Entities entities = new Entities();
            Course   course;

            while (reader.Read())
            {
                course            = new Course();
                course.CourseId   = reader.GetInt32(0);
                course.CourseName = reader.GetString(1);
                course.CourseType = (CourseType)reader.GetInt32(2);
                entities.Add(course);
            }
            return(entities);
        }
Esempio n. 27
0
 public T Create(T entity)
 {
     try
     {
         if (entity == null)
         {
             throw new ArgumentNullException(nameof(entity));
         }
         return(Entities.Add(entity));
     }
     catch (Exception ex)
     {
         throw ex;
     }
 }
Esempio n. 28
0
        public void Insert(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }
            if (entity is LoggedBaseEntity)
            {
                (entity as LoggedBaseEntity).InsertedDate = DateTime.Now;
                (entity as LoggedBaseEntity).UpdatedDate  = DateTime.Now;
            }

            Entities.Add(entity);
            _context.SaveChanges();
        }
Esempio n. 29
0
        public async void OnNavigatedTo(NavigationContext context)
        {
            if (!context.IsPopBack)
            {
                await ExecuteBusyAsync(async() =>
                {
                    allEntities = await inspectionService.QueryInspectionStatusListAsync();

                    foreach (var entity in allEntities.Where(x => x.IsChecked))
                    {
                        Entities.Add(entity);
                    }
                });
            }
        }
Esempio n. 30
0
        public EnumEntity RegisterEnum(string enumName, NamespaceEntity namespaceEntity)
        {
            var namespaceQualifiedId = namespaceEntity.GetNamespaceQualifiedId(enumName);

            if (Entities.Any(e => e.NamespaceQualifiedId.Equals(namespaceQualifiedId)))
            {
                throw new InvalidOperationException($"Enum entity with id '{namespaceQualifiedId}' already exists.");
            }

            var entity = new EnumEntity(enumName, namespaceQualifiedId, namespaceEntity);

            Entities.Add(entity);

            return(entity);
        }
Esempio n. 31
0
        public override void Enter()
        {
            Button button = new Button(new Vector2f(GameOptions.Width / 2.0f, GameOptions.Height - 52.0f - 48.0f), "Main Menu");

            button.OnClick += () =>
            {
                //Game.PopState();
                Game.SetState(new MainMenu());
                return(true);
            };

            Entities.Add(button);

            base.Enter();
        }
Esempio n. 32
0
 private static Entities JoinInternal(EntityGroup g, string pname, object k)
 {
     var rlt = new Entities();
     Entities list = g.GetEntities();
     PropertyInfo info = null;
     foreach (Entity i in list)
     {
         if (info == null)
         {
             Type type = i.GetType();
             info = type.GetProperty(pname);
         }
         if (k.Equals(info.GetValue(i)))
         {
             rlt.Add(i);
         }
     }
     return rlt;
 }
Esempio n. 33
0
	// METHODS
	
	// +decompile()
	// Attempts to convert a map in a Doom WAD into a usable .MAP file. This has many
	// challenges, not the least of which is the fact that the Doom engine didn't use
	// brushes (at least, not in any sane way).
	public virtual Entities decompile()
	{
		DecompilerThread.OnMessage(this, "Decompiling...");
		DecompilerThread.OnMessage(this, doomMap.MapName);
		
		mapFile = new Entities();
		Entity world = new Entity("worldspawn");
		mapFile.Add(world);
		
		string[] lowerWallTextures = new string[doomMap.Sidedefs.Count];
		string[] midWallTextures = new string[doomMap.Sidedefs.Count];
		string[] higherWallTextures = new string[doomMap.Sidedefs.Count];
		
		short[] sectorTag = new short[doomMap.Sectors.Count];
		string playerStartOrigin = "";
		
		// Since Doom relied on sectors to define a cieling and floor height, and nothing else,
		// need to find the minimum and maximum used Z values. This is because the Doom engine
		// is only a pseudo-3D engine. For all it cares, the cieling and floor extend to their
		// respective infinities. For a GC/Hammer map, however, this cannot be the case.
		int ZMin = 32767; // Even though the values in the map will never exceed these, use ints here to avoid
		int ZMax = - 32768; // overflows, in case the map DOES go within 32 units of these values.
		for (int i = 0; i < doomMap.Sectors.Count; i++)
		{
			DSector currentSector = doomMap.Sectors[i];
			sectorTag[i] = currentSector.Tag;
			if (currentSector.FloorHeight < ZMin + 32)
			{
				ZMin = currentSector.FloorHeight - 32; // Can't use the actual value, because that IS the floor
			}
			else
			{
				if (currentSector.CielingHeight > ZMax - 32)
				{
					ZMax = currentSector.CielingHeight + 32; // or the cieling. Subtract or add a sane value to it.
				}
			}
		}
		
		// I need to analyze the binary tree and get more information, particularly the
		// parent nodes of each subsector and node, as well as whether it's the right or
		// left child of that node. These are extremely important, as the parent defines
		// boundaries for the children, as well as inheriting further boundaries from its
		// parents. These boundaries are invaluable for forming brushes.
		int[] nodeparents = new int[doomMap.Nodes.Count];
		bool[] nodeIsLeft = new bool[doomMap.Nodes.Count];
		
		for (int i = 0; i < doomMap.Nodes.Count; i++)
		{
			nodeparents[i] = - 1; // There should only be one node left with -1 as a parent. This SHOULD be the root.
			for (int j = 0; j < doomMap.Nodes.Count; j++)
			{
				if (doomMap.Nodes[j].Child1 == i)
				{
					nodeparents[i] = j;
					break;
				}
				else
				{
					if (doomMap.Nodes[j].Child2 == i)
					{
						nodeparents[i] = j;
						nodeIsLeft[i] = true;
						break;
					}
				}
			}
		}
		
		// Keep a list of what subsectors belong to which sector
		int[] subsectorSectors = new int[doomMap.SubSectors.Count];
		// Keep a list of what sidedefs belong to what subsector as well
		int[][] subsectorSidedefs = new int[doomMap.SubSectors.Count][];
		
		short[][] sideDefShifts = new short[2][];
		for (int i2 = 0; i2 < 2; i2++)
		{
			sideDefShifts[i2] = new short[doomMap.Sidedefs.Count];
		}
		
		// Figure out what sector each subsector belongs to, and what node is its parent.
		// Depending on sector "tags" this will help greatly in creation of brushbased entities,
		// and also helps in finding subsector floor and cieling heights.
		int[] ssparents = new int[doomMap.SubSectors.Count];
		bool[] ssIsLeft = new bool[doomMap.SubSectors.Count];
		for (int i = 0; i < doomMap.SubSectors.Count; i++)
		{
			//DecompilerThread.OnMessage(this, "Populating texture lists for subsector " + i);
			// First, find the subsector's parent and whether it is the left or right child.
			ssparents[i] = - 1; // No subsector should have a -1 in here
			for (int j = 0; j < doomMap.Nodes.Count; j++)
			{
				// When a node references a subsector, it is not referenced by negative
				// index, as future BSP versions do. The bits 0-14 ARE the index, and
				// bit 15 (which is the sign bit in two's compliment math) determines
				// whether or not it is a node or subsector. Therefore, we need to add
				// 2^15 to the number to produce the actual index.
				if (doomMap.Nodes[j].Child1 + 32768 == i)
				{
					ssparents[i] = j;
					break;
				}
				else
				{
					if (doomMap.Nodes[j].Child2 + 32768 == i)
					{
						ssparents[i] = j;
						ssIsLeft[i] = true;
						break;
					}
				}
			}
			
			// Second, figure out what sector a subsector belongs to, and the type of sector it is.
			subsectorSectors[i] = - 1;
			Edge currentsubsector = doomMap.SubSectors[i];
			subsectorSidedefs[i] = new int[currentsubsector.NumSegs];
			for (int j = 0; j < currentsubsector.NumSegs; j++)
			{
				// For each segment the subsector references
				DSegment currentsegment = doomMap.Segments[currentsubsector.FirstSeg + j];
				DLinedef currentlinedef = doomMap.Linedefs[currentsegment.Linedef];
				int currentsidedefIndex;
				int othersideIndex;
				if (currentsegment.Direction == 0)
				{
					currentsidedefIndex = currentlinedef.Right;
					othersideIndex = currentlinedef.Left;
				}
				else
				{
					currentsidedefIndex = currentlinedef.Left;
					othersideIndex = currentlinedef.Right;
				}
				subsectorSidedefs[i][j] = currentsidedefIndex;
				DSidedef currentSidedef = doomMap.Sidedefs[currentsidedefIndex];
				if (currentlinedef.OneSided)
				{
					// A one-sided linedef should always be like this
					midWallTextures[currentsidedefIndex] = doomMap.WadName + "/" + currentSidedef.MidTexture;
					higherWallTextures[currentsidedefIndex] = "special/nodraw";
					lowerWallTextures[currentsidedefIndex] = "special/nodraw";
					sideDefShifts[X][currentsidedefIndex] = currentSidedef.OffsetX;
					sideDefShifts[Y][currentsidedefIndex] = currentSidedef.OffsetY;
				}
				else
				{
					// I don't really get why I need to apply these textures to the other side. But if it works I won't argue...
					if (!currentSidedef.MidTexture.Equals("-"))
					{
						midWallTextures[othersideIndex] = doomMap.WadName + "/" + currentSidedef.MidTexture;
					}
					else
					{
						midWallTextures[othersideIndex] = "special/nodraw";
					}
					if (!currentSidedef.HighTexture.Equals("-"))
					{
						higherWallTextures[othersideIndex] = doomMap.WadName + "/" + currentSidedef.HighTexture;
					}
					else
					{
						higherWallTextures[othersideIndex] = "special/nodraw";
					}
					if (!currentSidedef.LowTexture.Equals("-"))
					{
						lowerWallTextures[othersideIndex] = doomMap.WadName + "/" + currentSidedef.LowTexture;
					}
					else
					{
						lowerWallTextures[othersideIndex] = "special/nodraw";
					}
					sideDefShifts[X][othersideIndex] = currentSidedef.OffsetX;
					sideDefShifts[Y][othersideIndex] = currentSidedef.OffsetY;
				}
				// Sometimes a subsector seems to belong to more than one sector. Only the reference in the first seg is true.
				if (j == 0)
				{
					subsectorSectors[i] = currentSidedef.Sector;
				}
			}
		}
		bool[] linedefFlagsDealtWith = new bool[doomMap.Linedefs.Count];
		bool[] linedefSpecialsDealtWith = new bool[doomMap.Linedefs.Count];
		
		MAPBrush[][] sectorFloorBrushes = new MAPBrush[doomMap.Sectors.Count][];
		for (int i3 = 0; i3 < doomMap.Sectors.Count; i3++)
		{
			sectorFloorBrushes[i3] = new MAPBrush[0];
		}
		MAPBrush[][] sectorCielingBrushes = new MAPBrush[doomMap.Sectors.Count][];
		for (int i4 = 0; i4 < doomMap.Sectors.Count; i4++)
		{
			sectorCielingBrushes[i4] = new MAPBrush[0];
		}
		
		// For one-sided linedefs referenced by more than one subsector
		bool[] outsideBrushAlreadyCreated = new bool[doomMap.Linedefs.Count];
		
		int onePercent = (int)((doomMap.SubSectors.Count)/100);
		if(onePercent < 1) {
			onePercent = 1;
		}
		for (int i = 0; i < doomMap.SubSectors.Count; i++)
		{
			//DecompilerThread.OnMessage(this, "Creating brushes for subsector " + i);
			
			Edge currentsubsector = doomMap.SubSectors[i];
			
			// Third, create a few brushes out of the geometry.
			MAPBrush cielingBrush = new MAPBrush(numBrshs++, 0, false);
			MAPBrush floorBrush = new MAPBrush(numBrshs++, 0, false);
			MAPBrush midBrush = new MAPBrush(numBrshs++, 0, false);
			MAPBrush sectorTriggerBrush = new MAPBrush(numBrshs++, 0, false);
			DSector currentSector = doomMap.Sectors[subsectorSectors[i]];
			
			Vector3D[] roofPlane = new Vector3D[3];
			double[] roofTexS = new double[3];
			double[] roofTexT = new double[3];
			roofPlane[0] = new Vector3D(0, Settings.planePointCoef, ZMax);
			roofPlane[1] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, ZMax);
			roofPlane[2] = new Vector3D(Settings.planePointCoef, 0, ZMax);
			roofTexS[0] = 1;
			roofTexT[1] = - 1;
			
			Vector3D[] cileingPlane = new Vector3D[3];
			double[] cileingTexS = new double[3];
			double[] cileingTexT = new double[3];
			cileingPlane[0] = new Vector3D(0, 0, currentSector.CielingHeight);
			cileingPlane[1] = new Vector3D(Settings.planePointCoef, 0, currentSector.CielingHeight);
			cileingPlane[2] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, currentSector.CielingHeight);
			cileingTexS[0] = 1;
			cileingTexT[1] = - 1;
			
			Vector3D[] floorPlane = new Vector3D[3];
			double[] floorTexS = new double[3];
			double[] floorTexT = new double[3];
			floorPlane[0] = new Vector3D(0, Settings.planePointCoef, currentSector.FloorHeight);
			floorPlane[1] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, currentSector.FloorHeight);
			floorPlane[2] = new Vector3D(Settings.planePointCoef, 0, currentSector.FloorHeight);
			floorTexS[0] = 1;
			floorTexT[1] = - 1;
			
			Vector3D[] foundationPlane = new Vector3D[3];
			double[] foundationTexS = new double[3];
			double[] foundationTexT = new double[3];
			foundationPlane[0] = new Vector3D(0, 0, ZMin);
			foundationPlane[1] = new Vector3D(Settings.planePointCoef, 0, ZMin);
			foundationPlane[2] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, ZMin);
			foundationTexS[0] = 1;
			foundationTexT[1] = - 1;
			
			Vector3D[] topPlane = new Vector3D[3];
			double[] topTexS = new double[3];
			double[] topTexT = new double[3];
			topPlane[0] = new Vector3D(0, Settings.planePointCoef, currentSector.CielingHeight);
			topPlane[1] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, currentSector.CielingHeight);
			topPlane[2] = new Vector3D(Settings.planePointCoef, 0, currentSector.CielingHeight);
			topTexS[0] = 1;
			topTexT[1] = - 1;
			
			Vector3D[] bottomPlane = new Vector3D[3];
			double[] bottomTexS = new double[3];
			double[] bottomTexT = new double[3];
			bottomPlane[0] = new Vector3D(0, 0, currentSector.FloorHeight);
			bottomPlane[1] = new Vector3D(Settings.planePointCoef, 0, currentSector.FloorHeight);
			bottomPlane[2] = new Vector3D(Settings.planePointCoef, Settings.planePointCoef, currentSector.FloorHeight);
			bottomTexS[0] = 1;
			bottomTexT[1] = - 1;
			
			int nextNode = ssparents[i];
			bool leftSide = ssIsLeft[i];
			
			for (int j = 0; j < currentsubsector.NumSegs; j++)
			{
				// Iterate through the sidedefs defined by segments of this subsector
				DSegment currentseg = doomMap.Segments[currentsubsector.FirstSeg + j];
				Vector3D start = doomMap.Vertices[currentseg.StartVertex].Vector;
				Vector3D end = doomMap.Vertices[currentseg.EndVertex].Vector;
				DLinedef currentLinedef = doomMap.Linedefs[(int) currentseg.Linedef];
				
				Vector3D[] plane = new Vector3D[3];
				double[] texS = new double[3];
				double[] texT = new double[3];
				plane[0] = new Vector3D(start.X, start.Y, ZMin);
				plane[1] = new Vector3D(end.X, end.Y, ZMin);
				plane[2] = new Vector3D(end.X, end.Y, ZMax);
				
				Vector3D linestart = new Vector3D(doomMap.Vertices[currentLinedef.Start].Vector.X, doomMap.Vertices[currentLinedef.Start].Vector.Y, ZMin);
				Vector3D lineend = new Vector3D(doomMap.Vertices[currentLinedef.End].Vector.X, doomMap.Vertices[currentLinedef.End].Vector.Y, ZMax);
				
				double sideLength = System.Math.Sqrt(System.Math.Pow(start.X - end.X, 2) + System.Math.Pow(start.Y - end.Y, 2));
				
				bool upperUnpegged = !((currentLinedef.Flags[0] & ((sbyte) 1 << 3)) == 0);
				bool lowerUnpegged = !((currentLinedef.Flags[0] & ((sbyte) 1 << 4)) == 0);
				
				texS[0] = (start.X - end.X) / sideLength;
				texS[1] = (start.Y - end.Y) / sideLength;
				texS[2] = 0;
				texT[0] = 0;
				texT[1] = 0;
				texT[2] = - 1;
				
				double SShift = sideDefShifts[X][subsectorSidedefs[i][j]] - (texS[0] * end.X) - (texS[1] * end.Y);
				double lowTShift = 0;
				double highTShift = 0;
				if (!currentLinedef.OneSided)
				{
					DSector otherSideSector;
					if (doomMap.Sectors[doomMap.Sidedefs[currentLinedef.Left].Sector] == currentSector)
					{
						otherSideSector = doomMap.Sectors[doomMap.Sidedefs[currentLinedef.Right].Sector];
					}
					else
					{
						otherSideSector = doomMap.Sectors[doomMap.Sidedefs[currentLinedef.Left].Sector];
					}
					if (lowerUnpegged)
					{
						lowTShift = otherSideSector.CielingHeight;
					}
					else
					{
						lowTShift = currentSector.FloorHeight;
					}
					if (upperUnpegged)
					{
						highTShift = otherSideSector.CielingHeight;
					}
					else
					{
						highTShift = currentSector.CielingHeight;
					}
					lowTShift += sideDefShifts[Y][subsectorSidedefs[i][j]];
					highTShift += sideDefShifts[Y][subsectorSidedefs[i][j]];
				}
				MAPBrushSide low = new MAPBrushSide(plane, lowerWallTextures[subsectorSidedefs[i][j]], texS, SShift, texT, lowTShift, 0, 1, 1, 0, "wld_lightmap", 16, 0);
				MAPBrushSide high = new MAPBrushSide(plane, higherWallTextures[subsectorSidedefs[i][j]], texS, SShift, texT, highTShift, 0, 1, 1, 0, "wld_lightmap", 16, 0);
				MAPBrushSide mid;
				MAPBrushSide damage = new MAPBrushSide(plane, "special/trigger", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
				
				if (currentLinedef.OneSided)
				{
					if (!outsideBrushAlreadyCreated[currentseg.Linedef])
					{
						outsideBrushAlreadyCreated[currentseg.Linedef] = true;
						double highestCieling = currentSector.CielingHeight;
						double lowestFloor = currentSector.FloorHeight;
						if (currentSector.Tag != 0)
						{
							double temp = getHighestNeighborCielingHeight(subsectorSectors[i]);
							if (temp > highestCieling)
							{
								highestCieling = temp;
							}
							temp = getLowestNeighborFloorHeight(subsectorSectors[i]);
							if (temp < lowestFloor)
							{
								lowestFloor = temp;
							}
						}
						MAPBrush outsideBrush = null;
						if (lowestFloor <= highestCieling)
						{
							outsideBrush = MAPBrush.createFaceBrush(midWallTextures[subsectorSidedefs[i][j]], "special/nodraw", new Vector3D(linestart.X, linestart.Y, ZMin), new Vector3D(lineend.X, lineend.Y, ZMax), sideDefShifts[X][subsectorSidedefs[i][j]], sideDefShifts[Y][subsectorSidedefs[i][j]], lowerUnpegged, currentSector.CielingHeight, currentSector.FloorHeight);
						}
						else
						{
							outsideBrush = MAPBrush.createFaceBrush(midWallTextures[subsectorSidedefs[i][j]], "special/nodraw", new Vector3D(linestart.X, linestart.Y, lowestFloor), new Vector3D(lineend.X, lineend.Y, highestCieling), sideDefShifts[X][subsectorSidedefs[i][j]], sideDefShifts[Y][subsectorSidedefs[i][j]], lowerUnpegged, currentSector.CielingHeight, currentSector.FloorHeight);
						}
						world.Brushes.Add(outsideBrush);
					}
					mid = new MAPBrushSide(plane, "special/nodraw", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
				}
				else
				{
					double midTShift = sideDefShifts[Y][subsectorSidedefs[i][j]];
					if (lowerUnpegged)
					{
						midTShift += currentSector.FloorHeight;
					}
					else
					{
						midTShift += currentSector.CielingHeight;
					}
					mid = new MAPBrushSide(plane, midWallTextures[subsectorSidedefs[i][j]], texS, SShift, texT, midTShift, 0, 1, 1, 0, "wld_masked", 16, 0);
					if (!linedefFlagsDealtWith[currentseg.Linedef])
					{
						linedefFlagsDealtWith[currentseg.Linedef] = true;
						if (!((currentLinedef.Flags[0] & ((sbyte) 1 << 0)) == 0))
						{
							// Flag 0x0001 indicates "solid" but doesn't block bullets. It is assumed for all one-sided.
							MAPBrush solidBrush = MAPBrush.createFaceBrush("special/clip", "special/clip", linestart, lineend, 0, 0, false, 0, 0);
							world.Brushes.Add(solidBrush);
						}
						else
						{
							if (!((currentLinedef.Flags[0] & ((sbyte) 1 << 1)) == 0))
							{
								// Flag 0x0002 indicates "monster clip".
								MAPBrush solidBrush = MAPBrush.createFaceBrush("special/enemyclip", "special/enemyclip", linestart, lineend, 0, 0, false, 0, 0);
								world.Brushes.Add(solidBrush);
							}
						}
					}
					DSidedef otherside = doomMap.Sidedefs[currentLinedef.Left];
					if (currentLinedef.Action != 0 && !linedefSpecialsDealtWith[currentseg.Linedef])
					{
						linedefSpecialsDealtWith[currentseg.Linedef] = true;
						Entity trigger = null;
						MAPBrush triggerBrush = MAPBrush.createFaceBrush("special/trigger", "special/trigger", linestart, lineend, 0, 0, false, 0, 0);
						if (doomMap.Version == mapType.TYPE_HEXEN)
						{
							bool[] bitset = new bool[16];
							for (int k = 0; k < 8; k++)
							{
								bitset[k] = !((currentLinedef.Flags[0] & ((sbyte) k << 1)) == 0);
							}
							for (int k = 0; k < 8; k++)
							{
								bitset[k + 8] = !((currentLinedef.Flags[1] & ((sbyte) k << 1)) == 0);
							}
							if (bitset[10] && bitset[11] && !bitset[12])
							{
								// Triggered when "Used" by player
								trigger = new Entity("func_button");
								trigger["spawnflags"] = "1";
								if (bitset[9])
								{
									trigger["wait"] = "1";
								}
								else
								{
									trigger["wait"] = "-1";
								}
							}
							else
							{
								if (bitset[9])
								{
									// Can be activated more than once
									trigger = new Entity("trigger_multiple");
									trigger["wait"] = "1";
								}
								else
								{
									trigger = new Entity("trigger_once");
								}
							}
							switch (currentLinedef.Action)
							{
								case 21: 
								// Floor lower to lowest surrounding floor
								case 22:  // Floor lower to next lowest surrounding floor
									if (currentLinedef.Arguments[0] != 0)
									{
										trigger["target"] = "sector" + currentLinedef.Arguments[0] + "lowerfloor";
									}
									else
									{
										trigger["target"] = "sectornum" + otherside.Sector + "lowerfloor";
									}
									break;
								case 24: 
								// Floor raise to highest surrounding floor
								case 25:  // Floor raise to next highest surrounding floor
									if (currentLinedef.Arguments[0] != 0)
									{
										trigger["target"] = "sector" + currentLinedef.Arguments[0] + "raisefloor";
									}
									else
									{
										trigger["target"] = "sectornum" + otherside.Sector + "raisefloor";
									}
									break;
								case 70:  // Teleport
									trigger = new Entity("trigger_teleport");
									if (currentLinedef.Arguments[0] != 0)
									{
										trigger["target"] = "teledest" + currentLinedef.Arguments[0];
									}
									else
									{
										trigger["target"] = "sector" + currentLinedef.Tag + "teledest";
									}
									break;
								case 80:  // Exec script
									// This is a toughie. I can't write a script-to-entity converter.
									trigger["target"] = "script" + currentLinedef.Arguments[0];
									trigger["arg0"] = "" + currentLinedef.Arguments[2];
									trigger["arg1"] = "" + currentLinedef.Arguments[3];
									trigger["arg2"] = "" + currentLinedef.Arguments[4];
									break;
								case 181:  // PLANE_ALIGN
									trigger = null;
									if (!leftSide)
									{
										DSidedef getsector = doomMap.Sidedefs[currentLinedef.Left];
										DSector copyheight = doomMap.Sectors[getsector.Sector];
										short newHeight = copyheight.FloorHeight;
										//floorPlane[0]=new Vector3D(0, Settings.getPlanePointCoef(), 2000);
										//floorPlane[1]=new Vector3D(Settings.getPlanePointCoef(), Settings.getPlanePointCoef(), currentSector.getFloorHeight());
										//floorPlane[2]=new Vector3D(Settings.getPlanePointCoef(), 0, currentSector.getFloorHeight());
									}
									else
									{
										linedefSpecialsDealtWith[currentseg.Linedef] = false;
									}
									break;
								default: 
									trigger = null;
									break;
							}
						}
						else
						{
							switch (currentLinedef.Action)
							{
								
								case 1: 
								// Use Door. open, wait, close
								case 31:  // Use Door. Open, stay.
									trigger = new Entity("func_button");
									trigger["wait"] = "1";
									if (currentLinedef.Action == 31)
									{
										trigger["wait"] = "-1";
									}
									trigger["spawnflags"] = "1";
									if (doomMap.Sectors[otherside.Sector].Tag == 0)
									{
										trigger["target"] = "sectornum" + otherside.Sector + "door";
										if (currentLinedef.Action == 1)
										{
											sectorTag[otherside.Sector] = - 1;
										}
										if (currentLinedef.Action == 31)
										{
											sectorTag[otherside.Sector] = - 2;
										}
									}
									else
									{
										trigger["target"] = "sector" + doomMap.Sectors[otherside.Sector].Tag + "door";
									}
									break;
								
								case 36: 
								// Floor lower to 8 above next lowest neighboring sector
								case 38:  // Floor lower to next lowest neighboring sector
									trigger = new Entity("trigger_once");
									trigger["target"] = "sector" + currentLinedef.Tag + "lowerfloor";
									break;
								
								case 62:  // Floor lower to next lowest neighboring sector, wait 4s, goes back up
									trigger = new Entity("func_button");
									trigger["target"] = "sector" + currentLinedef.Tag + "vator";
									trigger["wait"] = "1";
									trigger["spawnflags"] = "1";
									break;
								
								case 63: 
								// Door with button, retriggerable
								case 103:  // Push button, one-time door open stay open
									trigger = new Entity("func_button");
									trigger["target"] = "sector" + currentLinedef.Tag + "door";
									trigger["wait"] = "1";
									if (currentLinedef.Action == 103)
									{
										trigger["wait"] = "-1";
									}
									trigger["spawnflags"] = "1";
									break;
								
								case 88:  // Walkover retriggerable elevator trigger
									trigger = new Entity("trigger_multiple");
									trigger["target"] = "sector" + currentLinedef.Tag + "vator";
									break;
								
								case 97:  // Walkover retriggerable Teleport
									trigger = new Entity("trigger_teleport");
									trigger["target"] = "sector" + currentLinedef.Tag + "teledest";
									break;
								
								case 109:  // Walkover one-time door open stay open
									trigger = new Entity("trigger_once");
									trigger["target"] = "sector" + currentLinedef.Tag + "door";
									break;
							}
						}
						if (trigger != null)
						{
							trigger.Brushes.Add(triggerBrush);
							mapFile.Add(trigger);
						}
					}
				}
				
				cielingBrush.add(high);
				midBrush.add(mid);
				floorBrush.add(low);
				sectorTriggerBrush.add(damage);
			}
			
			MAPBrushSide roof = new MAPBrushSide(roofPlane, "special/nodraw", roofTexS, 0, roofTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
			MAPBrushSide cieling = new MAPBrushSide(cileingPlane, doomMap.WadName + "/" + currentSector.CielingTexture, cileingTexS, 0, cileingTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
			MAPBrushSide floor = new MAPBrushSide(floorPlane, doomMap.WadName + "/" + currentSector.FloorTexture, floorTexS, 0, floorTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
			MAPBrushSide foundation = new MAPBrushSide(foundationPlane, "special/nodraw", foundationTexS, 0, foundationTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
			MAPBrushSide top = new MAPBrushSide(topPlane, "special/nodraw", topTexS, 0, topTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
			MAPBrushSide bottom = new MAPBrushSide(bottomPlane, "special/nodraw", bottomTexS, 0, bottomTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
			MAPBrushSide invertedFloor = new MAPBrushSide(Plane.flip(floorPlane), "special/trigger", floorTexS, 0, floorTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
			MAPBrushSide damageTop = new MAPBrushSide(new Vector3D[]{floorPlane[0]+new Vector3D(0, 0, 1), floorPlane[1]+new Vector3D(0, 0, 1), floorPlane[2]+new Vector3D(0, 0, 1)}, "special/trigger", floorTexS, 0, floorTexT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
			sectorTriggerBrush.add(damageTop);
			sectorTriggerBrush.add(invertedFloor);
			
			midBrush.add(top);
			midBrush.add(bottom);
			
			cielingBrush.add(cieling);
			cielingBrush.add(roof);
			
			floorBrush.add(floor);
			floorBrush.add(foundation);
			
			// Now need to add the data from node subdivisions. Neither segments nor nodes
			// will completely define a usable brush, but both of them together will.
			do 
			{
				DNode currentNode = doomMap.Nodes[nextNode];
				Vector3D start;
				Vector3D end;
				if (leftSide)
				{
					start = currentNode.VecHead+currentNode.VecTail;
					end = currentNode.VecHead;
				}
				else
				{
					start = currentNode.VecHead;
					end = currentNode.VecHead+currentNode.VecTail;
				}
				
				Vector3D[] plane = new Vector3D[3];
				double[] texS = new double[3];
				double[] texT = new double[3];
				// This is somehow always correct. And I'm okay with that.
				plane[0] = new Vector3D(start.X, start.Y, ZMin);
				plane[1] = new Vector3D(end.X, end.Y, ZMin);
				plane[2] = new Vector3D(start.X, start.Y, ZMax);
				
				double sideLength = System.Math.Sqrt(System.Math.Pow(start.X - end.X, 2) + System.Math.Pow(start.Y - end.Y, 2));
				
				texS[0] = (start.X - end.X) / sideLength;
				texS[1] = (start.Y - end.Y) / sideLength;
				texS[2] = 0;
				texT[0] = 0;
				texT[1] = 0;
				texT[2] = 1;
				MAPBrushSide low = new MAPBrushSide(plane, "special/nodraw", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
				MAPBrushSide high = new MAPBrushSide(plane, "special/nodraw", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
				MAPBrushSide mid = new MAPBrushSide(plane, "special/nodraw", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
				MAPBrushSide damage = new MAPBrushSide(plane, "special/trigger", texS, 0, texT, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
				
				cielingBrush.add(high);
				midBrush.add(mid);
				floorBrush.add(low);
				sectorTriggerBrush.add(damage);
				
				leftSide = nodeIsLeft[nextNode];
				nextNode = nodeparents[nextNode];
			}
			while (nextNode != - 1);
			// Now we need to get rid of all the sides that aren't used. Get a list of
			// the useless sides from one brush, and delete those sides from all of them,
			// since they all have the same sides.
			int[] badSides = new int[0];
			if (!Settings.dontCull)
			{
				badSides = MAPBrush.findUnusedPlanes(cielingBrush);
				// Need to iterate backward, since these lists go from low indices to high, and
				// the index of all subsequent items changes when something before it is removed.
				if (cielingBrush.NumSides - badSides.Length < 4)
				{
					DecompilerThread.OnMessage(this, "WARNING: Plane cull returned less than 4 sides for subsector " + i);
					badSides = new int[0];
				}
				else
				{
					for (int j = badSides.Length - 1; j > - 1; j--)
					{
						cielingBrush.delete(badSides[j]);
						floorBrush.delete(badSides[j]);
					}
				}
			}
			
			MAPBrush[] newFloorList = new MAPBrush[sectorFloorBrushes[subsectorSectors[i]].Length + 1];
			MAPBrush[] newCielingList = new MAPBrush[sectorCielingBrushes[subsectorSectors[i]].Length + 1];
			for (int j = 0; j < sectorFloorBrushes[subsectorSectors[i]].Length; j++)
			{
				newFloorList[j] = sectorFloorBrushes[subsectorSectors[i]][j];
				newCielingList[j] = sectorCielingBrushes[subsectorSectors[i]][j];
			}
			newFloorList[newFloorList.Length - 1] = floorBrush;
			newCielingList[newCielingList.Length - 1] = cielingBrush;
			sectorFloorBrushes[subsectorSectors[i]] = newFloorList;
			sectorCielingBrushes[subsectorSectors[i]] = newCielingList;
			
			bool containsMiddle = false;
			for (int j = 0; j < midBrush.NumSides; j++)
			{
				if (!midBrush[j].Texture.ToUpper().Equals("special/nodraw".ToUpper()))
				{
					containsMiddle = true;
					break;
				}
			}
			if (containsMiddle && currentSector.CielingHeight > currentSector.FloorHeight)
			{
				Entity middleEnt = new Entity("func_illusionary");
				if (midBrush.NumSides - badSides.Length >= 4)
				{
					for (int j = badSides.Length - 1; j > - 1; j--)
					{
						midBrush.delete(badSides[j]);
					}
				}
				
				middleEnt.Brushes.Add(midBrush);
				mapFile.Add(middleEnt);
			}
			Entity hurtMe = new Entity("trigger_hurt");
			Entity triggerSecret = new Entity("trigger_bondsecret");
			switch (currentSector.Type)
			{
				case 4: 
				// 20% damage/s with lighting properties
				case 11: 
				// 20% damage/s
				case 16:  // 20% damage/s plus end level when player is almost dead
					hurtMe["dmg"] = "40";
					if (!Settings.dontCull)
					{
						if (sectorTriggerBrush.NumSides - badSides.Length >= 4)
						{
							for (int j = badSides.Length - 1; j > - 1; j--)
							{
								sectorTriggerBrush.delete(badSides[j]);
							}
						}
					}
					hurtMe.Brushes.Add(sectorTriggerBrush);
					mapFile.Add(hurtMe);
					break;
				case 5:  // 10% damage/s
					hurtMe["dmg"] = "20";
					if (!Settings.dontCull)
					{
						if (sectorTriggerBrush.NumSides - badSides.Length >= 4)
						{
							for (int j = badSides.Length - 1; j > - 1; j--)
							{
								sectorTriggerBrush.delete(badSides[j]);
							}
						}
					}
					hurtMe.Brushes.Add(sectorTriggerBrush);
					mapFile.Add(hurtMe);
					break;
				case 7:  // 5% damage/s
					hurtMe["dmg"] = "10";
					if (!Settings.dontCull)
					{
						if (sectorTriggerBrush.NumSides - badSides.Length >= 4)
						{
							for (int j = badSides.Length - 1; j > - 1; j--)
							{
								sectorTriggerBrush.delete(badSides[j]);
							}
						}
					}
					hurtMe.Brushes.Add(sectorTriggerBrush);
					mapFile.Add(hurtMe);
					break;
				case 9:  // "secret"
					triggerSecret["Sound"] = "common/mission_success.wav";
					if (!Settings.dontCull)
					{
						if (sectorTriggerBrush.NumSides - badSides.Length >= 4)
						{
							for (int j = badSides.Length - 1; j > - 1; j--)
							{
								sectorTriggerBrush.delete(badSides[j]);
							}
						}
					}
					triggerSecret.Brushes.Add(sectorTriggerBrush);
					mapFile.Add(triggerSecret);
					break;
				case 10:  // 30 seconds after level start, "close" like a door
					if (currentSector.Tag == 0)
					{
						sectorTag[subsectorSectors[i]] = - 3;
					}
					break;
				case 14:  // 300 seconds after level start, "open" like a door
					if (currentSector.Tag == 0)
					{
						sectorTag[subsectorSectors[i]] = - 4;
					}
					break;
				default: 
					if (!Settings.dontCull)
					{
						if (sectorTriggerBrush.NumSides - badSides.Length >= 4)
						{
							for (int j = badSides.Length - 1; j > - 1; j--)
							{
								sectorTriggerBrush.delete(badSides[j]);
							}
						}
					}
					if ((currentSector.Type & 96) != 0)
					{
						// "Generalized" pain sectors
						if ((currentSector.Type & 96) == 32)
						{
							hurtMe["dmg"] = "10";
						}
						else
						{
							if ((currentSector.Type & 96) == 64)
							{
								hurtMe["dmg"] = "20";
							}
							else
							{
								if ((currentSector.Type & 96) == 96)
								{
									hurtMe["dmg"] = "40";
								}
							}
						}
						hurtMe.Brushes.Add(sectorTriggerBrush);
						mapFile.Add(hurtMe);
					}
					if ((currentSector.Type & 128) == 128)
					{
						// "Generalized" secret trigger
						triggerSecret["Sound"] = "common/mission_success.wav";
						triggerSecret.Brushes.Add(sectorTriggerBrush);
						mapFile.Add(triggerSecret);
					}
					break;
			}
			if((i+1)%onePercent == 0) {
				parent.OnProgress(this, (i+1)/(double)(doomMap.SubSectors.Count));
			}
			//Settings.setProgress(jobnum, i + 1, doomMap.SubSectors.Count, "Decompiling...");
		}
		
		// Add the brushes to the map, as world by default, or entities if they are supported.
		for (int i = 0; i < doomMap.Sectors.Count; i++)
		{
			bool[] floorsUsed = new bool[sectorFloorBrushes[i].Length];
			bool[] cielingsUsed = new bool[sectorCielingBrushes[i].Length];
			if (sectorTag[i] == 0)
			{
				for (int j = 0; j < sectorFloorBrushes[i].Length; j++)
				{
					world.Brushes.Add(sectorFloorBrushes[i][j]);
					floorsUsed[j] = true;
					world.Brushes.Add(sectorCielingBrushes[i][j]);
					cielingsUsed[j] = true;
				}
			}
			else
			{
				if (sectorTag[i] == - 1 || sectorTag[i] == - 2 || sectorTag[i] == - 3 || sectorTag[i] == - 4)
				{
					// I'm using this to mean a door with no tag number
					Entity newDoor = new Entity("func_door");
					newDoor["speed"] = "60";
					newDoor["angles"] = "270 0 0";
					newDoor["spawnflags"] = "256";
					newDoor["targetname"] = "sectornum" + i + "door";
					if (sectorTag[i] == - 1)
					{
						newDoor["wait"] = "4";
					}
					else
					{
						if (sectorTag[i] == - 2)
						{
							newDoor["wait"] = "-1";
						}
					}
					if (sectorTag[i] == - 3)
					{
						Entity triggerAuto = new Entity("trigger_auto");
						triggerAuto["target"] = "sectornum" + i + "door_mm";
						Entity multiManager = new Entity("multi_manager");
						multiManager["sectornum" + i + "door"] = "30";
						mapFile.Add(triggerAuto);
						mapFile.Add(multiManager);
					}
					if (sectorTag[i] == - 4)
					{
						newDoor["Spawnflags"] = "1";
						Entity triggerAuto = new Entity("trigger_auto");
						triggerAuto["target"] = "sectornum" + i + "door_mm";
						Entity multiManager = new Entity("multi_manager");
						multiManager["sectornum" + i + "door"] = "300";
						mapFile.Add(triggerAuto);
						mapFile.Add(multiManager);
					}
					int lowestNeighborCielingHeight = getLowestNeighborCielingHeight(i);
					int lip = ZMax - lowestNeighborCielingHeight + 4;
					newDoor["lip"] = "" + lip;
					for (int j = 0; j < sectorFloorBrushes[i].Length; j++)
					{
						cielingsUsed[j] = true;
						newDoor.Brushes.Add(sectorCielingBrushes[i][j]);
					}
					mapFile.Add(newDoor);
				}
				else
				{
					for (int j = 0; j < doomMap.Linedefs.Count; j++)
					{
						DLinedef currentLinedef = doomMap.Linedefs[j];
						int linedefTriggerType = currentLinedef.Action;
						if (doomMap.Version == mapType.TYPE_HEXEN)
						{
							switch (linedefTriggerType)
							{
								
								case 21: 
								// Floor lower to lowest neighbor
								case 22:  // Floor lower to nearest lower neighbor
									// I don't know where retriggerability is determined, or whether or not it goes back up.
									if (currentLinedef.Arguments[0] == sectorTag[i])
									{
										Entity newFloor = new Entity("func_door");
										newFloor["angles"] = "90 0 0";
										newFloor["wait"] = "-1";
										newFloor["speed"] = "" + currentLinedef.Arguments[1];
										if (currentLinedef.Arguments[0] == 0)
										{
											newFloor["targetname"] = "sectornum" + i + "lowerfloor";
										}
										else
										{
											newFloor["targetname"] = "sector" + currentLinedef.Arguments[0] + "lowerfloor";
										}
										int lowestNeighborFloorHeight;
										if (linedefTriggerType == 21)
										{
											lowestNeighborFloorHeight = getLowestNeighborFloorHeight(i);
										}
										else
										{
											lowestNeighborFloorHeight = getNextLowestNeighborFloorHeight(i);
										}
										if (lowestNeighborFloorHeight == 32768)
										{
											lowestNeighborFloorHeight = doomMap.Sectors[i].FloorHeight;
										}
										int lip = ZMin - lowestNeighborFloorHeight;
										newFloor["lip"] = "" + System.Math.Abs(lip);
										for (int k = 0; k < sectorFloorBrushes[i].Length; k++)
										{
											if (!floorsUsed[k])
											{
												floorsUsed[k] = true;
												newFloor.Brushes.Add(sectorFloorBrushes[i][k]);
											}
										}
										mapFile.Add(newFloor);
									}
									break;
								case 24: 
								// Floor raise to highest neighbor
								case 25:  // Floor raise to nearest higher neighbor
									// I don't know where retriggerability is determined, or whether or not it goes back up.
									if (currentLinedef.Arguments[0] == sectorTag[i])
									{
										Entity newFloor = new Entity("func_door");
										newFloor["angles"] = "270 0 0";
										newFloor["wait"] = "-1";
										newFloor["speed"] = "" + currentLinedef.Arguments[1];
										if (currentLinedef.Arguments[0] == 0)
										{
											newFloor["targetname"] = "sectornum" + i + "raisefloor";
										}
										else
										{
											newFloor["targetname"] = "sector" + currentLinedef.Arguments[0] + "raisefloor";
										}
										int highestNeighborFloorHeight;
										if (linedefTriggerType == 24)
										{
											highestNeighborFloorHeight = getHighestNeighborFloorHeight(i);
										}
										else
										{
											highestNeighborFloorHeight = getNextHighestNeighborFloorHeight(i);
										}
										if (highestNeighborFloorHeight == - 32768)
										{
											highestNeighborFloorHeight = doomMap.Sectors[i].FloorHeight;
										}
										int lip = ZMin - highestNeighborFloorHeight;
										newFloor["lip"] = "" + System.Math.Abs(lip);
										for (int k = 0; k < sectorFloorBrushes[i].Length; k++)
										{
											if (!floorsUsed[k])
											{
												floorsUsed[k] = true;
												newFloor.Brushes.Add(sectorFloorBrushes[i][k]);
											}
										}
										mapFile.Add(newFloor);
									}
									break;
								}
						}
						else
						{
							if (currentLinedef.Tag == sectorTag[i])
							{
								switch (linedefTriggerType)
								{
									
									case 36: 
									// Line crossed, floor lowers, stays 8 above next lowest
									case 38:  // Line crossed, floor lowers, stays at next lowest
										Entity newFloor = new Entity("func_door");
										newFloor["speed"] = "120";
										newFloor["angles"] = "90 0 0";
										newFloor["targetname"] = "sector" + sectorTag[i] + "lowerfloor";
										newFloor["wait"] = "-1";
										int lowestNeighborFloorHeight = getLowestNeighborFloorHeight(i);
										int lip = ZMin - lowestNeighborFloorHeight;
										if (linedefTriggerType == 36)
										{
											lip -= 8;
										}
										newFloor["lip"] = "" + System.Math.Abs(lip);
										for (int k = 0; k < sectorFloorBrushes[i].Length; k++)
										{
											if (!floorsUsed[k])
											{
												floorsUsed[k] = true;
												newFloor.Brushes.Add(sectorFloorBrushes[i][k]);
											}
										}
										mapFile.Add(newFloor);
										break;
									case 63: 
									// Push button, door opens, waits 4s, closes
									case 103: 
									// Push button, door opens, stays
									case 109:  // Cross line, door opens, stays
										Entity newDoor = new Entity("func_door");
										newDoor["speed"] = "60";
										newDoor["angles"] = "270 0 0";
										newDoor["targetname"] = "sector" + sectorTag[i] + "door";
										newDoor["wait"] = "-1";
										if (sectorTag[i] == 63)
										{
											newDoor["wait"] = "4";
										}
										int lowestNeighborCielingHeight = getLowestNeighborCielingHeight(i);
										lip = ZMax - lowestNeighborCielingHeight + 4;
										newDoor["lip"] = "" + lip;
										for (int k = 0; k < sectorFloorBrushes[i].Length; k++)
										{
											if (!cielingsUsed[k])
											{
												cielingsUsed[k] = true;
												newDoor.Brushes.Add(sectorCielingBrushes[i][k]);
											}
										}
										mapFile.Add(newDoor);
										break;
									case 62: 
									// Push button, Elevator goes down to lowest, wait 4s, goes up
									case 88:  // Elevator goes down to lowest, wait 4s, goes up
										Entity newVator = new Entity("func_door");
										newVator["speed"] = "120";
										newVator["angles"] = "90 0 0";
										newVator["targetname"] = "sector" + sectorTag[i] + "vator";
										newVator["wait"] = "4";
										lowestNeighborFloorHeight = getLowestNeighborFloorHeight(i);
										lip = System.Math.Abs(ZMin - lowestNeighborFloorHeight);
										newVator["lip"] = "" + lip;
										for (int k = 0; k < sectorFloorBrushes[i].Length; k++)
										{
											if (!floorsUsed[k])
											{
												newVator.Brushes.Add(sectorFloorBrushes[i][k]);
												floorsUsed[k] = true;
											}
										}
										mapFile.Add(newVator);
										break;
									default:  // I'd like to not use this evenutally, all the trigger types ought to be handled
										DecompilerThread.OnMessage(this, "WARNING: Unimplemented linedef trigger type " + linedefTriggerType + " for sector " + i + " tagged " + sectorTag[i]);
										for (int k = 0; k < sectorFloorBrushes[i].Length; k++)
										{
											if (!floorsUsed[k])
											{
												world.Brushes.Add(sectorFloorBrushes[i][k]);
												floorsUsed[k] = true;
											}
											if (!cielingsUsed[k])
											{
												world.Brushes.Add(sectorCielingBrushes[i][k]);
												cielingsUsed[k] = true;
											}
										}
										break;
								}
							}
						}
					}
				}
			}
			for (int j = 0; j < sectorFloorBrushes[i].Length; j++)
			{
				if (!cielingsUsed[j])
				{
					world.Brushes.Add(sectorCielingBrushes[i][j]);
				}
				if (!floorsUsed[j])
				{
					world.Brushes.Add(sectorFloorBrushes[i][j]);
				}
			}
		}
		
		// Convert THINGS
		for (int i = 0; i < doomMap.Things.Count; i++)
		{
			DThing currentThing = doomMap.Things[i];
			// To find the true height of a thing, I need to iterate through nodes until I come to a subsector
			// definition. Then I need to use the floor height of the sector that subsector belongs to.
			Vector3D origin = currentThing.Origin;
			int subsectorIndex = doomMap.Nodes.Count - 1;
			while (subsectorIndex >= 0)
			{
				// Once child is negative, subsector is found
				DNode currentNode = doomMap.Nodes[subsectorIndex];
				Vector3D start = currentNode.VecHead;
				Vector3D end = currentNode.VecHead+currentNode.VecTail;
				Plane currentPlane = new Plane(start, end, new Vector3D(start.X, start.Y, 1));
				if (currentPlane.distance(origin) < 0)
				{
					subsectorIndex = currentNode.Child1;
				}
				else
				{
					subsectorIndex = currentNode.Child2;
				}
			}
			subsectorIndex += 32768;
			int sectorIndex = subsectorSectors[subsectorIndex];
			DSector thingSector = doomMap.Sectors[sectorIndex];
			if (origin.Z == 0)
			{
				origin.Z=thingSector.FloorHeight;
			}
			
			Entity thing = null;
			// Things from both Doom. Currently converting to appropriate Doom 3 entities.
			switch (currentThing.ClassNum)
			{
				case 1: 
				// Single player spawn
				case 2: 
				// coop
				case 3: 
				// coop
				case 4:  // coop
					thing = new Entity("info_player_start");
					if (currentThing.ClassNum > 1)
					{
						thing["targetname"] = "coopspawn" + currentThing.ClassNum;
					}
					playerStartOrigin = origin.X + " " + origin.Y + " " + (origin.Z + 36);
					thing["origin"] = playerStartOrigin;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 11:  // Deathmatch spawn
					thing = new Entity("info_player_deathmatch");
					thing["origin"] = origin.X + " " + origin.Y + " " + (origin.Z + 36);
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 14:  // Teleport destination
					thing = new Entity("info_teleport_destination");
					if (currentThing.ID != 0)
					{
						thing["targetname"] = "teledest" + currentThing.ID;
					}
					else
					{
						thing["targetname"] = "sector" + thingSector.Tag + "teledest";
					}
					thing["origin"] = origin.X + " " + origin.Y + " " + (origin.Z + 36);
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 17:  // Big cell pack
					thing = new Entity("ammo_cells_large");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 82:  // Super shotgun
					thing = new Entity("weapon_shotgun_double");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2001:  // Shotgun
					thing = new Entity("weapon_shotgun");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2002:  // Chaingun
					thing = new Entity("weapon_chaingun");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2003:  // Rocket launcher
					thing = new Entity("weapon_rocketlauncher");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2004:  // Plasma gun
					thing = new Entity("weapon_plasmagun");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2005:  // Chainsaw
					thing = new Entity("weapon_chainsaw");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2006:  // BFG9000
					thing = new Entity("weapon_bfg");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2007:  // Ammo clip
					thing = new Entity("ammo_clip_small");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2008:  // Shotgun shells
					thing = new Entity("ammo_shells_small");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2010:  // Rocket
					thing = new Entity("ammo_rockets_small");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2046:  // Box of Rockets
					thing = new Entity("ammo_rockets_large");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2047:  // Cell pack
					thing = new Entity("ammo_cells_small");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2048:  // Box of ammo
					thing = new Entity("ammo_bullets_large");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				
				case 2049:  // Box of shells
					thing = new Entity("ammo_shells_large");
					thing["origin"] = origin.X + " " + origin.Y + " " + origin.Z;
					thing["angles"] = "0 " + currentThing.Angle + " 0";
					break;
				}
			
			if (thing != null)
			{
				mapFile.Add(thing);
			}
		}
		
		Entity playerequip = new Entity("game_player_equip");
		playerequip["weapon_pistol"] = "1";
		playerequip["origin"] = playerStartOrigin;
		mapFile.Add(playerequip);
		parent.OnProgress(this, 1.0);
		return mapFile;
	}
	// METHODS
	
	// Attempt to turn the BSP into a .MAP file
	public virtual Entities decompile() {
		DecompilerThread.OnMessage(this, "Decompiling...");
		// In the decompiler, it is not necessary to copy all entities to a new object, since
		// no writing is ever done back to the BSP file.
		mapFile = BSPObject.Entities;
		//int numAreaPortals=0;
		int numTotalItems = 0;
		int onePercent = (int)((BSPObject.Brushes.Count + BSPObject.Entities.Count)/100);
		if(onePercent < 1) {
			onePercent = 1;
		}
		int originalNumEntities = BSPObject.Entities.Count; // Need to keep track of this in this algorithm, since I create more entities on the fly
		for (int i = 0; i < originalNumEntities; i++) {
			// For each entity
			//DecompilerThread.OnMessage(this, "Entity " + i + ": " + mapFile[i]["classname"]);
			// getModelNumber() returns 0 for worldspawn, the *# for brush based entities, and -1 for everything else
			int currentModel = mapFile[i].ModelNumber;
			if (currentModel > - 1) { // If this is still -1 then it's strictly a point-based entity. Move on to the next one.
				Leaf[] leaves = BSPObject.getLeavesInModel(currentModel);
				int numLeaves = leaves.Length;
				bool[] brushesUsed = new bool[BSPObject.Brushes.Count]; // Keep a list of brushes already in the model, since sometimes the leaves lump references one brush several times
				numBrshs = 0; // Reset the brush count for each entity
				for (int j = 0; j < numLeaves; j++) {
					// For each leaf in the bunch
					Leaf currentLeaf = leaves[j];
					int firstMarkBrushIndex = currentLeaf.FirstMarkBrush;
					int numBrushIndices = currentLeaf.NumMarkBrushes;
					if (numBrushIndices > 0) {
						// A lot of leaves reference no brushes. If this is one, this iteration of the j loop is finished
						for (int k = 0; k < numBrushIndices; k++) {
							// For each brush referenced
							long currentBrushIndex = BSPObject.MarkBrushes[firstMarkBrushIndex + k];
							if (!brushesUsed[(int) currentBrushIndex]) {
								// If the current brush has NOT been used in this entity
								//Console.Write("Brush " + numBrshs);
								brushesUsed[(int) currentBrushIndex] = true;
								Brush brush = BSPObject.Brushes[(int) currentBrushIndex];
								decompileBrush(brush, i); // Decompile the brush
								numBrshs++;
								numTotalItems++;
								if(numTotalItems%onePercent == 0) {
									parent.OnProgress(this, numTotalItems/(double)(BSPObject.Brushes.Count + BSPObject.Entities.Count));
								}
							}
						}
					}
				}
			}
			numTotalItems++; // This entity
			if(numTotalItems%onePercent == 0) {
				parent.OnProgress(this, numTotalItems/(double)(BSPObject.Brushes.Count + BSPObject.Entities.Count));
			}
		}
		// Find displacement faces and generate brushes for them
		for (int i = 0; i < BSPObject.Faces.Count; i++) {
			Face face = BSPObject.Faces[i];
			if (face.Displacement > - 1)
			{
				SourceDispInfo disp = BSPObject.DispInfos[face.Displacement];
				TexInfo currentTexInfo;
				if (face.Texture > - 1)
				{
					currentTexInfo = BSPObject.TexInfo[face.Texture];
				}
				else
				{
					Vector3D[] axes = TexInfo.textureAxisFromPlane(BSPObject.Planes[face.Plane]);
					currentTexInfo = new TexInfo(axes[0], 0, axes[1], 0, 0, BSPObject.findTexDataWithTexture("tools/toolsclip"));
				}
				SourceTexData currentTexData = BSPObject.TexDatas[currentTexInfo.Texture];
				string texture = BSPObject.Textures.getTextureAtOffset((uint)BSPObject.TexTable[currentTexData.StringTableIndex]);
				double[] textureU = new double[3];
				double[] textureV = new double[3];
				// Get the lengths of the axis vectors
				double SAxisLength = System.Math.Sqrt(System.Math.Pow((double) currentTexInfo.SAxis.X, 2) + System.Math.Pow((double) currentTexInfo.SAxis.Y, 2) + System.Math.Pow((double) currentTexInfo.SAxis.Z, 2));
				double TAxisLength = System.Math.Sqrt(System.Math.Pow((double) currentTexInfo.TAxis.X, 2) + System.Math.Pow((double) currentTexInfo.TAxis.Y, 2) + System.Math.Pow((double) currentTexInfo.TAxis.Z, 2));
				// In compiled maps, shorter vectors=longer textures and vice versa. This will convert their lengths back to 1. We'll use the actual scale values for length.
				double texScaleU = (1 / SAxisLength); // Let's use these values using the lengths of the U and V axes we found above.
				double texScaleV = (1 / TAxisLength);
				textureU[0] = ((double) currentTexInfo.SAxis.X / SAxisLength);
				textureU[1] = ((double) currentTexInfo.SAxis.Y / SAxisLength);
				textureU[2] = ((double) currentTexInfo.SAxis.Z / SAxisLength);
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'"
				double textureShiftU = (double) currentTexInfo.SShift;
				textureV[0] = ((double) currentTexInfo.TAxis.X / TAxisLength);
				textureV[1] = ((double) currentTexInfo.TAxis.Y / TAxisLength);
				textureV[2] = ((double) currentTexInfo.TAxis.Z / TAxisLength);
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'"
				double textureShiftV = (double) currentTexInfo.TShift;
				
				if (face.NumEdges != 4)
				{
					DecompilerThread.OnMessage(this, "Displacement face with " + face.NumEdges + " edges!");
				}
				
				// Turn vertices and edges into arrays of vectors
				Vector3D[] froms = new Vector3D[face.NumEdges];
				Vector3D[] tos = new Vector3D[face.NumEdges];
				for (int j = 0; j < face.NumEdges; j++)
				{
					if (BSPObject.SurfEdges[face.FirstEdge + j] > 0)
					{
						froms[j] = BSPObject.Vertices[BSPObject.Edges[(int)BSPObject.SurfEdges[face.FirstEdge + j]].FirstVertex].Vector;
						tos[j] = BSPObject.Vertices[BSPObject.Edges[(int)BSPObject.SurfEdges[face.FirstEdge + j]].SecondVertex].Vector;
					}
					else
					{
						tos[j] = BSPObject.Vertices[BSPObject.Edges[(int) BSPObject.SurfEdges[face.FirstEdge + j] * (- 1)].FirstVertex].Vector;
						froms[j] = BSPObject.Vertices[BSPObject.Edges[(int) BSPObject.SurfEdges[face.FirstEdge + j] * (- 1)].SecondVertex].Vector;
					}
				}
				
				MAPBrush displacementBrush = MAPBrush.createBrushFromWind(froms, tos, texture, "TOOLS/TOOLSNODRAW", currentTexInfo);
				
				MAPDisplacement mapdisp = new MAPDisplacement(disp, BSPObject.DispVerts.getVertsInDisp(disp.DispVertStart, disp.Power));
				displacementBrush[0].Displacement = mapdisp;
				mapFile[0].Brushes.Add(displacementBrush);
			}
		}
		for (int i = 0; i < BSPObject.StaticProps.Count; i++)
		{
			Entity newStaticProp = new Entity("prop_static");
			SourceStaticProp currentProp = BSPObject.StaticProps[i];
			newStaticProp["model"] = BSPObject.StaticProps.Dictionary[currentProp.DictionaryEntry];
			newStaticProp["skin"] = currentProp.Skin + "";
			newStaticProp["origin"] = currentProp.Origin.X + " " + currentProp.Origin.Y + " " + currentProp.Origin.Z;
			newStaticProp["angles"] = currentProp.Angles.X + " " + currentProp.Angles.Y + " " + currentProp.Angles.Z;
			newStaticProp["solid"] = currentProp.Solidity + "";
			newStaticProp["fademindist"] = currentProp.MinFadeDist + "";
			newStaticProp["fademaxdist"] = currentProp.MaxFadeDist + "";
			newStaticProp["fadescale"] = currentProp.ForcedFadeScale + "";
			if (currentProp.Targetname != null)
			{
				newStaticProp["targetname"] = currentProp.Targetname;
			}
			mapFile.Add(newStaticProp);
		}
		for (int i = 0; i < BSPObject.Cubemaps.Count; i++)
		{
			Entity newCubemap = new Entity("env_cubemap");
			SourceCubemap currentCube = BSPObject.Cubemaps[i];
			newCubemap["origin"] = currentCube.Origin.X + " " + currentCube.Origin.Y + " " + currentCube.Origin.Z;
			newCubemap["cubemapsize"] = currentCube.Size + "";
			mapFile.Add(newCubemap);
		}
		if (!Settings.skipPlaneFlip)
		{
			DecompilerThread.OnMessage(this, "Num simple corrected brushes: " + numSimpleCorrects);
			DecompilerThread.OnMessage(this, "Num advanced corrected brushes: " + numAdvancedCorrects);
			DecompilerThread.OnMessage(this, "Num good brushes: " + numGoodBrushes);
		}
		parent.OnProgress(this, 1.0);
		return mapFile;
	}
Esempio n. 35
0
	public static Entities createLump(byte[] data) {
		int count = 0;
		bool inQuotes = false; // 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 prior to revision 55.
		for (int i = 0; i < data.Length; i++) {
			if (inQuotes) {
				if (data[i] == '\"' && inQuotes) {
					inQuotes = false;
				}
			} else {
				if (data[i] == '\"') {
					inQuotes = true;
				} else {
					if (data[i] == '{') {
						count++;
					}
				}
			}
		}
		Entities lump = new Entities(data.Length, count);
		char currentChar; // 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.
		int offset = 0;
		for (int i = 0; i < count; i++) {
			// For every entity
			string current = ""; // This will be the resulting entity, fed into the Entity class
			currentChar = (char)data[offset]; // begin reading the file
			while (currentChar != '{') {
				// Eat bytes until we find the beginning of an entity structure
				offset++;
				currentChar = (char)data[offset];
			}
			inQuotes = false;
			do {
				if (currentChar == '\"') {
					inQuotes = !inQuotes;
				}
				current += (currentChar + ""); // adds characters to the current string
				offset++;
				currentChar = (char)data[offset];
			} while (currentChar != '}' || inQuotes); // Read bytes until we find the end of the current entity structure
			current += (currentChar + ""); // adds the '}' to the current string
			lump.Add(Entity.parseString(current));
		}
		return lump;
	}