소스 검색

C#: Add option to embed dotnet build outputs into the data file

RedworkDE 2 년 전
부모
커밋
777d959e05
2개의 변경된 파일90개의 추가작업 그리고 15개의 파일을 삭제
  1. 46 4
      modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
  2. 44 11
      modules/mono/godotsharp_dirs.cpp

+ 46 - 4
modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs

@@ -3,6 +3,8 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
 using GodotTools.Build;
 using GodotTools.Core;
 using GodotTools.Internals;
@@ -45,6 +47,17 @@ namespace GodotTools.Export
                         }
                     },
                     { "default_value", true }
+                },
+                new Godot.Collections.Dictionary()
+                {
+                    {
+                        "option", new Godot.Collections.Dictionary()
+                        {
+                            { "name", "dotnet/embed_build_outputs" },
+                            { "type", (int)Variant.Type.Bool }
+                        }
+                    },
+                    { "default_value", false }
                 }
             };
         }
@@ -146,6 +159,8 @@ namespace GodotTools.Export
                 }
             }
 
+            bool embedBuildResults = (bool)GetOption("dotnet/embed_build_outputs");
+
             foreach (var arch in archs)
             {
                 string ridOS = DetermineRuntimeIdentifierOS(platform);
@@ -190,17 +205,44 @@ namespace GodotTools.Export
                         "Publish succeeded but project assembly not found in the output directory");
                 }
 
-                // Add to the exported project shared object list.
+                var manifest = new StringBuilder();
 
+                // Add to the exported project shared object list or packed resources.
                 foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
                 {
-                    AddSharedObject(file, tags: null,
-                        Path.Join(projectDataDirName,
-                            Path.GetRelativePath(publishOutputTempDir, Path.GetDirectoryName(file))));
+                    if (embedBuildResults)
+                    {
+                        var filePath = SanitizeSlashes(Path.GetRelativePath(publishOutputTempDir, file));
+                        var fileData = File.ReadAllBytes(file);
+                        var hash = Convert.ToBase64String(SHA512.HashData(fileData));
+
+                        manifest.Append($"{filePath}\t{hash}\n");
+
+                        AddFile($"res://.godot/mono/publish/{arch}/{filePath}", fileData, false);
+                    }
+                    else
+                    {
+                        AddSharedObject(file, tags: null,
+                            Path.Join(projectDataDirName,
+                                Path.GetRelativePath(publishOutputTempDir, Path.GetDirectoryName(file))));
+                    }
+                }
+
+                if (embedBuildResults)
+                {
+                    var fileData = Encoding.Default.GetBytes(manifest.ToString());
+                    AddFile($"res://.godot/mono/publish/{arch}/.dotnet-publish-manifest", fileData, false);
                 }
             }
         }
 
+        private string SanitizeSlashes(string path)
+        {
+            if (Path.DirectorySeparatorChar == '\\')
+                return path.Replace('\\', '/');
+            return path;
+        }
+
         private string DetermineRuntimeIdentifierOS(string platform)
             => OS.DotNetOSPlatformMap[platform];
 

+ 44 - 11
modules/mono/godotsharp_dirs.cpp

@@ -141,19 +141,52 @@ private:
 #else // TOOLS_ENABLED
 		String arch = Engine::get_singleton()->get_architecture_name();
 		String appname_safe = path::get_csharp_project_name();
-		String data_dir_root = exe_dir.path_join("data_" + appname_safe + "_" + arch);
-		if (!DirAccess::exists(data_dir_root)) {
-			data_dir_root = exe_dir.path_join("data_Godot_" + arch);
-		}
+		String packed_path = "res://.godot/mono/publish/" + arch;
+		if (DirAccess::exists(packed_path)) {
+			// The dotnet publish data is packed in the pck/zip.
+			String data_dir_root = OS::get_singleton()->get_cache_path().path_join("data_" + appname_safe + "_" + arch);
+			bool has_data = false;
+			if (!has_data) {
+				// 1. Try to access the data directly.
+				String global_packed = ProjectSettings::get_singleton()->globalize_path(packed_path);
+				if (global_packed.is_absolute_path() && FileAccess::exists(global_packed.path_join(".dotnet-publish-manifest"))) {
+					data_dir_root = global_packed;
+					has_data = true;
+				}
+			}
+			if (!has_data) {
+				// 2. Check if the data was extracted before and is up-to-date.
+				String packed_manifest = packed_path.path_join(".dotnet-publish-manifest");
+				String extracted_manifest = data_dir_root.path_join(".dotnet-publish-manifest");
+				if (FileAccess::exists(packed_manifest) && FileAccess::exists(extracted_manifest)) {
+					if (FileAccess::get_file_as_bytes(packed_manifest) == FileAccess::get_file_as_bytes(extracted_manifest)) {
+						has_data = true;
+					}
+				}
+			}
+			if (!has_data) {
+				// 3. Extract the data to a temporary location to load from there.
+				Ref<DirAccess> da = DirAccess::create_for_path(packed_path);
+				ERR_FAIL_NULL(da);
+				ERR_FAIL_COND(da->copy_dir(packed_path, data_dir_root) != OK);
+			}
+			api_assemblies_dir = data_dir_root;
+		} else {
+			// The dotnet publish data is in a directory next to the executable.
+			String data_dir_root = exe_dir.path_join("data_" + appname_safe + "_" + arch);
+			if (!DirAccess::exists(data_dir_root)) {
+				data_dir_root = exe_dir.path_join("data_Godot_" + arch);
+			}
 #ifdef MACOS_ENABLED
-		if (!DirAccess::exists(data_dir_root)) {
-			data_dir_root = res_dir.path_join("data_" + appname_safe + "_" + arch);
-		}
-		if (!DirAccess::exists(data_dir_root)) {
-			data_dir_root = res_dir.path_join("data_Godot_" + arch);
-		}
+			if (!DirAccess::exists(data_dir_root)) {
+				data_dir_root = res_dir.path_join("data_" + appname_safe + "_" + arch);
+			}
+			if (!DirAccess::exists(data_dir_root)) {
+				data_dir_root = res_dir.path_join("data_Godot_" + arch);
+			}
 #endif
-		api_assemblies_dir = data_dir_root;
+			api_assemblies_dir = data_dir_root;
+		}
 #endif
 	}