From 5e74e58b2204b223ab100cba09a151eeac888910 Mon Sep 17 00:00:00 2001 From: teinarss Date: Wed, 26 Aug 2020 22:00:34 +0200 Subject: [PATCH] Add support for dotnet core for Windows --- .github/workflows/ci.yaml | 13 +- .github/workflows/packaging.yml | 7 +- INSTALL.md | 10 +- Makefile | 12 +- OpenRA.Game/Game.cs | 10 +- OpenRA.Game/ObjectCreator.cs | 50 ++- OpenRA.Game/OpenRA.Game.csproj | 7 +- OpenRA.Game/Support/AssemblyLoader.cs | 363 ++++++++++++++++++ OpenRA.Launcher/OpenRA.Launcher.csproj | 5 +- OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj | 5 +- OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 4 +- OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj | 5 +- .../OpenRA.Platforms.Default.csproj | 3 +- .../ThreadedGraphicsContext.cs | 1 - OpenRA.Server/OpenRA.Server.csproj | 3 +- OpenRA.Test/OpenRA.Test.csproj | 13 +- OpenRA.Utility/OpenRA.Utility.csproj | 3 +- .../OpenRA.WindowsLauncher.csproj | 6 +- OpenRA.sln | 2 - launch-dedicated.sh | 2 +- launch-game.sh | 2 +- make.ps1 | 4 +- packaging/.itch.toml | 3 - packaging/functions.sh | 61 ++- packaging/linux/buildpackage.sh | 3 +- packaging/linux/openra-server.appimage.in | 2 +- packaging/linux/openra-server.in | 2 +- packaging/linux/openra-utility.appimage.in | 2 +- packaging/linux/openra.appimage.in | 2 +- packaging/linux/openra.in | 2 +- packaging/macos/buildpackage.sh | 2 +- packaging/macos/launcher-mono.m | 2 +- packaging/macos/launcher.m | 2 +- packaging/windows/OpenRA.nsi | 29 +- packaging/windows/buildpackage.sh | 12 +- .../windows/{MakeLAA.py => fixlauncher.py} | 14 +- utility.sh | 2 +- 37 files changed, 557 insertions(+), 113 deletions(-) create mode 100644 OpenRA.Game/Support/AssemblyLoader.cs rename packaging/windows/{MakeLAA.py => fixlauncher.py} (59%) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7299e6bce7..7cad46cc1f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,7 +18,6 @@ jobs: run: | mono --version make check - mono ~/.nuget/packages/nunit.consolerunner/3.11.1/tools/nunit3-console.exe --noresult bin/OpenRA.Test.dll - name: Check Mods run: | @@ -27,18 +26,26 @@ jobs: make test windows: - name: Windows (Framework 4.7) + name: Windows (Net 5.0) runs-on: windows-2019 steps: - name: Clone Repository uses: actions/checkout@v2 + - name: Install .NET 5 + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '5.0.x' + - name: Check Code shell: powershell run: | + # Work around runtime failures on the GH Actions runner + dotnet nuget locals all --clear .\make.ps1 check - Invoke-Expression "$home\.nuget\packages\nunit.consolerunner\3.11.1\tools\nunit3-console.exe --noresult bin/OpenRA.Test.dll" + dotnet build OpenRA.Test\OpenRA.Test.csproj -c Debug --nologo -p:TargetPlatform=win-x64 + dotnet test bin\OpenRA.Test.dll --test-adapter-path:. - name: Check Mods run: | diff --git a/.github/workflows/packaging.yml b/.github/workflows/packaging.yml index c688e7ef31..12ded6d867 100644 --- a/.github/workflows/packaging.yml +++ b/.github/workflows/packaging.yml @@ -69,10 +69,15 @@ jobs: - name: Clone Repository uses: actions/checkout@v2 + - name: Install .NET 5 + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '5.0.x' + - name: Prepare Environment run: | echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV} - sudo apt install nsis + sudo apt install nsis wine64 - name: Package Installers run: | diff --git a/INSTALL.md b/INSTALL.md index aeee3f5010..2600ffd0a0 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -8,18 +8,16 @@ Windows Compiling OpenRA requires the following dependencies: * [Windows PowerShell >= 4.0](http://microsoft.com/powershell) (included by default in recent Windows 10 versions) -* [.NET Framework 4.7.2 (Developer Pack)](https://dotnet.microsoft.com/download/dotnet-framework/net472) (or via Visual Studio 2017) -* [.NET Core 2.2 SDK](https://dotnet.microsoft.com/download/dotnet-core/2.2) (or via Visual Studio 2017) +* [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/5.0) (or via Visual Studio) - -To compile OpenRA, open the `OpenRA.sln` solution in the main folder, build it from the command-line with MSBuild or use the Makefile analogue command `make all` scripted in PowerShell syntax. +To compile OpenRA, open the `OpenRA.sln` solution in the main folder, build it from the command-line with `dotnet` or use the Makefile analogue command `make all` scripted in PowerShell syntax. Run the game with `launch-game.cmd`. It can be handed arguments that specify the exact mod one wishes to run, for example, run `launch-game.cmd Game.Mod=ra` to launch Red Alert, `launch-game.cmd Game.Mod=cnc` to start Tiberian dawn or `launch-game.cmd Game.Mod=d2k` to launch Dune 2000. Linux ===== -Mono, version 5.18 or later, is required to compile OpenRA. You can add the [upstream mono repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version if your system packages are not sufficient. +Mono, version 6.4 or later, is required to compile OpenRA. You can add the [upstream mono repository](https://www.mono-project.com/download/stable/#download-lin) for your distro to obtain the latest version if your system packages are not sufficient. To compile OpenRA, run `make` from the command line. After this one can run the game with `./launch-game.sh`. It is also possible to specify the mod you wish to run from the command line, e.g. with `./launch-game.sh Game.Mod=ts` if you wish to try the experimental Tiberian Sun mod. @@ -99,7 +97,7 @@ macOS ===== Before compiling OpenRA you must install the following dependencies: -* [Mono >= 5.18](https://www.mono-project.com/download/stable/#download-mac) +* [Mono >= 6.4](https://www.mono-project.com/download/stable/#download-mac) To compile OpenRA, run `make` from the command line. Run with `./launch-game.sh`. diff --git a/Makefile b/Makefile index 75c63cbbaf..a17f596718 100644 --- a/Makefile +++ b/Makefile @@ -28,14 +28,14 @@ ############################## TOOLCHAIN ############################### # # List of .NET assemblies that we can guarantee exist -WHITELISTED_OPENRA_ASSEMBLIES = OpenRA.exe OpenRA.Utility.exe OpenRA.Server.exe OpenRA.Platforms.Default.dll OpenRA.Game.dll OpenRA.Mods.Common.dll OpenRA.Mods.Cnc.dll OpenRA.Mods.D2k.dll +WHITELISTED_OPENRA_ASSEMBLIES = OpenRA.dll OpenRA.Utility.dll OpenRA.Server.dll OpenRA.Platforms.Default.dll OpenRA.Game.dll OpenRA.Mods.Common.dll OpenRA.Mods.Cnc.dll OpenRA.Mods.D2k.dll # These are explicitly shipped alongside our core files by the packaging script WHITELISTED_THIRDPARTY_ASSEMBLIES = ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll Eluant.dll BeaconLib.dll Open.Nat.dll SDL2-CS.dll OpenAL-CS.Core.dll DiscordRPC.dll Newtonsoft.Json.dll # These are shipped in our custom minimal mono runtime and also available in the full system-installed .NET/mono stack # This list *must* be kept in sync with the files packaged by the AppImageSupport and OpenRALauncherOSX repositories -WHITELISTED_CORE_ASSEMBLIES = mscorlib.dll System.dll System.Configuration.dll System.Core.dll System.Numerics.dll System.Security.dll System.Xml.dll Mono.Security.dll netstandard.dll +WHITELISTED_CORE_ASSEMBLIES = mscorlib.dll System.dll System.Configuration.dll System.Core.dll System.Numerics.dll System.Security.dll System.Xml.dll Mono.Security.dll netstandard.dll Microsoft.Win32.Registry.dll System.Security.AccessControl.dll System.Security.Principal.Windows.dll System.Xml.Linq.dll System.Runtime.Serialization.dll ######################### UTILITIES/SETTINGS ########################### # @@ -78,13 +78,13 @@ endif endif endif -OPENRA_UTILITY = ENGINE_DIR=".." $(MONO) --debug bin/OpenRA.Utility.exe +OPENRA_UTILITY = ENGINE_DIR=".." $(MONO) --debug bin/OpenRA.Utility.dll ##################### DEVELOPMENT BUILDS AND TESTS ##################### # all: @command -v $(firstword $(MSBUILD)) >/dev/null || (echo "OpenRA requires the '$(MSBUILD)' tool provided by Mono >= 5.18."; exit 1) - @$(MSBUILD) -t:Build -restore -p:Configuration=Release -p:TargetPlatform=$(TARGETPLATFORM) + @$(MSBUILD) -t:Build -restore -p:Configuration=Release -p:TargetPlatform=$(TARGETPLATFORM) -p:Mono=true -p:DefineConstants="MONO" ifeq ($(TARGETPLATFORM), unix-generic) @./configure-system-libraries.sh endif @@ -92,13 +92,13 @@ endif clean: @-$(RM_RF) ./bin ./*/bin ./*/obj - @$(MSBUILD) -t:Clean + @$(MSBUILD) -t:Clean -p:Mono=true @-$(RM_F) IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP check: @echo @echo "Compiling in debug mode..." - @$(MSBUILD) -t:build -restore -p:Configuration=Debug + @$(MSBUILD) -t:build -restore -p:Configuration=Debug -p:TargetPlatform=$(TARGETPLATFORM) -p:Mono=true -p:DefineConstants="MONO" @echo @echo "Checking runtime assemblies..." @$(OPENRA_UTILITY) all --check-runtime-assemblies $(WHITELISTED_OPENRA_ASSEMBLIES) $(WHITELISTED_THIRDPARTY_ASSEMBLIES) $(WHITELISTED_CORE_ASSEMBLIES) diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index cc2502fb18..bf83786454 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -297,6 +297,7 @@ namespace OpenRA EngineVersion = "Unknown"; Console.WriteLine("Engine version is {0}", EngineVersion); + Console.WriteLine("Runtime: {0}", Platform.RuntimeVersion); // Special case handling of Game.Mod argument: if it matches a real filesystem path // then we use this to override the mod search path, and replace it with the mod id @@ -329,9 +330,16 @@ namespace OpenRA try { var rendererPath = Path.Combine(Platform.BinDir, "OpenRA.Platforms." + p + ".dll"); - var assembly = Assembly.LoadFile(rendererPath); +#if !MONO + var loader = new AssemblyLoader(rendererPath); + var platformType = loader.LoadDefaultAssembly().GetTypes().SingleOrDefault(t => typeof(IPlatform).IsAssignableFrom(t)); + +#else + var assembly = Assembly.LoadFile(rendererPath); var platformType = assembly.GetTypes().SingleOrDefault(t => typeof(IPlatform).IsAssignableFrom(t)); +#endif + if (platformType == null) throw new InvalidOperationException("Platform dll must include exactly one IPlatform implementation."); diff --git a/OpenRA.Game/ObjectCreator.cs b/OpenRA.Game/ObjectCreator.cs index 78c2c3ee09..75f67d2189 100644 --- a/OpenRA.Game/ObjectCreator.cs +++ b/OpenRA.Game/ObjectCreator.cs @@ -15,6 +15,7 @@ using System.IO; using System.Linq; using System.Reflection; using OpenRA.Primitives; +using OpenRA.Support; namespace OpenRA { @@ -42,25 +43,48 @@ namespace OpenRA if (resolvedPath == null) throw new FileNotFoundException("Assembly `{0}` not found.".F(path)); - // .NET doesn't provide any way of querying the metadata of an assembly without either: - // (a) loading duplicate data into the application domain, breaking the world. - // (b) crashing if the assembly has already been loaded. - // We can't check the internal name of the assembly, so we'll work off the data instead - var hash = CryptoUtil.SHA1Hash(File.ReadAllBytes(resolvedPath)); - - if (!ResolvedAssemblies.TryGetValue(hash, out var assembly)) - { - assembly = Assembly.LoadFile(resolvedPath); - ResolvedAssemblies.Add(hash, assembly); - } - - assemblyList.Add(assembly); + LoadAssembly(assemblyList, resolvedPath); } AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; assemblies = assemblyList.SelectMany(asm => asm.GetNamespaces().Select(ns => (asm, ns))).ToArray(); } + void LoadAssembly(List assemblyList, string resolvedPath) + { + // .NET doesn't provide any way of querying the metadata of an assembly without either: + // (a) loading duplicate data into the application domain, breaking the world. + // (b) crashing if the assembly has already been loaded. + // We can't check the internal name of the assembly, so we'll work off the data instead + var hash = CryptoUtil.SHA1Hash(File.ReadAllBytes(resolvedPath)); + + if (!ResolvedAssemblies.TryGetValue(hash, out var assembly)) + { +#if MONO + assembly = Assembly.LoadFile(resolvedPath); + ResolvedAssemblies.Add(hash, assembly); + + // Allow mods to use libraries. + var assemblyPath = Path.GetDirectoryName(resolvedPath); + if (assemblyPath != null) + { + foreach (var referencedAssembly in assembly.GetReferencedAssemblies()) + { + var depedencyPath = Path.Combine(assemblyPath, referencedAssembly.Name + ".dll"); + if (File.Exists(depedencyPath)) + LoadAssembly(assemblyList, depedencyPath); + } + } +#else + var loader = new AssemblyLoader(resolvedPath); + assembly = loader.LoadDefaultAssembly(); + ResolvedAssemblies.Add(hash, assembly); +#endif + } + + assemblyList.Add(assembly); + } + Assembly ResolveAssembly(object sender, ResolveEventArgs e) { foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 1ef90c89c9..a5cb108d95 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -1,7 +1,7 @@  Library - net472 + netstandard2.1 true true false @@ -39,6 +39,11 @@ + + + + + diff --git a/OpenRA.Game/Support/AssemblyLoader.cs b/OpenRA.Game/Support/AssemblyLoader.cs new file mode 100644 index 0000000000..74b8ae10ea --- /dev/null +++ b/OpenRA.Game/Support/AssemblyLoader.cs @@ -0,0 +1,363 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +// Not used/usable on Mono. Only used for Dotnet Core. +// Based on https://github.com/natemcmaster/DotNetCorePlugins and used under the terms of the Apache 2.0 license +#if !MONO +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Loader; +using Microsoft.Extensions.DependencyModel; + +namespace OpenRA.Support +{ + public class AssemblyLoader + { + readonly string mainAssembly; + readonly AssemblyLoadContext context; + + public Assembly LoadDefaultAssembly() => context.LoadFromAssemblyPath(mainAssembly); + + public AssemblyLoader(string assemblyFile) + { + mainAssembly = assemblyFile; + var baseDir = Path.GetDirectoryName(assemblyFile); + + context = CreateLoadContext(baseDir, assemblyFile); + } + + static AssemblyLoadContext CreateLoadContext(string baseDir, string assemblyFile) + { + var depsJsonFile = Path.Combine(baseDir, Path.GetFileNameWithoutExtension(assemblyFile) + ".deps.json"); + + var builder = new AssemblyLoadContextBuilder(); + + builder.TryAddDependencyContext(depsJsonFile, out _); + builder.SetBaseDirectory(baseDir); + + return builder.Build(); + } + } + + public class AssemblyLoadContextBuilder + { + readonly Dictionary managedLibraries = new Dictionary(StringComparer.Ordinal); + readonly Dictionary nativeLibraries = new Dictionary(StringComparer.Ordinal); + string basePath; + + public AssemblyLoadContext Build() + { + return new ManagedLoadContext(basePath, managedLibraries, nativeLibraries); + } + + public AssemblyLoadContextBuilder SetBaseDirectory(string path) + { + if (string.IsNullOrEmpty(path)) + throw new ArgumentException("Argument must not be null or empty.", nameof(path)); + + if (!Path.IsPathRooted(path)) + throw new ArgumentException("Argument must be a full path.", nameof(path)); + + basePath = path; + return this; + } + + public AssemblyLoadContextBuilder AddManagedLibrary(ManagedLibrary library) + { + managedLibraries.Add(library.Name.Name, library); + return this; + } + + public AssemblyLoadContextBuilder AddNativeLibrary(NativeLibrary library) + { + ValidateRelativePath(library.AppLocalPath); + nativeLibraries.Add(library.Name, library); + return this; + } + + static void ValidateRelativePath(string probingPath) + { + if (string.IsNullOrEmpty(probingPath)) + throw new ArgumentException("Value must not be null or empty.", nameof(probingPath)); + + if (Path.IsPathRooted(probingPath)) + throw new ArgumentException("Argument must be a relative path.", nameof(probingPath)); + } + } + + class ManagedLoadContext : AssemblyLoadContext + { + readonly string basePath; + readonly Dictionary managedAssemblies; + readonly Dictionary nativeLibraries; + + static readonly string[] NativeLibraryExtensions; + static readonly string[] NativeLibraryPrefixes; + + static readonly string[] ManagedAssemblyExtensions = + { + ".dll", + ".ni.dll", + ".exe", + ".ni.exe" + }; + + static ManagedLoadContext() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + NativeLibraryPrefixes = new[] { "" }; + NativeLibraryExtensions = new[] { ".dll" }; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + NativeLibraryPrefixes = new[] { "", "lib", }; + NativeLibraryExtensions = new[] { ".dylib" }; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + NativeLibraryPrefixes = new[] { "", "lib" }; + NativeLibraryExtensions = new[] { ".so", ".so.1" }; + } + else + { + NativeLibraryPrefixes = Array.Empty(); + NativeLibraryExtensions = Array.Empty(); + } + } + + public ManagedLoadContext(string baseDirectory, Dictionary managedAssemblies, Dictionary nativeLibraries) + { + basePath = baseDirectory ?? throw new ArgumentNullException(nameof(baseDirectory)); + this.managedAssemblies = managedAssemblies ?? throw new ArgumentNullException(nameof(managedAssemblies)); + this.nativeLibraries = nativeLibraries ?? throw new ArgumentNullException(nameof(nativeLibraries)); + } + + protected override Assembly Load(AssemblyName assemblyName) + { + // If default context is preferred, check first for types in the default context unless the dependency has been declared as private + try + { + var defaultAssembly = Default.LoadFromAssemblyName(assemblyName); + if (defaultAssembly != null) + return null; + } + catch + { + // Swallow errors in loading from the default context + } + + if (managedAssemblies.TryGetValue(assemblyName.Name, out var library) && SearchForLibrary(library, out var path)) + return LoadFromAssemblyPath(path); + + return null; + } + + protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) + { + foreach (var prefix in NativeLibraryPrefixes) + if (nativeLibraries.TryGetValue(prefix + unmanagedDllName, out var library) && SearchForLibrary(library, prefix, out var path)) + return LoadUnmanagedDllFromPath(path); + + return base.LoadUnmanagedDll(unmanagedDllName); + } + + bool SearchForLibrary(ManagedLibrary library, out string path) + { + // 1. Search in base path + foreach (var ext in ManagedAssemblyExtensions) + { + var local = Path.Combine(basePath, library.Name.Name + ext); + if (File.Exists(local)) + { + path = local; + return true; + } + } + + path = null; + return false; + } + + bool SearchForLibrary(NativeLibrary library, string prefix, out string path) + { + // 1. Search in base path + foreach (var ext in NativeLibraryExtensions) + { + var candidate = Path.Combine(basePath, $"{prefix}{library.Name}{ext}"); + if (File.Exists(candidate)) + { + path = candidate; + return true; + } + } + + // 2. Search in base path + app local (for portable deployments of netcoreapp) + var local = Path.Combine(basePath, library.AppLocalPath); + if (File.Exists(local)) + { + path = local; + return true; + } + + path = null; + return false; + } + } + + public class ManagedLibrary + { + public AssemblyName Name { get; private set; } + + public static ManagedLibrary CreateFromPackage(string assetPath) + { + return new ManagedLibrary + { + Name = new AssemblyName(Path.GetFileNameWithoutExtension(assetPath)) + }; + } + } + + public class NativeLibrary + { + public string Name { get; private set; } + + public string AppLocalPath { get; private set; } + + public static NativeLibrary CreateFromPackage(string assetPath) + { + return new NativeLibrary + { + Name = Path.GetFileNameWithoutExtension(assetPath), + AppLocalPath = assetPath + }; + } + } + + public static class DependencyContextExtensions + { + public static AssemblyLoadContextBuilder TryAddDependencyContext(this AssemblyLoadContextBuilder builder, string depsFilePath, out Exception error) + { + error = null; + try + { + builder.AddDependencyContext(depsFilePath); + } + catch (Exception ex) + { + error = ex; + } + + return builder; + } + + public static AssemblyLoadContextBuilder AddDependencyContext(this AssemblyLoadContextBuilder builder, string depsFilePath) + { + var reader = new DependencyContextJsonReader(); + using (var file = File.OpenRead(depsFilePath)) + { + var deps = reader.Read(file); + builder.SetBaseDirectory(Path.GetDirectoryName(depsFilePath)); + builder.AddDependencyContext(deps); + } + + return builder; + } + + static string GetFallbackRid() + { + string ridBase; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + ridBase = "win10"; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + ridBase = "linux"; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + ridBase = "osx.10.12"; + else + return "any"; + + switch (RuntimeInformation.OSArchitecture) + { + case Architecture.X86: + return ridBase + "-x86"; + case Architecture.X64: + return ridBase + "-x64"; + case Architecture.Arm: + return ridBase + "-arm"; + case Architecture.Arm64: + return ridBase + "-arm64"; + } + + return ridBase; + } + + public static AssemblyLoadContextBuilder AddDependencyContext(this AssemblyLoadContextBuilder builder, DependencyContext dependencyContext) + { + var ridGraph = dependencyContext.RuntimeGraph.Any() + ? dependencyContext.RuntimeGraph + : DependencyContext.Default.RuntimeGraph; + + var rid = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.GetRuntimeIdentifier(); + var fallbackRid = GetFallbackRid(); + var fallbackGraph = ridGraph.FirstOrDefault(g => g.Runtime == rid) + ?? ridGraph.FirstOrDefault(g => g.Runtime == fallbackRid) + ?? new RuntimeFallbacks("any"); + + foreach (var managed in dependencyContext.ResolveRuntimeAssemblies(fallbackGraph)) + builder.AddManagedLibrary(managed); + + foreach (var native in dependencyContext.ResolveNativeAssets(fallbackGraph)) + builder.AddNativeLibrary(native); + + return builder; + } + + static IEnumerable ResolveRuntimeAssemblies(this DependencyContext depContext, RuntimeFallbacks runtimeGraph) + { + var rids = GetRids(runtimeGraph); + return from library in depContext.RuntimeLibraries + from assetPath in SelectAssets(rids, library.RuntimeAssemblyGroups) + select ManagedLibrary.CreateFromPackage(assetPath); + } + + static IEnumerable ResolveNativeAssets(this DependencyContext depContext, RuntimeFallbacks runtimeGraph) + { + var rids = GetRids(runtimeGraph); + return from library in depContext.RuntimeLibraries + from assetPath in SelectAssets(rids, library.NativeLibraryGroups) + where !assetPath.EndsWith(".a", StringComparison.Ordinal) + select NativeLibrary.CreateFromPackage(assetPath); + } + + static IEnumerable GetRids(RuntimeFallbacks runtimeGraph) + { + return Enumerable.Concat(new[] { runtimeGraph.Runtime }, runtimeGraph?.Fallbacks ?? Enumerable.Empty()); + } + + static IEnumerable SelectAssets(IEnumerable rids, IEnumerable groups) + { + foreach (var rid in rids) + { + var group = groups.FirstOrDefault(g => g.Runtime == rid); + if (group != null) + return group.AssetPaths; + } + + return groups.GetDefaultAssets(); + } + } +} +#endif diff --git a/OpenRA.Launcher/OpenRA.Launcher.csproj b/OpenRA.Launcher/OpenRA.Launcher.csproj index c9dae8d8dd..3e81754db5 100644 --- a/OpenRA.Launcher/OpenRA.Launcher.csproj +++ b/OpenRA.Launcher/OpenRA.Launcher.csproj @@ -1,7 +1,8 @@  Exe - net472 + net5.0 + netstandard2.1 true true false @@ -17,6 +18,8 @@ ..\OpenRA.ruleset Release;Debug OpenRA + false + true win-x64 diff --git a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj index daf5f10214..ff20634794 100644 --- a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj +++ b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj @@ -1,6 +1,6 @@  - net472 + netstandard2.1 true true 7.3 @@ -11,6 +11,7 @@ AnyCPU false ..\OpenRA.ruleset + false @@ -37,4 +38,4 @@ - \ No newline at end of file + diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 31a1304f50..70f8cb959c 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -1,6 +1,6 @@  - net472 + netstandard2.1 true true 7.3 @@ -11,6 +11,7 @@ AnyCPU false ..\OpenRA.ruleset + true @@ -24,6 +25,7 @@ False + diff --git a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj index daf5f10214..f8af8a5026 100644 --- a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj +++ b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj @@ -1,6 +1,6 @@  - net472 + netstandard2.1 true true 7.3 @@ -11,6 +11,7 @@ AnyCPU false ..\OpenRA.ruleset + false @@ -37,4 +38,4 @@ - \ No newline at end of file + diff --git a/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj b/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj index 79c16701ba..e633a24c46 100644 --- a/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj +++ b/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj @@ -1,6 +1,6 @@  - net472 + netstandard2.1 true true 7.3 @@ -11,6 +11,7 @@ AnyCPU false ..\OpenRA.ruleset + true win-x64 diff --git a/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs b/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs index 593c98810e..2aef6aae40 100644 --- a/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs +++ b/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs @@ -59,7 +59,6 @@ namespace OpenRA.Platforms.Default Name = "ThreadedGraphicsContext RenderThread", IsBackground = true }; - renderThread.SetApartmentState(ApartmentState.STA); lock (syncObject) { // Start and wait for the rendering thread to have initialized before returning. diff --git a/OpenRA.Server/OpenRA.Server.csproj b/OpenRA.Server/OpenRA.Server.csproj index 31188b7ed7..b6385d6745 100644 --- a/OpenRA.Server/OpenRA.Server.csproj +++ b/OpenRA.Server/OpenRA.Server.csproj @@ -1,7 +1,8 @@  Exe - net472 + net5.0 + netstandard2.1 true true false diff --git a/OpenRA.Test/OpenRA.Test.csproj b/OpenRA.Test/OpenRA.Test.csproj index e5a6a2a3f2..7f793a1f63 100644 --- a/OpenRA.Test/OpenRA.Test.csproj +++ b/OpenRA.Test/OpenRA.Test.csproj @@ -1,6 +1,6 @@  - net472 + net5.0 true 7.3 true @@ -10,6 +10,7 @@ AnyCPU false ..\OpenRA.ruleset + false @@ -22,14 +23,12 @@ - False + True + - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -40,4 +39,4 @@ - \ No newline at end of file + diff --git a/OpenRA.Utility/OpenRA.Utility.csproj b/OpenRA.Utility/OpenRA.Utility.csproj index 31188b7ed7..b6385d6745 100644 --- a/OpenRA.Utility/OpenRA.Utility.csproj +++ b/OpenRA.Utility/OpenRA.Utility.csproj @@ -1,7 +1,8 @@  Exe - net472 + net5.0 + netstandard2.1 true true false diff --git a/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj b/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj index 79233e8625..a477020314 100644 --- a/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj +++ b/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj @@ -1,7 +1,9 @@  winexe - net472 + net5.0 + false + $(LauncherIcon) true true false @@ -10,14 +12,12 @@ true false ../bin - false AnyCPU false false ..\OpenRA.ruleset Release;Debug $(LauncherName) - $(LauncherIcon) diff --git a/OpenRA.sln b/OpenRA.sln index 6b732e68e2..7625a59d00 100644 --- a/OpenRA.sln +++ b/OpenRA.sln @@ -58,9 +58,7 @@ Global {FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}.Release|Any CPU.ActiveCfg = Release|Any CPU {FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}.Release|Any CPU.Build.0 = Release|Any CPU {6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Debug|Any CPU.Build.0 = Debug|Any CPU {6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6CB8E1B7-6B36-4D93-8633-7C573E194AC4}.Release|Any CPU.Build.0 = Release|Any CPU {54DAE0E0-3125-49D3-992E-A0E931EB5FC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {54DAE0E0-3125-49D3-992E-A0E931EB5FC8}.Debug|Any CPU.Build.0 = Debug|Any CPU {54DAE0E0-3125-49D3-992E-A0E931EB5FC8}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/launch-dedicated.sh b/launch-dedicated.sh index b6cfa9e974..c5931f5dd8 100755 --- a/launch-dedicated.sh +++ b/launch-dedicated.sh @@ -25,7 +25,7 @@ ShareAnonymizedIPs="${ShareAnonymizedIPs:-"True"}" SupportDir="${SupportDir:-""}" while true; do - mono --debug bin/OpenRA.Server.exe Engine.EngineDir=".." Game.Mod="$Mod" \ + mono --debug bin/OpenRA.Server.dll Engine.EngineDir=".." Game.Mod="$Mod" \ Server.Name="$Name" \ Server.ListenPort="$ListenPort" \ Server.AdvertiseOnline="$AdvertiseOnline" \ diff --git a/launch-game.sh b/launch-game.sh index 2ef5a5875b..4fbc5236c9 100755 --- a/launch-game.sh +++ b/launch-game.sh @@ -25,7 +25,7 @@ then fi # Launch the engine with the appropriate arguments -mono --debug bin/OpenRA.exe Engine.EngineDir=".." Engine.LaunchPath="$MODLAUNCHER" $MODARG "$@" +mono --debug bin/OpenRA.dll Engine.EngineDir=".." Engine.LaunchPath="$MODLAUNCHER" $MODARG "$@" # Show a crash dialog if something went wrong if [ $? != 0 ] && [ $? != 1 ]; then diff --git a/make.ps1 b/make.ps1 index a317ee2cef..c82adae69f 100644 --- a/make.ps1 +++ b/make.ps1 @@ -10,7 +10,7 @@ function All-Command return } - dotnet build /p:Configuration=Release /nologo + dotnet build -c Release --nologo -p:TargetPlatform=win-x64 if ($lastexitcode -ne 0) { Write-Host "Build failed. If just the development tools failed to build, try installing Visual Studio. You may also still be able to run the game." -ForegroundColor Red @@ -111,7 +111,7 @@ function Test-Command function Check-Command { Write-Host "Compiling in debug configuration..." -ForegroundColor Cyan - dotnet build /p:Configuration=Debug /nologo + dotnet build -c Debug --nologo -p:TargetPlatform=win-x64 if ($lastexitcode -ne 0) { Write-Host "Build failed." -ForegroundColor Red diff --git a/packaging/.itch.toml b/packaging/.itch.toml index 281a87515b..96417d4a5f 100644 --- a/packaging/.itch.toml +++ b/packaging/.itch.toml @@ -1,6 +1,3 @@ -[[prereqs]] -name = "net-4.7.2" - [[actions]] os = "windows" name = "Red Alert" diff --git a/packaging/functions.sh b/packaging/functions.sh index fb85dfdad9..2e4e04d9a0 100755 --- a/packaging/functions.sh +++ b/packaging/functions.sh @@ -18,7 +18,6 @@ # Makefile (install target for local installs and downstream packaging) # Linux AppImage packaging # macOS packaging -# Windows packaging # Mod SDK Linux AppImage packaging # Mod SDK macOS packaging # Mod SDK Windows packaging @@ -33,26 +32,27 @@ install_assemblies_mono() { echo "Building assemblies" ORIG_PWD=$(pwd) cd "${SRC_PATH}" || exit 1 - msbuild -verbosity:m -nologo -t:Clean + + rm -rf "${SRC_PATH}/OpenRA."*/obj rm -rf "${SRC_PATH:?}/bin" - msbuild -verbosity:m -nologo -t:Build -restore -p:Configuration=Release -p:TargetPlatform="${TARGETPLATFORM}" + + msbuild -verbosity:m -nologo -t:Build -restore -p:Configuration=Release -p:TargetPlatform="${TARGETPLATFORM}" -p:Mono=true -p:DefineConstants="MONO" if [ "${TARGETPLATFORM}" = "unix-generic" ]; then ./configure-system-libraries.sh fi - ./fetch-geoip.sh cd "${ORIG_PWD}" || exit 1 echo "Installing engine to ${DEST_PATH}" install -d "${DEST_PATH}" # Core engine - install -m755 "${SRC_PATH}/bin/OpenRA.Server.exe" "${DEST_PATH}" - install -m755 "${SRC_PATH}/bin/OpenRA.Utility.exe" "${DEST_PATH}" + install -m755 "${SRC_PATH}/bin/OpenRA.Server.dll" "${DEST_PATH}" + install -m755 "${SRC_PATH}/bin/OpenRA.Utility.dll" "${DEST_PATH}" install -m644 "${SRC_PATH}/bin/OpenRA.Game.dll" "${DEST_PATH}" install -m644 "${SRC_PATH}/bin/OpenRA.Platforms.Default.dll" "${DEST_PATH}" if [ "${COPY_GENERIC_LAUNCHER}" = "True" ]; then - install -m755 "${SRC_PATH}/bin/OpenRA.exe" "${DEST_PATH}" + install -m755 "${SRC_PATH}/bin/OpenRA.dll" "${DEST_PATH}" fi # Mod dlls @@ -97,6 +97,32 @@ install_assemblies_mono() { fi } +# Compile and publish the core engine and specified mod assemblies to the target directory +# Arguments: +# SRC_PATH: Path to the root OpenRA directory +# DEST_PATH: Path to the root of the install destination (will be created if necessary) +# TARGETPLATFORM: Platform type (win-x86, win-x64, osx-x64, linux-x64, unix-generic) +# COPY_GENERIC_LAUNCHER: If set to True the OpenRA.exe will also be copied (True, False) +# COPY_CNC_DLL: If set to True the OpenRA.Mods.Cnc.dll will also be copied (True, False) +# COPY_D2K_DLL: If set to True the OpenRA.Mods.D2k.dll will also be copied (True, False) +# Used by: +# Windows packaging +install_assemblies() { + SRC_PATH="${1}" + DEST_PATH="${2}" + TARGETPLATFORM="${3}" + COPY_GENERIC_LAUNCHER="${4}" + COPY_CNC_DLL="${5}" + COPY_D2K_DLL="${6}" + + ORIG_PWD=$(pwd) + cd "${SRC_PATH}" || exit 1 + + dotnet publish -c Release -p:TargetPlatform="${TARGETPLATFORM}" -p:CopyGenericLauncher="${COPY_GENERIC_LAUNCHER}" -p:CopyCncDll="${COPY_CNC_DLL}" -p:CopyD2kDll="${COPY_D2K_DLL}" -r "${TARGETPLATFORM}" -o "${DEST_PATH}" + + cd "${ORIG_PWD}" || exit 1 +} + # Copy the core engine and specified mod data to the target directory # Arguments: # SRC_PATH: Path to the root OpenRA directory @@ -115,6 +141,8 @@ install_data() { DEST_PATH="${2}" shift 2 + "${SRC_PATH}"/fetch-geoip.sh + echo "Installing engine files to ${DEST_PATH}" for FILE in VERSION AUTHORS COPYING IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP "global mix database.dat"; do install -m644 "${SRC_PATH}/${FILE}" "${DEST_PATH}" @@ -160,20 +188,15 @@ install_windows_launcher() MOD_ID="${4}" LAUNCHER_NAME="${5}" MOD_NAME="${6}" - ICON_PATH="${7}" - FAQ_URL="${8}" + FAQ_URL="${7}" - msbuild -verbosity:m -nologo -t:Clean "${SRC_PATH}/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" - rm -rf "${SRC_PATH:?}/bin" - msbuild -t:Build "${SRC_PATH}/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" -restore -p:Configuration=Release -p:TargetPlatform="${TARGETPLATFORM}" -p:LauncherName="${LAUNCHER_NAME}" -p:LauncherIcon="${ICON_PATH}" -p:ModID="${MOD_ID}" -p:DisplayName="${MOD_NAME}" -p:FaqUrl="${FAQ_URL}" - install -m755 "${SRC_PATH}/bin/${LAUNCHER_NAME}.exe" "${DEST_PATH}" - install -m644 "${SRC_PATH}/bin/${LAUNCHER_NAME}.exe.config" "${DEST_PATH}" + rm -rf "${SRC_PATH}/OpenRA.WindowsLauncher/obj" + dotnet publish "${SRC_PATH}/OpenRA.WindowsLauncher/OpenRA.WindowsLauncher.csproj" -c Release -r "${TARGETPLATFORM}" -p:LauncherName="${LAUNCHER_NAME}" -p:TargetPlatform="${TARGETPLATFORM}" -p:ModID="${MOD_ID}" -p:DisplayName="${MOD_NAME}" -p:FaqUrl="${FAQ_URL}" -o "${DEST_PATH}" - # Enable the full 4GB address space for the 32 bit game executable - # The server and utility do not use enough memory to need this - if [ "${TARGETPLATFORM}" = "win-x86" ]; then - python3 "${SRC_PATH}/packaging/windows/MakeLAA.py" "${DEST_PATH}/${LAUNCHER_NAME}.exe" - fi + # NET 5 is unable to customize the application host for windows when compiling from Linux, + # so we must patch the properties we need in the PE header. + # Setting the application icon requires an external tool, so is left to the calling code + python3 "${SRC_PATH}/packaging/windows/fixlauncher.py" "${DEST_PATH}/${LAUNCHER_NAME}.exe" } # Write a version string to the engine VERSION file diff --git a/packaging/linux/buildpackage.sh b/packaging/linux/buildpackage.sh index f0200aec9b..3a36b8c4a4 100755 --- a/packaging/linux/buildpackage.sh +++ b/packaging/linux/buildpackage.sh @@ -2,11 +2,10 @@ # OpenRA packaging script for Linux (AppImage) set -e -command -v make >/dev/null 2>&1 || { echo >&2 "Linux packaging requires make."; exit 1; } command -v tar >/dev/null 2>&1 || { echo >&2 "Linux packaging requires tar."; exit 1; } command -v curl >/dev/null 2>&1 || command -v wget > /dev/null 2>&1 || { echo >&2 "Linux packaging requires curl or wget."; exit 1; } -DEPENDENCIES_TAG="20200328" +DEPENDENCIES_TAG="20201222" if [ $# -eq "0" ]; then echo "Usage: $(basename "$0") version [outputdir]" diff --git a/packaging/linux/openra-server.appimage.in b/packaging/linux/openra-server.appimage.in index cf8f77c1ba..dc089a9b76 100755 --- a/packaging/linux/openra-server.appimage.in +++ b/packaging/linux/openra-server.appimage.in @@ -2,4 +2,4 @@ HERE="$(dirname "$(readlink -f "${0}")")" cd "${HERE}/../lib/openra" || exit 1 -mono --debug OpenRA.Server.exe Game.Mod="{MODID}" "$@" +mono --debug OpenRA.Server.dll Game.Mod="{MODID}" "$@" diff --git a/packaging/linux/openra-server.in b/packaging/linux/openra-server.in index 894afc741a..b869d2a478 100755 --- a/packaging/linux/openra-server.in +++ b/packaging/linux/openra-server.in @@ -1,4 +1,4 @@ #!/bin/sh cd "{GAME_INSTALL_DIR}" -mono {DEBUG} OpenRA.Server.exe Game.Mod={MODID} "$@" +mono {DEBUG} OpenRA.Server.dll Game.Mod={MODID} "$@" diff --git a/packaging/linux/openra-utility.appimage.in b/packaging/linux/openra-utility.appimage.in index 3c96c1bc6b..cf123fd748 100755 --- a/packaging/linux/openra-utility.appimage.in +++ b/packaging/linux/openra-utility.appimage.in @@ -2,4 +2,4 @@ # OpenRA.Utility relies on keeping the original working directory, so don't change directory HERE="$(dirname "$(readlink -f "${0}")")" -mono --debug "${HERE}/../lib/openra/OpenRA.Utility.exe" {MODID} "$@" +mono --debug "${HERE}/../lib/openra/OpenRA.Utility.dll" {MODID} "$@" diff --git a/packaging/linux/openra.appimage.in b/packaging/linux/openra.appimage.in index 7a85988005..130517270a 100755 --- a/packaging/linux/openra.appimage.in +++ b/packaging/linux/openra.appimage.in @@ -35,7 +35,7 @@ fi # Run the game export SDL_VIDEO_X11_WMCLASS="openra-{MODID}-{TAG}" -mono --debug OpenRA.exe Game.Mod={MODID} Engine.LaunchPath="${LAUNCHER}" Engine.LaunchWrapper="${HERE}/restore-environment.sh" "${JOIN_SERVER}" "$@" +mono --debug OpenRA.dll Game.Mod={MODID} Engine.LaunchPath="${LAUNCHER}" Engine.LaunchWrapper="${HERE}/restore-environment.sh" "${JOIN_SERVER}" "$@" # Show a crash dialog if something went wrong if [ $? != 0 ] && [ $? != 1 ]; then diff --git a/packaging/linux/openra.in b/packaging/linux/openra.in index 63c27bc047..85bcec0ca0 100755 --- a/packaging/linux/openra.in +++ b/packaging/linux/openra.in @@ -9,7 +9,7 @@ if [ "${1#${PROTOCOL_PREFIX}}" != "${1}" ]; then fi # Run the game -mono {DEBUG} OpenRA.exe Game.Mod={MODID} Engine.LaunchPath="{BIN_DIR}/openra-{MODID}" "${JOIN_SERVER}" "$@" +mono {DEBUG} OpenRA.dll Game.Mod={MODID} Engine.LaunchPath="{BIN_DIR}/openra-{MODID}" "${JOIN_SERVER}" "$@" # Show a crash dialog if something went wrong if [ $? != 0 ] && [ $? != 1 ]; then diff --git a/packaging/macos/buildpackage.sh b/packaging/macos/buildpackage.sh index 35838ff2c6..b606721def 100755 --- a/packaging/macos/buildpackage.sh +++ b/packaging/macos/buildpackage.sh @@ -15,7 +15,7 @@ # set -e -MONO_TAG="osx-launcher-20200830" +MONO_TAG="osx-launcher-20201222" if [ $# -ne "2" ]; then echo "Usage: $(basename "$0") tag outputdir" diff --git a/packaging/macos/launcher-mono.m b/packaging/macos/launcher-mono.m index e2d803d3a8..d726c4989a 100644 --- a/packaging/macos/launcher-mono.m +++ b/packaging/macos/launcher-mono.m @@ -238,7 +238,7 @@ static int check_mono_version(const char *version, const char *req_version) [self exitWithMonoPrompt]; // Default values - can be overriden by setting certain keys Info.plist - NSString *gameName = @"OpenRA.exe"; + NSString *gameName = @"OpenRA.dll"; NSString *modId = nil; NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; diff --git a/packaging/macos/launcher.m b/packaging/macos/launcher.m index ef9a9a403c..95153a9d31 100644 --- a/packaging/macos/launcher.m +++ b/packaging/macos/launcher.m @@ -131,7 +131,7 @@ NSTask *gameTask; launched = YES; // Default values - can be overriden by setting certain keys Info.plist - NSString *gameName = @"OpenRA.exe"; + NSString *gameName = @"OpenRA.dll"; NSString *modId = nil; NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; diff --git a/packaging/windows/OpenRA.nsi b/packaging/windows/OpenRA.nsi index 60fc213237..c47055216c 100644 --- a/packaging/windows/OpenRA.nsi +++ b/packaging/windows/OpenRA.nsi @@ -129,14 +129,16 @@ Section "Game" GAME SetOutPath "$INSTDIR" File "${SRCDIR}\*.exe" - File "${SRCDIR}\*.exe.config" + File "${SRCDIR}\*.dll.config" File "${SRCDIR}\*.dll" File "${SRCDIR}\*.ico" + File "${SRCDIR}\*.deps.json" + File "${SRCDIR}\*.runtimeconfig.json" + File "${SRCDIR}\global mix database.dat" + File "${SRCDIR}\IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP" File "${SRCDIR}\VERSION" File "${SRCDIR}\AUTHORS" File "${SRCDIR}\COPYING" - File "${SRCDIR}\global mix database.dat" - File "${SRCDIR}\IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP" !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory "$SMPROGRAMS\$StartMenuFolder" @@ -162,6 +164,7 @@ Section "Game" GAME SetShellVarContext all CreateDirectory "$APPDATA\OpenRA\ModMetadata" + SetOutPath "$INSTDIR" nsExec::ExecToLog '"$INSTDIR\OpenRA.Utility.exe" ra --register-mod "$INSTDIR\RedAlert.exe" system' nsExec::ExecToLog '"$INSTDIR\OpenRA.Utility.exe" ra --clear-invalid-mod-registrations system' nsExec::ExecToLog '"$INSTDIR\OpenRA.Utility.exe" cnc --register-mod "$INSTDIR\TiberianDawn.exe" system' @@ -182,21 +185,6 @@ Section "Desktop Shortcut" DESKTOPSHORTCUT "$INSTDIR\Dune2000.exe" "" "" "" "" SectionEnd -;*************************** -;Dependency Sections -;*************************** -Section "-DotNet" DotNet - ClearErrors - ; https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed - ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" "Release" - IfErrors error 0 - IntCmp $0 461808 done error done - error: - MessageBox MB_OK ".NET Framework v4.7.2 or later is required to run OpenRA." - Abort - done: -SectionEnd - ;*************************** ;Uninstaller Sections ;*************************** @@ -225,14 +213,17 @@ Function ${UN}Clean RMDir /r $INSTDIR\glsl RMDir /r $INSTDIR\lua Delete $INSTDIR\*.exe - Delete $INSTDIR\*.exe.config Delete $INSTDIR\*.dll Delete $INSTDIR\*.ico + Delete $INSTDIR\*.dll.config + Delete $INSTDIR\*.deps.json + Delete $INSTDIR\*.runtimeconfig.json Delete $INSTDIR\VERSION Delete $INSTDIR\AUTHORS Delete $INSTDIR\COPYING Delete "$INSTDIR\global mix database.dat" Delete $INSTDIR\IP2LOCATION-LITE-DB1.IPV6.BIN.ZIP + RMDir /r $INSTDIR\Support DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenRA${SUFFIX}" diff --git a/packaging/windows/buildpackage.sh b/packaging/windows/buildpackage.sh index 794ce236ff..1ed137c9d4 100755 --- a/packaging/windows/buildpackage.sh +++ b/packaging/windows/buildpackage.sh @@ -32,6 +32,12 @@ elif [[ ${TAG} == playtest* ]]; then SUFFIX=" (playtest)" fi +if command -v curl >/dev/null 2>&1; then + curl -s -L -O https://github.com/electron/rcedit/releases/download/v1.1.1/rcedit-x64.exe || exit 3 +else + wget -cq https://github.com/electron/rcedit/releases/download/v1.1.1/rcedit-x64.exe || exit 3 +fi + function makelauncher() { LAUNCHER_NAME="${1}" @@ -40,7 +46,9 @@ function makelauncher() PLATFORM="${4}" convert "${ARTWORK_DIR}/${MOD_ID}_16x16.png" "${ARTWORK_DIR}/${MOD_ID}_24x24.png" "${ARTWORK_DIR}/${MOD_ID}_32x32.png" "${ARTWORK_DIR}/${MOD_ID}_48x48.png" "${ARTWORK_DIR}/${MOD_ID}_256x256.png" "${BUILTDIR}/${MOD_ID}.ico" - install_windows_launcher "${SRCDIR}" "${BUILTDIR}" "win-${PLATFORM}" "${MOD_ID}" "${LAUNCHER_NAME}" "${DISPLAY_NAME}" "${BUILTDIR}/${MOD_ID}.ico" "${FAQ_URL}" + install_windows_launcher "${SRCDIR}" "${BUILTDIR}" "win-${PLATFORM}" "${MOD_ID}" "${LAUNCHER_NAME}" "${DISPLAY_NAME}" "${FAQ_URL}" + + wine64 rcedit-x64.exe "${BUILTDIR}/${LAUNCHER_NAME}.exe" --set-icon "${BUILTDIR}/${MOD_ID}.ico" } function build_platform() @@ -54,7 +62,7 @@ function build_platform() USE_PROGRAMFILES32="" fi - install_assemblies_mono "${SRCDIR}" "${BUILTDIR}" "win-${PLATFORM}" "False" "True" "True" + install_assemblies "${SRCDIR}" "${BUILTDIR}" "win-${PLATFORM}" "False" "True" "True" install_data "${SRCDIR}" "${BUILTDIR}" "cnc" "d2k" "ra" set_engine_version "${TAG}" "${BUILTDIR}" set_mod_version "${TAG}" "${BUILTDIR}/mods/cnc/mod.yaml" "${BUILTDIR}/mods/d2k/mod.yaml" "${BUILTDIR}/mods/ra/mod.yaml" "${BUILTDIR}/mods/modcontent/mod.yaml" diff --git a/packaging/windows/MakeLAA.py b/packaging/windows/fixlauncher.py similarity index 59% rename from packaging/windows/MakeLAA.py rename to packaging/windows/fixlauncher.py index c66f81fd2e..d42a1e3662 100644 --- a/packaging/windows/MakeLAA.py +++ b/packaging/windows/fixlauncher.py @@ -9,11 +9,21 @@ import struct import sys if __name__ == "__main__": - print(sys.argv[1] + ': Enabling /LARGEADDRESSAWARE') + print('Patching ' + sys.argv[1] + ':') with open(sys.argv[1], 'r+b') as assembly: assembly.seek(0x3c) - peOffset = struct.unpack('i', assembly.read(4))[0] + peOffset = struct.unpack('H', assembly.read(2))[0] + + assembly.seek(peOffset) + peSignature = struct.unpack('I', assembly.read(4))[0] + if peSignature != 0x4550: + print(" ERROR: Invalid PE signature") + + print(' - Setting /LARGEADDRESSAWARE') assembly.seek(peOffset + 4 + 18) flags = struct.unpack('B', assembly.read(1))[0] | 0x20 assembly.seek(peOffset + 4 + 18) assembly.write(struct.pack('B', flags)) + print(' - Setting /subsystem:windows') + assembly.seek(peOffset + 0x5C) + assembly.write(struct.pack("H", 0x02)) diff --git a/utility.sh b/utility.sh index 0a2abab63f..49f378a472 100755 --- a/utility.sh +++ b/utility.sh @@ -1,2 +1,2 @@ #!/bin/sh -ENGINE_DIR=.. mono --debug bin/OpenRA.Utility.exe $@ +ENGINE_DIR=.. mono --debug bin/OpenRA.Utility.dll $@