private bool VerifyMobSpawners(
            DungeonLayout layout)
        {
            bool success = true;


            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                 iterator.Valid;
                 iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room         room         = layout.GetRoomByIndex(roomIndex);
                RoomTemplate roomTemplate =
                    layout.LayoutRoomTemplateSet.GetTemplateByName(room.static_room_data.room_template_name);

                // We don't add the mob spawner to the room if we create it
                // and it doesn't have any mobs left (spawner initially has 0 mobs.
                // TODO: Add this check back in when we support non-zero min spawn count
                //if (roomTemplate.MobSpawnerTemplates.Count() != room.mobSpawners.Count)
                //{
                //    _logger.WriteLine("DungeonValidator: FAILED: Mob spawner template count != mob spawner count");
                //    _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                //    _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                //        room.room_key.x, room.room_key.y, room.room_key.z));
                //    success = false;
                //    break;
                //}

                foreach (MobSpawner spawner in room.mobSpawners)
                {
                    if (spawner.SpawnTable == null)
                    {
                        _logger.WriteLine("DungeonValidator: FAILED: Mob spawner missing spawn table!");
                        _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                        _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                                        room.room_key.x, room.room_key.y, room.room_key.z));
                        success = false;
                        break;
                    }

                    while (spawner.RemainingSpawnCount > 0)
                    {
                        Mob mob = spawner.SpawnRandomMob();

                        if (mob == null)
                        {
                            _logger.WriteLine("DungeonValidator: FAILED: Mob spawner failed to produce valid mob!");
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                                            room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                            break;
                        }
                    }
                }
            }

            return(success);
        }
Beispiel #2
0
        public void ApplyLayout(
            DungeonLayout layout)
        {
            // Copy over all the rooms in the layout into the world
            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                iterator.Valid;
                iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                RoomLayout room = layout.GetRoomByIndex(roomIndex);
                RoomTemplate roomTemplate= layout.LayoutRoomTemplateSet.GetTemplateByName(room.static_room_data.room_template_name);

                room.runtime_nav_mesh = new NavMesh(room.room_key, roomTemplate.NavMeshTemplate);

                m_rooms.Add(room.room_key, room);
            }
        }
        private Dictionary <int, Portal> BuildPortalIdMap(
            DungeonLayout layout)
        {
            Dictionary <int, Portal> portalIdToPortalMap = new Dictionary <int, Portal>();

            // Generate a mapping from portal id to portal
            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                 iterator.Valid;
                 iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);

                // Add all of the portals to the map
                foreach (Portal portal in room.portals)
                {
                    portalIdToPortalMap.Add(portal.portal_id, portal);
                }
            }

            return(portalIdToPortalMap);
        }
        private bool VerifyRoomPortals(
            DungeonLayout layout,
            Dictionary<int, Portal> portalIdToPortalMap)
        {
            bool success = true;
            MathConstants.eSignedDirection[] roomSides = new MathConstants.eSignedDirection[] {
                MathConstants.eSignedDirection.positive_x,
                MathConstants.eSignedDirection.negative_x,
                MathConstants.eSignedDirection.positive_y,
                MathConstants.eSignedDirection.negative_y,
                MathConstants.eSignedDirection.positive_z,
                MathConstants.eSignedDirection.negative_z
            };

            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                iterator.Valid;
                iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);

                // Verify the the portal bitmask matches the existing portals
                foreach (MathConstants.eSignedDirection roomSide in roomSides)
                {
                    if (room.RoomHasPortalOnSide(roomSide))
                    {
                        if (room.portals.Count(p => p.room_side == roomSide) == 0)
                        {
                            _logger.WriteLine("DungeonValidator: FAILED: Expected portal on room side {0} but found none!", roomSide);
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                            break;
                        }
                    }
                    else
                    {
                        if (room.portals.Count(p => p.room_side == roomSide) != 0)
                        {
                            _logger.WriteLine("DungeonValidator: FAILED: Expected no portal on room side {0} but found one!", roomSide);
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                            break;
                        }
                    }
                }

                // Verify that the portals are the right expected type
                foreach (Portal portal in room.portals)
                {
                    MathConstants.eSignedDirection roomSide = portal.room_side;

                    switch (portal.portal_type)
                    {
                        case ePortalType.door:
                            if (roomSide != MathConstants.eSignedDirection.positive_x && roomSide != MathConstants.eSignedDirection.negative_x &&
                                roomSide != MathConstants.eSignedDirection.positive_y && roomSide != MathConstants.eSignedDirection.negative_y)
                            {
                                _logger.WriteLine(
                                    string.Format(
                                    "DungeonValidator: FAILED: Door portal id={0} on unexpected side={1}",
                                    portal.portal_id, roomSide));
                                _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                                _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                    room.room_key.x, room.room_key.y, room.room_key.z));
                                success = false;
                            }
                            break;
                        case ePortalType.stairs:
                            if (roomSide != MathConstants.eSignedDirection.positive_z && roomSide != MathConstants.eSignedDirection.negative_z)
                            {
                                _logger.WriteLine(
                                    string.Format(
                                    "DungeonValidator: FAILED: Stairs portal id={0} on unexpected side={1}",
                                    portal.portal_id, roomSide));
                                _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                                _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                    room.room_key.x, room.room_key.y, room.room_key.z));
                                success = false;
                            }
                            break;
                        case ePortalType.teleporter:
                            if (roomSide != MathConstants.eSignedDirection.none)
                            {
                                _logger.WriteLine(
                                    string.Format(
                                    "DungeonValidator: FAILED: Teleporter portal id={0} on unexpected side={1}",
                                    portal.portal_id, roomSide));
                                _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                                _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                    room.room_key.x, room.room_key.y, room.room_key.z));
                                success = false;
                            }
                            break;
                    }
                }

                // Verify that the portals connect to a valid target portal
                foreach (Portal portal in room.portals)
                {
                    if (portalIdToPortalMap.ContainsKey(portal.target_portal_id))
                    {
                        Portal targetPortal = portalIdToPortalMap[portal.target_portal_id];

                        if (targetPortal.target_portal_id != portal.portal_id)
                        {
                            _logger.WriteLine("DungeonValidator: FAILED: Target Portal is not connected to a valid portal!");
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                            break;
                        }
                    }
                    else
                    {
                        _logger.WriteLine("DungeonValidator: FAILED: Portal is not connected to a valid target portal!");
                        _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                        _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                            room.room_key.x, room.room_key.y, room.room_key.z));
                        success = false;
                        break;
                    }
                }
            }

            return success;
        }
        private bool VerifyRoomAccessibility(
            DungeonLayout layout,
            Dictionary<int, Portal> portalIdToPortalMap)
        {
            UnionFind<RoomKey> roomUnion = new UnionFind<RoomKey>();
            RoomKey targetRoomKey = new RoomKey();
            bool success = true;

            // Do a first pass over the rooms to fill out the union and the portal map
            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                iterator.Valid;
                iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);

                // Add the room to the union set
                roomUnion.AddElement(room.room_key);
            }

            // Union together all of the rooms connected by portals
            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                iterator.Valid;
                iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);

                foreach (Portal portal in room.portals)
                {
                    Portal targetPortal= portalIdToPortalMap[portal.target_portal_id];

                    targetRoomKey.game_id= layout.GameID;
                    targetRoomKey.x= targetPortal.room_x;
                    targetRoomKey.y= targetPortal.room_y;
                    targetRoomKey.z= targetPortal.room_z;

                    roomUnion.Union(room.room_key, targetRoomKey);
                }
            }

            // Verify that all rooms share the same connectivity id
            int sharedConnectivityId = -1;
            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                iterator.Valid;
                iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);

                int roomConnectivityId= roomUnion.FindRootIndex(room.room_key);

                if (sharedConnectivityId != -1)
                {
                    if (sharedConnectivityId != roomConnectivityId)
                    {
                        _logger.WriteLine("DungeonValidator: FAILED: Found room not connected to other rooms in dungeon!");
                        _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                        _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                            room.room_key.x, room.room_key.y, room.room_key.z));
                        success= false;
                        break;
                    }
                }
                else
                {
                    sharedConnectivityId= roomConnectivityId;
                }
            }

            return success;
        }
        private bool VerifyMobSpawners(
            DungeonLayout layout)
        {
            bool success = true;

            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                iterator.Valid;
                iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);
                RoomTemplate roomTemplate=
                    layout.LayoutRoomTemplateSet.GetTemplateByName(room.static_room_data.room_template_name);

                // We don't add the mob spawner to the room if we create it
                // and it doesn't have any mobs left (spawner initially has 0 mobs.
                // TODO: Add this check back in when we support non-zero min spawn count
                //if (roomTemplate.MobSpawnerTemplates.Count() != room.mobSpawners.Count)
                //{
                //    _logger.WriteLine("DungeonValidator: FAILED: Mob spawner template count != mob spawner count");
                //    _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                //    _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                //        room.room_key.x, room.room_key.y, room.room_key.z));
                //    success = false;
                //    break;
                //}

                foreach (MobSpawner spawner in room.mobSpawners)
                {
                    if (spawner.SpawnTable == null)
                    {
                        _logger.WriteLine("DungeonValidator: FAILED: Mob spawner missing spawn table!");
                        _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                        _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                            room.room_key.x, room.room_key.y, room.room_key.z));
                        success = false;
                        break;
                    }

                    while (spawner.RemainingSpawnCount > 0)
                    {
                        Mob mob= spawner.SpawnRandomMob();

                        if (mob == null)
                        {
                            _logger.WriteLine("DungeonValidator: FAILED: Mob spawner failed to produce valid mob!");
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                            break;
                        }
                    }
                }
            }

            return success;
        }
        private void DumpLayoutGeometry(
            string dumpGeometryPath, 
            DungeonLayout layout)
        {
            GeometryFileWriter fileWriter = new GeometryFileWriter();
            string filename= string.Format("DungeonLayout_Game{0}_Size{1}", layout.GameID, layout.LayoutWorldTemplate.dungeon_size);
            string header = string.Format("DungeonLayout for GameID:{0} DungeonSize: {1}", layout.GameID, layout.LayoutWorldTemplate.dungeon_size);
            string result = SuccessMessages.GENERAL_SUCCESS;
            Vector3d roomSize = new Vector3d(WorldConstants.ROOM_X_SIZE, WorldConstants.ROOM_Y_SIZE, WorldConstants.ROOM_Z_SIZE);

            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                iterator.Valid;
                iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);
                AABB3d roomAABB = new AABB3d(room.world_position, room.world_position + roomSize);
                AABB3d shrunkRoomAABB = roomAABB.ScaleAboutCenter(0.5f);
                AABB3d centerAABB = roomAABB.ScaleAboutCenter(0.05f);

                // Add the AABB for this room
                fileWriter.AppendAABB(shrunkRoomAABB);

                // Create portal AABBs to all adjacent rooms
                for (MathConstants.eSignedDirection roomSide = MathConstants.eSignedDirection.first;
                    roomSide < MathConstants.eSignedDirection.count;
                    ++roomSide)
                {
                    if (room.RoomHasPortalOnSide(roomSide))
                    {
                        DungeonLayout.RoomIndex neighborRoomIndex = null;
                        switch (roomSide)
                        {
                            case MathConstants.eSignedDirection.positive_x:
                                neighborRoomIndex = roomIndex.Offset(1, 0, 0);
                                break;
                            case MathConstants.eSignedDirection.negative_x:
                                neighborRoomIndex = roomIndex.Offset(-1, 0, 0);
                                break;
                            case MathConstants.eSignedDirection.positive_y:
                                neighborRoomIndex = roomIndex.Offset(0, 1, 0);
                                break;
                            case MathConstants.eSignedDirection.negative_y:
                                neighborRoomIndex = roomIndex.Offset(0, -1, 0);
                                break;
                            case MathConstants.eSignedDirection.positive_z:
                                neighborRoomIndex = roomIndex.Offset(0, 0, 1);
                                break;
                            case MathConstants.eSignedDirection.negative_z:
                                neighborRoomIndex = roomIndex.Offset(0, 0, -1);
                                break;
                        }

                        Room neighborRoom = layout.GetRoomByIndex(neighborRoomIndex);
                        AABB3d neighborRoomAABB = new AABB3d(neighborRoom.world_position, neighborRoom.world_position + roomSize);
                        AABB3d neighborCenterAABB = neighborRoomAABB.ScaleAboutCenter(0.05f);
                        AABB3d portalAABB = centerAABB.EncloseAABB(neighborCenterAABB);

                        fileWriter.AppendAABB(portalAABB);
                    }
                }

                // TODO: DumpLayoutGeometry: Color the rooms by teleporter pair
            }

            if (!fileWriter.SaveFile(dumpGeometryPath, filename, header, out result))
            {
                _logger.WriteLine("DungeonValidator: WARNING: Failed to save layout geometry file");
                _logger.WriteLine(result);
            }
        }
        private Dictionary<int, Portal> BuildPortalIdMap(
            DungeonLayout layout)
        {
            Dictionary<int, Portal> portalIdToPortalMap = new Dictionary<int, Portal>();

            // Generate a mapping from portal id to portal
            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                iterator.Valid;
                iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);

                // Add all of the portals to the map
                foreach (Portal portal in room.portals)
                {
                    portalIdToPortalMap.Add(portal.portal_id, portal);
                }
            }

            return portalIdToPortalMap;
        }
        private void DumpLayoutGeometry(
            string dumpGeometryPath,
            DungeonLayout layout)
        {
            GeometryFileWriter fileWriter = new GeometryFileWriter();
            string             filename   = string.Format("DungeonLayout_Game{0}_Size{1}", layout.GameID, layout.LayoutWorldTemplate.dungeon_size);
            string             header     = string.Format("DungeonLayout for GameID:{0} DungeonSize: {1}", layout.GameID, layout.LayoutWorldTemplate.dungeon_size);
            string             result     = SuccessMessages.GENERAL_SUCCESS;
            Vector3d           roomSize   = new Vector3d(WorldConstants.ROOM_X_SIZE, WorldConstants.ROOM_Y_SIZE, WorldConstants.ROOM_Z_SIZE);

            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                 iterator.Valid;
                 iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room   room           = layout.GetRoomByIndex(roomIndex);
                AABB3d roomAABB       = new AABB3d(room.world_position, room.world_position + roomSize);
                AABB3d shrunkRoomAABB = roomAABB.ScaleAboutCenter(0.5f);
                AABB3d centerAABB     = roomAABB.ScaleAboutCenter(0.05f);

                // Add the AABB for this room
                fileWriter.AppendAABB(shrunkRoomAABB);

                // Create portal AABBs to all adjacent rooms
                for (MathConstants.eSignedDirection roomSide = MathConstants.eSignedDirection.first;
                     roomSide < MathConstants.eSignedDirection.count;
                     ++roomSide)
                {
                    if (room.RoomHasPortalOnSide(roomSide))
                    {
                        DungeonLayout.RoomIndex neighborRoomIndex = null;
                        switch (roomSide)
                        {
                        case MathConstants.eSignedDirection.positive_x:
                            neighborRoomIndex = roomIndex.Offset(1, 0, 0);
                            break;

                        case MathConstants.eSignedDirection.negative_x:
                            neighborRoomIndex = roomIndex.Offset(-1, 0, 0);
                            break;

                        case MathConstants.eSignedDirection.positive_y:
                            neighborRoomIndex = roomIndex.Offset(0, 1, 0);
                            break;

                        case MathConstants.eSignedDirection.negative_y:
                            neighborRoomIndex = roomIndex.Offset(0, -1, 0);
                            break;

                        case MathConstants.eSignedDirection.positive_z:
                            neighborRoomIndex = roomIndex.Offset(0, 0, 1);
                            break;

                        case MathConstants.eSignedDirection.negative_z:
                            neighborRoomIndex = roomIndex.Offset(0, 0, -1);
                            break;
                        }

                        Room   neighborRoom       = layout.GetRoomByIndex(neighborRoomIndex);
                        AABB3d neighborRoomAABB   = new AABB3d(neighborRoom.world_position, neighborRoom.world_position + roomSize);
                        AABB3d neighborCenterAABB = neighborRoomAABB.ScaleAboutCenter(0.05f);
                        AABB3d portalAABB         = centerAABB.EncloseAABB(neighborCenterAABB);

                        fileWriter.AppendAABB(portalAABB);
                    }
                }

                // TODO: DumpLayoutGeometry: Color the rooms by teleporter pair
            }

            if (!fileWriter.SaveFile(dumpGeometryPath, filename, header, out result))
            {
                _logger.WriteLine("DungeonValidator: WARNING: Failed to save layout geometry file");
                _logger.WriteLine(result);
            }
        }
        private bool VerifyRoomAccessibility(
            DungeonLayout layout,
            Dictionary <int, Portal> portalIdToPortalMap)
        {
            UnionFind <RoomKey> roomUnion     = new UnionFind <RoomKey>();
            RoomKey             targetRoomKey = new RoomKey();
            bool success = true;

            // Do a first pass over the rooms to fill out the union and the portal map
            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                 iterator.Valid;
                 iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);

                // Add the room to the union set
                roomUnion.AddElement(room.room_key);
            }

            // Union together all of the rooms connected by portals
            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                 iterator.Valid;
                 iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);

                foreach (Portal portal in room.portals)
                {
                    Portal targetPortal = portalIdToPortalMap[portal.target_portal_id];

                    targetRoomKey.game_id = layout.GameID;
                    targetRoomKey.x       = targetPortal.room_x;
                    targetRoomKey.y       = targetPortal.room_y;
                    targetRoomKey.z       = targetPortal.room_z;

                    roomUnion.Union(room.room_key, targetRoomKey);
                }
            }

            // Verify that all rooms share the same connectivity id
            int sharedConnectivityId = -1;

            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                 iterator.Valid;
                 iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);

                int roomConnectivityId = roomUnion.FindRootIndex(room.room_key);

                if (sharedConnectivityId != -1)
                {
                    if (sharedConnectivityId != roomConnectivityId)
                    {
                        _logger.WriteLine("DungeonValidator: FAILED: Found room not connected to other rooms in dungeon!");
                        _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                        _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                                        room.room_key.x, room.room_key.y, room.room_key.z));
                        success = false;
                        break;
                    }
                }
                else
                {
                    sharedConnectivityId = roomConnectivityId;
                }
            }

            return(success);
        }
        private bool VerifyRoomPortals(
            DungeonLayout layout,
            Dictionary <int, Portal> portalIdToPortalMap)
        {
            bool success = true;

            MathConstants.eSignedDirection[] roomSides = new MathConstants.eSignedDirection[] {
                MathConstants.eSignedDirection.positive_x,
                MathConstants.eSignedDirection.negative_x,
                MathConstants.eSignedDirection.positive_y,
                MathConstants.eSignedDirection.negative_y,
                MathConstants.eSignedDirection.positive_z,
                MathConstants.eSignedDirection.negative_z
            };

            for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid);
                 iterator.Valid;
                 iterator.Next())
            {
                DungeonLayout.RoomIndex roomIndex = iterator.Current;
                Room room = layout.GetRoomByIndex(roomIndex);

                // Verify the the portal bitmask matches the existing portals
                foreach (MathConstants.eSignedDirection roomSide in roomSides)
                {
                    if (room.RoomHasPortalOnSide(roomSide))
                    {
                        if (room.portals.Count(p => p.room_side == roomSide) == 0)
                        {
                            _logger.WriteLine("DungeonValidator: FAILED: Expected portal on room side {0} but found none!", roomSide);
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                                            room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                            break;
                        }
                    }
                    else
                    {
                        if (room.portals.Count(p => p.room_side == roomSide) != 0)
                        {
                            _logger.WriteLine("DungeonValidator: FAILED: Expected no portal on room side {0} but found one!", roomSide);
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                                            room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                            break;
                        }
                    }
                }

                // Verify that the portals are the right expected type
                foreach (Portal portal in room.portals)
                {
                    MathConstants.eSignedDirection roomSide = portal.room_side;

                    switch (portal.portal_type)
                    {
                    case ePortalType.door:
                        if (roomSide != MathConstants.eSignedDirection.positive_x && roomSide != MathConstants.eSignedDirection.negative_x &&
                            roomSide != MathConstants.eSignedDirection.positive_y && roomSide != MathConstants.eSignedDirection.negative_y)
                        {
                            _logger.WriteLine(
                                string.Format(
                                    "DungeonValidator: FAILED: Door portal id={0} on unexpected side={1}",
                                    portal.portal_id, roomSide));
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                                            room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                        }
                        break;

                    case ePortalType.stairs:
                        if (roomSide != MathConstants.eSignedDirection.positive_z && roomSide != MathConstants.eSignedDirection.negative_z)
                        {
                            _logger.WriteLine(
                                string.Format(
                                    "DungeonValidator: FAILED: Stairs portal id={0} on unexpected side={1}",
                                    portal.portal_id, roomSide));
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                                            room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                        }
                        break;

                    case ePortalType.teleporter:
                        if (roomSide != MathConstants.eSignedDirection.none)
                        {
                            _logger.WriteLine(
                                string.Format(
                                    "DungeonValidator: FAILED: Teleporter portal id={0} on unexpected side={1}",
                                    portal.portal_id, roomSide));
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                                            room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                        }
                        break;
                    }
                }

                // Verify that the portals connect to a valid target portal
                foreach (Portal portal in room.portals)
                {
                    if (portalIdToPortalMap.ContainsKey(portal.target_portal_id))
                    {
                        Portal targetPortal = portalIdToPortalMap[portal.target_portal_id];

                        if (targetPortal.target_portal_id != portal.portal_id)
                        {
                            _logger.WriteLine("DungeonValidator: FAILED: Target Portal is not connected to a valid portal!");
                            _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                            _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                                            room.room_key.x, room.room_key.y, room.room_key.z));
                            success = false;
                            break;
                        }
                    }
                    else
                    {
                        _logger.WriteLine("DungeonValidator: FAILED: Portal is not connected to a valid target portal!");
                        _logger.WriteLine(string.Format("  game_id: {0}", layout.GameID));
                        _logger.WriteLine(string.Format("  room_key: {0},{1},{2}",
                                                        room.room_key.x, room.room_key.y, room.room_key.z));
                        success = false;
                        break;
                    }
                }
            }

            return(success);
        }