From 328bae550c8124b9b072ef29351c8c56ddf02544 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 20 Jan 2017 19:09:02 +0000 Subject: [PATCH 1/8] Implement external mod registration and launching. --- OpenRA.Game/ExternalMods.cs | 125 +++++++++++++++++++++++++++++++++ OpenRA.Game/Game.cs | 32 ++++++++- OpenRA.Game/OpenRA.Game.csproj | 1 + 3 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 OpenRA.Game/ExternalMods.cs diff --git a/OpenRA.Game/ExternalMods.cs b/OpenRA.Game/ExternalMods.cs new file mode 100644 index 0000000000..b95df2b5ff --- /dev/null +++ b/OpenRA.Game/ExternalMods.cs @@ -0,0 +1,125 @@ +#region Copyright & License Information +/* + * Copyright 2007-2017 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 + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using OpenRA.Graphics; + +namespace OpenRA +{ + public class ExternalMod + { + public readonly string Id; + public readonly string Version; + public readonly string Title; + public readonly string LaunchPath; + public readonly string[] LaunchArgs; + public Sprite Icon { get; internal set; } + + public static string MakeKey(Manifest mod) { return MakeKey(mod.Id, mod.Metadata.Version); } + public static string MakeKey(ExternalMod mod) { return MakeKey(mod.Id, mod.Version); } + public static string MakeKey(string modId, string modVersion) { return modId + "-" + modVersion; } + } + + public class ExternalMods : IReadOnlyDictionary + { + readonly Dictionary mods; + readonly SheetBuilder sheetBuilder; + readonly string launchPath; + + public ExternalMods(string launchPath) + { + // Process.Start requires paths to not be quoted, even if they contain spaces + if (launchPath.First() == '"' && launchPath.Last() == '"') + launchPath = launchPath.Substring(1, launchPath.Length - 2); + + this.launchPath = launchPath; + sheetBuilder = new SheetBuilder(SheetType.BGRA, 256); + mods = LoadMods(); + } + + Dictionary LoadMods() + { + var ret = new Dictionary(); + var supportPath = Platform.ResolvePath(Path.Combine("^", "ModMetadata")); + if (!Directory.Exists(supportPath)) + return ret; + + foreach (var path in Directory.GetFiles(supportPath, "*.yaml")) + { + try + { + var yaml = MiniYaml.FromStream(File.OpenRead(path), path).First().Value; + var mod = FieldLoader.Load(yaml); + var iconNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon"); + if (iconNode != null && !string.IsNullOrEmpty(iconNode.Value.Value)) + { + using (var stream = new MemoryStream(Convert.FromBase64String(iconNode.Value.Value))) + using (var bitmap = new Bitmap(stream)) + mod.Icon = sheetBuilder.Add(bitmap); + } + + ret.Add(ExternalMod.MakeKey(mod), mod); + } + catch (Exception e) + { + Log.Write("debug", "Failed to parse mod metadata file '{0}'", path); + Log.Write("debug", e.ToString()); + } + } + + return ret; + } + + internal void Register(Manifest mod) + { + if (mod.Metadata.Hidden) + return; + + var iconData = ""; + using (var stream = mod.Package.GetStream("icon.png")) + if (stream != null) + iconData = Convert.ToBase64String(stream.ReadAllBytes()); + + var key = ExternalMod.MakeKey(mod); + var yaml = new List() + { + new MiniYamlNode("Registration", new MiniYaml("", new List() + { + new MiniYamlNode("Id", mod.Id), + new MiniYamlNode("Version", mod.Metadata.Version), + new MiniYamlNode("Title", mod.Metadata.Title), + new MiniYamlNode("Icon", iconData), + new MiniYamlNode("LaunchPath", launchPath), + new MiniYamlNode("LaunchArgs", "Game.Mod=" + mod.Id) + })) + }; + + var supportPath = Platform.ResolvePath(Path.Combine("^", "ModMetadata")); + Directory.CreateDirectory(supportPath); + + File.WriteAllLines(Path.Combine(supportPath, key + ".yaml"), yaml.ToLines(false).ToArray()); + } + + public ExternalMod this[string key] { get { return mods[key]; } } + public int Count { get { return mods.Count; } } + public ICollection Keys { get { return mods.Keys; } } + public ICollection Values { get { return mods.Values; } } + public bool ContainsKey(string key) { return mods.ContainsKey(key); } + public IEnumerator> GetEnumerator() { return mods.GetEnumerator(); } + public bool TryGetValue(string key, out ExternalMod value) { return mods.TryGetValue(key, out value); } + IEnumerator IEnumerable.GetEnumerator() { return mods.GetEnumerator(); } + } +} diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 6a764b488c..50bb78bab7 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -37,6 +37,7 @@ namespace OpenRA public const int TimestepJankThreshold = 250; // Don't catch up for delays larger than 250ms public static InstalledMods Mods { get; private set; } + public static ExternalMods ExternalMods { get; private set; } public static ModData ModData; public static Settings Settings; @@ -314,10 +315,16 @@ namespace OpenRA GlobalChat = new GlobalChat(); Mods = new InstalledMods(customModPath); - Console.WriteLine("Available mods:"); + Console.WriteLine("Internal mods:"); foreach (var mod in Mods) Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Metadata.Title, mod.Value.Metadata.Version); + var launchPath = args.GetValue("Engine.LaunchPath", Assembly.GetEntryAssembly().Location); + ExternalMods = new ExternalMods(launchPath); + Console.WriteLine("External mods:"); + foreach (var mod in ExternalMods) + Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version); + InitializeMod(Settings.Game.Mod, args); } @@ -370,6 +377,7 @@ namespace OpenRA Sound.StopVideo(); ModData = new ModData(Mods[mod], Mods, true); + ExternalMods.Register(ModData.Manifest); using (new PerfTimer("LoadMaps")) ModData.MapCache.LoadMaps(); @@ -457,6 +465,28 @@ namespace OpenRA return shellmaps.Random(CosmeticRandom); } + public static void SwitchToExternalMod(ExternalMod mod, string[] launchArguments = null, Action onFailed = null) + { + try + { + var argsString = mod.LaunchArgs.Append(launchArguments) + .Select(a => "\"" + a + "\"").JoinWith(" "); + + var p = Process.Start(mod.LaunchPath, argsString); + if (p == null || p.HasExited) + onFailed(); + else + { + p.Close(); + Exit(); + } + } + catch + { + onFailed(); + } + } + static RunStatus state = RunStatus.Running; public static event Action OnQuit = () => { }; diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 96b0fe5cf7..e7788cf931 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -246,6 +246,7 @@ + From 25a0d5be5bbb88246b9e32aed3e3c3fe720a21f5 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 22 Jan 2017 11:15:43 +0000 Subject: [PATCH 2/8] Load icons for installed mods. --- OpenRA.Game/InstalledMods.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/OpenRA.Game/InstalledMods.cs b/OpenRA.Game/InstalledMods.cs index 92d7e5a8a6..2d191b6509 100644 --- a/OpenRA.Game/InstalledMods.cs +++ b/OpenRA.Game/InstalledMods.cs @@ -12,9 +12,11 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Drawing; using System.IO; using System.Linq; using OpenRA.FileSystem; +using OpenRA.Graphics; using OpenRA.Primitives; namespace OpenRA @@ -22,9 +24,15 @@ namespace OpenRA public class InstalledMods : IReadOnlyDictionary { readonly Dictionary mods; + readonly SheetBuilder sheetBuilder; + + readonly Dictionary icons = new Dictionary(); + public readonly IReadOnlyDictionary Icons; public InstalledMods(string customModPath) { + sheetBuilder = new SheetBuilder(SheetType.BGRA, 256); + Icons = new ReadOnlyDictionary(icons); mods = GetInstalledMods(customModPath); } @@ -53,7 +61,7 @@ namespace OpenRA return mods; } - static Manifest LoadMod(string id, string path) + Manifest LoadMod(string id, string path) { IReadOnlyPackage package = null; try @@ -76,6 +84,11 @@ namespace OpenRA if (!package.Contains("mod.yaml")) throw new InvalidDataException(path + " is not a valid mod package"); + using (var stream = package.GetStream("icon.png")) + if (stream != null) + using (var bitmap = new Bitmap(stream)) + icons[id] = sheetBuilder.Add(bitmap); + // Mods in the support directory and oramod packages (which are listed later // in the CandidateMods list) override mods in the main install. return new Manifest(id, package); @@ -89,7 +102,7 @@ namespace OpenRA } } - static Dictionary GetInstalledMods(string customModPath) + Dictionary GetInstalledMods(string customModPath) { var ret = new Dictionary(); var candidates = GetCandidateMods(); From 4d982f00e4e11ba6e0c175f46c722246fe434293 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 20 Jan 2017 20:30:01 +0000 Subject: [PATCH 3/8] Add 32px icons for default mods. --- mods/cnc/icon.png | Bin 0 -> 2569 bytes mods/d2k/icon.png | Bin 0 -> 4297 bytes mods/ra/icon.png | Bin 0 -> 1346 bytes mods/ts/icon.png | Bin 0 -> 3396 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 mods/cnc/icon.png create mode 100644 mods/d2k/icon.png create mode 100644 mods/ra/icon.png create mode 100644 mods/ts/icon.png diff --git a/mods/cnc/icon.png b/mods/cnc/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..22b05bd91f27b969a84bf4b63449ba2cce94632b GIT binary patch literal 2569 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 literal 0 HcmV?d00001 diff --git a/mods/d2k/icon.png b/mods/d2k/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c3913dbe75df5daeeb816765095afc6e0d04bc GIT binary patch literal 4297 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 B*-!ug literal 0 HcmV?d00001 diff --git a/mods/ra/icon.png b/mods/ra/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..220da01e3b72f10f2cd8a53d89e9ce77be1fc780 GIT binary patch literal 1346 zcmV-I1-<%-P)-xtw^V$VWxmU z5!&AO+xzp6)5usxp|^=X$w|)1z2E0~e&65o`<}!25gSi&e4OHq=olx*xUjO8z5h4$ z$?S_!!HjA-#vto4>lQI|6~6sXZ5{=0rWKqI? z{3_zzp5?v-hD*GZpywdBE+WxId>-auHV#Z8(as|eo!`Efchm41*A*h6NrUX2N=q|| ziNyD?c$k@(g+9X5e*j-h9%1VV3G z=(t*Vu2JYGd~T+2{P#lTfH1U2=vpjnO$sYNA{^W*yzw((>1?5%Y?|+@a_TOqll;0*^)9Sg;FSTgZJ<_=X6Vu$i zjJCP_WFz@gjQ@pB?1eTl5?`;p)*0T=31+bcN=YCh=04`yS%6z0_}|^Nalbo%aam$mRIc zA@&_2ljWIiPM&t8>JD5x$JcJ0Yt{Z<(^vFL+%O!S^M34@Lf?mk#>pyy%Gom#iPPdU z&M+{6p-D_T#tRkwC8kzoU<99-LiZNxN}}Yyfgh18vn@X|PLr&Svt}vjIm8O0H_cOI z^3mk$xmYLO7fIILLE(AAX2KHkDgKSy-skTNQ}nfvdw}pD;i@R3k5wfOwfyaygl|P( zzL_*T@WD|^8d7YoA#)4iV}w-Hw5l*YNofhC6axvCkD+#XoU>O_j78CDtj55D2sP}& zv?}VSC)kaE&s1YzOM=d73g3lTJPPU))f88=>M?Wu2X;2;HwY*9E&u=k07*qoM6N<$ Ef(Ia_kpKVy literal 0 HcmV?d00001 diff --git a/mods/ts/icon.png b/mods/ts/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a82496dac351e553f28c695abdd91c8a154f6c8e GIT binary patch literal 3396 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 literal 0 HcmV?d00001 From 2da4e87b9452f7443044d20b516fd92c8e15cf7d Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 20 Jan 2017 20:29:51 +0000 Subject: [PATCH 4/8] Implement new server-connection mod switching logic. --- OpenRA.Game/Network/GameServer.cs | 23 +++- OpenRA.Game/Network/OrderManager.cs | 2 + OpenRA.Game/Network/UnitOrders.cs | 21 ++- .../Widgets/Logic/ConnectionLogic.cs | 120 +++++++++++++++++- .../Widgets/Logic/Lobby/LobbyLogic.cs | 4 +- mods/cnc/chrome/connection.yaml | 69 ++++++++++ mods/ra/chrome/connection.yaml | 68 ++++++++++ 7 files changed, 292 insertions(+), 15 deletions(-) diff --git a/OpenRA.Game/Network/GameServer.cs b/OpenRA.Game/Network/GameServer.cs index 62ffb58264..0ef4ac4c3a 100644 --- a/OpenRA.Game/Network/GameServer.cs +++ b/OpenRA.Game/Network/GameServer.cs @@ -39,16 +39,29 @@ namespace OpenRA.Network FieldLoader.Load(this, yaml); Manifest mod; + ExternalMod external; var modVersion = Mods.Split('@'); - if (modVersion.Length == 2 && Game.Mods.TryGetValue(modVersion[0], out mod)) + + ModLabel = "Unknown mod: {0}".F(Mods); + if (modVersion.Length == 2) { ModId = modVersion[0]; ModVersion = modVersion[1]; - ModLabel = "{0} ({1})".F(mod.Metadata.Title, modVersion[1]); - IsCompatible = Game.Settings.Debug.IgnoreVersionMismatch || ModVersion == mod.Metadata.Version; + + if (Game.Mods.TryGetValue(modVersion[0], out mod)) + { + ModLabel = "{0} ({1})".F(mod.Metadata.Title, modVersion[1]); + IsCompatible = Game.Settings.Debug.IgnoreVersionMismatch || ModVersion == mod.Metadata.Version; + } + + var externalKey = ExternalMod.MakeKey(modVersion[0], modVersion[1]); + if (!IsCompatible && Game.ExternalMods.TryGetValue(externalKey, out external) + && external.Version == modVersion[1]) + { + ModLabel = "{0} ({1})".F(external.Title, external.Version); + IsCompatible = true; + } } - else - ModLabel = "Unknown mod: {0}".F(Mods); var mapAvailable = Game.Settings.Game.AllowDownloading || Game.ModData.MapCache[Map].Status == MapStatus.Available; IsJoinable = IsCompatible && State == 1 && mapAvailable; diff --git a/OpenRA.Game/Network/OrderManager.cs b/OpenRA.Game/Network/OrderManager.cs index 246a221673..b103e4c7ae 100644 --- a/OpenRA.Game/Network/OrderManager.cs +++ b/OpenRA.Game/Network/OrderManager.cs @@ -34,6 +34,8 @@ namespace OpenRA.Network public string ServerError = "Server is not responding"; public bool AuthenticationFailed = false; + public Manifest ServerMod = null; + public ExternalMod ServerExternalMod = null; public int NetFrameNumber { get; private set; } public int LocalFrameNumber; diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index 4e2bbc9f4c..798d430908 100644 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -140,14 +140,20 @@ namespace OpenRA.Network Game.Mods.TryGetValue(request.Mod, out serverMod) && serverMod.Metadata.Version == request.Version) { - var replay = orderManager.Connection as ReplayConnection; - var launchCommand = replay != null ? - "Launch.Replay=" + replay.Filename : - "Launch.Connect=" + orderManager.Host + ":" + orderManager.Port; - - Game.ModData.LoadScreen.Display(); - Game.InitializeMod(request.Mod, new Arguments(launchCommand)); + // The ConnectionFailedLogic will prompt the user to switch mods + orderManager.ServerMod = serverMod; + orderManager.Connection.Dispose(); + break; + } + var externalKey = ExternalMod.MakeKey(request.Mod, request.Version); + ExternalMod external; + if ((request.Mod != mod.Id || request.Version != mod.Metadata.Version) + && Game.ExternalMods.TryGetValue(externalKey, out external)) + { + // The ConnectionFailedLogic will prompt the user to switch mods + orderManager.ServerExternalMod = external; + orderManager.Connection.Dispose(); break; } @@ -187,6 +193,7 @@ namespace OpenRA.Network case "AuthenticationError": { + // The ConnectionFailedLogic will prompt the user for the password orderManager.ServerError = order.TargetString; orderManager.AuthenticationFailed = true; break; diff --git a/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs index 096ab6eb7b..fae22d4c5c 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs @@ -10,6 +10,7 @@ #endregion using System; +using OpenRA.Graphics; using OpenRA.Network; using OpenRA.Widgets; @@ -30,7 +31,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic else if (om.Connection.ConnectionState == ConnectionState.NotConnected) { CloseWindow(); - Ui.OpenWindow("CONNECTIONFAILED_PANEL", new WidgetArgs() + + var switchPanel = (om.ServerExternalMod != null || om.ServerMod != null) ? + "CONNECTION_SWITCHMOD_PANEL" : "CONNECTIONFAILED_PANEL"; + Ui.OpenWindow(switchPanel, new WidgetArgs() { { "orderManager", om }, { "onAbort", onAbort }, @@ -146,4 +150,116 @@ namespace OpenRA.Mods.Common.Widgets.Logic } } } -} \ No newline at end of file + + public class ConnectionSwitchModLogic : ChromeLogic + { + [ObjectCreator.UseCtor] + public ConnectionSwitchModLogic(Widget widget, OrderManager orderManager, Action onAbort, Action onRetry) + { + var panel = widget; + var abortButton = panel.Get("ABORT_BUTTON"); + var switchButton = panel.Get("SWITCH_BUTTON"); + + var modTitle = ""; + var modVersion = ""; + Sprite modIcon = null; + if (orderManager.ServerExternalMod != null) + { + modTitle = orderManager.ServerExternalMod.Title; + modVersion = orderManager.ServerExternalMod.Version; + modIcon = orderManager.ServerExternalMod.Icon; + } + else + { + modTitle = orderManager.ServerMod.Metadata.Title; + modVersion = orderManager.ServerMod.Metadata.Version; + modIcon = Game.Mods.Icons[orderManager.ServerMod.Id]; + } + + switchButton.OnClick = () => + { + // Note: Switching mods for directly launched replays is handled by the load screen + // and the replay browser prevents loading replays from other mods, so it doesn't look + // like this replay case is ever hit. + var replay = orderManager.Connection as ReplayConnection; + var launchCommand = replay != null ? + "Launch.Replay=" + replay.Filename : + "Launch.Connect=" + orderManager.Host + ":" + orderManager.Port; + + if (orderManager.ServerExternalMod != null) + { + Game.SwitchToExternalMod(orderManager.ServerExternalMod, new[] { launchCommand }, () => + { + orderManager.ServerError = "Failed to switch mod."; + Ui.CloseWindow(); + Ui.OpenWindow("CONNECTIONFAILED_PANEL", new WidgetArgs() + { + { "orderManager", orderManager }, + { "onAbort", onAbort }, + { "onRetry", onRetry } + }); + }); + } + else + { + Game.ModData.LoadScreen.Display(); + Game.InitializeMod(orderManager.ServerMod.Id, new Arguments(launchCommand)); + } + }; + + abortButton.Visible = onAbort != null; + abortButton.OnClick = () => { Ui.CloseWindow(); onAbort(); }; + + var width = 0; + var title = panel.GetOrNull("MOD_TITLE"); + if (title != null) + { + var font = Game.Renderer.Fonts[title.Font]; + var label = WidgetUtils.TruncateText(modTitle, title.Bounds.Width, font); + var labelWidth = font.Measure(label).X; + width = Math.Max(width, title.Bounds.X + labelWidth); + title.Bounds.Width = labelWidth; + title.GetText = () => label; + } + + var version = panel.GetOrNull("MOD_VERSION"); + if (version != null) + { + var font = Game.Renderer.Fonts[version.Font]; + var label = WidgetUtils.TruncateText(modVersion, version.Bounds.Width, font); + var labelWidth = font.Measure(label).X; + width = Math.Max(width, version.Bounds.X + labelWidth); + version.Bounds.Width = labelWidth; + version.GetText = () => label; + } + + var logo = panel.GetOrNull("MOD_ICON"); + if (logo != null && modIcon != null) + logo.GetSprite = () => modIcon; + + if (logo != null && modIcon == null) + { + // Hide the logo and center just the text + if (title != null) + title.Bounds.Offset(logo.Bounds.Left - title.Bounds.Left, 0); + + if (version != null) + version.Bounds.Offset(logo.Bounds.Left - version.Bounds.Left, 0); + + width -= logo.Bounds.Width; + } + else + { + // Add an equal logo margin on the right of the text + width += logo.Bounds.Width; + } + + var container = panel.GetOrNull("MOD_CONTAINER"); + if (container != null) + { + container.Bounds.Offset((container.Bounds.Width - width) / 2, 0); + container.Bounds.Width = width; + } + } + } +} diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs index 65978de228..2e734f48a8 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs @@ -91,7 +91,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic Action onRetry = password => ConnectionLogic.Connect(om.Host, om.Port, password, onConnect, onExit); - Ui.OpenWindow("CONNECTIONFAILED_PANEL", new WidgetArgs() + var switchPanel = (om.ServerExternalMod != null || om.ServerMod != null) ? + "CONNECTION_SWITCHMOD_PANEL" : "CONNECTIONFAILED_PANEL"; + Ui.OpenWindow(switchPanel, new WidgetArgs() { { "orderManager", om }, { "onAbort", onExit }, diff --git a/mods/cnc/chrome/connection.yaml b/mods/cnc/chrome/connection.yaml index 1ef3c5f73b..1527a3f0ae 100644 --- a/mods/cnc/chrome/connection.yaml +++ b/mods/cnc/chrome/connection.yaml @@ -90,3 +90,72 @@ Container@CONNECTIONFAILED_PANEL: Width: 140 Height: 35 Text: Retry + +Container@CONNECTION_SWITCHMOD_PANEL: + Logic: ConnectionSwitchModLogic + X: (WINDOW_RIGHT - WIDTH)/2 + Y: (WINDOW_BOTTOM - 90)/2 + Width: 370 + Height: 134 + Children: + Label@TITLE: + Width: PARENT_RIGHT + Y: 0-25 + Font: BigBold + Contrast: true + Align: Center + Text: Switch Mod + Background@CONNECTION_BACKGROUND: + Width: 370 + Height: 120 + Background: panel-black + Children: + Label@DESC: + Y: 15 + Width: PARENT_RIGHT + Height: 25 + Text: This server is running a different mod: + Font: Bold + Align: Center + Container@MOD_CONTAINER: + X: 0 + Y: 42 + Width: PARENT_RIGHT + Children: + RGBASprite@MOD_ICON: + Y: 4 + Width: 32 + Height: 32 + Label@MOD_TITLE: + X: 37 + Width: PARENT_RIGHT - 37 + Height: 25 + Font: Bold + Align: Left + Label@MOD_VERSION: + X: 37 + Y: 15 + Width: PARENT_RIGHT - 37 + Height: 25 + Font: Tiny + Align: Left + Label@DESC2: + Y: 80 + Width: PARENT_RIGHT + Height: 25 + Text: Switch mods and join server? + Font: Bold + Align: Center + Button@ABORT_BUTTON: + Key: escape + Y: 119 + Width: 140 + Height: 35 + Text: Abort + Button@SWITCH_BUTTON: + Key: return + X: 230 + Y: 119 + Width: 140 + Height: 35 + Text: Switch diff --git a/mods/ra/chrome/connection.yaml b/mods/ra/chrome/connection.yaml index ddebd34792..7fa93e7cb1 100644 --- a/mods/ra/chrome/connection.yaml +++ b/mods/ra/chrome/connection.yaml @@ -88,3 +88,71 @@ Background@CONNECTING_PANEL: Text: Abort Font: Bold Key: escape + +Background@CONNECTION_SWITCHMOD_PANEL: + Logic: ConnectionSwitchModLogic + X: (WINDOW_RIGHT - WIDTH)/2 + Y: (WINDOW_BOTTOM - HEIGHT)/2 + Width: 450 + Height: 191 + Children: + Label@TITLE: + X: 0 + Y: 20 + Width: 450 + Height: 25 + Align: Center + Font: Bold + Text: Switch Mod + Label@DESC: + Y: 45 + Width: PARENT_RIGHT + Height: 25 + Text: This server is running a different mod: + Font: Bold + Align: Center + Container@MOD_CONTAINER: + X: 0 + Y: 72 + Width: PARENT_RIGHT + Children: + RGBASprite@MOD_ICON: + Y: 4 + Width: 32 + Height: 32 + Label@MOD_TITLE: + X: 37 + Width: PARENT_RIGHT - 37 + Height: 25 + Font: Bold + Align: Left + Label@MOD_VERSION: + X: 37 + Y: 15 + Width: PARENT_RIGHT - 37 + Height: 25 + Font: Tiny + Align: Left + Label@DESC2: + Y: 110 + Width: PARENT_RIGHT + Height: 25 + Text: Switch mods and join server? + Font: Bold + Align: Center + Button@SWITCH_BUTTON: + X: PARENT_RIGHT - 430 + Y: PARENT_BOTTOM - 45 + Width: 160 + Height: 25 + Text: Switch + Font: Bold + Key: return + Button@ABORT_BUTTON: + X: PARENT_RIGHT - 180 + Y: PARENT_BOTTOM - 45 + Width: 160 + Height: 25 + Text: Cancel + Font: Bold + Key: escape From 2f7446e9fc153f9c4f1536499224f72f10fc1b77 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 23 Jan 2017 19:04:02 +0000 Subject: [PATCH 5/8] Pass Engine.LaunchPath from windows launcher. --- OpenRA.GameMonitor/GameMonitor.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/OpenRA.GameMonitor/GameMonitor.cs b/OpenRA.GameMonitor/GameMonitor.cs index 3b185e9334..c730795408 100644 --- a/OpenRA.GameMonitor/GameMonitor.cs +++ b/OpenRA.GameMonitor/GameMonitor.cs @@ -27,12 +27,17 @@ namespace OpenRA [STAThread] static void Main(string[] args) { - var executableDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - var processName = Path.Combine(executableDirectory, "OpenRA.Game.exe"); + var launcherPath = Assembly.GetExecutingAssembly().Location; + var directory = Path.GetDirectoryName(launcherPath); + var enginePath = Path.Combine(directory, "OpenRA.Game.exe"); - Directory.SetCurrentDirectory(executableDirectory); + Directory.SetCurrentDirectory(directory); - var psi = new ProcessStartInfo(processName, string.Join(" ", args.Select(arg => "\"" + arg + "\""))); + var engineArgs = args + .Append("Engine.LaunchPath=" + launcherPath) + .Select(arg => "\"" + arg + "\""); + + var psi = new ProcessStartInfo(enginePath, string.Join(" ", engineArgs)); try { From 8385207fbadd6c21e7b3014325065131fa599944 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 23 Jan 2017 19:08:53 +0000 Subject: [PATCH 6/8] Pass Engine.LaunchPath from linux launchers. --- Makefile | 5 +++-- launch-game.sh | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 5e5cca3568..2fd68b7605 100644 --- a/Makefile +++ b/Makefile @@ -441,10 +441,11 @@ install-man-page: man-page install-linux-scripts: @echo "#!/bin/sh" > openra @echo 'cd "$(gameinstalldir)"' >> openra +# Note: this relies on the non-standard -f flag implemented by gnu readlink ifeq ($(DEBUG), $(filter $(DEBUG),false no n off 0)) - @echo 'mono OpenRA.Game.exe "$$@"' >> openra + @echo 'mono OpenRA.Game.exe Engine.LaunchPath="$(readlink -f $0)" "$$@"' >> openra else - @echo 'mono --debug OpenRA.Game.exe "$$@"' >> openra + @echo 'mono --debug OpenRA.Game.exe Engine.LaunchPath="$(readlink -f $0)" "$$@"' >> openra endif @echo 'if [ $$? != 0 -a $$? != 1 ]' >> openra @echo 'then' >> openra diff --git a/launch-game.sh b/launch-game.sh index 72838f4d3f..80ffa4af69 100755 --- a/launch-game.sh +++ b/launch-game.sh @@ -1,6 +1,6 @@ #!/bin/sh -# launch script (executed by Desura) -mono OpenRA.Game.exe "$@" +# Note: this relies on the non-standard -f flag implemented by gnu readlink +mono OpenRA.Game.exe Engine.LaunchPath="$(readlink -f $0)" "$@" if [ $? != 0 -a $? != 1 ] then ZENITY=`which zenity` || echo "OpenRA needs zenity installed to display a graphical error dialog. See ~/.openra. for log files." From 69a869fe436f07c57c65cb20d77a0fe7d3e3dd86 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 11 Feb 2017 16:45:09 +0000 Subject: [PATCH 7/8] Pass Engine.LaunchPath from OSX launcher. --- packaging/osx/buildpackage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/osx/buildpackage.sh b/packaging/osx/buildpackage.sh index 64430e8b10..f93fd95e1f 100755 --- a/packaging/osx/buildpackage.sh +++ b/packaging/osx/buildpackage.sh @@ -1,7 +1,7 @@ #!/bin/bash # OpenRA packaging script for Mac OSX -LAUNCHER_TAG="osx-launcher-20161223" +LAUNCHER_TAG="osx-launcher-20170211" if [ $# -ne "3" ]; then echo "Usage: `basename $0` tag files-dir outputdir" From f2e6601e07a73e43207bbb04f0143c63e1c60fcc Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 11 Feb 2017 16:25:36 +0000 Subject: [PATCH 8/8] Remove legacy MP lobby mod and replay switching logic. --- OpenRA.Game/Network/OrderManager.cs | 1 - OpenRA.Game/Network/UnitOrders.cs | 11 ---- .../Widgets/Logic/ConnectionLogic.cs | 54 +++++-------------- .../Widgets/Logic/Lobby/LobbyLogic.cs | 3 +- 4 files changed, 14 insertions(+), 55 deletions(-) diff --git a/OpenRA.Game/Network/OrderManager.cs b/OpenRA.Game/Network/OrderManager.cs index b103e4c7ae..3028a70e50 100644 --- a/OpenRA.Game/Network/OrderManager.cs +++ b/OpenRA.Game/Network/OrderManager.cs @@ -34,7 +34,6 @@ namespace OpenRA.Network public string ServerError = "Server is not responding"; public bool AuthenticationFailed = false; - public Manifest ServerMod = null; public ExternalMod ServerExternalMod = null; public int NetFrameNumber { get; private set; } diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index 798d430908..e3a2972292 100644 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -135,17 +135,6 @@ namespace OpenRA.Network var mod = Game.ModData.Manifest; var request = HandshakeRequest.Deserialize(order.TargetString); - Manifest serverMod; - if (request.Mod != mod.Id && - Game.Mods.TryGetValue(request.Mod, out serverMod) && - serverMod.Metadata.Version == request.Version) - { - // The ConnectionFailedLogic will prompt the user to switch mods - orderManager.ServerMod = serverMod; - orderManager.Connection.Dispose(); - break; - } - var externalKey = ExternalMod.MakeKey(request.Mod, request.Version); ExternalMod external; if ((request.Mod != mod.Id || request.Version != mod.Metadata.Version) diff --git a/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs index fae22d4c5c..a37505dad9 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ConnectionLogic.cs @@ -32,8 +32,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic { CloseWindow(); - var switchPanel = (om.ServerExternalMod != null || om.ServerMod != null) ? - "CONNECTION_SWITCHMOD_PANEL" : "CONNECTIONFAILED_PANEL"; + var switchPanel = om.ServerExternalMod != null ? "CONNECTION_SWITCHMOD_PANEL" : "CONNECTIONFAILED_PANEL"; Ui.OpenWindow(switchPanel, new WidgetArgs() { { "orderManager", om }, @@ -160,51 +159,24 @@ namespace OpenRA.Mods.Common.Widgets.Logic var abortButton = panel.Get("ABORT_BUTTON"); var switchButton = panel.Get("SWITCH_BUTTON"); - var modTitle = ""; - var modVersion = ""; - Sprite modIcon = null; - if (orderManager.ServerExternalMod != null) - { - modTitle = orderManager.ServerExternalMod.Title; - modVersion = orderManager.ServerExternalMod.Version; - modIcon = orderManager.ServerExternalMod.Icon; - } - else - { - modTitle = orderManager.ServerMod.Metadata.Title; - modVersion = orderManager.ServerMod.Metadata.Version; - modIcon = Game.Mods.Icons[orderManager.ServerMod.Id]; - } + var modTitle = orderManager.ServerExternalMod.Title; + var modVersion = orderManager.ServerExternalMod.Version; + var modIcon = orderManager.ServerExternalMod.Icon; switchButton.OnClick = () => { - // Note: Switching mods for directly launched replays is handled by the load screen - // and the replay browser prevents loading replays from other mods, so it doesn't look - // like this replay case is ever hit. - var replay = orderManager.Connection as ReplayConnection; - var launchCommand = replay != null ? - "Launch.Replay=" + replay.Filename : - "Launch.Connect=" + orderManager.Host + ":" + orderManager.Port; - - if (orderManager.ServerExternalMod != null) + var launchCommand = "Launch.Connect=" + orderManager.Host + ":" + orderManager.Port; + Game.SwitchToExternalMod(orderManager.ServerExternalMod, new[] { launchCommand }, () => { - Game.SwitchToExternalMod(orderManager.ServerExternalMod, new[] { launchCommand }, () => + orderManager.ServerError = "Failed to switch mod."; + Ui.CloseWindow(); + Ui.OpenWindow("CONNECTIONFAILED_PANEL", new WidgetArgs() { - orderManager.ServerError = "Failed to switch mod."; - Ui.CloseWindow(); - Ui.OpenWindow("CONNECTIONFAILED_PANEL", new WidgetArgs() - { - { "orderManager", orderManager }, - { "onAbort", onAbort }, - { "onRetry", onRetry } - }); + { "orderManager", orderManager }, + { "onAbort", onAbort }, + { "onRetry", onRetry } }); - } - else - { - Game.ModData.LoadScreen.Display(); - Game.InitializeMod(orderManager.ServerMod.Id, new Arguments(launchCommand)); - } + }); }; abortButton.Visible = onAbort != null; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs index 2e734f48a8..b9500e8aac 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs @@ -91,8 +91,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic Action onRetry = password => ConnectionLogic.Connect(om.Host, om.Port, password, onConnect, onExit); - var switchPanel = (om.ServerExternalMod != null || om.ServerMod != null) ? - "CONNECTION_SWITCHMOD_PANEL" : "CONNECTIONFAILED_PANEL"; + var switchPanel = om.ServerExternalMod != null ? "CONNECTION_SWITCHMOD_PANEL" : "CONNECTIONFAILED_PANEL"; Ui.OpenWindow(switchPanel, new WidgetArgs() { { "orderManager", om },