From 706d3ae52a31d7fdb606d35ca2ee1eb0d53af516 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 4 Jul 2015 12:12:44 +0100 Subject: [PATCH] Move dedicated server code to OpenRA.Server.exe --- Makefile | 29 +++++- OpenRA.Game/Game.cs | 45 +-------- OpenRA.Game/Renderer.cs | 10 +- OpenRA.Game/Server/Server.cs | 17 ++-- OpenRA.Game/Settings.cs | 6 -- .../ServerTraits/PlayerPinger.cs | 2 +- OpenRA.Server/OpenRA.Server.csproj | 99 +++++++++++++++++++ OpenRA.Server/Program.cs | 58 +++++++++++ OpenRA.sln | 6 ++ launch-dedicated.sh | 4 +- launch-game.sh | 2 +- packaging/package-all.sh | 2 +- packaging/windows/OpenRA.nsi | 2 + 13 files changed, 212 insertions(+), 70 deletions(-) create mode 100644 OpenRA.Server/OpenRA.Server.csproj create mode 100644 OpenRA.Server/Program.cs diff --git a/Makefile b/Makefile index 17a7f27fdf..a9600dcb0f 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,7 @@ INSTALL_PROGRAM = $(INSTALL) -m755 INSTALL_DATA = $(INSTALL) -m644 # program targets -CORE = pdefault pnull game utility +CORE = pdefault pnull game utility server TOOLS = gamemonitor VERSION = $(shell git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null || echo git-`git rev-parse --short HEAD`) @@ -231,6 +231,9 @@ check: utility mods @echo @echo "Checking for explicit interface violations..." @mono --debug OpenRA.Utility.exe all --check-explicit-interfaces + @echo + @echo "Checking for code style violations in OpenRA.Server..." + @mono --debug OpenRA.Utility.exe ra --check-code-style OpenRA.Server NUNIT_CONSOLE := $(shell test -f thirdparty/download/nunit3-console.exe && echo mono thirdparty/download/nunit3-console.exe || \ which nunit3-console 2>/dev/null || which nunit2-console 2>/dev/null || which nunit-console 2>/dev/null) @@ -286,6 +289,15 @@ utility_LIBS = $(COMMON_LIBS) $(utility_DEPS) thirdparty/download/ICSharpCode.Sh PROGRAMS += utility utility: $(utility_TARGET) +# Dedicated server +server_SRCS := $(shell find OpenRA.Server/ -iname '*.cs') +server_TARGET = OpenRA.Server.exe +server_KIND = exe +server_DEPS = $(game_TARGET) +server_LIBS = $(COMMON_LIBS) $(server_DEPS) +PROGRAMS += server +server: $(server_TARGET) + # Patches binary headers to work around a mono bug fixheader.exe: packaging/fixheader.cs @echo CSC fixheader.exe @@ -315,7 +327,7 @@ $(foreach prog,$(PROGRAMS),$(eval $(call BUILD_ASSEMBLY,$(prog)))) # default: core -core: game platforms mods utility +core: game platforms mods utility server tools: gamemonitor @@ -465,9 +477,22 @@ endif @$(INSTALL_PROGRAM) -m +rx openra "$(BIN_INSTALL_DIR)" @-$(RM) openra + @echo "#!/bin/sh" > openra-server + @echo 'cd "$(gameinstalldir)"' >> openra-server +ifeq ($(DEBUG), $(filter $(DEBUG),false no n off 0)) + @echo 'mono OpenRA.Server.exe "$$@"' >> openra-server +else + @echo 'mono --debug OpenRA.Server.exe "$$@"' >> openra-server +endif + + @$(INSTALL_DIR) "$(BIN_INSTALL_DIR)" + @$(INSTALL_PROGRAM) -m +rx openra-server "$(BIN_INSTALL_DIR)" + @-$(RM) openra-server + uninstall: @-$(RM_R) "$(DATA_INSTALL_DIR)" @-$(RM_F) "$(BIN_INSTALL_DIR)/openra" + @-$(RM_F) "$(BIN_INSTALL_DIR)/openra-server" @-$(RM_F) "$(DESTDIR)$(datadir)/applications/openra.desktop" @-$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/16x16/apps/openra.png" @-$(RM_F) "$(DESTDIR)$(datadir)/icons/hicolor/32x32/apps/openra.png" diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 373fb11504..64031fe1e3 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -279,7 +279,7 @@ namespace OpenRA } } - Sound = new Sound(Settings.Server.Dedicated ? "Null" : Settings.Sound.Engine); + Sound = new Sound(Settings.Sound.Engine); GlobalChat = new GlobalChat(); @@ -341,17 +341,11 @@ namespace OpenRA Sound.StopVideo(); - ModData = new ModData(mod, !Settings.Server.Dedicated); + ModData = new ModData(mod, true); using (new PerfTimer("LoadMaps")) ModData.MapCache.LoadMaps(); - if (Settings.Server.Dedicated) - { - RunDedicatedServer(); - Environment.Exit(0); - } - var installData = ModData.Manifest.Get(); var isModContentInstalled = installData.TestFiles.All(f => File.Exists(Platform.ResolvePath(f))); @@ -398,37 +392,6 @@ namespace OpenRA ModData.LoadScreen.StartGame(args); } - public static void RunDedicatedServer() - { - while (true) - { - Settings.Server.Map = ModData.MapCache.ChooseInitialMap(Settings.Server.Map, CosmeticRandom); - Settings.Save(); - CreateServer(Settings.Server.Clone()); - - while (true) - { - Thread.Sleep(100); - - if (server.State == Server.ServerState.GameStarted && server.Conns.Count < 1) - { - Console.WriteLine("No one is playing, shutting down..."); - server.Shutdown(); - break; - } - } - - if (Settings.Server.DedicatedLoop) - { - Console.WriteLine("Starting a new server instance..."); - ModData.MapCache.LoadMaps(); - continue; - } - - break; - } - } - public static void LoadEditor(string mapUid) { StartGame(mapUid, WorldType.Editor); @@ -811,7 +774,7 @@ namespace OpenRA public static void CreateServer(ServerSettings settings) { - server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, ModData); + server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, ModData, false); } public static int CreateLocalServer(string map) @@ -824,7 +787,7 @@ namespace OpenRA AllowPortForward = false }; - server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, ModData); + server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, ModData, false); return server.Port; } diff --git a/OpenRA.Game/Renderer.cs b/OpenRA.Game/Renderer.cs index 04232b179f..4690dae2e4 100644 --- a/OpenRA.Game/Renderer.cs +++ b/OpenRA.Game/Renderer.cs @@ -50,16 +50,12 @@ namespace OpenRA { var resolution = GetResolution(graphicSettings); - var rendererName = serverSettings.Dedicated ? "Null" : graphicSettings.Renderer; + var rendererName = graphicSettings.Renderer; var rendererPath = Platform.ResolvePath(Path.Combine(".", "OpenRA.Platforms." + rendererName + ".dll")); Device = CreateDevice(Assembly.LoadFile(rendererPath), resolution.Width, resolution.Height, graphicSettings.Mode); - - if (!serverSettings.Dedicated) - { - TempBufferSize = graphicSettings.BatchSize; - SheetSize = graphicSettings.SheetSize; - } + TempBufferSize = graphicSettings.BatchSize; + SheetSize = graphicSettings.SheetSize; WorldSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("shp")); WorldRgbaSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("rgba")); diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index 6271ecdc01..3806c40c84 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -38,6 +38,7 @@ namespace OpenRA.Server public readonly IPAddress Ip; public readonly int Port; public readonly MersenneTwister Random = new MersenneTwister(); + public readonly bool Dedicated; // Valid player connections public List Conns = new List(); @@ -117,7 +118,7 @@ namespace OpenRA.Server t.GameEnded(this); } - public Server(IPEndPoint endpoint, ServerSettings settings, ModData modData) + public Server(IPEndPoint endpoint, ServerSettings settings, ModData modData, bool dedicated) { Log.AddChannel("server", "server.log"); @@ -126,7 +127,7 @@ namespace OpenRA.Server var localEndpoint = (IPEndPoint)listener.LocalEndpoint; Ip = localEndpoint.Address; Port = localEndpoint.Port; - + Dedicated = dedicated; Settings = settings; Settings.Name = OpenRA.Settings.SanitizedServerName(Settings.Name); @@ -148,7 +149,7 @@ namespace OpenRA.Server RandomSeed = randomSeed, Map = settings.Map, ServerName = settings.Name, - Dedicated = settings.Dedicated, + Dedicated = dedicated, DisableSingleplayer = settings.DisableSinglePlayer, } }; @@ -380,7 +381,7 @@ namespace OpenRA.Server // Send initial ping SendOrderTo(newConn, "Ping", Game.RunTime.ToString(CultureInfo.InvariantCulture)); - if (Settings.Dedicated) + if (Dedicated) { var motdFile = Platform.ResolvePath("^", "motd.txt"); if (!File.Exists(motdFile)) @@ -490,7 +491,7 @@ namespace OpenRA.Server { DispatchOrdersToClients(null, 0, new ServerOrder("Message", text).Serialize()); - if (Settings.Dedicated) + if (Dedicated) Console.WriteLine("[{0}] {1}".F(DateTime.Now.ToString(Settings.TimestampFormat), text)); } @@ -587,7 +588,7 @@ namespace OpenRA.Server // Client was the server admin // TODO: Reassign admin for game in progress via an order - if (LobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers) + if (Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers) { // Remove any bots controlled by the admin LobbyInfo.Clients.RemoveAll(c => c.Bot != null && c.BotControllerClientIndex == toDrop.PlayerIndex); @@ -607,10 +608,10 @@ namespace OpenRA.Server if (!Conns.Any()) TempBans.Clear(); - if (Conns.Any() || LobbyInfo.GlobalSettings.Dedicated) + if (Conns.Any() || Dedicated) SyncLobbyClients(); - if (!LobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin) + if (!Dedicated && dropClient.IsAdmin) Shutdown(); } diff --git a/OpenRA.Game/Settings.cs b/OpenRA.Game/Settings.cs index ce24c64b20..6d9e967688 100644 --- a/OpenRA.Game/Settings.cs +++ b/OpenRA.Game/Settings.cs @@ -65,12 +65,6 @@ namespace OpenRA [Desc("Value in milliseconds when to terminate the game. Needs to be at least 10000 (10 s) to enable the timer.")] public int TimeOut = 0; - [Desc("Run in headless mode with an empty renderer and without sound output.")] - public bool Dedicated = false; - - [Desc("Automatically restart when a game ends. Disable this when something else already takes care about it.")] - public bool DedicatedLoop = true; - [Desc("Disallow games where only one player plays with bots.")] public bool DisableSinglePlayer = false; diff --git a/OpenRA.Mods.Common/ServerTraits/PlayerPinger.cs b/OpenRA.Mods.Common/ServerTraits/PlayerPinger.cs index 7374816316..a7cfd7db10 100644 --- a/OpenRA.Mods.Common/ServerTraits/PlayerPinger.cs +++ b/OpenRA.Mods.Common/ServerTraits/PlayerPinger.cs @@ -36,7 +36,7 @@ namespace OpenRA.Mods.Common.Server lastPing = Game.RunTime; // Ignore client timeout in singleplayer games to make debugging easier - if (server.LobbyInfo.IsSinglePlayer && !server.Settings.Dedicated) + if (server.LobbyInfo.IsSinglePlayer && !server.Dedicated) foreach (var c in server.Conns.ToList()) server.SendOrderTo(c, "Ping", Game.RunTime.ToString()); else diff --git a/OpenRA.Server/OpenRA.Server.csproj b/OpenRA.Server/OpenRA.Server.csproj new file mode 100644 index 0000000000..8a40e94b90 --- /dev/null +++ b/OpenRA.Server/OpenRA.Server.csproj @@ -0,0 +1,99 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {76F621A1-3D8E-4A99-9F7E-B071EB657817} + Exe + Properties + OpenRA.Server + OpenRA.Server + 512 + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + ..\ + DEBUG;TRACE + prompt + false + AllRules.ruleset + x86 + true + + + true + ..\ + TRACE + true + pdbonly + x86 + false + prompt + AllRules.ruleset + true + + + + + 4.0 + + + + + + + + + {0DFB103F-2962-400F-8C6D-E2C28CCBA633} + OpenRA.Game + False + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/OpenRA.Server/Program.cs b/OpenRA.Server/Program.cs new file mode 100644 index 0000000000..b843618dde --- /dev/null +++ b/OpenRA.Server/Program.cs @@ -0,0 +1,58 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 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; +using System.Net; +using System.Threading; +using OpenRA.Support; + +namespace OpenRA.Server +{ + class Program + { + static void Main(string[] args) + { + Log.AddChannel("debug", "dedicated-debug.log"); + Log.AddChannel("perf", "dedicated-perf.log"); + Log.AddChannel("server", "dedicated-server.log"); + + // HACK: The engine code assumes that Game.Settings is set. + // This isn't nearly as bad as ModData, but is still not very nice. + Game.InitializeSettings(new Arguments(args)); + var settings = Game.Settings.Server; + + // HACK: The engine code *still* assumes that Game.ModData is set + var mod = Game.Settings.Game.Mod; + var modData = Game.ModData = new ModData(mod, false); + modData.MapCache.LoadMaps(); + + settings.Map = modData.MapCache.ChooseInitialMap(settings.Map, new MersenneTwister()); + + Console.WriteLine("Starting dedicated server for mod: " + mod); + while (true) + { + var server = new Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, modData, true); + + while (true) + { + Thread.Sleep(1000); + if (server.State == ServerState.GameStarted && server.Conns.Count < 1) + { + Console.WriteLine("No one is playing, shutting down..."); + server.Shutdown(); + break; + } + } + + Console.WriteLine("Starting a new server instance..."); + } + } + } +} diff --git a/OpenRA.sln b/OpenRA.sln index 9d60c43a25..dd0679d53e 100644 --- a/OpenRA.sln +++ b/OpenRA.sln @@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRA.Utility", "OpenRA.Ut EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRA.Platforms.Null", "OpenRA.Platforms.Null\OpenRA.Platforms.Null.csproj", "{0C4AEC1A-E7D5-4114-8CCD-3EEC82872981}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRA.Server", "OpenRA.Server\OpenRA.Server.csproj", "{76F621A1-3D8E-4A99-9F7E-B071EB657817}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRA.Mods.D2k", "OpenRA.Mods.D2k\OpenRA.Mods.D2k.csproj", "{C0B0465C-6BE2-409C-8770-3A9BF64C4344}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRA.Mods.TS", "OpenRA.Mods.TS\OpenRA.Mods.TS.csproj", "{5457CBF5-4CE4-421E-A8BF-9FD6C9732E1D}" @@ -127,6 +129,10 @@ Global {F33337BE-CB69-4B24-850F-07D23E408DDF}.Debug|x86.Build.0 = Debug|x86 {F33337BE-CB69-4B24-850F-07D23E408DDF}.Release|x86.ActiveCfg = Release|x86 {F33337BE-CB69-4B24-850F-07D23E408DDF}.Release|x86.Build.0 = Release|x86 + {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Debug|x86.ActiveCfg = Debug|x86 + {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Debug|x86.Build.0 = Debug|x86 + {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Release|x86.ActiveCfg = Release|x86 + {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Release|x86.Build.0 = Release|x86 {0C4AEC1A-E7D5-4114-8CCD-3EEC82872981}.Debug|x86.ActiveCfg = Debug|x86 {0C4AEC1A-E7D5-4114-8CCD-3EEC82872981}.Debug|x86.Build.0 = Debug|x86 {0C4AEC1A-E7D5-4114-8CCD-3EEC82872981}.Release|x86.ActiveCfg = Release|x86 diff --git a/launch-dedicated.sh b/launch-dedicated.sh index 52505a9f67..747b651f25 100755 --- a/launch-dedicated.sh +++ b/launch-dedicated.sh @@ -8,15 +8,13 @@ Name="${Name:-"Dedicated Server"}" Mod="${Mod:-"ra"}" -Dedicated="True" -DedicatedLoop="True" ListenPort="${ListenPort:-"1234"}" ExternalPort="${ExternalPort:-"1234"}" AdvertiseOnline="${AdvertiseOnline:-"True"}" AllowPortForward="${AllowPortForward:-"False"}" while true; do - mono --debug OpenRA.Game.exe Game.Mod=$Mod Server.Dedicated=$Dedicated Server.DedicatedLoop=$DedicatedLoop \ + mono --debug OpenRA.Server.exe Game.Mod=$Mod \ Server.Name="$Name" Server.ListenPort=$ListenPort Server.ExternalPort=$ExternalPort \ Server.AdvertiseOnline=$AdvertiseOnline Server.AllowPortForward=$AllowPortForward done diff --git a/launch-game.sh b/launch-game.sh index 6bb036e790..72838f4d3f 100755 --- a/launch-game.sh +++ b/launch-game.sh @@ -1,6 +1,6 @@ #!/bin/sh # launch script (executed by Desura) -mono OpenRA.Game.exe Server.Dedicated=False Server.DedicatedLoop=False "$@" +mono OpenRA.Game.exe "$@" if [ $? != 0 -a $? != 1 ] then ZENITY=`which zenity` || echo "OpenRA needs zenity installed to display a graphical error dialog. See ~/.openra. for log files." diff --git a/packaging/package-all.sh b/packaging/package-all.sh index 1345600f1e..073477dc5d 100755 --- a/packaging/package-all.sh +++ b/packaging/package-all.sh @@ -31,7 +31,7 @@ markdown DOCUMENTATION.md > DOCUMENTATION.html markdown Lua-API.md > Lua-API.html # List of files that are packaged on all platforms -FILES=('OpenRA.Game.exe' 'OpenRA.Game.exe.config' 'OpenRA.Utility.exe' \ +FILES=('OpenRA.Game.exe' 'OpenRA.Game.exe.config' 'OpenRA.Utility.exe' 'OpenRA.Server.exe' \ 'OpenRA.Platforms.Default.dll' 'OpenRA.Platforms.Null.dll' \ 'lua' 'glsl' 'mods/common' 'mods/ra' 'mods/cnc' 'mods/d2k' 'mods/modchooser' \ 'AUTHORS' 'COPYING' 'README.html' 'CONTRIBUTING.html' 'DOCUMENTATION.html' 'CHANGELOG.html' \ diff --git a/packaging/windows/OpenRA.nsi b/packaging/windows/OpenRA.nsi index 87c7c7aef1..0d3a1379b7 100644 --- a/packaging/windows/OpenRA.nsi +++ b/packaging/windows/OpenRA.nsi @@ -85,6 +85,7 @@ Section "Game" GAME File "${SRCDIR}\OpenRA.Game.exe" File "${SRCDIR}\OpenRA.Game.exe.config" File "${SRCDIR}\OpenRA.Utility.exe" + File "${SRCDIR}\OpenRA.Server.exe" File "${SRCDIR}\OpenRA.Platforms.Null.dll" File "${SRCDIR}\OpenRA.Platforms.Default.dll" File "${SRCDIR}\ICSharpCode.SharpZipLib.dll" @@ -190,6 +191,7 @@ Function ${UN}Clean Delete $INSTDIR\OpenRA.Game.exe Delete $INSTDIR\OpenRA.Game.exe.config Delete $INSTDIR\OpenRA.Utility.exe + Delete $INSTDIR\OpenRA.Server.exe Delete $INSTDIR\OpenRA.Platforms.Null.dll Delete $INSTDIR\OpenRA.Platforms.Default.dll Delete $INSTDIR\ICSharpCode.SharpZipLib.dll