diff --git a/Source/Engine/Level/Actors/Light.cpp b/Source/Engine/Level/Actors/Light.cpp index ad7fe54a2..6de7977c9 100644 --- a/Source/Engine/Level/Actors/Light.cpp +++ b/Source/Engine/Level/Actors/Light.cpp @@ -107,6 +107,7 @@ void LightWithShadow::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE(ContactShadowsLength); SERIALIZE(ShadowsUpdateRate); SERIALIZE(ShadowsUpdateRateAtDistance); + SERIALIZE(ShadowsResolution); } void LightWithShadow::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) @@ -125,4 +126,5 @@ void LightWithShadow::Deserialize(DeserializeStream& stream, ISerializeModifier* DESERIALIZE(ContactShadowsLength); DESERIALIZE(ShadowsUpdateRate); DESERIALIZE(ShadowsUpdateRateAtDistance); + DESERIALIZE(ShadowsResolution); } diff --git a/Source/Tools/Flax.Build/Build/Builder.cs b/Source/Tools/Flax.Build/Build/Builder.cs index 3a4286254..775bef1dc 100644 --- a/Source/Tools/Flax.Build/Build/Builder.cs +++ b/Source/Tools/Flax.Build/Build/Builder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using Flax.Build.Graph; using Flax.Build.NativeCpp; @@ -424,5 +425,120 @@ namespace Flax.Build return failed; } + + private static void DeployFiles(TaskGraph graph, Target target, BuildOptions targetBuildOptions, string outputPath) + { + using (new ProfileEventScope("DeployFiles")) + { + foreach (var srcFile in targetBuildOptions.OptionalDependencyFiles.Where(File.Exists).Union(targetBuildOptions.DependencyFiles)) + { + var dstFile = Path.Combine(outputPath, Path.GetFileName(srcFile)); + graph.AddCopyFile(dstFile, srcFile); + } + + if (targetBuildOptions.NugetPackageReferences.Any()) + { + // Find all packages to deploy (incl. dependencies) and restore if needed + var nugetPath = Utilities.GetNugetPackagesPath(); + Log.Verbose($"Deploying NuGet packages from {nugetPath}"); + var restoreOnce = true; + var nugetFiles = new HashSet(); + foreach (var reference in targetBuildOptions.NugetPackageReferences) + { + var folder = reference.GetLibFolder(nugetPath); + if (!Directory.Exists(folder) && restoreOnce) + { + // Package binaries folder is missing so restore packages (incl. dependency packages) + RestoreNugetPackages(graph, target, targetBuildOptions); + restoreOnce = false; + } + + DeployNuGetPackage(nugetPath, targetBuildOptions, nugetFiles, reference, folder); + } + + // Copy libraries from all referenced packages to the output folder + foreach (var file in nugetFiles) + { + var dstFile = Path.Combine(outputPath, Path.GetFileName(file)); + graph.AddCopyFile(dstFile, file); + } + } + } + } + + private static void RestoreNugetPackages(TaskGraph graph, Target target, BuildOptions targetBuildOptions) + { + // Generate a dummy csproj file to restore package from it + var csprojPath = Path.Combine(targetBuildOptions.IntermediateFolder, "nuget.restore.csproj"); + var dotnetSdk = DotNetSdk.Instance; + var csProjectFileContent = new StringBuilder(); + csProjectFileContent.AppendLine(""); + csProjectFileContent.AppendLine(" "); + csProjectFileContent.AppendLine($" net{dotnetSdk.Version.Major}.{dotnetSdk.Version.Minor}"); + csProjectFileContent.AppendLine(" false"); + csProjectFileContent.AppendLine(" false"); + csProjectFileContent.AppendLine(" false"); + csProjectFileContent.AppendLine(" false"); + csProjectFileContent.AppendLine(" false"); + csProjectFileContent.AppendLine(" false"); + csProjectFileContent.AppendLine($" {dotnetSdk.CSharpLanguageVersion}"); + csProjectFileContent.AppendLine(" 512"); + csProjectFileContent.AppendLine(" true"); + csProjectFileContent.AppendLine(" "); + csProjectFileContent.AppendLine(" "); + foreach (var reference in targetBuildOptions.NugetPackageReferences) + csProjectFileContent.AppendLine($" "); + csProjectFileContent.AppendLine(" "); + csProjectFileContent.AppendLine(""); + Utilities.WriteFileIfChanged(csprojPath, csProjectFileContent.ToString()); + + // Restore packages using dotnet CLI (synchronous to prevent task ordering issues on C# library building) + Log.Info($"Restoring NuGet packages for target {target.Name}"); + Utilities.Run(Utilities.GetDotNetPath(), $"restore \"{csprojPath}\"", null, null, Utilities.RunOptions.DefaultTool); + } + + private static void DeployNuGetPackage(string nugetPath, BuildOptions targetBuildOptions, HashSet nugetFiles, NugetPackage package, string folder = null) + { + // Deploy library + var path = package.GetLibPath(nugetPath, folder); + if (!File.Exists(path)) + return; + Log.Verbose($"Deploying NuGet package {package.Name}, {package.Version}, {package.Framework}"); + nugetFiles.Add(path); + + // Copy additional files (if included) + path = Path.ChangeExtension(path, "xml"); + if (File.Exists(path)) + nugetFiles.Add(path); + path = Path.ChangeExtension(path, "pdb"); + if (targetBuildOptions.Configuration != TargetConfiguration.Release && File.Exists(path)) + nugetFiles.Add(path); + + // Read package dependencies + var nuspecFile = package.GetNuspecPath(nugetPath); + if (File.Exists(nuspecFile)) + { + var doc = System.Xml.Linq.XDocument.Load(nuspecFile); + var root = (System.Xml.Linq.XElement)doc.FirstNode; + var metadataNode = root.Descendants().First(x => x.Name.LocalName== "metadata"); + var dependenciesNode = metadataNode.Descendants().First(x => x.Name.LocalName == "dependencies"); + var groupNode = dependenciesNode.Descendants().FirstOrDefault(x => x.Attribute("targetFramework")?.Value == package.Framework); + if (groupNode == null) + { + Log.Warning($"Cannot find framework {package.Framework} inside NuGet package {package.Name}, {package.Version}"); + return; + } + foreach (var dependency in groupNode.Descendants()) + { + if (dependency.Name.LocalName != "dependency") + continue; + + // Deploy dependency package + var dependencyId = dependency.Attribute("id").Value; + var dependencyVersion = dependency.Attribute("version").Value; + DeployNuGetPackage(nugetPath, targetBuildOptions, nugetFiles, new NugetPackage { Name = dependencyId, Version = dependencyVersion, Framework = package.Framework } ); + } + } + } } } diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs index 23646a3d7..54136b490 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs @@ -135,27 +135,7 @@ namespace Flax.Build // Deploy files if (!target.IsPreBuilt) { - using (new ProfileEventScope("DeployFiles")) - { - foreach (var srcFile in targetBuildOptions.OptionalDependencyFiles.Where(File.Exists).Union(targetBuildOptions.DependencyFiles)) - { - var dstFile = Path.Combine(outputPath, Path.GetFileName(srcFile)); - graph.AddCopyFile(dstFile, srcFile); - } - - if (targetBuildOptions.NugetPackageReferences.Any()) - { - var nugetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages"); - foreach (var reference in targetBuildOptions.NugetPackageReferences) - { - var path = Path.Combine(nugetPath, reference.Name, reference.Version, "lib", reference.Framework, $"{reference.Name}.dll"); - if (!File.Exists(path)) - Utilities.RestoreNugetPackages(graph, target); - var dstFile = Path.Combine(outputPath, Path.GetFileName(path)); - graph.AddCopyFile(dstFile, path); - } - } - } + DeployFiles(graph, target, targetBuildOptions, outputPath); } using (new ProfileEventScope("PostBuild")) @@ -301,10 +281,10 @@ namespace Flax.Build // Reference Nuget package if (buildData.TargetOptions.NugetPackageReferences.Any()) { - var nugetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages"); + var nugetPath = Utilities.GetNugetPackagesPath(); foreach (var reference in buildOptions.NugetPackageReferences) { - var path = Path.Combine(nugetPath, reference.Name, reference.Version, "lib", reference.Framework, $"{reference.Name}.dll"); + var path = reference.GetLibPath(nugetPath); args.Add(string.Format("/reference:\"{0}\"", path)); } } diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs index 13ecd1982..8251ff186 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/BuildOptions.cs @@ -102,6 +102,51 @@ namespace Flax.Build.NativeCpp Version = version; Framework = framework; } + + internal string GetLibFolder(string nugetPath) + { + var libFolder = Path.Combine(nugetPath, Name, Version, "lib", Framework); + if (Directory.Exists(libFolder)) + return libFolder; + + // Try to find nearest framework folder + if (Framework.StartsWith("net")) + { + var baseVersion = int.Parse(Framework.Substring(3, Framework.IndexOf('.') - 3)); + for (int version = baseVersion - 1; version >= 5; version--) + { + var framework = $"net{version}.0"; + libFolder = Path.Combine(nugetPath, Name, Version, "lib", framework); + if (Directory.Exists(libFolder)) + { + Framework = framework; + return libFolder; + } + } + } + + Log.Error($"Missing NuGet package \"{Name}, {Version}, {Framework}\" (nuget: {nugetPath})"); + return string.Empty; + } + + internal string GetNuspecPath(string nugetPath) + { + var files = Directory.GetFiles(Path.Combine(nugetPath, Name, Version), "*.nuspec", SearchOption.TopDirectoryOnly); + return files[0]; + } + + internal string GetLibPath(string nugetPath, string libFolder = null) + { + if (libFolder == null) + libFolder = GetLibFolder(nugetPath); + var dlls = Directory.GetFiles(libFolder, "*.dll", SearchOption.TopDirectoryOnly); + if (dlls.Length == 0) + { + Log.Error($"Missing NuGet package \"{Name}, {Version}, {Framework}\" binaries (folder: {libFolder})"); + return string.Empty; + } + return dlls[0]; + } } /// @@ -167,7 +212,7 @@ namespace Flax.Build.NativeCpp /// /// The nuget package references. /// - public List NugetPackageReferences = new List(); + public HashSet NugetPackageReferences = new HashSet(); /// /// The collection of defines with preprocessing symbol for a source files of this module. Inherited by the modules that include it. diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs b/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs index 4c9d521b4..322f1c3c1 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs @@ -1057,27 +1057,7 @@ namespace Flax.Build // Deploy files if (!buildData.Target.IsPreBuilt) { - using (new ProfileEventScope("DeployFiles")) - { - foreach (var srcFile in targetBuildOptions.OptionalDependencyFiles.Where(File.Exists).Union(targetBuildOptions.DependencyFiles)) - { - var dstFile = Path.Combine(outputPath, Path.GetFileName(srcFile)); - graph.AddCopyFile(dstFile, srcFile); - } - - if (targetBuildOptions.NugetPackageReferences.Any()) - { - var nugetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages"); - foreach (var reference in targetBuildOptions.NugetPackageReferences) - { - var path = Path.Combine(nugetPath, reference.Name, reference.Version, "lib", reference.Framework, $"{reference.Name}.dll"); - if (!File.Exists(path)) - Utilities.RestoreNugetPackages(graph, target); - var dstFile = Path.Combine(outputPath, Path.GetFileName(path)); - graph.AddCopyFile(dstFile, path); - } - } - } + DeployFiles(graph, target, targetBuildOptions, outputPath); } using (new ProfileEventScope("PostBuild")) @@ -1270,27 +1250,7 @@ namespace Flax.Build // Deploy files if (!buildData.Target.IsPreBuilt) { - using (new ProfileEventScope("DeployFiles")) - { - foreach (var srcFile in targetBuildOptions.OptionalDependencyFiles.Where(File.Exists).Union(targetBuildOptions.DependencyFiles)) - { - var dstFile = Path.Combine(outputPath, Path.GetFileName(srcFile)); - graph.AddCopyFile(dstFile, srcFile); - } - - if (targetBuildOptions.NugetPackageReferences.Any()) - { - var nugetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages"); - foreach (var reference in targetBuildOptions.NugetPackageReferences) - { - var path = Path.Combine(nugetPath, reference.Name, reference.Version, "lib", reference.Framework, $"{reference.Name}.dll"); - if (!File.Exists(path)) - Utilities.RestoreNugetPackages(graph, target); - var dstFile = Path.Combine(outputPath, Path.GetFileName(path)); - graph.AddCopyFile(dstFile, path); - } - } - } + DeployFiles(graph, target, targetBuildOptions, outputPath); } using (new ProfileEventScope("PostBuild")) diff --git a/Source/Tools/Flax.Build/Utilities/Utilities.cs b/Source/Tools/Flax.Build/Utilities/Utilities.cs index 917b8aa77..872b269ee 100644 --- a/Source/Tools/Flax.Build/Utilities/Utilities.cs +++ b/Source/Tools/Flax.Build/Utilities/Utilities.cs @@ -42,21 +42,14 @@ namespace Flax.Build } /// - /// Restores a targets nuget packages. + /// Gets the NuGet packages cache folder path. /// - /// The task graph. - /// The target. - /// The dotnet path. - public static void RestoreNugetPackages(Graph.TaskGraph graph, Target target) + /// The path. + public static string GetNugetPackagesPath() { - var dotNetPath = GetDotNetPath(); - var task = graph.Add(); - task.WorkingDirectory = target.FolderPath; - task.InfoMessage = $"Restoring Nuget Packages for {target.Name}"; - task.CommandPath = dotNetPath; - task.CommandArguments = $"restore"; + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages"); } - + /// /// Gets the hash code for the string (the same for all platforms). Matches Engine algorithm for string hashing. ///