Пример #1
0
        public int CountFilesWithRoot(FileLocation fileLocation, string fileNameRoot)
        {
            EnsureFolderStructureExistence();
            var location = ResolveLocationEnum(fileLocation);

            return(DirectoryOp.GetFiles(location).Count(f => f.StartsWith(location + fileNameRoot)));
        }
Пример #2
0
        public IEnumerable <string> ListFilesWithRoot(FileLocation fileLocation, string fileNameRoot, FileExtension fileExtension = FileExtension.json)
        {
            EnsureFolderStructureExistence();
            var location  = ResolveLocationEnum(fileLocation);
            var extension = ResolveExtensionEnum(fileExtension);

            return(DirectoryOp.GetFiles(location).Where(f => f.StartsWith(location + fileNameRoot)).Select(x => x.Replace(location, "").Replace(extension, "")));
        }
Пример #3
0
        public EpisodeSelectSection()
        {
            JsonParser  jsonParser = new JsonParser();
            IImageCodec imageCodec = ImageCodec.GetRead(ImageCodec.FormatPng);

            foreach (string episode in DirectoryOp.GetDirectories(PathOp.Combine(DualityApp.DataDirectory, "Episodes")))
            {
                string pathAbsolute = PathOp.Combine(episode, ".res");
                if (FileOp.Exists(pathAbsolute))
                {
                    Episode json;
                    using (Stream s = DualityApp.SystemBackend.FileSystem.OpenFile(pathAbsolute, FileAccessMode.Read)) {
                        json = jsonParser.Parse <Episode>(s);
                    }
                    json.Token = PathOp.GetFileName(episode);

                    if (!DirectoryOp.Exists(PathOp.Combine(episode, json.FirstLevel)))
                    {
                        continue;
                    }

                    EpisodeEntry entry;
                    entry.Episode = json;
                    if (json.PreviousEpisode != null)
                    {
                        int time = Preferences.Get <int>("EpisodeEnd_Time_" + json.PreviousEpisode);
                        entry.IsAvailable = (time > 0);
                    }
                    else
                    {
                        entry.IsAvailable = true;
                    }

                    entry.CanContinue = Preferences.Get <byte[]>("EpisodeContinue_Misc_" + entry.Episode.Token) != null;

                    string logoPath = PathOp.Combine(episode, ".png");
                    if (FileOp.Exists(logoPath))
                    {
                        PixelData pixelData;
                        using (Stream s = FileOp.Open(logoPath, FileAccessMode.Read)) {
                            pixelData = imageCodec.Read(s);
                        }

                        Texture texture = new Texture(new Pixmap(pixelData), TextureSizeMode.NonPowerOfTwo);
                        entry.Logo = new Material(DrawTechnique.Alpha, texture);
                    }
                    else
                    {
                        entry.Logo = null;
                    }

                    episodes.Add(entry);
                }
            }

            episodes.Sort((x, y) => x.Episode.Position.CompareTo(y.Episode.Position));
        }
Пример #4
0
        /// <summary>
        /// Returns all Resource files that are located in the specified directory. This doesn't affect
        /// any actual content- or load states.
        /// </summary>
        /// <param name="folderPath"></param>
        public static IEnumerable <string> GetResourceFiles(string folderPath = null)
        {
            if (string.IsNullOrEmpty(folderPath))
            {
                folderPath = DualityApp.DataDirectory;
            }
            IEnumerable <string> resFiles = DirectoryOp.GetFiles(folderPath, true);

            return(resFiles.Where(path => path.EndsWith(Resource.FileExt, StringComparison.OrdinalIgnoreCase)));
        }
Пример #5
0
        /// <summary>
        /// Loads the Resource from the specified <see cref="Stream"/>. You shouldn't need this method in almost all cases.
        /// Only use it when you know exactly what you're doing. Consider requesting the Resource from the <see cref="ContentProvider"/> instead.
        /// </summary>
        /// <typeparam name="T">
        /// Desired Type of the returned reference. Does not affect the loaded Resource in any way - it is simply returned as T.
        /// Results in returning null if the loaded Resource's Type isn't assignable to T.
        /// </typeparam>
        /// <param name="str">The stream to load the Resource from.</param>
        /// <param name="resPath">The path that is assumed as the loaded Resource's origin.</param>
        /// <param name="loadCallback">An optional callback that is invoked right after loading the Resource, but before initializing it.</param>
        /// <param name="initResource">
        /// Specifies whether or not the Resource is initialized by calling <see cref="Resource.OnLoaded"/>. Never attempt to use
        /// uninitialized Resources or register them in the ContentProvider.
        /// </param>
        /// <returns>The Resource that has been loaded.</returns>
        //public static T Load<T>(Serializer formatter, string resPath = null, Action<T> loadCallback = null, bool initResource = true) where T : Resource
        //{
        //    T newContent = null;
        //
        //    try {
        //        Resource res = formatter.ReadObject<Resource>();
        //        if (res == null) throw new Exception("Loading Resource failed");
        //
        //        res.initState = InitState.Initializing;
        //        res.path = resPath;
        //        if (loadCallback != null) loadCallback(res as T); // Callback before initializing.
        //        if (initResource) Init(res);
        //        newContent = res as T;
        //    } catch (Exception e) {
        //        Console.WriteLine("Can't load {0} from '{1}', because an error occurred: {3}{2}",
        //		    /*Log.Type(*/typeof(T)/*)*/,
        //		    resPath ?? formatter.ToString(),
        //		    /*Log.Exception(*/e/*)*/,
        //		    Environment.NewLine);
        //    }
        //
        //    return newContent;
        //}

        /// <summary>
        /// Initializes a Resource that has been loaded without initialization. You shouldn't need this method in almost all cases.
        /// Only use it when you know exactly what you're doing. Consider requesting the Resource from the <see cref="ContentProvider"/> instead.
        /// </summary>
        /// <param name="res">The Resource to initialize.</param>
        //public static void Init(Resource res)
        //{
        //    if (res.initState != InitState.Initializing) return;
        //    res.OnLoaded();
        //    if (ResourceLoaded != null) ResourceLoaded(res, new ResourceEventArgs(res));
        //    res.initState = InitState.Initialized;
        //}

        /// <summary>
        /// Determines whether or not the specified path points to a Duality Resource file.
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        //public static bool IsResourceFile(string filePath)
        //{
        //    return string.Equals(PathOp.GetExtension(filePath), FileExt, StringComparison.OrdinalIgnoreCase);
        //}
        /// <summary>
        /// Returns all Resource files that are located in the specified directory. This doesn't affect
        /// any actual content- or load states.
        /// </summary>
        /// <param name="folderPath"></param>
        /// <returns></returns>
        public static IEnumerable <string> GetResourceFiles(string folderPath = null)
        {
            // ToDo: Root directory instead of "."
            if (string.IsNullOrEmpty(folderPath))
            {
                folderPath = ".";
            }
            IEnumerable <string> resFiles = DirectoryOp.GetFiles(folderPath, true);

            return(resFiles.Where(path => path.EndsWith(Resource.FileExt, StringComparison.OrdinalIgnoreCase)));
        }
Пример #6
0
 private void CheckAndCreateFolder(string path)
 {
     if (!DirectoryOp.Exists(path))
     {
         Log.Game.Write($"Folder: [{path}] doesn't exist - creating");
         DirectoryOp.Create(path);
     }
     else
     {
         Log.Game.Write($"Folder: [{path}] exists");
     }
 }
Пример #7
0
        /// <summary>
        /// Saves an object to the specified data file. If it already exists, the file will be overwritten.
        /// Automatically creates the appropriate directory structure, if it doesn't exist yet.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="file"></param>
        /// <param name="preferredSerializer"></param>
        public static void WriteObject <T>(T obj, string file, Type preferredSerializer = null)
        {
            string dirName = PathOp.GetDirectoryName(file);

            if (!string.IsNullOrEmpty(dirName) && !DirectoryOp.Exists(dirName))
            {
                DirectoryOp.Create(dirName);
            }
            using (Stream str = FileOp.Create(file))
            {
                Serializer.WriteObject <T>(obj, str, preferredSerializer);
            }
        }
Пример #8
0
        /// <summary>
        /// Saves the Resource to the specified path.
        /// </summary>
        /// <param name="saveAsPath">The path to which this Resource is saved to. If null, the Resources <see cref="Path"/> is used as destination.</param>
        /// <param name="makePermanent">
        /// When true, the Resource will be made permanently available from now on. If it has been generated at runtime
        /// or was loaded explicitly outside the ContentProvider, this will set the Resources <see cref="Path"/> Property
        /// and register it in the <see cref="ContentProvider"/>. If the Resource already is a permanent, this parameter will be ignored.
        /// </param>
        public void Save(string saveAsPath = null, bool makePermanent = true)
        {
            if (this.Disposed)
            {
                throw new ObjectDisposedException("Can't save a Resource that has been disposed.");
            }
            if (string.IsNullOrWhiteSpace(saveAsPath))
            {
                saveAsPath = this.path;
                if (string.IsNullOrWhiteSpace(saveAsPath))
                {
                    throw new ArgumentException("Can't save a Resource to an undefined path.", "saveAsPath");
                }
            }

            // Prepare saving the Resource and abort if an error occurred in the process
            bool preparedSuccessfully = this.CheckedOnSaving(saveAsPath);

            if (!preparedSuccessfully)
            {
                return;
            }

            // We're saving a new Resource for the first time: Register it in the library
            bool isPermanent = !string.IsNullOrWhiteSpace(this.path);

            if (makePermanent && !isPermanent)
            {
                this.path = saveAsPath;
                ContentProvider.AddContent(this.path, this);
            }

            string dirName = PathOp.GetDirectoryName(saveAsPath);

            if (!string.IsNullOrEmpty(dirName) && !DirectoryOp.Exists(dirName))
            {
                DirectoryOp.Create(dirName);
            }
            using (Stream str = FileOp.Create(saveAsPath))
            {
                this.WriteToStream(str);
            }
            this.CheckedOnSaved(saveAsPath);
        }
Пример #9
0
        internal static void InitDefaultMethod()
        {
            // By default, assume one of the builtin serializers, depending on execution environment
            if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor)
            {
                defaultSerializer = typeof(XmlSerializer);
            }
            else
            {
                defaultSerializer = typeof(BinarySerializer);
            }

            // Search for actual Resource files and detect their serialization format
            if (DirectoryOp.Exists(DualityApp.DataDirectory))
            {
                foreach (string resFile in DirectoryOp.GetFiles(DualityApp.DataDirectory, true))
                {
                    if (!resFile.EndsWith(Resource.FileExt, StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }
                    using (Stream stream = FileOp.Open(resFile, FileAccessMode.Read))
                    {
                        try
                        {
                            Type matchingSerializer = Detect(stream);
                            if (matchingSerializer != null)
                            {
                                defaultSerializer = matchingSerializer;
                                break;
                            }
                        }
                        catch (Exception) {}
                    }
                }
            }
        }
Пример #10
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);
        }
Пример #11
0
        private void PrerenderTexturedBackground()
        {
            try {
                IImageCodec codec = ImageCodec.GetRead(ImageCodec.FormatPng);

                // Try to use "The Secret Files" background
                string levelPath = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "secretf", "01_easter1");
                if (!DirectoryOp.Exists(levelPath))
                {
                    // Try to use "Base Game" background
                    levelPath = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "prince", "03_carrot1");
                    if (!DirectoryOp.Exists(levelPath))
                    {
                        // Try to use "Holiday Hare '98" background
                        levelPath = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "xmas98", "03_xmas3");
                        if (!DirectoryOp.Exists(levelPath))
                        {
                            // Try to use "Christmas Chronicles" background
                            levelPath = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "xmas99", "03_xmas3");
                            if (!DirectoryOp.Exists(levelPath))
                            {
                                // Try to use "Shareware Demo" background;
                                levelPath = PathOp.Combine(DualityApp.DataDirectory, "Episodes", "share", "02_share2");
                                if (!DirectoryOp.Exists(levelPath))
                                {
                                    // No usable background found
                                    throw new FileNotFoundException();
                                }
                            }
                        }
                    }
                }

                // Load metadata
                JsonParser json = new JsonParser();
                LevelHandler.LevelConfigJson config;
                using (Stream s = FileOp.Open(PathOp.Combine(levelPath, ".res"), FileAccessMode.Read)) {
                    config = 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)
                    {
                    case BackgroundStyle.Sky:
                    default:
                        texturedBackgroundShader = ContentResolver.Current.RequestShader("TexturedBackground");
                        break;

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

                // Render background layer to texture
                string tilesetPath = PathOp.Combine(DualityApp.DataDirectory, "Tilesets", config.Description.DefaultTileset);

                ColorRgba[] tileMapPalette = TileSet.LoadPalette(PathOp.Combine(tilesetPath, ".palette"));
                ContentResolver.Current.ApplyBasePalette(tileMapPalette);

                TileSet levelTileset = new TileSet(config.Description.DefaultTileset);
                if (!levelTileset.IsValid)
                {
                    throw new InvalidDataException();
                }

                using (Stream s = FileOp.Open(PathOp.Combine(levelPath, "Sky.layer"), FileAccessMode.Read)) {
                    using (DeflateStream deflate = new DeflateStream(s, CompressionMode.Decompress))
                        using (BinaryReader r = new BinaryReader(deflate)) {
                            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) {
                Console.WriteLine("Cannot prerender textured background: " + ex);

                cachedTexturedBackground = new Texture(new Pixmap(new PixelData(2, 2, ColorRgba.Black)));
            }
        }
Пример #12
0
        void IPreferencesBackend.Commit()
        {
            if (!dirty)
            {
                return;
            }

            dirty = false;

            string path = PathOp.Combine(PathOp.GetDirectoryName(Assembly.GetEntryAssembly().Location), "Jazz2.settings");

            if (!FileOp.Exists(path))
            {
                path = PathOp.Combine(DualityApp.SystemBackend.GetNamedPath(NamedDirectory.ApplicationData), "Jazz2", "Jazz2.settings");
            }

            try {
                DirectoryOp.Create(PathOp.GetDirectoryName(path));
            } catch {
                // Nothing to do...
            }

            try {
                using (Stream s = FileOp.Create(path))
                    using (BinaryWriter w = new BinaryWriter(s)) {
                        w.Write((ushort)data.Count);

                        foreach (var pair in data)
                        {
                            w.Write(pair.Key);

                            switch (pair.Value)
                            {
                            case string value: {
                                w.Write((byte)0);
                                w.Write(value);
                                break;
                            }

                            case bool value: {
                                w.Write((byte)1);
                                w.Write(value);
                                break;
                            }

                            case byte value: {
                                w.Write((byte)2);
                                w.Write(value);
                                break;
                            }

                            case int value: {
                                w.Write((byte)3);
                                w.Write(value);
                                break;
                            }

                            case long value: {
                                w.Write((byte)4);
                                w.Write(value);
                                break;
                            }

                            case short value: {
                                w.Write((byte)5);
                                w.Write(value);
                                break;
                            }

                            case uint value: {
                                w.Write((byte)6);
                                w.Write(value);
                                break;
                            }

                            case string[] value: {
                                w.Write((byte)10);
                                w.Write((byte)value.Length);
                                for (int j = 0; j < value.Length; j++)
                                {
                                    w.Write(value[j]);
                                }
                                break;
                            }

                            case bool[] value: {
                                w.Write((byte)11);
                                w.Write((byte)value.Length);
                                for (int j = 0; j < value.Length; j++)
                                {
                                    w.Write(value[j]);
                                }
                                break;
                            }

                            case byte[] value: {
                                w.Write((byte)12);
                                w.Write((byte)value.Length);
                                for (int j = 0; j < value.Length; j++)
                                {
                                    w.Write(value[j]);
                                }
                                break;
                            }

                            case int[] value: {
                                w.Write((byte)13);
                                w.Write((byte)value.Length);
                                for (int j = 0; j < value.Length; j++)
                                {
                                    w.Write(value[j]);
                                }
                                break;
                            }

                            case long[] value: {
                                w.Write((byte)14);
                                w.Write((byte)value.Length);
                                for (int j = 0; j < value.Length; j++)
                                {
                                    w.Write(value[j]);
                                }
                                break;
                            }

                            case short[] value: {
                                w.Write((byte)15);
                                w.Write((byte)value.Length);
                                for (int j = 0; j < value.Length; j++)
                                {
                                    w.Write(value[j]);
                                }
                                break;
                            }

                            case uint[] value: {
                                w.Write((byte)16);
                                w.Write((byte)value.Length);
                                for (int j = 0; j < value.Length; j++)
                                {
                                    w.Write(value[j]);
                                }
                                break;
                            }

                            default:
                                Log.Write(LogType.Warning, "Unknown preference type: " + pair.Value.GetType().FullName);
                                break;
                            }
                        }
                    }
            } catch (Exception ex) {
                Log.Write(LogType.Error, "Can't save preferences: " + ex);
            }
        }