diff --git a/source/X39.UnitedTacticalForces.Api/Constants.cs b/source/X39.UnitedTacticalForces.Api/Constants.cs index a3707c3..42b902b 100644 --- a/source/X39.UnitedTacticalForces.Api/Constants.cs +++ b/source/X39.UnitedTacticalForces.Api/Constants.cs @@ -17,6 +17,7 @@ public static class AppId public const long Arma3 = 107410; public const long DayZStandalone = 221100; public const long DayZStandaloneServer = 223350; + public const long DayZStandaloneExperimentalServer = 1042420; } } diff --git a/source/X39.UnitedTacticalForces.Api/Controllers/GameServersController.cs b/source/X39.UnitedTacticalForces.Api/Controllers/GameServersController.cs index 767d6bb..f848e9c 100644 --- a/source/X39.UnitedTacticalForces.Api/Controllers/GameServersController.cs +++ b/source/X39.UnitedTacticalForces.Api/Controllers/GameServersController.cs @@ -83,7 +83,9 @@ public GameServersController( public async Task> GetGameServerCountAsync( CancellationToken cancellationToken) { - var count = await _apiDbContext.GameServers.CountAsync(cancellationToken); + var count = await _apiDbContext.GameServers + .Where((q) => q.IsActive) + .CountAsync(cancellationToken); return Ok(count); } @@ -100,6 +102,7 @@ public async Task>> GetGameServersAsync CancellationToken cancellationToken) { var allServers = await _apiDbContext.GameServers + .Where((q) => q.IsActive) .OrderBy((q) => q.Title) .ToArrayAsync(cancellationToken); var gameServerInfos = new List(); diff --git a/source/X39.UnitedTacticalForces.Api/Services/GameServerController/Controllers/DayZStandaloneExperimentalGameServerController.cs b/source/X39.UnitedTacticalForces.Api/Services/GameServerController/Controllers/DayZStandaloneExperimentalGameServerController.cs new file mode 100644 index 0000000..192f452 --- /dev/null +++ b/source/X39.UnitedTacticalForces.Api/Services/GameServerController/Controllers/DayZStandaloneExperimentalGameServerController.cs @@ -0,0 +1,157 @@ +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; +using X39.UnitedTacticalForces.Api.Data; +using X39.UnitedTacticalForces.Api.Data.Authority; +using X39.UnitedTacticalForces.Api.Data.Hosting; +using X39.UnitedTacticalForces.Api.Services.UpdateStreamService; + +namespace X39.UnitedTacticalForces.Api.Services.GameServerController.Controllers; + +/// +/// Implementation of for DayZ Standalone game servers. +/// +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public class DayZStandaloneExperimentalGameServerController : SteamGameServerControllerBase, IGameServerControllerCreatable +{ + /// + public DayZStandaloneExperimentalGameServerController( + GameServer gameServer, + IDbContextFactory dbContextFactory, + ILogger logger, + IConfiguration configuration, + IUpdateStreamService updateStreamService) + : base(configuration, gameServer, dbContextFactory, updateStreamService, logger) + { + } + + /// + public override bool AllowAnyConfigurationEntry => false; + + /// + public override bool CanModifyGameFiles => false; + + /// + protected override long ServerAppId => Constants.Steam.AppId.DayZStandaloneExperimentalServer; + + /// + protected override long GameAppId => Constants.Steam.AppId.DayZStandalone; + + /// + protected override bool RequireLogin => true; + + /// + protected override bool RequirePurchaseForWorkshop => true; + + /// + public static string Identifier => $"dayz-experimental-{Constants.Steam.AppId.DayZStandaloneExperimentalServer}"; + + /// + public override IEnumerable GetConfigurationEntryDefinitions(CultureInfo cultureInfo) + { + return Enumerable.Empty(); + } + + /// + public override Task> GetGameFoldersAsync( + CultureInfo cultureInfo, + CancellationToken cancellationToken = default) + { + return Task.FromResult>(Array.Empty()); + } + + /// + public override Task> GetGameFolderFilesAsync( + GameFolder folder, + CultureInfo cultureInfo, + CancellationToken cancellationToken = default) + { + return Task.FromResult>(Array.Empty()); + } + + /// + public override Task GetGameFolderFileAsync( + GameFolder folder, + GameFileInfo file, + CancellationToken cancellationToken = default) + { + return Task.FromResult(new MemoryStream()); + } + + /// + public override Task UploadFileAsync(GameFolder folder, GameFileInfo file, Stream stream) + { + throw new NotSupportedException(); + } + + /// + public override Task DeleteFileAsync(GameFolder folder, GameFileInfo file) + { + throw new NotSupportedException(); + } + + /// + public override Task GetCommonConfigurationAsync( + ECommonConfiguration commonConfig, + CultureInfo cultureInfo, + CancellationToken cancellationToken = default) + { + return commonConfig switch + { + ECommonConfiguration.Title => Task.FromResult("DayZ Standalone Experimental"), + ECommonConfiguration.Port => Task.FromResult("2302"), + ECommonConfiguration.Password => Task.FromResult(""), + _ => throw new ArgumentOutOfRangeException(nameof(commonConfig), commonConfig, null) + }; + } + + /// + protected override Task DoUpdateConfigurationAsync() + { + return Task.CompletedTask; + } + + /// + protected override ValueTask GetProcessStartInfoAsync(ApiDbContext dbContext, User? executingUser) + { + var fileName = Path.Combine( + GameInstallPath, + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? "DayZServer_x64.exe" + : "dayzserver_x64"); + var psi = new ProcessStartInfo + { + FileName = fileName, + RedirectStandardError = true, + RedirectStandardInput = false, + RedirectStandardOutput = true, + StandardErrorEncoding = Encoding.UTF8, + // StandardInputEncoding = Encoding.UTF8, + StandardOutputEncoding = Encoding.UTF8, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + UseShellExecute = false, + WorkingDirectory = GameInstallPath, + }; + return ValueTask.FromResult(psi); + } + + /// + public static Task CreateAsync( + IServiceProvider serviceProvider, + IConfiguration configuration, + GameServer gameServer, + IUpdateStreamService updateStreamService) + { + var controller = new DayZStandaloneExperimentalGameServerController( + gameServer, + serviceProvider.GetRequiredService>(), + serviceProvider.GetRequiredService().CreateLogger(), + configuration, + updateStreamService); + return Task.FromResult(controller); + } +} \ No newline at end of file