Merge branch 'master' of https://github.com/Regalis11/Barotrauma into develop
This commit is contained in:
@@ -10,10 +10,10 @@ public static class Deployables
|
||||
{
|
||||
public const string ResultPath = "Deploy/bin/content";
|
||||
|
||||
private const string clientProjFmt = "Barotrauma/BarotraumaClient/{0}Client.csproj";
|
||||
private const string serverProjFmt = "Barotrauma/BarotraumaServer/{0}Server.csproj";
|
||||
private const string ClientProjFmt = "Barotrauma/BarotraumaClient/{0}Client.csproj";
|
||||
private const string ServerProjFmt = "Barotrauma/BarotraumaServer/{0}Server.csproj";
|
||||
|
||||
private static readonly ImmutableArray<(string Project, string Runtime)> platforms = new[]
|
||||
private static readonly ImmutableArray<(string Project, string Runtime)> Platforms = new[]
|
||||
{
|
||||
("Windows", "win-x64"),
|
||||
("Mac", "osx-x64"),
|
||||
@@ -28,11 +28,11 @@ public static class Deployables
|
||||
Path.Combine(ResultPath, "readme.txt"),
|
||||
$"This is Barotrauma {configuration} v{version} ({gitBranch}, {gitRevision}) built on {DateTime.Now}");
|
||||
|
||||
foreach (var (project, runtime) in platforms)
|
||||
foreach (var (project, runtime) in Platforms)
|
||||
{
|
||||
string serverPath = Path.Combine(ResultPath, project, "Server");
|
||||
|
||||
void checkVersion(string projPath)
|
||||
void CheckVersion(string projPath)
|
||||
{
|
||||
Version projVersion = Version.Parse(
|
||||
XDocument.Load(projPath).Root?
|
||||
@@ -45,11 +45,11 @@ public static class Deployables
|
||||
}
|
||||
}
|
||||
|
||||
string serverProj = string.Format(serverProjFmt, project);
|
||||
string clientProj = string.Format(clientProjFmt, project);
|
||||
string serverProj = string.Format(ServerProjFmt, project);
|
||||
string clientProj = string.Format(ClientProjFmt, project);
|
||||
|
||||
checkVersion(serverProj);
|
||||
checkVersion(clientProj);
|
||||
CheckVersion(serverProj);
|
||||
CheckVersion(clientProj);
|
||||
|
||||
Console.WriteLine(
|
||||
$"*** Building Barotrauma {configuration}{project} v{version} ({gitBranch}, {gitRevision}) to \"{Path.Combine(ResultPath, project)}\" ***");
|
||||
|
||||
@@ -16,7 +16,7 @@ public static class DotnetCmd
|
||||
{
|
||||
private const string DotnetAppName = "dotnet";
|
||||
|
||||
private const string desiredRuntimeVersion = "6.0.8";
|
||||
private const string DesiredRuntimeVersion = "6.0.8";
|
||||
|
||||
public static void Publish(string projPath, string configuration, string runtime, string resultPath)
|
||||
{
|
||||
@@ -36,7 +36,7 @@ public static class DotnetCmd
|
||||
"/p:Platform=x64",
|
||||
"/p:ErrorOnDuplicatePublishOutputFiles=false", //TODO: fix our duplicate files
|
||||
"/p:RollForward=Disable",
|
||||
$"/p:RuntimeFrameworkVersion={desiredRuntimeVersion}",
|
||||
$"/p:RuntimeFrameworkVersion={DesiredRuntimeVersion}",
|
||||
"-o",
|
||||
resultPath
|
||||
},
|
||||
|
||||
143
Deploy/DeployAll/EgsAssistant.cs
Normal file
143
Deploy/DeployAll/EgsAssistant.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace DeployAll;
|
||||
|
||||
public static class EgsAssistant
|
||||
{
|
||||
private static string BuildToolFilePath
|
||||
=> Path.Combine(BuildToolExtractRootPath, true switch
|
||||
{
|
||||
_ when RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
=> "Engine/Binaries/Win64/BuildPatchTool.exe",
|
||||
_ when RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
|
||||
=> "Engine/Binaries/Linux/BuildPatchTool",
|
||||
_ when RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
|
||||
=> "Engine/Binaries/Mac/BuildPatchTool",
|
||||
_ => throw new Exception($"Unsupported host platform: {RuntimeInformation.OSDescription}")
|
||||
});
|
||||
|
||||
private const string BuildToolExtractRootPath = "Deploy/bin/EpicBuildTool";
|
||||
private const string BuildToolConfig = $"{BuildToolExtractRootPath}/epic_build_tool_config.xml";
|
||||
|
||||
private const string CloudDir = $"{BuildToolExtractRootPath}/CloudDir";
|
||||
|
||||
private const string FileIgnoreListPath = $"{BuildToolExtractRootPath}/ignore.txt";
|
||||
private const string FileAttributeListPath = $"{BuildToolExtractRootPath}/fileattributes.txt";
|
||||
|
||||
public static void Upload(Version version, string configuration, string revision)
|
||||
{
|
||||
while (!File.Exists(BuildToolFilePath))
|
||||
{
|
||||
Directory.CreateDirectory(BuildToolExtractRootPath);
|
||||
if (Util.AskQuestion(
|
||||
$"Epic BuildPatchTool not found. Extract it to {BuildToolExtractRootPath}, then enter Y to continue. Enter nothing to cancel.")
|
||||
.AnsweredNo())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
XDocument? cfg = null;
|
||||
while (!Util.TryLoadXml(BuildToolConfig, out cfg)
|
||||
|| cfg.Root!.Attributes().Any(attr => !attr.Value.IsValidEpicCfg()))
|
||||
{
|
||||
if (!File.Exists(BuildToolConfig))
|
||||
{
|
||||
var doc = new XDocument(
|
||||
new XElement("config"));
|
||||
doc.Root!.Add(new XAttribute("OrganizationId", " ORGANIZATION ID "));
|
||||
doc.Root!.Add(new XAttribute("ProductId", " PRODUCT ID "));
|
||||
doc.Root!.Add(new XAttribute("ArtifactId", " ARTIFACT ID "));
|
||||
doc.Root!.Add(new XAttribute("ClientId", " BUILDPATCHTOOL CLIENT ID "));
|
||||
doc.Root!.Add(new XAttribute("ClientSecret", " BUILDPATCHTOOL CLIENT SECRET "));
|
||||
|
||||
var xmlWriterSettings = new XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
OmitXmlDeclaration = true,
|
||||
NewLineOnAttributes = true
|
||||
};
|
||||
|
||||
using var writer = XmlWriter.Create(BuildToolConfig, xmlWriterSettings);
|
||||
doc.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
if (Util.AskQuestion(
|
||||
$"Parameters for BuildPatchTool are missing or invalid. Fill in {BuildToolConfig} with the appropriate values, then enter Y to continue. Enter nothing to cancel.")
|
||||
.AnsweredNo())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(CloudDir);
|
||||
|
||||
XElement configElement = cfg.Root;
|
||||
string organizationId = configElement.GetAttributeOrThrow("OrganizationId");
|
||||
string productId = configElement.GetAttributeOrThrow("ProductId");
|
||||
string artifactId = configElement.GetAttributeOrThrow("ArtifactId");
|
||||
string clientId = configElement.GetAttributeOrThrow("ClientId");
|
||||
string clientSecret = configElement.GetAttributeOrThrow("ClientSecret");
|
||||
|
||||
var supportedPlatforms = new (string Platform, string ExecutablePath)[]
|
||||
{
|
||||
("Windows", "Barotrauma.exe"),
|
||||
|
||||
// TODO: reevaluate macOS support for the Epic Games Store version of Barotrauma
|
||||
// This was dropped because of QA difficulty and missing features on the platform
|
||||
// but it may be possible to get it working well enough to be shipped.
|
||||
//("Mac", "Barotrauma.app/Contents/MacOS/Barotrauma")
|
||||
};
|
||||
|
||||
foreach ((string platform, string executablePath) in supportedPlatforms)
|
||||
{
|
||||
string RelativeToAbsolute(string relativePath)
|
||||
=> Path.Combine(Path.GetDirectoryName(executablePath) ?? "", relativePath).NormalizePathSeparators();
|
||||
|
||||
var filesToIgnore = new[] { "steam_api64.dll", "libsteam_api64.dylib", "libsteam_api64.so" }
|
||||
.Select(RelativeToAbsolute)
|
||||
.ToArray();
|
||||
File.WriteAllLines(FileIgnoreListPath, filesToIgnore);
|
||||
var fileAttributes = platform == "Mac"
|
||||
? new[] { "DedicatedServer" }
|
||||
: Array.Empty<string>();
|
||||
fileAttributes = fileAttributes
|
||||
.Select(RelativeToAbsolute)
|
||||
.Select(f => $"\"{f}\" executable")
|
||||
.ToArray();
|
||||
File.WriteAllLines(FileAttributeListPath, fileAttributes);
|
||||
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = BuildToolFilePath,
|
||||
ArgumentList =
|
||||
{
|
||||
$"-OrganizationId=\"{organizationId}\"",
|
||||
$"-ProductId=\"{productId}\"",
|
||||
$"-ArtifactId=\"{artifactId}\"",
|
||||
$"-ClientId=\"{clientId}\"",
|
||||
$"-ClientSecret=\"{clientSecret}\"",
|
||||
"-mode=UploadBinary",
|
||||
$"-BuildRoot=\"{Path.GetFullPath(Path.Combine(Deployables.ResultPath, platform, "Client")).NormalizePathSeparators()}\"",
|
||||
$"-CloudDir=\"{Path.GetFullPath(CloudDir).NormalizePathSeparators()}\"",
|
||||
$"-BuildVersion=\"{version}-{platform}{configuration}-{revision}\"",
|
||||
$"-AppLaunch=\"{executablePath}\"",
|
||||
"-AppArgs=\"\"",
|
||||
$"-FileIgnoreList={Path.GetFullPath(FileIgnoreListPath).NormalizePathSeparators()}",
|
||||
$"-FileAttributeList={Path.GetFullPath(FileAttributeListPath).NormalizePathSeparators()}"
|
||||
},
|
||||
RedirectStandardOutput = false,
|
||||
RedirectStandardError = false
|
||||
};
|
||||
var process = Util.StartProcess(psi);
|
||||
process.WaitForExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,13 @@ namespace DeployAll;
|
||||
|
||||
public static class GitCmd
|
||||
{
|
||||
private const string gitCmdName = "git";
|
||||
private const string GitCmdName = "git";
|
||||
|
||||
private static ProcessStartInfo MakePsi(params string[] args)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = gitCmdName,
|
||||
FileName = GitCmdName,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardOutput = true
|
||||
};
|
||||
|
||||
@@ -4,6 +4,8 @@ using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using DeployAll;
|
||||
|
||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => Console.WriteLine("Bye!");
|
||||
|
||||
while (!Directory.GetFiles(".").Any(f => f.EndsWith(".sln")))
|
||||
{
|
||||
Directory.SetCurrentDirectory("..");
|
||||
@@ -46,6 +48,13 @@ if (string.IsNullOrWhiteSpace(configuration)) { return; }
|
||||
|
||||
Deployables.Generate(configuration, gameVersion, gitBranch, gitRevision);
|
||||
|
||||
if (Util.AskQuestion("Would you like to upload the generated builds to EGS? [y/n]")
|
||||
.AnsweredYes())
|
||||
{
|
||||
EgsAssistant.Upload(gameVersion, configuration, gitRevision);
|
||||
}
|
||||
|
||||
|
||||
if (Util.AskQuestion("Would you like to upload the generated builds to Steam? [y/n]")
|
||||
.AnsweredNo()) { return; }
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ public static class SteamPipeAssistant
|
||||
}
|
||||
}
|
||||
|
||||
private static string steamCmdUrl
|
||||
private static string SteamCmdUrl
|
||||
=> true switch
|
||||
{
|
||||
_ when RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
@@ -46,7 +46,7 @@ public static class SteamPipeAssistant
|
||||
_ => throw new Exception($"Unsupported host platform: {RuntimeInformation.OSDescription}")
|
||||
};
|
||||
|
||||
private static string[] steamCmdFilenames
|
||||
private static string[] SteamCmdFilenames
|
||||
=> true switch
|
||||
{
|
||||
_ when RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
@@ -71,9 +71,9 @@ public static class SteamPipeAssistant
|
||||
|
||||
Util.RecreateDirectory(SteamCmdPath);
|
||||
|
||||
var steamCmdPkg = Util.DownloadFile(steamCmdUrl).ToArray();
|
||||
var steamCmdPkg = Util.DownloadFile(SteamCmdUrl, out _).ToArray();
|
||||
|
||||
if (Path.GetExtension(steamCmdUrl) == ".zip")
|
||||
if (Path.GetExtension(SteamCmdUrl) == ".zip")
|
||||
{
|
||||
using var memStream = new MemoryStream(steamCmdPkg);
|
||||
using ZipArchive archive = new ZipArchive(memStream, ZipArchiveMode.Read);
|
||||
@@ -81,7 +81,7 @@ public static class SteamPipeAssistant
|
||||
}
|
||||
else
|
||||
{
|
||||
string downloadResultPath = Path.Combine(SteamCmdPath, Path.GetFileName(steamCmdUrl));
|
||||
string downloadResultPath = Path.Combine(SteamCmdPath, Path.GetFileName(SteamCmdUrl));
|
||||
File.WriteAllBytes(downloadResultPath, steamCmdPkg);
|
||||
|
||||
var psi = new ProcessStartInfo
|
||||
@@ -102,7 +102,7 @@ public static class SteamPipeAssistant
|
||||
|
||||
File.Delete(downloadResultPath);
|
||||
|
||||
foreach (var filename in steamCmdFilenames)
|
||||
foreach (var filename in SteamCmdFilenames)
|
||||
{
|
||||
psi = new ProcessStartInfo
|
||||
{
|
||||
@@ -126,7 +126,7 @@ public static class SteamPipeAssistant
|
||||
private const string ScriptPath = "Deploy/bin/scripts";
|
||||
private const string BuildOutput = "Deploy/bin/output";
|
||||
|
||||
private const string appIdScriptFileFmt = "app_{0}.vdf";
|
||||
private const string AppIdScriptFileFmt = "app_{0}.vdf";
|
||||
|
||||
private const ulong ClientAppId = 602960;
|
||||
private const ulong ClientWindowsDepotId = 602961;
|
||||
@@ -194,14 +194,14 @@ public static class SteamPipeAssistant
|
||||
new SingleItem("contentroot", Path.GetFullPath(Deployables.ResultPath)),
|
||||
new SingleItem("setlive", appId switch
|
||||
{
|
||||
ClientAppId => "experimental",
|
||||
ServerAppId => "development",
|
||||
ClientAppId => "refactor_our_souls",
|
||||
ServerAppId => "refactor_our_souls",
|
||||
_ => throw new InvalidOperationException()
|
||||
}),
|
||||
new SingleItem("preview", "0"),
|
||||
depotScripts);
|
||||
|
||||
var scriptFileName = Path.Combine(ScriptPath, string.Format(appIdScriptFileFmt, appId));
|
||||
var scriptFileName = Path.Combine(ScriptPath, string.Format(AppIdScriptFileFmt, appId));
|
||||
File.WriteAllText(scriptFileName, script.ToString());
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ public static class SteamPipeAssistant
|
||||
|
||||
ProcessStartInfo psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = Path.Combine(SteamCmdPath, steamCmdFilenames.First()),
|
||||
FileName = Path.Combine(SteamCmdPath, SteamCmdFilenames.First()),
|
||||
ArgumentList =
|
||||
{
|
||||
"+login",
|
||||
@@ -233,13 +233,13 @@ public static class SteamPipeAssistant
|
||||
RedirectStandardError = false
|
||||
};
|
||||
|
||||
void addScriptCmd(ulong appId)
|
||||
void AddScriptCmd(ulong appId)
|
||||
{
|
||||
psi.ArgumentList.Add("+run_app_build");
|
||||
psi.ArgumentList.Add(Path.GetFullPath(Path.Combine(ScriptPath, string.Format(appIdScriptFileFmt, appId))));
|
||||
psi.ArgumentList.Add(Path.GetFullPath(Path.Combine(ScriptPath, string.Format(AppIdScriptFileFmt, appId))));
|
||||
}
|
||||
addScriptCmd(ClientAppId);
|
||||
if (configuration == "Release") { addScriptCmd(ServerAppId); }
|
||||
AddScriptCmd(ClientAppId);
|
||||
if (configuration == "Release") { AddScriptCmd(ServerAppId); }
|
||||
|
||||
psi.ArgumentList.Add("+quit");
|
||||
var process = Util.StartProcess(psi);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace DeployAll;
|
||||
|
||||
@@ -64,13 +66,16 @@ public static class Util
|
||||
DeleteDirectory(path);
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
public static IReadOnlyList<byte> DownloadFile(string url)
|
||||
|
||||
public static IReadOnlyList<byte> DownloadFile(string url, out string finalUrl)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
finalUrl = url;
|
||||
|
||||
using var httpClient = new HttpClient();
|
||||
var response = httpClient.Send(new HttpRequestMessage(
|
||||
HttpMethod.Get,
|
||||
new Uri(url)));
|
||||
finalUrl = response.RequestMessage?.RequestUri?.AbsoluteUri ?? url;
|
||||
using var stream = response.Content.ReadAsStream();
|
||||
|
||||
using var reader = new BinaryReader(stream);
|
||||
@@ -100,6 +105,50 @@ public static class Util
|
||||
public static bool AnsweredNo(this string answer)
|
||||
=> !answer.AnsweredYes();
|
||||
|
||||
public static bool IsValidEpicCfg(this char c)
|
||||
=> char.IsDigit(c)
|
||||
|| c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '-' or '_' or '+' or '/';
|
||||
|
||||
public static bool IsValidEpicCfg(this string s)
|
||||
=> !string.IsNullOrEmpty(s) && s.All(IsValidEpicCfg);
|
||||
|
||||
public static bool TryLoadXml(string path, [NotNullWhen(returnValue: true)]out XDocument? doc)
|
||||
{
|
||||
try
|
||||
{
|
||||
doc = XDocument.Load(path);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
doc = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetAttributeOrThrow(this XElement element, string attributeName)
|
||||
{
|
||||
var attribute = element
|
||||
.Attributes()
|
||||
.FirstOrDefault(e => e.Name.LocalName.Equals(attributeName, StringComparison.OrdinalIgnoreCase));
|
||||
if (attribute != null
|
||||
&& !string.IsNullOrEmpty(attribute.Value))
|
||||
{
|
||||
return attribute.Value;
|
||||
}
|
||||
|
||||
throw new Exception($"{attributeName} is not set");
|
||||
}
|
||||
|
||||
public static string ThrowIfNullOrEmpty(this string? s, string msg)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s)) { throw new Exception(msg); }
|
||||
return s;
|
||||
}
|
||||
|
||||
public static string NormalizePathSeparators(this string s)
|
||||
=> s.Replace("\\", "/");
|
||||
|
||||
public static Process StartProcess(ProcessStartInfo info)
|
||||
=> Process.Start(info)
|
||||
?? throw new Exception($"Failed to start process \"{info.FileName}\"");
|
||||
|
||||
Reference in New Issue
Block a user