├── .github └── FUNDING.yml ├── .gitignore ├── Banner.png ├── GameBundle.sln ├── GameBundle ├── .config │ └── dotnet-tools.json ├── GameBundle.csproj ├── Options.cs └── Program.cs ├── LICENSE ├── Logo.png ├── README.md └── Test ├── Bundle.bat ├── Content ├── Content.mgcb └── Textures │ ├── Anim.png │ ├── AutoTiling.png │ ├── Test.png │ └── Tree.png ├── GameImpl.cs ├── Program.cs ├── Test.csproj └── macmain.txt /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: Ellpeck 2 | ko_fi: Ellpeck 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | bin 3 | obj 4 | packages 5 | *.user -------------------------------------------------------------------------------- /Banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/GameBundle/00bff9817bb6fb3b238e7e12f727217bcf332fca/Banner.png -------------------------------------------------------------------------------- /GameBundle.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameBundle", "GameBundle\GameBundle.csproj", "{18B83BC9-B35C-4E04-AA1C-85057CB2B6BB}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{6FD8768A-7F59-4815-BF41-33DA9ACDB81A}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {18B83BC9-B35C-4E04-AA1C-85057CB2B6BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {18B83BC9-B35C-4E04-AA1C-85057CB2B6BB}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {18B83BC9-B35C-4E04-AA1C-85057CB2B6BB}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {18B83BC9-B35C-4E04-AA1C-85057CB2B6BB}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {6FD8768A-7F59-4815-BF41-33DA9ACDB81A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {6FD8768A-7F59-4815-BF41-33DA9ACDB81A}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {6FD8768A-7F59-4815-BF41-33DA9ACDB81A}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {6FD8768A-7F59-4815-BF41-33DA9ACDB81A}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /GameBundle/.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "nulastudio.ncbeauty": { 6 | "version": "1.2.9.5", 7 | "commands": [ 8 | "ncbeauty" 9 | ] 10 | }, 11 | "nulastudio.nbeauty": { 12 | "version": "2.1.5.0", 13 | "commands": [ 14 | "nbeauty2" 15 | ] 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /GameBundle/GameBundle.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | Major 7 | 8 | Ellpeck 9 | A tool to package MonoGame and other .NET applications into several distributable formats 10 | windows linux mac bundler build monogame build-tool release-automation mono xna netcore dotnet publish bundle tool 11 | https://github.com/Ellpeck/GameBundle 12 | https://github.com/Ellpeck/GameBundle 13 | MIT 14 | README.md 15 | Logo.png 16 | true 17 | gamebundle 18 | 1.8.0 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | PreserveNewest 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /GameBundle/Options.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using CommandLine; 4 | using CommandLine.Text; 5 | 6 | namespace GameBundle; 7 | 8 | public class Options { 9 | 10 | [Option('s', "source", HelpText = "The location of the .csproj file that should be built and bundled. By default, the current directory is scanned for one")] 11 | public string SourceFile { get; set; } 12 | [Option('o', "output", Default = "bin/Bundled", HelpText = "The location of the directory that the bundles should be stored in")] 13 | public string OutputDirectory { get; set; } 14 | [Option('v', "verbose", HelpText = "Display verbose output while building")] 15 | public bool Verbose { get; set; } 16 | 17 | [Option('w', "win", HelpText = "Bundle for windows")] 18 | public bool BuildWindows { get; set; } 19 | [Option('l', "linux", HelpText = "Bundle for linux")] 20 | public bool BuildLinux { get; set; } 21 | [Option('m', "mac", HelpText = "Bundle for mac")] 22 | public bool BuildMac { get; set; } 23 | [Option("win-rid", Default = "win-x64", HelpText = "The RID to use for windows builds")] 24 | public string WindowsRid { get; set; } 25 | [Option("linux-rid", Default = "linux-x64", HelpText = "The RID to use for linux builds")] 26 | public string LinuxRid { get; set; } 27 | [Option("mac-rid", Default = "osx-x64", HelpText = "The RID to use for mac builds")] 28 | public string MacRid { get; set; } 29 | 30 | [Option('W', "win-arm", HelpText = "Bundle for windows arm")] 31 | public bool BuildWindowsArm { get; set; } 32 | [Option('L', "linux-arm", HelpText = "Bundle for linux arm")] 33 | public bool BuildLinuxArm { get; set; } 34 | [Option('M', "mac-arm", HelpText = "Bundle for mac arm")] 35 | public bool BuildMacArm { get; set; } 36 | [Option("win-arm-rid", Default = "win-arm64", HelpText = "The RID to use for windows arm builds")] 37 | public string WindowsArmRid { get; set; } 38 | [Option("linux-arm-rid", Default = "linux-arm64", HelpText = "The RID to use for linux arm builds")] 39 | public string LinuxArmRid { get; set; } 40 | [Option("mac-arm-rid", Default = "osx-arm64", HelpText = "The RID to use for mac arm builds")] 41 | public string MacArmRid { get; set; } 42 | 43 | [Option('z', "zip", HelpText = "Store the build results in zip files instead of folders")] 44 | public bool Zip { get; set; } 45 | [Option('b', "mac-bundle", HelpText = "Create an app bundle for mac")] 46 | public bool MacBundle { get; set; } 47 | [Option("mac-bundle-resources", Default = new[] {"Content", "*.icns"}, HelpText = "When creating an app bundle for mac, things that should go into the Resources folder rather than the MacOS folder")] 48 | public IEnumerable MacBundleResources { get; set; } 49 | [Option("mac-bundle-ignore", HelpText = "When creating an app bundle for mac, things that should be left out of the mac bundle and stay in the output folder")] 50 | public IEnumerable MacBundleIgnore { get; set; } 51 | 52 | [Option("nbeauty2", HelpText = "Use NetBeauty2 for beautifying instead of NetCoreBeauty")] 53 | public bool NBeauty2 { get; set; } 54 | [Option("skip-lib", HelpText = "When bundling, skip beautifying the output by moving files to the library folder")] 55 | public bool SkipLib { get; set; } 56 | [Option('e', "exclude", HelpText = "Files that should not be moved to the library folder")] 57 | public IEnumerable ExcludedFiles { get; set; } 58 | [Option("mg", HelpText = $"Exclude MonoGame's native libraries from being moved to the library folder, which is a requirement for DesktopGL version 3.8.2.1105 or later.\nThis has the same behavior as supplying the --exclude arguments {Program.MonoGameExclusions}")] 59 | public bool MonoGameExclusions { get; set; } 60 | [Option("lib-name", Default = "Lib", HelpText = "The name of the library folder that is created")] 61 | public string LibFolder { get; set; } 62 | 63 | [Option('t', "trim", HelpText = "Trim the application when publishing")] 64 | public bool Trim { get; set; } 65 | [Option('A', "aot", HelpText = "Use NativeAOT compilation mode")] 66 | public bool Aot { get; set; } 67 | [Option('c', "config", Default = "Release", HelpText = "The build configuration to use")] 68 | public string BuildConfig { get; set; } 69 | [Option('a', "build-args", HelpText = "Additional arguments that should be passed to the dotnet publish command")] 70 | public string BuildArgs { get; set; } 71 | [Option('n', "name-builds", HelpText = "Name the build output directories by the name of the executable")] 72 | public bool NameBuilds { get; set; } 73 | [Option('N', "name-addition", HelpText = "An additional string of text that should be included in the names of the output directories")] 74 | public string NameAddition { get; set; } 75 | [Option('V', "include-version", HelpText = "Include the project's version in the names of the output directories")] 76 | public bool IncludeVersion { get; set; } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /GameBundle/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.IO.Compression; 6 | using System.IO.Enumeration; 7 | using System.Linq; 8 | using CommandLine; 9 | 10 | namespace GameBundle; 11 | 12 | internal static class Program { 13 | 14 | public const string MonoGameExclusions = 15 | "soft_oal.dll, openal.dll, SDL2.dll, " + // win 16 | "libopenal.so.1, libopenal.so, libSDL2-2.0.so.0, " + // linux 17 | "libopenal.1.dylib, libopenal.dylib, libSDL2.dylib, libSDL2-2.0.0.dylib"; // mac 18 | 19 | private static int Main(string[] args) { 20 | return new Parser(c => { 21 | c.HelpWriter = Console.Error; 22 | c.EnableDashDash = true; 23 | }).ParseArguments(args).MapResult(Program.Run, _ => -1); 24 | } 25 | 26 | private static int Run(Options options) { 27 | // make sure all of the required tools are installed 28 | if (Program.RunProcess(options, "dotnet", "tool restore", AppDomain.CurrentDomain.BaseDirectory) != 0) { 29 | Console.WriteLine("dotnet tool restore failed, aborting"); 30 | return -1; 31 | } 32 | 33 | var proj = Program.GetProjectFile(options); 34 | if (proj == null || !proj.Exists) { 35 | Console.WriteLine("Project file not found, aborting"); 36 | return -1; 37 | } 38 | Console.WriteLine($"Bundling project {proj.FullName}"); 39 | 40 | var builtAnything = false; 41 | var toBuild = new List { 42 | // regular builds 43 | new("windows", "win", options.WindowsRid, options.BuildWindows), 44 | new("linux", "linux", options.LinuxRid, options.BuildLinux), 45 | new("mac", "mac", options.MacRid, options.BuildMac, false, d => options.MacBundle ? Program.CreateMacBundle(options, d) : 0), 46 | // arm builds 47 | new("windows arm", "win-arm", options.WindowsArmRid, options.BuildWindowsArm, true), 48 | new("linux arm", "linux-arm", options.LinuxArmRid, options.BuildLinuxArm, true), 49 | new("mac arm", "mac-arm", options.MacArmRid, options.BuildMacArm, true, d => options.MacBundle ? Program.CreateMacBundle(options, d) : 0) 50 | }; 51 | foreach (var config in toBuild) { 52 | if (config.ShouldBuild) { 53 | Console.WriteLine($"Bundling for {config.DisplayName}"); 54 | var res = Program.Publish(options, proj, config); 55 | if (res != 0) 56 | return res; 57 | builtAnything = true; 58 | } 59 | } 60 | if (!builtAnything) 61 | Console.WriteLine("No build took place. Supply -w, -l or -m arguments or see available arguments using --help."); 62 | 63 | Console.WriteLine("Done"); 64 | return 0; 65 | } 66 | 67 | private static int Publish(Options options, FileInfo proj, BuildConfig config) { 68 | var buildDir = Program.GetBuildDir(options, config.DirectoryName); 69 | var publishResult = Program.RunProcess(options, "dotnet", string.Join(' ', 70 | $"publish \"{proj.FullName}\"", 71 | $"-o \"{buildDir.FullName}\"", 72 | $"-r {config.Rid}", 73 | "--self-contained", 74 | $"-c {options.BuildConfig}", 75 | $"/p:PublishTrimmed={options.Trim || options.Aot}", 76 | $"/p:PublishAot={options.Aot}", 77 | $"{options.BuildArgs}")); 78 | if (publishResult != 0) 79 | return publishResult; 80 | 81 | // Run beauty 82 | if (!options.SkipLib && !config.SkipLib && !options.Aot) { 83 | var exclude = options.ExcludedFiles.ToList(); 84 | if (options.MonoGameExclusions) 85 | exclude.AddRange(Program.MonoGameExclusions.Split(',').Select(s => s.Trim())); 86 | var excludeString = exclude.Count > 0 ? $"\"{string.Join(";", exclude)}\"" : ""; 87 | var log = options.Verbose ? "Detail" : "Error"; 88 | var baseCommand = options.NBeauty2 ? "nbeauty2" : "ncbeauty --force=True --noflag=True"; 89 | var beautyResult = Program.RunProcess(options, "dotnet", $"{baseCommand} --loglevel={log} \"{buildDir.FullName}\" \"{options.LibFolder}\" {excludeString}", AppDomain.CurrentDomain.BaseDirectory); 90 | if (beautyResult != 0) { 91 | Console.WriteLine("NetBeauty failed, likely because the artifact for the specified RID does not exist. See https://github.com/nulastudio/NetBeauty2/discussions/36 for more information, and run GameBundle with the --verbose option to see more details."); 92 | return beautyResult; 93 | } 94 | } 95 | 96 | // Add version if named builds are enabled 97 | if (options.IncludeVersion) { 98 | var version = Program.GetBuildVersion(buildDir); 99 | if (version == null) { 100 | Console.WriteLine("Couldn't determine build version, aborting"); 101 | return -1; 102 | } 103 | var dest = Path.Combine(buildDir.Parent.FullName, $"{version}-{buildDir.Name}"); 104 | Program.MoveDirectory(options, buildDir, dest); 105 | } 106 | 107 | // Rename build folder if named builds are enabled 108 | if (options.NameBuilds) { 109 | var name = Program.GetBuildName(buildDir); 110 | if (name == null) { 111 | Console.WriteLine("Couldn't determine build name, aborting"); 112 | return -1; 113 | } 114 | var dest = Path.Combine(buildDir.Parent.FullName, $"{name}-{buildDir.Name}"); 115 | Program.MoveDirectory(options, buildDir, dest); 116 | } 117 | 118 | // Run any additional actions like creating the mac bundle 119 | if (config.AdditionalAction != null) { 120 | var result = config.AdditionalAction.Invoke(buildDir); 121 | if (result != 0) 122 | return result; 123 | } 124 | 125 | // Zip the output if required 126 | if (options.Zip) { 127 | var zipLocation = Path.Combine(buildDir.Parent.FullName, $"{buildDir.Name}.zip"); 128 | if (File.Exists(zipLocation)) 129 | File.Delete(zipLocation); 130 | ZipFile.CreateFromDirectory(buildDir.FullName, zipLocation, CompressionLevel.Optimal, true); 131 | buildDir.Delete(true); 132 | if (options.Verbose) 133 | Console.WriteLine($"Zipped build to {zipLocation}"); 134 | } 135 | return 0; 136 | } 137 | 138 | private static int RunProcess(Options options, string program, string args, string workingDir = "") { 139 | if (options.Verbose) 140 | Console.WriteLine($"> {program} {args}"); 141 | var info = new ProcessStartInfo(program, args) {WorkingDirectory = workingDir}; 142 | if (!options.Verbose) 143 | info.CreateNoWindow = true; 144 | var process = Process.Start(info); 145 | process.WaitForExit(); 146 | if (options.Verbose) 147 | Console.WriteLine($"{program} finished with exit code {process.ExitCode}"); 148 | return process.ExitCode; 149 | } 150 | 151 | private static FileInfo GetProjectFile(Options options) { 152 | if (!string.IsNullOrEmpty(options.SourceFile)) 153 | return new FileInfo(options.SourceFile); 154 | var dir = new DirectoryInfo("."); 155 | foreach (var file in dir.EnumerateFiles()) { 156 | if (Path.GetExtension(file.FullName).Contains("proj")) 157 | return file; 158 | } 159 | return null; 160 | } 161 | 162 | private static int CreateMacBundle(Options options, DirectoryInfo buildDir) { 163 | var buildName = Program.GetBuildName(buildDir); 164 | var app = buildDir.CreateSubdirectory($"{buildName}.app"); 165 | var contents = app.CreateSubdirectory("Contents"); 166 | var resources = contents.CreateSubdirectory("Resources"); 167 | var macOs = contents.CreateSubdirectory("MacOS"); 168 | 169 | if (options.Verbose) 170 | Console.WriteLine($"Creating app bundle {app}"); 171 | 172 | foreach (var file in buildDir.GetFiles()) { 173 | if (options.MacBundleIgnore.Any(g => FileSystemName.MatchesSimpleExpression(g, file.Name))) 174 | continue; 175 | var destDir = options.MacBundleResources.Any(g => FileSystemName.MatchesSimpleExpression(g, file.Name)) ? resources : macOs; 176 | if (file.Name.EndsWith("plist") || file.Name == "PkgInfo") 177 | destDir = contents; 178 | file.MoveTo(Path.Combine(destDir.FullName, file.Name), true); 179 | } 180 | foreach (var sub in buildDir.GetDirectories()) { 181 | if (sub.Name == app.Name || options.MacBundleIgnore.Any(g => FileSystemName.MatchesSimpleExpression(g, sub.Name))) 182 | continue; 183 | var destDir = options.MacBundleResources.Any(g => FileSystemName.MatchesSimpleExpression(g, sub.Name)) ? resources : macOs; 184 | var dest = new DirectoryInfo(Path.Combine(destDir.FullName, sub.Name)); 185 | if (dest.Exists) 186 | dest.Delete(true); 187 | sub.MoveTo(dest.FullName); 188 | } 189 | 190 | var info = Path.Combine(contents.FullName, "PkgInfo"); 191 | if (!File.Exists(info)) { 192 | File.WriteAllText(info, "APPL????"); 193 | if (options.Verbose) 194 | Console.WriteLine($"Creating package info at {info}"); 195 | } 196 | 197 | return 0; 198 | } 199 | 200 | private static DirectoryInfo GetBuildDir(Options options, string name) { 201 | if (options.NameAddition != null) 202 | name = $"{options.NameAddition}-{name}"; 203 | return new DirectoryInfo(Path.Combine(Path.GetFullPath(options.OutputDirectory), name)); 204 | } 205 | 206 | private static string GetBuildName(DirectoryInfo buildDir) { 207 | return Path.GetFileNameWithoutExtension(Program.GetAssemblyFile(buildDir)?.Name); 208 | } 209 | 210 | private static string GetBuildVersion(DirectoryInfo buildDir) { 211 | var assemblyFile = Program.GetAssemblyFile(buildDir); 212 | if (assemblyFile == null) 213 | return null; 214 | var version = FileVersionInfo.GetVersionInfo(assemblyFile.FullName); 215 | return version.ProductVersion; 216 | } 217 | 218 | private static FileInfo GetAssemblyFile(DirectoryInfo buildDir) { 219 | var files = buildDir.GetFiles(); 220 | 221 | foreach (var file in files) { 222 | if (file.Extension != ".dll") 223 | continue; 224 | // the assembly is (most likely) the dll file that has a matching binary or exe file in the same location 225 | if (files.Any(f => f.Extension is ".exe" or "" && Path.GetFileNameWithoutExtension(f.Name) == Path.GetFileNameWithoutExtension(file.Name))) 226 | return file; 227 | } 228 | 229 | // if we didn't find a file, try to see if there is a single exe in the directory (which will be the case with AOT builds) 230 | var exes = files.Where(f => f.Extension is ".exe" or "").ToArray(); 231 | if (exes.Length == 1) 232 | return exes[0]; 233 | 234 | return null; 235 | } 236 | 237 | private static void MoveDirectory(Options options, DirectoryInfo dir, string dest) { 238 | if (Directory.Exists(dest)) 239 | Directory.Delete(dest, true); 240 | dir.MoveTo(dest!); 241 | if (options.Verbose) 242 | Console.WriteLine($"Moved build directory to {dir.FullName}"); 243 | } 244 | 245 | private readonly struct BuildConfig { 246 | 247 | public readonly string DisplayName; 248 | public readonly string DirectoryName; 249 | public readonly string Rid; 250 | public readonly bool ShouldBuild; 251 | public readonly bool SkipLib; 252 | public readonly Func AdditionalAction; 253 | 254 | public BuildConfig(string displayName, string directoryName, string rid, bool shouldBuild, bool skipLib = false, Func additionalAction = null) { 255 | this.DisplayName = displayName; 256 | this.DirectoryName = directoryName; 257 | this.Rid = rid; 258 | this.ShouldBuild = shouldBuild; 259 | this.SkipLib = skipLib; 260 | this.AdditionalAction = additionalAction; 261 | } 262 | 263 | } 264 | 265 | } 266 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ellpeck 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/GameBundle/00bff9817bb6fb3b238e7e12f727217bcf332fca/Logo.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![The GameBundle logo](https://raw.githubusercontent.com/Ellpeck/GameBundle/main/Banner.png) 2 | 3 | **GameBundle** is a tool to package MonoGame and other .NET applications into several distributable formats. 4 | 5 | # Installing 6 | GameBundle is a `dotnet` tool, meaning you can install it very easily like so: 7 | ``` 8 | dotnet tool install --global GameBundle 9 | ``` 10 | 11 | # Using 12 | By default, GameBundle builds the `.csproj` file that it finds in the directory that it is run from. The bundled outputs go into `bin/Bundled` by default. 13 | 14 | To build and bundle your app for Windows, Linux and Mac, all you have to do is run the following command from the directory that contains your project file: 15 | ``` 16 | gamebundle -wlm 17 | ``` 18 | 19 | GameBundle will then build a self-contained release of your application for each system using `dotnet publish` and clean up the output directory using [NetBeauty](https://github.com/nulastudio/NetBeauty2) by moving most of the libraries into a `Lib` subdirectory. 20 | 21 | ## Building a MonoGame Project 22 | If you're building a MonoGame project using MonoGame's DesktopGL version 3.8.2.1105 or later, you can additionally supply the `--mg` argument to automatically exclude MonoGame's native libraries from being moved into the `Lib` subdirectory, which is a requirement for your game to run. 23 | 24 | # Configuring 25 | GameBundle takes several optional arguments to modify the way it works. To see a list of all possible arguments, simply run 26 | ``` 27 | gamebundle --help 28 | ``` 29 | 30 | Here is a list of them as of GameBundle version 1.8.0: 31 | ``` 32 | -s, --source The location of the .csproj file that should be built and bundled. By default, the current directory is scanned for one 33 | 34 | -o, --output (Default: bin/Bundled) The location of the directory that the bundles should be stored in 35 | 36 | -v, --verbose Display verbose output while building 37 | 38 | -w, --win Bundle for windows 39 | 40 | -l, --linux Bundle for linux 41 | 42 | -m, --mac Bundle for mac 43 | 44 | --win-rid (Default: win-x64) The RID to use for windows builds 45 | 46 | --linux-rid (Default: linux-x64) The RID to use for linux builds 47 | 48 | --mac-rid (Default: osx-x64) The RID to use for mac builds 49 | 50 | -W, --win-arm Bundle for windows arm 51 | 52 | -L, --linux-arm Bundle for linux arm 53 | 54 | -M, --mac-arm Bundle for mac arm 55 | 56 | --win-arm-rid (Default: win-arm64) The RID to use for windows arm builds 57 | 58 | --linux-arm-rid (Default: linux-arm64) The RID to use for linux arm builds 59 | 60 | --mac-arm-rid (Default: osx-arm64) The RID to use for mac arm builds 61 | 62 | -z, --zip Store the build results in zip files instead of folders 63 | 64 | -b, --mac-bundle Create an app bundle for mac 65 | 66 | --mac-bundle-resources (Default: Content *.icns) When creating an app bundle for mac, things that should go into the Resources folder rather than the MacOS folder 67 | 68 | --mac-bundle-ignore When creating an app bundle for mac, things that should be left out of the mac bundle and stay in the output folder 69 | 70 | --nbeauty2 Use NetBeauty2 for beautifying instead of NetCoreBeauty 71 | 72 | --skip-lib When bundling, skip beautifying the output by moving files to the library folder 73 | 74 | -e, --exclude Files that should not be moved to the library folder 75 | 76 | --mg Exclude MonoGame's native libraries from being moved to the library folder, which is a requirement for DesktopGL version 3.8.2.1105 or later. 77 | This has the same behavior as supplying the --exclude arguments soft_oal.dll, openal.dll, SDL2.dll, libopenal.so.1, libopenal.so, libSDL2-2.0.so.0, libopenal.1.dylib, 78 | libopenal.dylib, libSDL2.dylib, libSDL2-2.0.0.dylib 79 | 80 | --lib-name (Default: Lib) The name of the library folder that is created 81 | 82 | -t, --trim Trim the application when publishing 83 | 84 | -A, --aot Use NativeAOT compilation mode 85 | 86 | -c, --config (Default: Release) The build configuration to use 87 | 88 | -a, --build-args Additional arguments that should be passed to the dotnet publish command 89 | 90 | -n, --name-builds Name the build output directories by the name of the executable 91 | 92 | -N, --name-addition An additional string of text that should be included in the names of the output directories 93 | 94 | -V, --include-version Include the project's version in the names of the output directories 95 | 96 | --help Display this help screen. 97 | 98 | --version Display version information. 99 | ``` 100 | -------------------------------------------------------------------------------- /Test/Bundle.bat: -------------------------------------------------------------------------------- 1 | dotnet build ../GameBundle/GameBundle.csproj 2 | rmdir /S /Q "bin/Bundled" 3 | "../GameBundle/bin/Debug/net8.0/GameBundle.exe" -wlmWL -bnV --mg -s Test.csproj -o bin/Bundled -v --mac-bundle-ignore macmain.txt -N ncbeauty 4 | "../GameBundle/bin/Debug/net8.0/GameBundle.exe" -wlmWL -bnV --mg -s Test.csproj -o bin/Bundled -v --mac-bundle-ignore macmain.txt -N nbeauty2 --nbeauty2 5 | -------------------------------------------------------------------------------- /Test/Content/Content.mgcb: -------------------------------------------------------------------------------- 1 | 2 | #----------------------------- Global Properties ----------------------------# 3 | 4 | /outputDir:bin 5 | /intermediateDir:obj 6 | /platform:DesktopGL 7 | /config: 8 | /profile:Reach 9 | /compress:False 10 | 11 | #-------------------------------- References --------------------------------# 12 | 13 | 14 | #---------------------------------- Content ---------------------------------# 15 | 16 | #begin Textures/Anim.png 17 | /importer:TextureImporter 18 | /processor:TextureProcessor 19 | /processorParam:ColorKeyColor=255,0,255,255 20 | /processorParam:ColorKeyEnabled=True 21 | /processorParam:GenerateMipmaps=False 22 | /processorParam:PremultiplyAlpha=True 23 | /processorParam:ResizeToPowerOfTwo=False 24 | /processorParam:MakeSquare=False 25 | /processorParam:TextureFormat=Color 26 | /build:Textures/Anim.png 27 | 28 | #begin Textures/AutoTiling.png 29 | /importer:TextureImporter 30 | /processor:TextureProcessor 31 | /processorParam:ColorKeyColor=255,0,255,255 32 | /processorParam:ColorKeyEnabled=True 33 | /processorParam:GenerateMipmaps=False 34 | /processorParam:PremultiplyAlpha=True 35 | /processorParam:ResizeToPowerOfTwo=False 36 | /processorParam:MakeSquare=False 37 | /processorParam:TextureFormat=Color 38 | /build:Textures/AutoTiling.png 39 | 40 | #begin Textures/Test.png 41 | /importer:TextureImporter 42 | /processor:TextureProcessor 43 | /processorParam:ColorKeyColor=255,0,255,255 44 | /processorParam:ColorKeyEnabled=True 45 | /processorParam:GenerateMipmaps=False 46 | /processorParam:PremultiplyAlpha=True 47 | /processorParam:ResizeToPowerOfTwo=False 48 | /processorParam:MakeSquare=False 49 | /processorParam:TextureFormat=Color 50 | /build:Textures/Test.png 51 | 52 | #begin Textures/Tree.png 53 | /importer:TextureImporter 54 | /processor:TextureProcessor 55 | /processorParam:ColorKeyColor=255,0,255,255 56 | /processorParam:ColorKeyEnabled=True 57 | /processorParam:GenerateMipmaps=False 58 | /processorParam:PremultiplyAlpha=True 59 | /processorParam:ResizeToPowerOfTwo=False 60 | /processorParam:MakeSquare=False 61 | /processorParam:TextureFormat=Color 62 | /build:Textures/Tree.png 63 | 64 | -------------------------------------------------------------------------------- /Test/Content/Textures/Anim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/GameBundle/00bff9817bb6fb3b238e7e12f727217bcf332fca/Test/Content/Textures/Anim.png -------------------------------------------------------------------------------- /Test/Content/Textures/AutoTiling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/GameBundle/00bff9817bb6fb3b238e7e12f727217bcf332fca/Test/Content/Textures/AutoTiling.png -------------------------------------------------------------------------------- /Test/Content/Textures/Test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/GameBundle/00bff9817bb6fb3b238e7e12f727217bcf332fca/Test/Content/Textures/Test.png -------------------------------------------------------------------------------- /Test/Content/Textures/Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ellpeck/GameBundle/00bff9817bb6fb3b238e7e12f727217bcf332fca/Test/Content/Textures/Tree.png -------------------------------------------------------------------------------- /Test/GameImpl.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using Microsoft.Xna.Framework.Graphics; 3 | using MLEM.Startup; 4 | 5 | namespace Test; 6 | 7 | public class GameImpl : MlemGame { 8 | 9 | public static GameImpl Instance { get; private set; } 10 | private Texture2D texture; 11 | 12 | public GameImpl() { 13 | GameImpl.Instance = this; 14 | } 15 | 16 | protected override void LoadContent() { 17 | base.LoadContent(); 18 | this.texture = MlemGame.LoadContent("Textures/Test"); 19 | } 20 | 21 | protected override void DoDraw(GameTime gameTime) { 22 | this.GraphicsDevice.Clear(Color.Black); 23 | base.DoDraw(gameTime); 24 | this.SpriteBatch.Begin(samplerState: SamplerState.PointClamp, transformMatrix: Matrix.CreateScale(10)); 25 | this.SpriteBatch.Draw(this.texture, Vector2.Zero, Color.White); 26 | this.SpriteBatch.End(); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /Test/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using MLEM.Misc; 3 | 4 | namespace Test; 5 | 6 | public static class Program { 7 | 8 | public static void Main() { 9 | TextInputWrapper.Current = new TextInputWrapper.DesktopGl((w, c) => w.TextInput += c); 10 | using var game = new GameImpl(); 11 | game.Run(); 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /Test/Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | false 7 | false 8 | Test Project 9 | 1.2.3 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Test/macmain.txt: -------------------------------------------------------------------------------- 1 | This file should not be added to the mac bundle --------------------------------------------------------------------------------