Skip to content

Commit 777d959

Browse files
committed
C#: Add option to embed dotnet build outputs into the data file
1 parent c83f912 commit 777d959

2 files changed

Lines changed: 90 additions & 15 deletions

File tree

modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using System.Collections.Generic;
44
using System.IO;
55
using System.Linq;
6+
using System.Security.Cryptography;
7+
using System.Text;
68
using GodotTools.Build;
79
using GodotTools.Core;
810
using GodotTools.Internals;
@@ -45,6 +47,17 @@ public partial class ExportPlugin : EditorExportPlugin
4547
}
4648
},
4749
{ "default_value", true }
50+
},
51+
new Godot.Collections.Dictionary()
52+
{
53+
{
54+
"option", new Godot.Collections.Dictionary()
55+
{
56+
{ "name", "dotnet/embed_build_outputs" },
57+
{ "type", (int)Variant.Type.Bool }
58+
}
59+
},
60+
{ "default_value", false }
4861
}
4962
};
5063
}
@@ -146,6 +159,8 @@ private void _ExportBeginImpl(string[] features, bool isDebug, string path, long
146159
}
147160
}
148161

162+
bool embedBuildResults = (bool)GetOption("dotnet/embed_build_outputs");
163+
149164
foreach (var arch in archs)
150165
{
151166
string ridOS = DetermineRuntimeIdentifierOS(platform);
@@ -190,17 +205,44 @@ private void _ExportBeginImpl(string[] features, bool isDebug, string path, long
190205
"Publish succeeded but project assembly not found in the output directory");
191206
}
192207

193-
// Add to the exported project shared object list.
208+
var manifest = new StringBuilder();
194209

210+
// Add to the exported project shared object list or packed resources.
195211
foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
196212
{
197-
AddSharedObject(file, tags: null,
198-
Path.Join(projectDataDirName,
199-
Path.GetRelativePath(publishOutputTempDir, Path.GetDirectoryName(file))));
213+
if (embedBuildResults)
214+
{
215+
var filePath = SanitizeSlashes(Path.GetRelativePath(publishOutputTempDir, file));
216+
var fileData = File.ReadAllBytes(file);
217+
var hash = Convert.ToBase64String(SHA512.HashData(fileData));
218+
219+
manifest.Append($"{filePath}\t{hash}\n");
220+
221+
AddFile($"res://.godot/mono/publish/{arch}/{filePath}", fileData, false);
222+
}
223+
else
224+
{
225+
AddSharedObject(file, tags: null,
226+
Path.Join(projectDataDirName,
227+
Path.GetRelativePath(publishOutputTempDir, Path.GetDirectoryName(file))));
228+
}
229+
}
230+
231+
if (embedBuildResults)
232+
{
233+
var fileData = Encoding.Default.GetBytes(manifest.ToString());
234+
AddFile($"res://.godot/mono/publish/{arch}/.dotnet-publish-manifest", fileData, false);
200235
}
201236
}
202237
}
203238

239+
private string SanitizeSlashes(string path)
240+
{
241+
if (Path.DirectorySeparatorChar == '\\')
242+
return path.Replace('\\', '/');
243+
return path;
244+
}
245+
204246
private string DetermineRuntimeIdentifierOS(string platform)
205247
=> OS.DotNetOSPlatformMap[platform];
206248

modules/mono/godotsharp_dirs.cpp

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,19 +141,52 @@ class _GodotSharpDirs {
141141
#else // TOOLS_ENABLED
142142
String arch = Engine::get_singleton()->get_architecture_name();
143143
String appname_safe = path::get_csharp_project_name();
144-
String data_dir_root = exe_dir.path_join("data_" + appname_safe + "_" + arch);
145-
if (!DirAccess::exists(data_dir_root)) {
146-
data_dir_root = exe_dir.path_join("data_Godot_" + arch);
147-
}
144+
String packed_path = "res://.godot/mono/publish/" + arch;
145+
if (DirAccess::exists(packed_path)) {
146+
// The dotnet publish data is packed in the pck/zip.
147+
String data_dir_root = OS::get_singleton()->get_cache_path().path_join("data_" + appname_safe + "_" + arch);
148+
bool has_data = false;
149+
if (!has_data) {
150+
// 1. Try to access the data directly.
151+
String global_packed = ProjectSettings::get_singleton()->globalize_path(packed_path);
152+
if (global_packed.is_absolute_path() && FileAccess::exists(global_packed.path_join(".dotnet-publish-manifest"))) {
153+
data_dir_root = global_packed;
154+
has_data = true;
155+
}
156+
}
157+
if (!has_data) {
158+
// 2. Check if the data was extracted before and is up-to-date.
159+
String packed_manifest = packed_path.path_join(".dotnet-publish-manifest");
160+
String extracted_manifest = data_dir_root.path_join(".dotnet-publish-manifest");
161+
if (FileAccess::exists(packed_manifest) && FileAccess::exists(extracted_manifest)) {
162+
if (FileAccess::get_file_as_bytes(packed_manifest) == FileAccess::get_file_as_bytes(extracted_manifest)) {
163+
has_data = true;
164+
}
165+
}
166+
}
167+
if (!has_data) {
168+
// 3. Extract the data to a temporary location to load from there.
169+
Ref<DirAccess> da = DirAccess::create_for_path(packed_path);
170+
ERR_FAIL_NULL(da);
171+
ERR_FAIL_COND(da->copy_dir(packed_path, data_dir_root) != OK);
172+
}
173+
api_assemblies_dir = data_dir_root;
174+
} else {
175+
// The dotnet publish data is in a directory next to the executable.
176+
String data_dir_root = exe_dir.path_join("data_" + appname_safe + "_" + arch);
177+
if (!DirAccess::exists(data_dir_root)) {
178+
data_dir_root = exe_dir.path_join("data_Godot_" + arch);
179+
}
148180
#ifdef MACOS_ENABLED
149-
if (!DirAccess::exists(data_dir_root)) {
150-
data_dir_root = res_dir.path_join("data_" + appname_safe + "_" + arch);
151-
}
152-
if (!DirAccess::exists(data_dir_root)) {
153-
data_dir_root = res_dir.path_join("data_Godot_" + arch);
154-
}
181+
if (!DirAccess::exists(data_dir_root)) {
182+
data_dir_root = res_dir.path_join("data_" + appname_safe + "_" + arch);
183+
}
184+
if (!DirAccess::exists(data_dir_root)) {
185+
data_dir_root = res_dir.path_join("data_Godot_" + arch);
186+
}
155187
#endif
156-
api_assemblies_dir = data_dir_root;
188+
api_assemblies_dir = data_dir_root;
189+
}
157190
#endif
158191
}
159192

0 commit comments

Comments
 (0)