1
0
mirror of https://github.com/ncblakely/GiantsTools synced 2024-11-21 21:55:38 +01:00

Merge pull request #4 from ncblakely/users/tos/merge

Merge missing commits from 1.5.0.x branch.
This commit is contained in:
ncblakely 2022-09-04 20:31:01 -07:00 committed by GitHub
commit 05490c58bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 191 additions and 95 deletions

View File

@ -16,7 +16,6 @@ namespace Giants.Launcher
public partial class LauncherForm : Form public partial class LauncherForm : Form
{ {
// Constant settings // Constant settings
private const string GameName = "Giants: Citizen Kabuto";
private const string GamePath = "GiantsMain.exe"; private const string GamePath = "GiantsMain.exe";
private const string RegistryKey = @"HKEY_CURRENT_USER\Software\PlanetMoon\Giants"; private const string RegistryKey = @"HKEY_CURRENT_USER\Software\PlanetMoon\Giants";
private const string RegistryValue = "DestDir"; private const string RegistryValue = "DestDir";
@ -38,7 +37,7 @@ namespace Giants.Launcher
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
// Set window title // Set window title
this.Text = GameName; this.SetTitle();
// Read newer file-based game settings // Read newer file-based game settings
this.config = new Config(); this.config = new Config();
@ -97,7 +96,7 @@ namespace Giants.Launcher
private void btnOptions_Click(object sender, EventArgs e) private void btnOptions_Click(object sender, EventArgs e)
{ {
OptionsForm form = new OptionsForm(GameName + " Options", this.gamePath); OptionsForm form = new OptionsForm(Resources.AppName + " Options", this.gamePath);
form.StartPosition = FormStartPosition.CenterParent; form.StartPosition = FormStartPosition.CenterParent;
form.ShowDialog(); form.ShowDialog();
@ -116,7 +115,7 @@ namespace Giants.Launcher
if (this.gamePath == null || !File.Exists(this.gamePath)) if (this.gamePath == null || !File.Exists(this.gamePath))
{ {
string message = string.Format(Resources.AppNotFound, GameName); string message = string.Format(Resources.AppNotFound, Resources.AppName);
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.Exit(); Application.Exit();
return; return;
@ -131,7 +130,7 @@ namespace Giants.Launcher
Version gameVersion = VersionHelper.GetGameVersion(this.gamePath); Version gameVersion = VersionHelper.GetGameVersion(this.gamePath);
if (gameVersion == null) if (gameVersion == null)
{ {
string message = string.Format(Resources.AppNotFound, GameName); string message = string.Format(Resources.AppNotFound, Resources.AppName);
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.Exit(); Application.Exit();
} }
@ -330,6 +329,21 @@ namespace Giants.Launcher
} }
Process.Start(this.communityAppUri); Process.Start(this.communityAppUri);
}
private void SetTitle()
{
string title = Resources.AppName;
#if DEBUG
title += " DEBUG";
#endif
#if BETA
title += " BETA";
#endif
this.Text = title;
} }
} }
} }

View File

@ -22,6 +22,7 @@ namespace Giants.Launcher
{ {
// Must come first as other options depend on it // Must come first as other options depend on it
this.PopulateRenderers(); this.PopulateRenderers();
this.SetRenderer();
this.PopulateResolution(); this.PopulateResolution();
this.PopulateAnisotropy(); this.PopulateAnisotropy();
@ -40,6 +41,24 @@ namespace Giants.Launcher
.ToArray()); .ToArray());
} }
private void SetRenderer()
{
string selectedRenderer = GameSettings.Get<string>(RegistryKeys.Renderer);
RendererInfo renderer =
GameSettings.CompatibleRenderers.Find(
r => Path.GetFileName(r.FilePath).Equals(selectedRenderer, StringComparison.OrdinalIgnoreCase));
if (renderer != null)
{
this.cmbRenderer.SelectedItem = renderer;
}
else
{
renderer = GameSettings.CompatibleRenderers.Find(r => r.FileName == "gg_dx7r.dll");
this.cmbRenderer.SelectedItem = renderer;
}
}
private void SetOptions() private void SetOptions()
{ {
var resolutions = (List<ScreenResolution>)this.cmbResolution.DataSource; var resolutions = (List<ScreenResolution>)this.cmbResolution.DataSource;
@ -53,19 +72,6 @@ namespace Giants.Launcher
this.cmbAntialiasing.SelectedIndex = 0; this.cmbAntialiasing.SelectedIndex = 0;
this.chkUpdates.Checked = GameSettings.Get<int>(RegistryKeys.NoAutoUpdate) != 1; this.chkUpdates.Checked = GameSettings.Get<int>(RegistryKeys.NoAutoUpdate) != 1;
RendererInfo renderer = GameSettings.CompatibleRenderers.Find(
r => StringComparer.OrdinalIgnoreCase.Compare(Path.GetFileName(r.FilePath), GameSettings.Get<string>(RegistryKeys.Renderer)) == 0);
if (renderer != null)
{
this.cmbRenderer.SelectedItem = renderer;
}
else
{
renderer = GameSettings.CompatibleRenderers.Find(r => r.FileName == "gg_dx7r.dll");
this.cmbRenderer.SelectedItem = renderer;
}
} }
private void PopulateAntialiasing() private void PopulateAntialiasing()

View File

@ -6,9 +6,13 @@ namespace Giants.Launcher
{ {
static class NativeMethods static class NativeMethods
{ {
[DllImport("kernel32.dll")] [DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibrary(string dllToLoad); public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

View File

@ -58,6 +58,8 @@ namespace Giants.Launcher
{ {
try try
{ {
NativeMethods.SetDllDirectory(Environment.CurrentDirectory);
// Make interop call to native renderer DLLs to get capability info // Make interop call to native renderer DLLs to get capability info
var interopCaps = new RendererInterop.GFXCapabilityInfo(); var interopCaps = new RendererInterop.GFXCapabilityInfo();
string path = Path.Combine(file.DirectoryName, file.Name); string path = Path.Combine(file.DirectoryName, file.Name);

View File

@ -60,6 +60,15 @@ namespace Giants.Launcher {
} }
} }
/// <summary>
/// Looks up a localized string similar to Giants: Citizen Kabuto.
/// </summary>
internal static string AppName {
get {
return ResourceManager.GetString("AppName", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Could not locate an installation of {0}. The launcher will now exit.. /// Looks up a localized string similar to Could not locate an installation of {0}. The launcher will now exit..
/// </summary> /// </summary>

View File

@ -205,4 +205,7 @@
<data name="ErrorNoConfigFile" xml:space="preserve"> <data name="ErrorNoConfigFile" xml:space="preserve">
<value>Settings file {0} was not found.</value> <value>Settings file {0} was not found.</value>
</data> </data>
<data name="AppName" xml:space="preserve">
<value>Giants: Citizen Kabuto</value>
</data>
</root> </root>

View File

@ -4,7 +4,7 @@
public class ServerInfo : DataContract.V1.ServerInfo, IIdentifiable public class ServerInfo : DataContract.V1.ServerInfo, IIdentifiable
{ {
public string id => this.HostIpAddress; public string id => $"{this.HostIpAddress}-{this.GameName}-{this.Port}";
public string DocumentType => nameof(ServerInfo); public string DocumentType => nameof(ServerInfo);
@ -17,6 +17,8 @@
return obj is ServerInfo info && return obj is ServerInfo info &&
base.Equals(obj) && base.Equals(obj) &&
this.HostIpAddress == info.HostIpAddress && this.HostIpAddress == info.HostIpAddress &&
this.Port == info.Port &&
this.GameName == info.GameName &&
this.DocumentType == info.DocumentType; this.DocumentType == info.DocumentType;
} }

View File

@ -7,6 +7,8 @@
{ {
Task DeleteServer(string ipAddress); Task DeleteServer(string ipAddress);
Task DeleteServer(string ipAddress, string gameName, int port);
Task<IEnumerable<ServerInfo>> GetAllServers(); Task<IEnumerable<ServerInfo>> GetAllServers();
Task AddServer(ServerInfo server); Task AddServer(ServerInfo server);

View File

@ -4,16 +4,18 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using AutoMapper;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
public class ServerRegistryService : IServerRegistryService public class ServerRegistryService : IServerRegistryService
{ {
private static readonly string[] SupportedGameNames = new[] { "Giants" }; private static readonly string[] SupportedGameNames = new[] { "Giants", "Giants Beta", "Giants Beta Dedicated", "Giants Dedicated" };
private readonly ILogger<ServerRegistryService> logger; private readonly ILogger<ServerRegistryService> logger;
private readonly IServerRegistryStore registryStore; private readonly IServerRegistryStore registryStore;
private readonly IConfiguration configuration; private readonly IConfiguration configuration;
private readonly int maxServerCount; private readonly int maxServerCount;
private readonly int maxServersPerIp;
public ServerRegistryService( public ServerRegistryService(
ILogger<ServerRegistryService> logger, ILogger<ServerRegistryService> logger,
@ -24,6 +26,7 @@
this.registryStore = registryStore; this.registryStore = registryStore;
this.configuration = configuration; this.configuration = configuration;
this.maxServerCount = Convert.ToInt32(this.configuration["MaxServerCount"]); this.maxServerCount = Convert.ToInt32(this.configuration["MaxServerCount"]);
this.maxServersPerIp = Convert.ToInt32(this.configuration["MaxServersPerIp"]);
} }
public async Task AddServer( public async Task AddServer(
@ -32,11 +35,19 @@
ArgumentUtility.CheckForNull(serverInfo, nameof(serverInfo)); ArgumentUtility.CheckForNull(serverInfo, nameof(serverInfo));
ArgumentUtility.CheckStringForNullOrEmpty(serverInfo.HostIpAddress, nameof(serverInfo.HostIpAddress)); ArgumentUtility.CheckStringForNullOrEmpty(serverInfo.HostIpAddress, nameof(serverInfo.HostIpAddress));
string gameName = serverInfo.GameName.Replace("Dedicated", string.Empty).Trim();
serverInfo.GameName = gameName;
if (!SupportedGameNames.Contains(serverInfo.GameName, StringComparer.OrdinalIgnoreCase)) if (!SupportedGameNames.Contains(serverInfo.GameName, StringComparer.OrdinalIgnoreCase))
{ {
throw new ArgumentException($"Unsupported game name {serverInfo.GameName}", nameof(serverInfo)); throw new ArgumentException($"Unsupported game name {serverInfo.GameName}", nameof(serverInfo));
} }
var existingServers = await this.registryStore.GetServerInfos(whereExpression: x => x.HostIpAddress == serverInfo.HostIpAddress);
if (existingServers.GroupBy(g => new { g.HostIpAddress }).Any(g => g.Count() > this.maxServersPerIp))
{
throw new InvalidOperationException("Exceeded maximum servers per IP.");
}
await this.registryStore.UpsertServerInfo(serverInfo); await this.registryStore.UpsertServerInfo(serverInfo);
} }
@ -46,16 +57,36 @@
.Take(this.maxServerCount); .Take(this.maxServerCount);
} }
// Old API, soon to be deprecated
public async Task DeleteServer(string ipAddress) public async Task DeleteServer(string ipAddress)
{ {
ArgumentUtility.CheckStringForNullOrEmpty(ipAddress, nameof(ipAddress)); ArgumentUtility.CheckStringForNullOrEmpty(ipAddress, nameof(ipAddress));
ServerInfo serverInfo = await this.registryStore.GetServerInfo(ipAddress); var serverInfos = await this.registryStore.GetServerInfos(whereExpression: x => x.HostIpAddress == ipAddress);
if (serverInfo != null) foreach (var serverInfo in serverInfos)
{ {
await this.registryStore.DeleteServer(serverInfo.id); await this.registryStore.DeleteServer(serverInfo.id);
} }
} }
public async Task DeleteServer(string ipAddress, string gameName, int port)
{
ArgumentUtility.CheckStringForNullOrEmpty(ipAddress, nameof(ipAddress));
ArgumentUtility.CheckStringForNullOrEmpty(gameName, nameof(gameName));
ArgumentUtility.CheckForNonnegativeInt(port, nameof(port));
var existingServerInfo = (await this.registryStore.GetServerInfos(
whereExpression:
x => x.HostIpAddress == ipAddress &&
x.Port == port &&
x.GameName.Equals(gameName, StringComparison.OrdinalIgnoreCase)))
.FirstOrDefault();
if (existingServerInfo != null)
{
await this.registryStore.DeleteServer(existingServerInfo.id);
}
}
} }
} }

View File

@ -41,10 +41,11 @@
bool includeExpired = false, bool includeExpired = false,
string partitionKey = null) string partitionKey = null)
{ {
ConcurrentDictionary<string, ServerInfo> serverInfo = await this.memoryCache.GetOrCreateAsync(CacheKeys.ServerInfo, this.PopulateCache); ConcurrentDictionary<string, IList<ServerInfo>> serverInfo = await this.memoryCache.GetOrCreateAsync(CacheKeys.ServerInfo, this.PopulateCache);
IQueryable<ServerInfo> serverInfoQuery = serverInfo IQueryable<ServerInfo> serverInfoQuery = serverInfo
.Values .Values
.SelectMany(s => s)
.AsQueryable(); .AsQueryable();
if (whereExpression != null) if (whereExpression != null)
@ -67,10 +68,11 @@
Expression<Func<ServerInfo, bool>> whereExpression = null, Expression<Func<ServerInfo, bool>> whereExpression = null,
string partitionKey = null) string partitionKey = null)
{ {
ConcurrentDictionary<string, ServerInfo> serverInfo = await this.memoryCache.GetOrCreateAsync(CacheKeys.ServerInfo, this.PopulateCache); ConcurrentDictionary<string, IList<ServerInfo>> serverInfo = await this.memoryCache.GetOrCreateAsync(CacheKeys.ServerInfo, this.PopulateCache);
IQueryable<ServerInfo> serverInfoQuery = serverInfo IQueryable<ServerInfo> serverInfoQuery = serverInfo
.Values .Values
.SelectMany(s => s)
.AsQueryable(); .AsQueryable();
if (serverInfoQuery != null) if (serverInfoQuery != null)
@ -88,65 +90,55 @@
.ToList(); .ToList();
} }
public async Task<ServerInfo> GetServerInfo(string ipAddress)
{
ArgumentUtility.CheckStringForNullOrEmpty(ipAddress, nameof(ipAddress));
ConcurrentDictionary<string, ServerInfo> serverInfo = await this.memoryCache.GetOrCreateAsync(CacheKeys.ServerInfo, this.PopulateCache);
if (serverInfo.ContainsKey(ipAddress))
{
try
{
return serverInfo[ipAddress];
}
catch (Exception e)
{
this.logger.LogInformation("Cached server for {IPAddress} no longer found: {Exception}", ipAddress, e.ToString());
// May have been removed from the cache by another thread. Ignore and query DB instead.
}
}
return await this.client.GetItemById<ServerInfo>(ipAddress);
}
public async Task UpsertServerInfo(ServerInfo serverInfo) public async Task UpsertServerInfo(ServerInfo serverInfo)
{ {
ArgumentUtility.CheckForNull(serverInfo, nameof(serverInfo)); ArgumentUtility.CheckForNull(serverInfo, nameof(serverInfo));
// Check cache before we write to store // Check cache before we write to store
ConcurrentDictionary<string, ServerInfo> allServerInfo = await this.memoryCache.GetOrCreateAsync(CacheKeys.ServerInfo, this.PopulateCache); ConcurrentDictionary<string, IList<ServerInfo>> allServerInfo = await this.memoryCache.GetOrCreateAsync(CacheKeys.ServerInfo, this.PopulateCache);
if (allServerInfo.ContainsKey(serverInfo.HostIpAddress)) if (allServerInfo.ContainsKey(serverInfo.HostIpAddress))
{ {
ServerInfo existingServerInfo = allServerInfo[serverInfo.HostIpAddress]; IList<ServerInfo> serverInfoForHostIp = allServerInfo[serverInfo.HostIpAddress];
ServerInfo existingServerInfo = FindExistingServerForHostIp(serverInfoForHostIp, serverInfo);
// DDOS protection: skip write to Cosmos if parameters have not changed, // DDOS protection: skip write to Cosmos if parameters have not changed,
// or it's not been long enough. // or it's not been long enough.
if (existingServerInfo.Equals(serverInfo) if (existingServerInfo != null && Math.Abs((existingServerInfo.LastHeartbeat - serverInfo.LastHeartbeat).TotalMinutes) < ServerRefreshIntervalInMinutes)
&& Math.Abs((existingServerInfo.LastHeartbeat - serverInfo.LastHeartbeat).TotalMinutes) < ServerRefreshIntervalInMinutes)
{ {
this.logger.LogInformation("State for {IPAddress} is unchanged. Skipping write to store.", serverInfo.HostIpAddress); this.logger.LogInformation("State for {IPAddress} is unchanged. Skipping write to store.", serverInfo.HostIpAddress);
return; return;
} }
this.logger.LogInformation("State for {IPAddress} has changed. Committing update to store.", serverInfo.HostIpAddress);
await this.client.UpsertItem(
item: serverInfo,
partitionKey: new PartitionKey(serverInfo.DocumentType));
// Update cache
if (existingServerInfo != null)
{
var newServerInfo = serverInfoForHostIp.Where(s => !s.Equals(serverInfo)).ToList();
newServerInfo.Add(serverInfo);
allServerInfo[serverInfo.HostIpAddress] = newServerInfo;
this.logger.LogInformation("Updating cache for request from {IPAddress} (replaced existing server).", serverInfo.HostIpAddress);
}
else else
{ {
this.logger.LogInformation("State for {IPAddress} has changed. Committing update to store.", serverInfo.HostIpAddress); allServerInfo[serverInfo.HostIpAddress].Add(serverInfo);
this.logger.LogInformation("Updating cache for request from {IPAddress} (added new server).", serverInfo.HostIpAddress);
} }
} }
await this.client.UpsertItem(
item: serverInfo,
partitionKey: new PartitionKey(serverInfo.DocumentType));
this.logger.LogInformation("Updating cache for request from {IPAddress}.", serverInfo.HostIpAddress);
if (allServerInfo.ContainsKey(serverInfo.HostIpAddress))
{
allServerInfo[serverInfo.HostIpAddress] = serverInfo;
}
else else
{ {
allServerInfo.TryAdd(serverInfo.HostIpAddress, serverInfo); // Update cache
await this.client.UpsertItem(
item: serverInfo,
partitionKey: new PartitionKey(serverInfo.DocumentType));
this.logger.LogInformation("Updating cache for request from {IPAddress} (no existing servers).", serverInfo.HostIpAddress);
allServerInfo.TryAdd(serverInfo.HostIpAddress, new List<ServerInfo>() { serverInfo });
} }
} }
@ -155,8 +147,21 @@
await this.client.DeleteItem<ServerInfo>(id, partitionKey); await this.client.DeleteItem<ServerInfo>(id, partitionKey);
// Remove from cache // Remove from cache
ConcurrentDictionary<string, ServerInfo> allServerInfo = await this.memoryCache.GetOrCreateAsync(CacheKeys.ServerInfo, this.PopulateCache); ConcurrentDictionary<string, IList<ServerInfo>> allServerInfo = await this.memoryCache.GetOrCreateAsync(CacheKeys.ServerInfo, this.PopulateCache);
allServerInfo.TryRemove(id, out ServerInfo _); if (allServerInfo.ContainsKey(id))
{
var serverInfoCopy = allServerInfo[id].Where(s => s.id != id).ToList();
if (!serverInfoCopy.Any())
{
// No remaining servers, remove the key
allServerInfo.TryRemove(id, out IList<ServerInfo> _);
}
else
{
// Shallow-copy and replace to keep thread safety guarantee
allServerInfo[id] = serverInfoCopy;
}
}
} }
public async Task DeleteServers(IEnumerable<string> ids, string partitionKey = null) public async Task DeleteServers(IEnumerable<string> ids, string partitionKey = null)
@ -182,15 +187,31 @@
await this.client.Initialize(); await this.client.Initialize();
} }
private async Task<ConcurrentDictionary<string, ServerInfo>> PopulateCache(ICacheEntry entry) private async Task<ConcurrentDictionary<string, IList<ServerInfo>>> PopulateCache(ICacheEntry entry)
{ {
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1); entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
IDictionary<string, ServerInfo> serverInfo = var allServerInfo = (await this.client.GetItems<ServerInfo>());
(await this.client.GetItems<ServerInfo>()) var serverInfoDictionary = new ConcurrentDictionary<string, IList<ServerInfo>>();
.ToDictionary(x => x.HostIpAddress, y => y);
return new ConcurrentDictionary<string, ServerInfo>(serverInfo); foreach (var serverInfo in allServerInfo)
{
if (!serverInfoDictionary.ContainsKey(serverInfo.HostIpAddress))
{
serverInfoDictionary[serverInfo.HostIpAddress] = new List<ServerInfo>() { serverInfo };
}
else
{
serverInfoDictionary[serverInfo.HostIpAddress].Add(serverInfo);
}
}
return serverInfoDictionary;
}
private static ServerInfo FindExistingServerForHostIp(IList<ServerInfo> serverInfoForHostIp, ServerInfo candidateServerInfo)
{
return serverInfoForHostIp.FirstOrDefault(s => s.Equals(candidateServerInfo));
} }
} }
} }

View File

@ -13,8 +13,6 @@
Task DeleteServers(IEnumerable<string> ids, string partitionKey = null); Task DeleteServers(IEnumerable<string> ids, string partitionKey = null);
Task<ServerInfo> GetServerInfo(string ipAddress);
Task<IEnumerable<ServerInfo>> GetServerInfos(Expression<Func<ServerInfo, bool>> whereExpression = null, bool includeExpired = false, string partitionKey = null); Task<IEnumerable<ServerInfo>> GetServerInfos(Expression<Func<ServerInfo, bool>> whereExpression = null, bool includeExpired = false, string partitionKey = null);
Task<IEnumerable<TSelect>> GetServerInfos<TSelect>( Task<IEnumerable<TSelect>> GetServerInfos<TSelect>(

View File

@ -6,6 +6,7 @@
[ApiController] [ApiController]
[ApiVersion("1.0")] [ApiVersion("1.0")]
[ApiVersion("1.1")]
[Route("api/[controller]")] [Route("api/[controller]")]
public class CommunityController : ControllerBase public class CommunityController : ControllerBase
{ {

View File

@ -13,6 +13,7 @@
[ApiController] [ApiController]
[ApiVersion("1.0")] [ApiVersion("1.0")]
[ApiVersion("1.1")]
[Route("api/[controller]")] [Route("api/[controller]")]
public class CrashReportsController : ControllerBase public class CrashReportsController : ControllerBase
{ {

View File

@ -14,6 +14,7 @@ namespace Giants.Web.Controllers
{ {
[ApiController] [ApiController]
[ApiVersion("1.0")] [ApiVersion("1.0")]
[ApiVersion("1.1")]
[Route("api/[controller]")] [Route("api/[controller]")]
public class ServersController : ControllerBase public class ServersController : ControllerBase
{ {
@ -44,6 +45,17 @@ namespace Giants.Web.Controllers
await this.serverRegistryService.DeleteServer(requestIpAddress); await this.serverRegistryService.DeleteServer(requestIpAddress);
} }
[HttpDelete]
[MapToApiVersion("1.1")]
public async Task DeleteServer(string gameName, int port)
{
string requestIpAddress = this.GetRequestIpAddress();
this.logger.LogInformation("Deleting server from {IPAddress}", requestIpAddress);
await this.serverRegistryService.DeleteServer(requestIpAddress, gameName, port);
}
[HttpGet] [HttpGet]
public async Task<IEnumerable<ServerInfoWithHostAddress>> GetServers() public async Task<IEnumerable<ServerInfoWithHostAddress>> GetServers()
{ {

View File

@ -7,6 +7,7 @@ namespace Giants.WebApi.Controllers
{ {
[ApiController] [ApiController]
[ApiVersion("1.0")] [ApiVersion("1.0")]
[ApiVersion("1.1")]
[Route("api/[controller]")] [Route("api/[controller]")]
public class VersionController : ControllerBase public class VersionController : ControllerBase
{ {

View File

@ -12,6 +12,7 @@
"ServerTimeoutPeriodInMinutes": "7", "ServerTimeoutPeriodInMinutes": "7",
"ServerCleanupIntervalInMinutes": "1", "ServerCleanupIntervalInMinutes": "1",
"MaxServerCount": 1000, "MaxServerCount": 1000,
"MaxServersPerIp": 5,
"DiscordUri": "https://discord.gg/Avj4azU", "DiscordUri": "https://discord.gg/Avj4azU",
"BlobConnectionString": "", "BlobConnectionString": "",
"CrashBlobContainerName": "crashes" "CrashBlobContainerName": "crashes"

View File

@ -82,6 +82,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="Vcpkg">
<VcpkgEnabled>false</VcpkgEnabled>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>

View File

@ -111,6 +111,7 @@
<EnablePREfast>true</EnablePREfast> <EnablePREfast>true</EnablePREfast>
<LanguageStandard>stdcpplatest</LanguageStandard> <LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -165,6 +166,7 @@
<EnablePREfast>true</EnablePREfast> <EnablePREfast>true</EnablePREfast>
<LanguageStandard>stdcpplatest</LanguageStandard> <LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
@ -220,7 +222,6 @@
</ClCompile> </ClCompile>
<ClCompile Include="ServerDialog.cpp" /> <ClCompile Include="ServerDialog.cpp" />
<ClCompile Include="ServerConsoleApp.cpp" /> <ClCompile Include="ServerConsoleApp.cpp" />
<ClCompile Include="Utils.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="res\ServerConsole.rc2" /> <None Include="res\ServerConsole.rc2" />
@ -233,7 +234,6 @@
<ClInclude Include="ServerDialog.h" /> <ClInclude Include="ServerDialog.h" />
<ClInclude Include="ServerConsoleApp.h" /> <ClInclude Include="ServerConsoleApp.h" />
<ClInclude Include="targetver.h" /> <ClInclude Include="targetver.h" />
<ClInclude Include="Utils.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="ServerConsole.rc" /> <ResourceCompile Include="ServerConsole.rc" />

View File

@ -1,5 +1,4 @@
#include "pch.h" #include "pch.h"
#include <initguid.h>
#include "ServerConsoleApp.h" #include "ServerConsoleApp.h"
#include "ServerDialog.h" #include "ServerDialog.h"

View File

@ -2,7 +2,6 @@
#include "ServerConsoleApp.h" #include "ServerConsoleApp.h"
#include "ServerDialog.h" #include "ServerDialog.h"
#include "Utils.h"
IMPLEMENT_DYNAMIC(ServerDialog, CDialogEx) IMPLEMENT_DYNAMIC(ServerDialog, CDialogEx)
@ -111,9 +110,10 @@ void ServerDialog::OnCancel()
{ {
AFX_MANAGE_STATE(AfxGetStaticModuleState()); AFX_MANAGE_STATE(AfxGetStaticModuleState());
KillTimer((UINT_PTR)this);
ShowWindow(SW_HIDE); ShowWindow(SW_HIDE);
DestroyWindow(); DestroyWindow();
KillTimer((UINT_PTR)this);
m_pParentWnd->SendMessage(WM_CLOSE, 0, 0);
} }
void ServerDialog::RefreshPlayers() void ServerDialog::RefreshPlayers()

View File

@ -1,12 +0,0 @@
#include "pch.h"
#include <codecvt>
#include "Utils.h"
std::wstring to_wstring(const std::string_view& sourceString)
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
return converter.from_bytes(sourceString.data());
}

View File

@ -1,5 +0,0 @@
#pragma once
#include <string>
std::wstring to_wstring(const std::string_view& sourceString);

View File

@ -38,6 +38,9 @@
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup /> <PropertyGroup />
<PropertyGroup Label="Vcpkg">
<VcpkgEnabled>false</VcpkgEnabled>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<FxCompile> <FxCompile>
<ShaderType>Effect</ShaderType> <ShaderType>Effect</ShaderType>