Browse Source

feat: 添加抽象的文件系统内容包

LanzaSchneider 2 years ago
parent
commit
e4a028e12d

+ 2 - 0
Content.cs

@@ -1,4 +1,6 @@
 using System;
+using System.IO;
+using Zio;
 
 namespace TBL.GodotSharp.Content
 {

+ 0 - 1
FileSystem/GodotFileSystem.cs

@@ -1,7 +1,6 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
-using System.Text.RegularExpressions;
 using Godot;
 using TBL.GodotSharp.IO.File;
 using Zio;

+ 76 - 0
Package/FileSystemPackage.cs

@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Godot;
+using Zio;
+
+namespace TBL.GodotSharp.Content.Package
+{
+    /// <summary>
+    /// 基于文件系统的抽象内容包
+    /// <para>会在内部自动检索配置文件来获取描述符和依赖项信息</para>
+    /// </summary>
+    public class FileSystemPackage : PackageNode
+    {
+        public override IFileSystem SelfFileSystem { get; }
+        
+        public sealed override Info SelfInfo { get; }
+        
+        public sealed override IEnumerable<DependencyInfo> Dependencies { get; }
+
+        public FileSystemPackage(IFileSystem fileSystem)
+        {
+            Dependencies = null;
+            var iniFound = false;
+            foreach (var iniPath in fileSystem.EnumeratePaths(UPath.Root, "*.ini", SearchOption.TopDirectoryOnly, SearchTarget.File))
+            {
+                var ini = new ConfigFile();
+                var err = ini.Parse(fileSystem.ReadAllText(iniPath));
+                if (err != Error.Ok)
+                    throw new GodotException(err);
+
+                iniFound = true;
+
+                if (SelfInfo.Name.Empty() && ini.HasSection(nameof(SelfInfo)))
+                {
+                    SelfInfo = new Info(
+                        ini.GetValue(nameof(SelfInfo), nameof(SelfInfo.Name)) as string,
+                        ini.GetValue(nameof(SelfInfo), nameof(SelfInfo.AuthorInfo)) as string,
+                        ini.GetValue(nameof(SelfInfo), nameof(SelfInfo.VersionInfo)) as string
+                        );
+                }
+
+                if (Dependencies == null && ini.HasSection(nameof(Dependencies)))
+                {
+                    var dependencies = new List<DependencyInfo>();
+                    foreach (var dependencyName in ini.GetSectionKeys(nameof(Dependencies)))
+                    {
+                        var info = ini.GetValue(nameof(Dependencies), dependencyName) as Godot.Collections.Array;
+                        if (info == null || info.Count < 3)
+                            continue;
+                        var flags = DependencyInfo.FlagsEnum.None;
+                        if (info.Count > 3 && info[3] is string flagsInfo)
+                        {
+                            foreach (var flagInfo in flagsInfo.Split(';'))
+                                if (Enum.TryParse<DependencyInfo.FlagsEnum>(flagInfo.Trim(), out var flag))
+                                    flags |= flag;
+                        }
+                        var dependency = new DependencyInfo(new Info(info[0] as string, info[1] as string, info[2] as string), flags);
+                        dependencies.Add(dependency);
+                    }
+                    Dependencies = dependencies;
+                }
+
+                if (!SelfInfo.Name.Empty() &&
+                    Dependencies != null)
+                {
+                    break;
+                }
+            }
+
+            if (!iniFound)
+                throw new GodotException(Error.FileNotFound);
+            SelfFileSystem = fileSystem;
+        }
+    }
+}

+ 13 - 4
Package/InternalPackage.cs

@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using Godot;
 using TBL.GodotSharp.Content.FileSystem;
 using Zio;
 
@@ -7,17 +8,25 @@ namespace TBL.GodotSharp.Content.Package
     /// <summary>
     /// 内部内容包
     /// </summary>
-    public class InternalPackage : PackageNode
+    internal class InternalPackage : PackageNode
     {
-        public override IFileSystem SelfFileSystem { get; } = new GodotFileSystem("res://");
+        public override IFileSystem SelfFileSystem { get; }
 
         public override Info SelfInfo { get; }
     
         public override IEnumerable<DependencyInfo> Dependencies { get; }
 
-        public InternalPackage(Info info)
+        public InternalPackage(Info info) : this(info, string.Empty)
         {
-            SelfInfo = info;
+        }
+        
+        public InternalPackage(Info info, string root)
+        {
+            SelfFileSystem = new GodotFileSystem($"res://{root}");
+            SelfInfo = root.Empty() 
+                ? info
+                : new Info($"{info.Name}.{root}", info.AuthorInfo, info.VersionInfo)
+                ;
             Dependencies = null;
         }
     }

+ 15 - 0
Package/ZipArchivePackage.cs

@@ -0,0 +1,15 @@
+using System.IO;
+using Zio.FileSystems;
+
+namespace TBL.GodotSharp.Content.Package
+{
+    /// <summary>
+    /// Zip 归档内容包
+    /// </summary>
+    public class ZipArchivePackage : FileSystemPackage
+    {
+        public ZipArchivePackage(Stream zipStream) : base(new ZipArchiveFileSystem(zipStream))
+        {
+        }
+    }
+}

+ 40 - 1
PackageContainer.cs

@@ -1,4 +1,6 @@
-using Godot;
+using System.Diagnostics;
+using Godot;
+using TBL.GodotSharp.Content.Package;
 using Zio.FileSystems;
 
 namespace TBL.GodotSharp.Content
@@ -17,5 +19,42 @@ namespace TBL.GodotSharp.Content
         {
             Name = nameof(PackageContainer);
         }
+
+        /// <summary>
+        /// 卸载所有内容包
+        /// </summary>
+        public void UnloadPackages()
+        {
+            for (var i = GetChildCount() - 1; i >= 0; i--) 
+            {
+                if (GetChild(i) is PackageNode packageNode)
+                {
+                    RemoveChild(packageNode);
+                    packageNode.QueueFree();
+                }
+            }
+        }
+
+        /// <summary>
+        /// 重装载所有内容包,将内部目录全部以内部内容包加载
+        /// </summary>
+        public void ReloadPackages() => ReloadPackages(string.Empty);
+
+        /// <summary>
+        /// 指定内部内容包目录,重装载所有内容包
+        /// </summary>
+        /// <param name="internalPackageRoot">内部内容包根目录,传入 null 可以不装载内部内容包</param>
+        public void ReloadPackages(string internalPackageRoot)
+        {
+            UnloadPackages();
+            // 添加内部内容包
+            if (internalPackageRoot != null)
+            {
+                var title = ProjectSettings.GetSetting("application/config/name") as string;
+                var assembly = Game.Instance.GetType().Assembly;
+                var versionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
+                AddChild(new InternalPackage(new PackageNode.Info(title, versionInfo.CompanyName, versionInfo.ProductVersion), internalPackageRoot));
+            }
+        }
     }
 }

+ 1 - 1
PackageNode.DependencyInfo.cs

@@ -49,7 +49,7 @@ namespace TBL.GodotSharp.Content
                     (target.Flags & DependencyInfo.FlagsEnum.Strict) != 0 ? 1 : 0);
             }
 
-            public override string ToString() => $"{Name}_{AuthorInfo}_{VersionInfo}";
+            public override string ToString() => $"[{Name}][{AuthorInfo}][{VersionInfo}]";
         }
 
         /// <summary>