Example #1
0
        public CustomLevelSelectSection()
        {
            levelList = new List <CustomLevel>();

            isLoading          = true;
            isLoadingAnimation = 1f;

            ThreadPool.UnsafeQueueUserWorkItem(_ => {
                JsonParser json = new JsonParser();

                try {
                    string path = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "unknown");
                    if (DirectoryOp.Exists(path))
                    {
                        foreach (string levelPath in DirectoryOp.GetFiles(path))
                        {
                            if (api == null)
                            {
                                break;
                            }

                            if (!levelPath.EndsWith(".level"))
                            {
                                continue;
                            }

                            IFileSystem levelPackage = new CompressedContent(levelPath);

                            using (
                                Stream s = levelPackage.OpenFile(".res", FileAccessMode.Read)) {
                                string levelToken = PathOp.GetFileNameWithoutExtension(levelPath);

                                LevelConfigJson config = json.Parse <LevelConfigJson>(s);

                                string icon = "";
#if DEBUG
                                if ((config.Description.Flags & LevelFlags.FastCamera) != 0)
                                {
                                    icon += " Fast";
                                }
                                if ((config.Description.Flags & LevelFlags.HasPit) != 0)
                                {
                                    icon += " Pit";
                                }
#endif
                                if ((config.Description.Flags & LevelFlags.Multiplayer) != 0 && (config.Description.Flags & (LevelFlags.MultiplayerRace | LevelFlags.MultiplayerFlags)) == 0)
                                {
                                    icon += " Battle";
                                }
                                if ((config.Description.Flags & LevelFlags.MultiplayerRace) != 0)
                                {
                                    icon += " Race";
                                }
                                if ((config.Description.Flags & LevelFlags.MultiplayerFlags) != 0)
                                {
                                    icon += " CTF";
                                }

                                levelList.Add(new CustomLevel(config.Description.Name, "unknown", levelToken, icon));
                            }
                        }

                        levelList.Sort((x, y) => {
                            string xs = BitmapFont.StripFormatting(x.DisplayName);
                            string ys = BitmapFont.StripFormatting(y.DisplayName);
                            int i     = string.Compare(xs, ys, StringComparison.InvariantCulture);
                            if (i != 0)
                            {
                                return(i);
                            }

                            return(string.Compare(x.LevelName, y.LevelName, StringComparison.InvariantCulture));
                        });
                    }
                } catch {
                    // ToDo: Handle exceptions
                } finally {
                    isLoading = false;
                }
            }, null);
        }
Example #2
0
        private void PrerenderTexturedBackground()
        {
            try {
                // Try to use "The Secret Files" background
                string levelPath = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "secretf", "01_easter1.level");
                if (!FileOp.Exists(levelPath))
                {
                    // Try to use "Base Game" background
                    levelPath = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "prince", "03_carrot1.level");
                    if (!FileOp.Exists(levelPath))
                    {
                        // Try to use "Holiday Hare '98" background
                        levelPath = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "xmas98", "03_xmas3.level");
                        if (!FileOp.Exists(levelPath))
                        {
                            // Try to use "Christmas Chronicles" background
                            levelPath = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "xmas99", "03_xmas3.level");
                            if (!FileOp.Exists(levelPath))
                            {
                                // Try to use "Shareware Demo" background;
                                levelPath = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "share", "02_share2.level");
                                if (!FileOp.Exists(levelPath))
                                {
                                    // No usable background found
                                    throw new FileNotFoundException();
                                }
                            }
                        }
                    }
                }

                // Load metadata
                IFileSystem levelPackage = new CompressedContent(levelPath);

                LevelHandler.LevelConfigJson config;
                using (Stream s = levelPackage.OpenFile(".res", FileAccessMode.Read)) {
                    config = ContentResolver.Current.Json.Parse <LevelHandler.LevelConfigJson>(s);
                }

                LevelHandler.LevelConfigJson.LayerSection layer;
                if (config.Layers.TryGetValue("Sky", out layer))
                {
                    if (layer.BackgroundColor != null && layer.BackgroundColor.Count >= 3)
                    {
                        horizonColor = new Vector4(layer.BackgroundColor[0] / 255f, layer.BackgroundColor[1] / 255f, layer.BackgroundColor[2] / 255f, 1f);
                    }

                    switch ((BackgroundStyle)layer.BackgroundStyle)
                    {
                    default:
                    case BackgroundStyle.Sky:
                        texturedBackgroundShader = ContentResolver.Current.RequestShader("TexturedBackground");
                        break;

                    case BackgroundStyle.Circle:
                        texturedBackgroundShader = ContentResolver.Current.RequestShader("TexturedBackgroundCircle");
                        break;
                    }
                }

                // Render background layer to texture
                TileSet levelTileset = new TileSet(config.Description.DefaultTileset, true, null);
                if (!levelTileset.IsValid)
                {
                    throw new InvalidDataException();
                }

                using (Stream s = levelPackage.OpenFile("Sky.layer", FileAccessMode.Read)) {
                    using (BinaryReader r = new BinaryReader(s)) {
                        int width  = r.ReadInt32();
                        int height = r.ReadInt32();

                        TileMapLayer newLayer = new TileMapLayer();
                        newLayer.Layout = new LayerTile[width * height];

                        for (int i = 0; i < newLayer.Layout.Length; i++)
                        {
                            ushort tileType = r.ReadUInt16();

                            byte flags = r.ReadByte();
                            if (flags == 0)
                            {
                                newLayer.Layout[i] = levelTileset.GetDefaultTile(tileType);
                                continue;
                            }

                            bool isFlippedX        = (flags & 0x01) > 0;
                            bool isFlippedY        = (flags & 0x02) > 0;
                            bool isAnimated        = (flags & 0x04) > 0;
                            bool legacyTranslucent = (flags & 0x80) > 0;

                            // Invalid tile numbers (higher than tileset tile amount) are silently changed to empty tiles
                            if (tileType >= levelTileset.TileCount && !isAnimated)
                            {
                                tileType = 0;
                            }

                            LayerTile tile;

                            // Copy the default tile and do stuff with it
                            tile            = levelTileset.GetDefaultTile(tileType);
                            tile.IsFlippedX = isFlippedX;
                            tile.IsFlippedY = isFlippedY;
                            tile.IsAnimated = isAnimated;

                            if (legacyTranslucent)
                            {
                                tile.MaterialAlpha = /*127*/ 140;
                            }

                            newLayer.Layout[i] = tile;
                        }

                        newLayer.LayoutWidth = width;

                        RecreateTexturedBackground(levelTileset, ref newLayer);
                    }
                }
            } catch (Exception ex) {
                Log.Write(LogType.Warning, "Cannot prerender textured background: " + ex);

                cachedTexturedBackground = new Texture(new Pixmap(new PixelData(2, 2, ColorRgba.Black)));
            }
        }
Example #3
0
        public void RequestTileset(string path, bool applyPalette, ColorRgba[] customPalette, out ContentRef<Material> materialRef, out PixelData mask)
        {
            IFileSystem tilesetPackage = new CompressedContent(PathOp.Combine(DualityApp.DataDirectory, "Tilesets", path + ".set"));

            // Palette
            if (applyPalette) {
                if (customPalette != null) {
                    ApplyBasePalette(customPalette);
                } else if (tilesetPackage.FileExists("Main.palette")) {
                    ApplyBasePalette(TileSet.LoadPalette(tilesetPackage.OpenFile("Main.palette", FileAccessMode.Read)));
                }
            }

            // Load textures
            PixelData texturePixels;
            using (Stream s = tilesetPackage.OpenFile("Diffuse.png", FileAccessMode.Read)) {
                texturePixels = new Png(s).GetPixelData();
            }

#if !DISABLE_NORMAL_MAPPING
            PixelData normalPixels;
            if (tilesetPackage.FileExists("Normals.png")) {
                using (Stream s = tilesetPackage.OpenFile("Normals.png", FileAccessMode.Read)) {
                    normalPixels = new Png(s).GetPixelData();
                }
            } else {
                normalPixels = null;
            }
#endif

            using (Stream s = tilesetPackage.OpenFile("Mask.png", FileAccessMode.Read)) {
                mask = new Png(s).GetPixelData();
            }

            // Apply palette to tileset
            ColorRgba[] palette = paletteTexture.Res.BasePixmap.Res.MainLayer.Data;

            ColorRgba[] data = texturePixels.Data;
#if !DISABLE_ASYNC
            Parallel.ForEach(Partitioner.Create(0, data.Length), range => {
                for (int i = range.Item1; i < range.Item2; i++) {
#else
                for (int i = 0; i < data.Length; i++) {
#endif
                    int colorIdx = data[i].R;
                    data[i] = palette[colorIdx].WithAlpha(palette[colorIdx].A * data[i].A / (255f * 255f));
                }
#if !DISABLE_ASYNC
            });
#endif

            ContentRef<Texture> mainTex = new Texture(new Pixmap(texturePixels));

            ContentRef<Texture> normalTex;
#if !DISABLE_NORMAL_MAPPING
            if (normalPixels == null) {
                normalTex = DefaultNormalMap;
            } else {
                normalTex = new Texture(new Pixmap(normalPixels));
                normalTex.Res.DetachSource();
            }
#else
            normalTex = DefaultNormalMap;
#endif

            // Create material
            Material material = new Material(RequestShader("BasicNormal"));
            material.SetTexture("mainTex", mainTex);
            material.SetTexture("normalTex", normalTex);
            material.SetValue("normalMultiplier", Vector2.One);

            materialRef = material;
        }
Example #4
0
        private void LoadLevel(string level, string episode)
        {
            string      levelPath    = PathOp.Combine(DualityApp.DataDirectory, "Episodes", episode, level + ".level");
            IFileSystem levelPackage = new CompressedContent(levelPath);

            // ToDo: Cache parser, move JSON parsing to ContentResolver
            JsonParser      jsonParser = new JsonParser();
            LevelConfigJson json;

            using (Stream s = levelPackage.OpenFile(".res", FileAccessMode.Read)) {
                json = jsonParser.Parse <LevelConfigJson>(s);
            }

            if (json.Version.LayerFormat > LayerFormatVersion || json.Version.EventSet > EventSetVersion)
            {
                throw new NotSupportedException("Level version not supported");
            }

            App.Log("Loading level \"" + json.Description.Name + "\"...");

            root.Title     = BitmapFont.StripFormatting(json.Description.Name);
            root.Immersive = false;

            defaultNextLevel    = json.Description.NextLevel;
            defaultSecretLevel  = json.Description.SecretLevel;
            ambientLightDefault = json.Description.DefaultLight;
            ambientLightCurrent = ambientLightTarget = ambientLightDefault * 0.01f;

            if (json.Description.DefaultDarkness != null && json.Description.DefaultDarkness.Count >= 4)
            {
                darknessColor = new Vector4(json.Description.DefaultDarkness[0] / 255f, json.Description.DefaultDarkness[1] / 255f, json.Description.DefaultDarkness[2] / 255f, json.Description.DefaultDarkness[3] / 255f);
            }
            else
            {
                darknessColor = new Vector4(0, 0, 0, 1);
            }

            // Palette
            ColorRgba[] tileMapPalette;
            if (levelPackage.FileExists("Main.palette"))
            {
                using (Stream s = levelPackage.OpenFile("Main.palette", FileAccessMode.Read)) {
                    tileMapPalette = TileSet.LoadPalette(s);
                }
            }
            else
            {
                tileMapPalette = null;
            }

            // Tileset
            tileMap = new TileMap(this, json.Description.DefaultTileset, tileMapPalette, (json.Description.Flags & LevelFlags.HasPit) != 0);

            // Additional tilesets
            if (json.Tilesets != null)
            {
                for (int i = 0; i < json.Tilesets.Count; i++)
                {
                    LevelConfigJson.TilesetSection part = json.Tilesets[i];
                    tileMap.ReadTilesetPart(part.Name, part.Offset, part.Count);
                }
            }

            // Read all layers
            json.Layers.Add("Sprite", new LevelConfigJson.LayerSection {
                XSpeed = 1,
                YSpeed = 1
            });

            foreach (var layer in json.Layers.OrderBy(layer => layer.Value.Depth))
            {
                LayerType type;
                if (layer.Key == "Sprite")
                {
                    type = LayerType.Sprite;
                }
                else if (layer.Key == "Sky")
                {
                    type = LayerType.Sky;

                    //if (layer.Value.BackgroundStyle != 0 /*Plain*/ && layer.Value.BackgroundColor != null && layer.Value.BackgroundColor.Count >= 3) {
                    //    camera.GetComponent<Camera>().ClearColor = new ColorRgba((byte)layer.Value.BackgroundColor[0], (byte)layer.Value.BackgroundColor[1], (byte)layer.Value.BackgroundColor[2]);
                    //}
                }
                else
                {
                    type = LayerType.Other;
                }

                using (Stream s = levelPackage.OpenFile(layer.Key + ".layer", FileAccessMode.Read)) {
                    tileMap.ReadLayerConfiguration(type, s, layer.Value);
                }
            }

            // Read animated tiles
            if (levelPackage.FileExists("Animated.tiles"))
            {
                using (Stream s = levelPackage.OpenFile("Animated.tiles", FileAccessMode.Read)) {
                    tileMap.ReadAnimatedTiles(s);
                }
            }

            levelBounds = new Rect(tileMap.Size * tileMap.Tileset.TileSize);

            // Read events
            eventMap = new EventMap(this, tileMap.Size);

            if (levelPackage.FileExists("Events.layer"))
            {
                using (Stream s2 = levelPackage.OpenFile("Events.layer", FileAccessMode.Read)) {
                    eventMap.ReadEvents(s2, json.Version.LayerFormat, difficulty);
                }
            }

            GameObject tilemapHandler = new GameObject();

            tilemapHandler.Parent = rootObject;
            tilemapHandler.AddComponent(tileMap);

            // Load default music
            musicPath = PathOp.Combine(DualityApp.DataDirectory, "Music", json.Description.DefaultMusic);
            music     = new OpenMptStream(musicPath, true);
            music.BeginFadeIn(0.5f);
            DualityApp.Sound.PlaySound(music);

            // Apply weather
            if (json.Description.DefaultWeather != WeatherType.None)
            {
                ApplyWeather(
                    json.Description.DefaultWeather,
                    json.Description.DefaultWeatherIntensity,
                    json.Description.DefaultWeatherOutdoors);
            }

            // Load level text events
            levelTexts = json.TextEvents ?? new List <string>();

            if (FileOp.Exists(levelPath + "." + i18n.Language))
            {
                try {
                    using (Stream s = FileOp.Open(levelPath + "." + i18n.Language, FileAccessMode.Read)) {
                        json = jsonParser.Parse <LevelConfigJson>(s);
                        if (json.TextEvents != null)
                        {
                            for (int i = 0; i < json.TextEvents.Count && i < levelTexts.Count; i++)
                            {
                                if (json.TextEvents[i] != null)
                                {
                                    levelTexts[i] = json.TextEvents[i];
                                }
                            }
                        }
                    }
                } catch (Exception ex) {
                    App.Log("Cannot load i18n for this level: " + ex);
                }
            }
        }
Example #5
0
        private void LoadLevel(string level, string episode)
        {
            string      levelPath    = PathOp.Combine(DualityApp.DataDirectory, "Episodes", episode, level + ".level");
            IFileSystem levelPackage = new CompressedContent(levelPath);

            LevelConfigJson json;

            using (Stream s = levelPackage.OpenFile(".res", FileAccessMode.Read)) {
                json = ContentResolver.Current.Json.Parse <LevelConfigJson>(s);
            }

            if (json.Version.LayerFormat > LayerFormatVersion || json.Version.EventSet > EventSetVersion)
            {
                throw new NotSupportedException("Level version not supported");
            }

            Log.Write(LogType.Info, "Loading level \"" + json.Description.Name + "\"...");

            levelFriendlyName = json.Description.Name;

            //defaultNextLevel = json.Description.NextLevel;
            //defaultSecretLevel = json.Description.SecretLevel;

            // Palette
            ColorRgba[] tileMapPalette;
            if (levelPackage.FileExists("Main.palette"))
            {
                using (Stream s = levelPackage.OpenFile("Main.palette", FileAccessMode.Read)) {
                    tileMapPalette = TileSet.LoadPalette(s);
                }
            }
            else
            {
                tileMapPalette = null;
            }

            // Tileset
            tileMap = new TileMap(this, json.Description.DefaultTileset, tileMapPalette, (json.Description.Flags & LevelFlags.HasPit) != 0);

            // Additional tilesets
            if (json.Tilesets != null)
            {
                for (int i = 0; i < json.Tilesets.Count; i++)
                {
                    LevelConfigJson.TilesetSection part = json.Tilesets[i];
                    tileMap.ReadTilesetPart(part.Name, part.Offset, part.Count);
                }
            }

            // Read all layers
            json.Layers.Add("Sprite", new LevelConfigJson.LayerSection {
                XSpeed = 1,
                YSpeed = 1
            });

            foreach (var layer in json.Layers.OrderBy(layer => layer.Value.Depth))
            {
                LayerType type;
                if (layer.Key == "Sprite")
                {
                    type = LayerType.Sprite;
                }
                else if (layer.Key == "Sky")
                {
                    type = LayerType.Sky;

                    //if (layer.Value.BackgroundStyle != 0 /*Plain*/ && layer.Value.BackgroundColor != null && layer.Value.BackgroundColor.Count >= 3) {
                    //    camera.GetComponent<Camera>().ClearColor = new ColorRgba((byte)layer.Value.BackgroundColor[0], (byte)layer.Value.BackgroundColor[1], (byte)layer.Value.BackgroundColor[2]);
                    //}
                }
                else
                {
                    type = LayerType.Other;
                }

                using (Stream s = levelPackage.OpenFile(layer.Key + ".layer", FileAccessMode.Read)) {
                    tileMap.ReadLayerConfiguration(type, s, layer.Value);
                }
            }

            // Read animated tiles
            if (levelPackage.FileExists("Animated.tiles"))
            {
                using (Stream s = levelPackage.OpenFile("Animated.tiles", FileAccessMode.Read)) {
                    tileMap.ReadAnimatedTiles(s);
                }
            }

            levelBounds = new Rect(tileMap.Size * tileMap.Tileset.TileSize);

            // Read events
            eventMap = new EventMap(this, tileMap.Size);

            if (levelPackage.FileExists("Events.layer"))
            {
                using (Stream s2 = levelPackage.OpenFile("Events.layer", FileAccessMode.Read)) {
                    eventMap.ReadEvents(s2, json.Version.LayerFormat, difficulty);
                }
            }

            GameObject tilemapHandler = new GameObject();

            tilemapHandler.Parent = rootObject;
            tilemapHandler.AddComponent(tileMap);

            // Apply weather
            if (json.Description.DefaultWeather != WeatherType.None)
            {
                ApplyWeather(
                    json.Description.DefaultWeather,
                    json.Description.DefaultWeatherIntensity,
                    json.Description.DefaultWeatherOutdoors);
            }

            // Load level text events
            levelTexts = json.TextEvents ?? new List <string>();

            /*if (FileOp.Exists(levelPath + "." + i18n.Language)) {
             *  try {
             *      using (Stream s = FileOp.Open(levelPath + "." + i18n.Language, FileAccessMode.Read)) {
             *          json = ContentResolver.Current.Json.Parse<LevelConfigJson>(s);
             *          if (json.TextEvents != null) {
             *              for (int i = 0; i < json.TextEvents.Count && i < levelTexts.Count; i++) {
             *                  if (json.TextEvents[i] != null) {
             *                      levelTexts[i] = json.TextEvents[i];
             *                  }
             *              }
             *          }
             *      }
             *  } catch (Exception ex) {
             *      Log.Write(LogType.Warning, "Cannot load i18n for this level: " + ex);
             *  }
             * }*/

            eventMap.ActivateEvents(int.MinValue, int.MinValue, int.MaxValue, int.MaxValue, false);
        }
Example #6
0
        public bool ChangeLevel(string levelName, MultiplayerLevelType levelType)
        {
            string path = Path.Combine(DualityApp.DataDirectory, "Episodes", levelName + ".level");

            if (!File.Exists(path))
            {
                return(false);
            }

            IFileSystem levelPackage = new CompressedContent(path);

            lock (sync) {
                currentLevel     = levelName;
                currentLevelType = levelType;

                // Load new level
                using (Stream s = levelPackage.OpenFile(".res", FileAccessMode.Read)) {
                    // ToDo: Cache parser
                    JsonParser json = new JsonParser();
                    LevelHandler.LevelConfigJson config = json.Parse <LevelHandler.LevelConfigJson>(s);

                    if (config.Version.LayerFormat > LevelHandler.LayerFormatVersion || config.Version.EventSet > LevelHandler.EventSetVersion)
                    {
                        throw new NotSupportedException("Version not supported");
                    }

                    currentLevelFriendlyName = BitmapFont.StripFormatting(config.Description.Name);

                    Log.Write(LogType.Info, "Loading level \"" + currentLevelFriendlyName + "\" (" + currentLevelType + ")...");

                    Point2 tileMapSize;
                    using (Stream s2 = levelPackage.OpenFile("Sprite.layer", FileAccessMode.Read))
                        using (BinaryReader r = new BinaryReader(s2)) {
                            tileMapSize.X = r.ReadInt32();
                            tileMapSize.Y = r.ReadInt32();
                        }

                    levelBounds = new Rect(tileMapSize * /*tileMap.Tileset.TileSize*/ 32);

                    collisions = new DynamicTreeBroadPhase <ICollisionable>();

                    // Read events
                    eventMap = new ServerEventMap(tileMapSize);

                    if (levelPackage.FileExists("Events.layer"))
                    {
                        using (Stream s2 = levelPackage.OpenFile("Events.layer", FileAccessMode.Read)) {
                            eventMap.ReadEvents(s2, config.Version.LayerFormat);
                        }
                    }
                }

                // Send request to change level to all players
                foreach (KeyValuePair <NetConnection, Player> pair in players)
                {
                    pair.Value.State = PlayerState.NotReady;
                }

                playerConnections.Clear();

                foreach (KeyValuePair <NetConnection, Player> pair in players)
                {
                    Send(new LoadLevel {
                        LevelName           = currentLevel,
                        LevelType           = currentLevelType,
                        AssignedPlayerIndex = pair.Value.Index
                    }, 64, pair.Key, NetDeliveryMethod.ReliableUnordered, PacketChannels.Main);
                }
            }

            return(true);
        }