From ec7a32184ebb96d7663b735653286a1ce3c86664 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 13 Dec 2014 12:47:34 +1300 Subject: [PATCH 1/4] Move the mod-level initialisation code back into the load screen. --- OpenRA.Game/Game.cs | 40 +--------- OpenRA.Game/ModData.cs | 2 +- OpenRA.Mods.Cnc/CncLoadScreen.cs | 17 ++-- .../LoadScreens/BlankLoadScreen.cs | 78 +++++++++++++++++++ ...tLoadScreen.cs => LogoStripeLoadScreen.cs} | 13 +--- .../LoadScreens/ModChooserLoadScreen.cs | 2 +- .../LoadScreens/NullLoadScreen.cs | 39 ---------- OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 4 +- mods/d2k/mod.yaml | 2 +- mods/ra/mod.yaml | 2 +- mods/ts/mod.yaml | 2 +- 11 files changed, 97 insertions(+), 104 deletions(-) create mode 100644 OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs rename OpenRA.Mods.Common/LoadScreens/{DefaultLoadScreen.cs => LogoStripeLoadScreen.cs} (89%) delete mode 100644 OpenRA.Mods.Common/LoadScreens/NullLoadScreen.cs diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 1fbb6d8683..422edf20f6 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -331,45 +331,7 @@ namespace OpenRA Environment.Exit(0); } else - { - var window = args != null ? args.GetValue("Launch.Window", null) : null; - if (!string.IsNullOrEmpty(window)) - { - var installData = modData.Manifest.ContentInstaller; - if (installData.InstallerBackgroundWidget != null) - Ui.LoadWidget(installData.InstallerBackgroundWidget, Ui.Root, new WidgetArgs()); - - Widgets.Ui.OpenWindow(window, new WidgetArgs()); - } - else - { - modData.LoadScreen.StartGame(); - Settings.Save(); - var replay = args != null ? args.GetValue("Launch.Replay", null) : null; - if (!string.IsNullOrEmpty(replay)) - Game.JoinReplay(replay); - } - } - } - - public static void TestAndContinue() - { - Ui.ResetAll(); - var installData = modData.Manifest.ContentInstaller; - if (!installData.TestFiles.All(f => GlobalFileSystem.Exists(f))) - { - var args = new WidgetArgs() - { - { "continueLoading", () => InitializeMod(Game.Settings.Game.Mod, null) }, - }; - - if (installData.InstallerBackgroundWidget != null) - Ui.LoadWidget(installData.InstallerBackgroundWidget, Ui.Root, args); - - Ui.OpenWindow(installData.InstallerMenuWidget, args); - } - else - LoadShellMap(); + modData.LoadScreen.StartGame(args); } public static void LoadShellMap() diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index 3715a3fbe6..8dff28832a 100644 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -184,6 +184,6 @@ namespace OpenRA { void Init(Manifest m, Dictionary info); void Display(); - void StartGame(); + void StartGame(Arguments args); } } diff --git a/OpenRA.Mods.Cnc/CncLoadScreen.cs b/OpenRA.Mods.Cnc/CncLoadScreen.cs index 1f3d424737..d81ba334c9 100644 --- a/OpenRA.Mods.Cnc/CncLoadScreen.cs +++ b/OpenRA.Mods.Cnc/CncLoadScreen.cs @@ -12,12 +12,15 @@ using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using OpenRA.Graphics; +using OpenRA.Mods.Common.LoadScreens; using OpenRA.Widgets; namespace OpenRA.Mods.Cnc { - public sealed class CncLoadScreen : ILoadScreen + public sealed class CncLoadScreen : BlankLoadScreen { + readonly NullInputHandler nih = new NullInputHandler(); + Dictionary loadInfo; Stopwatch loadTimer = Stopwatch.StartNew(); Sheet sheet; @@ -27,9 +30,8 @@ namespace OpenRA.Mods.Cnc Sprite nodLogo, gdiLogo, evaLogo, brightBlock, dimBlock; Rectangle bounds; Renderer r; - readonly NullInputHandler nih = new NullInputHandler(); - public void Init(Manifest m, Dictionary info) + public override void Init(Manifest m, Dictionary info) { loadInfo = info; @@ -72,7 +74,7 @@ namespace OpenRA.Mods.Cnc string loadingText, versionText; float2 loadingPos, versionPos; - public void Display() + public override void Display() { if (r == null || loadTimer.Elapsed.TotalSeconds < 0.25) return; @@ -118,12 +120,7 @@ namespace OpenRA.Mods.Cnc r.EndFrame(nih); } - public void StartGame() - { - Game.TestAndContinue(); - } - - public void Dispose() + public override void Dispose() { if (sheet != null) sheet.Dispose(); diff --git a/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs new file mode 100644 index 0000000000..4074bc50a8 --- /dev/null +++ b/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs @@ -0,0 +1,78 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileSystem; +using OpenRA.Widgets; + +namespace OpenRA.Mods.Common.LoadScreens +{ + public class BlankLoadScreen : ILoadScreen + { + public virtual void Init(Manifest m, Dictionary info) { } + + public virtual void Display() + { + if (Game.Renderer == null) + return; + + // Draw a black screen + Game.Renderer.BeginFrame(int2.Zero, 1f); + Game.Renderer.EndFrame(new NullInputHandler()); + } + + void TestAndContinue() + { + Ui.ResetAll(); + var installData = Game.modData.Manifest.ContentInstaller; + if (!installData.TestFiles.All(f => GlobalFileSystem.Exists(f))) + { + var args = new WidgetArgs() + { + { "continueLoading", () => Game.InitializeMod(Game.Settings.Game.Mod, null) }, + }; + + if (installData.InstallerBackgroundWidget != null) + Ui.LoadWidget(installData.InstallerBackgroundWidget, Ui.Root, args); + + Ui.OpenWindow(installData.InstallerMenuWidget, args); + } + else + Game.LoadShellMap(); + + Game.Settings.Save(); + } + + public void StartGame(Arguments args) + { + var window = args != null ? args.GetValue("Launch.Window", null) : null; + if (!string.IsNullOrEmpty(window)) + { + var installData = Game.modData.Manifest.ContentInstaller; + if (installData.InstallerBackgroundWidget != null) + Ui.LoadWidget(installData.InstallerBackgroundWidget, Ui.Root, new WidgetArgs()); + + Ui.OpenWindow(window, new WidgetArgs()); + } + else + { + TestAndContinue(); + + var replay = args != null ? args.GetValue("Launch.Replay", null) : null; + if (!string.IsNullOrEmpty(replay)) + Game.JoinReplay(replay); + } + } + + public virtual void Dispose() { } + } +} + diff --git a/OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs similarity index 89% rename from OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs rename to OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs index c04fa6738d..ab18d9b026 100644 --- a/OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs @@ -16,7 +16,7 @@ using OpenRA.Widgets; namespace OpenRA.Mods.Common.LoadScreens { - public sealed class DefaultLoadScreen : ILoadScreen + public sealed class LogoStripeLoadScreen : BlankLoadScreen { Stopwatch lastUpdate = Stopwatch.StartNew(); Renderer r; @@ -27,7 +27,7 @@ namespace OpenRA.Mods.Common.LoadScreens Sprite stripe, logo; string[] messages; - public void Init(Manifest m, Dictionary info) + public override void Init(Manifest m, Dictionary info) { // Avoid standard loading mechanisms so we // can display the loadscreen as early as possible @@ -43,7 +43,7 @@ namespace OpenRA.Mods.Common.LoadScreens logoPos = new float2(r.Resolution.Width / 2 - 128, r.Resolution.Height / 2 - 128); } - public void Display() + public override void Display() { if (r == null) return; @@ -66,12 +66,7 @@ namespace OpenRA.Mods.Common.LoadScreens r.EndFrame(new NullInputHandler()); } - public void StartGame() - { - Game.TestAndContinue(); - } - - public void Dispose() + public override void Dispose() { if (sheet != null) sheet.Dispose(); diff --git a/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs index ccc18e204e..bfea1e2aee 100644 --- a/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs @@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.LoadScreens r.EndFrame(new NullInputHandler()); } - public void StartGame() + public void StartGame(Arguments args) { Ui.LoadWidget("MODCHOOSER", Ui.Root, new WidgetArgs()); } diff --git a/OpenRA.Mods.Common/LoadScreens/NullLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/NullLoadScreen.cs deleted file mode 100644 index ce0c7b149c..0000000000 --- a/OpenRA.Mods.Common/LoadScreens/NullLoadScreen.cs +++ /dev/null @@ -1,39 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2014 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. For more information, - * see COPYING. - */ -#endregion - -using System.Collections.Generic; -using OpenRA.Widgets; - -namespace OpenRA.Mods.Common.LoadScreens -{ - public sealed class NullLoadScreen : ILoadScreen - { - public void Init(Manifest m, Dictionary info) { } - - public void Display() - { - if (Game.Renderer == null) - return; - - // Draw a black screen - Game.Renderer.BeginFrame(int2.Zero, 1f); - Game.Renderer.EndFrame(new NullInputHandler()); - } - - public void StartGame() - { - Ui.ResetAll(); - } - - public void Dispose() - { - } - } -} diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 4ed8a1ab5a..7401ff88fb 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -78,9 +78,7 @@ - - @@ -239,6 +237,8 @@ + + diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 6d3018f755..7a47f5d1db 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -117,7 +117,7 @@ Movies: Translations: ./mods/d2k/languages/english.yaml -LoadScreen: DefaultLoadScreen +LoadScreen: LogoStripeLoadScreen Image: ./mods/d2k/uibits/loadscreen.png Text: Filling Crates..., Breeding Sandworms... diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 57294f8cc5..bbdff772b3 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -132,7 +132,7 @@ Movies: Translations: ./mods/ra/languages/english.yaml -LoadScreen: DefaultLoadScreen +LoadScreen: LogoStripeLoadScreen Image: ./mods/ra/uibits/loadscreen.png Text: Filling Crates..., Charging Capacitors..., Reticulating Splines..., Planting Trees..., Building Bridges..., Aging Empires..., Compiling EVA..., Constructing Pylons..., Activating Skynet..., Splitting Atoms... diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index b0d26fefb1..997fe876d2 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -162,7 +162,7 @@ Movies: Translations: ./mods/ts/languages/english.yaml -LoadScreen: DefaultLoadScreen +LoadScreen: LogoStripeLoadScreen Image: ./mods/ts/uibits/loadscreen.png Text: Updating EVA installation..., Changing perspective... From 7bfffeadc23e4edd1b26d25a203d4d9dc5bc8632 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 13 Dec 2014 13:34:36 +1300 Subject: [PATCH 2/4] Simplify mod content installation plumbing. --- OpenRA.Game/InstallUtils.cs | 5 +- .../LoadScreens/BlankLoadScreen.cs | 71 +++++++++---------- .../Widgets/Logic/MusicPlayerLogic.cs | 2 +- mods/cnc/mod.yaml | 5 +- mods/d2k/mod.yaml | 3 +- mods/ra/mod.yaml | 3 +- mods/ts/mod.yaml | 3 +- 7 files changed, 46 insertions(+), 46 deletions(-) diff --git a/OpenRA.Game/InstallUtils.cs b/OpenRA.Game/InstallUtils.cs index b3a2449f7f..95f89b0127 100644 --- a/OpenRA.Game/InstallUtils.cs +++ b/OpenRA.Game/InstallUtils.cs @@ -20,8 +20,9 @@ namespace OpenRA { public class InstallData { - public readonly string InstallerMenuWidget = null; - public readonly string InstallerBackgroundWidget = null; + public readonly string MenuWidget = null; + public readonly string MusicMenuWidget = null; + public readonly string BackgroundWidget = null; public readonly string[] TestFiles = {}; public readonly string[] DiskTestFiles = {}; public readonly string PackageToExtractFromCD = null; diff --git a/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs index 4074bc50a8..1649fc3986 100644 --- a/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs @@ -29,50 +29,45 @@ namespace OpenRA.Mods.Common.LoadScreens Game.Renderer.EndFrame(new NullInputHandler()); } - void TestAndContinue() - { - Ui.ResetAll(); - var installData = Game.modData.Manifest.ContentInstaller; - if (!installData.TestFiles.All(f => GlobalFileSystem.Exists(f))) - { - var args = new WidgetArgs() - { - { "continueLoading", () => Game.InitializeMod(Game.Settings.Game.Mod, null) }, - }; - - if (installData.InstallerBackgroundWidget != null) - Ui.LoadWidget(installData.InstallerBackgroundWidget, Ui.Root, args); - - Ui.OpenWindow(installData.InstallerMenuWidget, args); - } - else - Game.LoadShellMap(); - - Game.Settings.Save(); - } - public void StartGame(Arguments args) { - var window = args != null ? args.GetValue("Launch.Window", null) : null; - if (!string.IsNullOrEmpty(window)) - { - var installData = Game.modData.Manifest.ContentInstaller; - if (installData.InstallerBackgroundWidget != null) - Ui.LoadWidget(installData.InstallerBackgroundWidget, Ui.Root, new WidgetArgs()); + Ui.ResetAll(); + Game.Settings.Save(); - Ui.OpenWindow(window, new WidgetArgs()); - } - else - { - TestAndContinue(); + // Check whether the mod content is installed + // TODO: The installation code has finally been beaten into shape, so we can + // finally move it all into the planned "Manage Content" panel in the modchooser mod. + var installData = Game.modData.Manifest.ContentInstaller; + var installModContent = !installData.TestFiles.All(f => GlobalFileSystem.Exists(f)); + var installModMusic = args != null && args.Contains("Install.Music"); - var replay = args != null ? args.GetValue("Launch.Replay", null) : null; - if (!string.IsNullOrEmpty(replay)) - Game.JoinReplay(replay); + if (installModContent || installModMusic) + { + var widgetArgs = new WidgetArgs() + { + { "continueLoading", () => Game.InitializeMod(Game.Settings.Game.Mod, args) }, + }; + + if (installData.BackgroundWidget != null) + Ui.LoadWidget(installData.BackgroundWidget, Ui.Root, widgetArgs); + + var menu = installModContent ? installData.MenuWidget : installData.MusicMenuWidget; + Ui.OpenWindow(menu, widgetArgs); + + return; } + + var replay = args != null ? args.GetValue("Launch.Replay", null) : null; + if (!string.IsNullOrEmpty(replay)) + { + Game.JoinReplay(replay); + return; + } + + Game.LoadShellMap(); + Game.Settings.Save(); } public virtual void Dispose() { } } -} - +} \ No newline at end of file diff --git a/OpenRA.Mods.RA/Widgets/Logic/MusicPlayerLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/MusicPlayerLogic.cs index c3d1252729..692b1ede52 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/MusicPlayerLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/MusicPlayerLogic.cs @@ -85,7 +85,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (installButton != null) { installButton.IsDisabled = () => world == null || !world.IsShellmap; - var args = new string[] { "Launch.Window=INSTALL_MUSIC_PANEL" }; + var args = new string[] { "Install.Music=true" }; installButton.OnClick = () => { Game.modData.LoadScreen.Display(); // HACK: prevent a flicker when transitioning to the installation dialog diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 7cdb8baf1d..d9f10c2634 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -138,8 +138,9 @@ LoadScreen: CncLoadScreen ContentInstaller: TestFiles: conquer.mix, desert.mix, sounds.mix, speech.mix, temperat.mix, tempicnh.mix, winter.mix - InstallerBackgroundWidget: INSTALL_BACKGROUND - InstallerMenuWidget: INSTALL_PANEL + BackgroundWidget: INSTALL_BACKGROUND + MenuWidget: INSTALL_PANEL + MusicMenuWidget: INSTALL_MUSIC_PANEL FilesToCopy: CONQUER.MIX, DESERT.MIX, SCORES.MIX, SOUNDS.MIX, TEMPERAT.MIX, WINTER.MIX FilesToExtract: speech.mix, tempicnh.mix, transit.mix PackageMirrorList: http://www.openra.net/packages/cnc-mirrors.txt diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 7a47f5d1db..fa729a95e3 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -122,7 +122,8 @@ LoadScreen: LogoStripeLoadScreen Text: Filling Crates..., Breeding Sandworms... ContentInstaller: - InstallerMenuWidget: INSTALL_PANEL + MenuWidget: INSTALL_PANEL + MusicMenuWidget: INSTALL_MUSIC_PANEL # TODO: check if DATA.R8 is at 1.03 patch level with 4840 frames TestFiles: BLOXBASE.R8, BLOXBAT.R8, BLOXBGBS.R8, BLOXICE.R8, BLOXTREE.R8, BLOXWAST.R8, DATA.R8, SOUND.RS PackageMirrorList: http://www.openra.net/packages/d2k-103-mirrors.txt diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index bbdff772b3..7a888b3089 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -137,7 +137,8 @@ LoadScreen: LogoStripeLoadScreen Text: Filling Crates..., Charging Capacitors..., Reticulating Splines..., Planting Trees..., Building Bridges..., Aging Empires..., Compiling EVA..., Constructing Pylons..., Activating Skynet..., Splitting Atoms... ContentInstaller: - InstallerMenuWidget: INSTALL_PANEL + MenuWidget: INSTALL_PANEL + MusicMenuWidget: INSTALL_MUSIC_PANEL TestFiles: allies.mix, conquer.mix, interior.mix, redalert.mix, russian.mix, snow.mix, sounds.mix, temperat.mix PackageMirrorList: http://www.openra.net/packages/ra-mirrors.txt DiskTestFiles: MAIN.MIX, INSTALL/REDALERT.MIX diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index 997fe876d2..78f54919b5 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -167,7 +167,8 @@ LoadScreen: LogoStripeLoadScreen Text: Updating EVA installation..., Changing perspective... ContentInstaller: - InstallerMenuWidget: INSTALL_PANEL + MenuWidget: INSTALL_PANEL + MusicMenuWidget: INSTALL_MUSIC_PANEL TestFiles: cache.mix, conquer.mix, isosnow.mix, isotemp.mix, local.mix, sidec01.mix, sidec02.mix, sno.mix, snow.mix, sounds.mix, speech01.mix, tem.mix, temperat.mix PackageMirrorList: http://www.openra.net/packages/ts-mirrors.txt DiskTestFiles: MULTI.MIX, INSTALL/TIBSUN.MIX From 660f6682ff00b21f07b0ae30d37c6d6d11507462 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 13 Dec 2014 14:33:54 +1300 Subject: [PATCH 3/4] Add Launch.Connect parameter for launching directly to a server. --- OpenRA.Game/Game.cs | 9 +++++++++ .../LoadScreens/BlankLoadScreen.cs | 18 ++++++++++++++++++ OpenRA.Mods.RA/Widgets/Logic/MainMenuLogic.cs | 16 +++++++++++++++- .../Widgets/Logic/ServerBrowserLogic.cs | 14 +++++++++++++- 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 422edf20f6..b3afb462a6 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -86,10 +86,16 @@ namespace OpenRA public const int Timestep = 40; public const int TimestepJankThreshold = 250; // Don't catch up for delays larger than 250ms + public static event Action OnRemoteDirectConnect = (a, b) => { }; public static event Action ConnectionStateChanged = _ => { }; static ConnectionState lastConnectionState = ConnectionState.PreConnecting; public static int LocalClientId { get { return orderManager.Connection.LocalClientId; } } + public static void RemoteDirectConnect(string host, int port) + { + OnRemoteDirectConnect(host, port); + } + // Hacky workaround for orderManager visibility public static Widget OpenWindow(World world, string widget) { @@ -261,6 +267,9 @@ namespace OpenRA LobbyInfoChanged = () => { }; ConnectionStateChanged = om => { }; BeforeGameStart = () => { }; + OnRemoteDirectConnect = (a, b) => { }; + delayedActions = new ActionQueue(); + Ui.ResetAll(); if (worldRenderer != null) diff --git a/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs index 1649fc3986..a8fcaa3e1a 100644 --- a/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.FileSystem; using OpenRA.Widgets; +using OpenRA.Mods.Common.Widgets.Logic; namespace OpenRA.Mods.Common.LoadScreens { @@ -57,6 +58,23 @@ namespace OpenRA.Mods.Common.LoadScreens return; } + // Join a server directly + var connect = args != null ? args.GetValue("Launch.Connect", null) : null; + if (!string.IsNullOrEmpty(connect)) + { + var parts = connect.Split(':'); + + if (parts.Length == 2) + { + var host = parts[0]; + var port = Exts.ParseIntegerInvariant(parts[1]); + Game.LoadShellMap(); + Game.RemoteDirectConnect(host, port); + return; + } + } + + // Load a replay directly var replay = args != null ? args.GetValue("Launch.Replay", null) : null; if (!string.IsNullOrEmpty(replay)) { diff --git a/OpenRA.Mods.RA/Widgets/Logic/MainMenuLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/MainMenuLogic.cs index 43d78833cf..d037ee8bf3 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/MainMenuLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/MainMenuLogic.cs @@ -48,7 +48,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic Ui.OpenWindow("SERVERBROWSER_PANEL", new WidgetArgs { { "onStart", RemoveShellmapUI }, - { "onExit", () => menuType = MenuType.Main } + { "onExit", () => menuType = MenuType.Main }, + { "directConnectHost", null }, + { "directConnectPort", 0 }, }); }; @@ -173,6 +175,18 @@ namespace OpenRA.Mods.RA.Widgets.Logic newsButton.IsHighlighted = () => newsHighlighted && Game.LocalTick % 50 < 25; } + + Game.OnRemoteDirectConnect += (host, port) => + { + menuType = MenuType.None; + Ui.OpenWindow("SERVERBROWSER_PANEL", new WidgetArgs + { + { "onStart", RemoveShellmapUI }, + { "onExit", () => menuType = MenuType.Main }, + { "directConnectHost", host }, + { "directConnectPort", port }, + }); + }; } void SetNewsStatus(string message) diff --git a/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs index 114f823c0e..96bf17574f 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/ServerBrowserLogic.cs @@ -51,7 +51,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic } [ObjectCreator.UseCtor] - public ServerBrowserLogic(Widget widget, Action onStart, Action onExit) + public ServerBrowserLogic(Widget widget, Action onStart, Action onExit, string directConnectHost, int directConnectPort) { panel = widget; this.onStart = onStart; @@ -116,6 +116,18 @@ namespace OpenRA.Mods.RA.Widgets.Logic } RefreshServerList(); + + if (directConnectHost != null) + { + // The connection window must be opened at the end of the tick for the widget hierarchy to + // work out, but we also want to prevent the server browser from flashing visible for one tick. + widget.Visible = false; + Game.RunAfterTick(() => + { + ConnectionLogic.Connect(directConnectHost, directConnectPort, "", OpenLobby, DoNothing); + widget.Visible = true; + }); + } } void RefreshServerList() From 96b5b1fc660d929a39e88acefcea9ae5d627effe Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 13 Dec 2014 16:00:29 +1300 Subject: [PATCH 4/4] Automatically switch mods when connecting to a server / replay. --- OpenRA.Game/Network/OrderManager.cs | 11 +++++++++++ OpenRA.Game/Network/ReplayConnection.cs | 3 +++ OpenRA.Game/Network/UnitOrders.cs | 21 +++++++++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/OpenRA.Game/Network/OrderManager.cs b/OpenRA.Game/Network/OrderManager.cs index 56f221af6e..b4dd17b7f1 100644 --- a/OpenRA.Game/Network/OrderManager.cs +++ b/OpenRA.Game/Network/OrderManager.cs @@ -51,6 +51,8 @@ namespace OpenRA.Network public readonly ReadOnlyList ChatCache; + bool disposed; + static void OutOfSync(int frame) { throw new InvalidOperationException("Out of sync in frame {0}.\n Compare syncreport.log with other players.".F(frame)); @@ -122,8 +124,16 @@ namespace OpenRA.Network }); foreach (var p in immediatePackets) + { foreach (var o in p.Second.ToOrderList(World)) + { UnitOrders.ProcessOrder(this, World, p.First, o); + + // A mod switch or other event has pulled the ground from beneath us + if (disposed) + return; + } + } } Dictionary syncForFrame = new Dictionary(); @@ -213,6 +223,7 @@ namespace OpenRA.Network public void Dispose() { + disposed = true; if (Connection != null) Connection.Dispose(); } diff --git a/OpenRA.Game/Network/ReplayConnection.cs b/OpenRA.Game/Network/ReplayConnection.cs index 32afbfad6a..5924ff7b6b 100755 --- a/OpenRA.Game/Network/ReplayConnection.cs +++ b/OpenRA.Game/Network/ReplayConnection.cs @@ -33,9 +33,12 @@ namespace OpenRA.Network public readonly int TickCount; public readonly bool IsValid; public readonly Session LobbyInfo; + public readonly string Filename; public ReplayConnection(string replayFilename) { + Filename = replayFilename; + // Parse replay data into a struct that can be fed to the game in chunks // to avoid issues with all immediate orders being resolved on the first tick. using (var rs = File.OpenRead(replayFilename)) diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index a7ff1e32a3..4a1d1d2818 100644 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -119,10 +119,27 @@ namespace OpenRA.Network case "HandshakeRequest": { - // TODO: Switch to the server's mod if we have it - // Otherwise send the handshake with our current settings and let the server reject us + // Switch to the server's mod if we need and are able to var mod = Game.modData.Manifest.Mod; + var request = HandshakeRequest.Deserialize(order.TargetString); + ModMetadata serverMod; + if (request.Mod != mod.Id && + ModMetadata.AllMods.TryGetValue(request.Mod, out serverMod) && + serverMod.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)); + + break; + } + + // Otherwise send the handshake with our current settings and let the server reject us var info = new Session.Client() { Name = Game.Settings.Player.Name,