mirror of
https://github.com/ncblakely/GiantsTools
synced 2024-12-05 02:53:08 +01:00
Compare commits
5 Commits
00d1d374c5
...
ad343d425f
Author | SHA1 | Date | |
---|---|---|---|
|
ad343d425f | ||
|
2f198adbce | ||
|
3ca6c77bc5 | ||
|
9f500e9084 | ||
|
98a81d3289 |
@ -13,5 +13,8 @@
|
||||
|
||||
[Required]
|
||||
public Uri InstallerUri { get; set; }
|
||||
|
||||
[Required]
|
||||
public string BranchName { get; set;}
|
||||
}
|
||||
}
|
||||
|
@ -2,5 +2,5 @@
|
||||
|
||||
namespace Giants.DataContract.Contracts.V1
|
||||
{
|
||||
public record VersionInfoUpdate(string AppName, AppVersion AppVersion, string FileName);
|
||||
public record VersionInfoUpdate(string AppName, AppVersion AppVersion, string FileName, string BranchName, bool ForceUpdate);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Newtonsoft.Json;
|
||||
@ -10,6 +11,7 @@
|
||||
{
|
||||
private const string defaultConfigFileName = "GiantsDefault.config";
|
||||
private const string playerConfigFileName = "Giants.config";
|
||||
private bool dirty = false;
|
||||
|
||||
private IDictionary<string, dynamic> defaultConfig = new Dictionary<string, dynamic>();
|
||||
private IDictionary<string, dynamic> userConfig = new Dictionary<string, dynamic>();
|
||||
@ -34,14 +36,45 @@
|
||||
}
|
||||
}
|
||||
|
||||
public string GetString(string section, string key)
|
||||
public void Write()
|
||||
{
|
||||
if (!this.dirty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string userConfigFilePath = this.GetUserConfigPath();
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(userConfigFilePath));
|
||||
|
||||
using (var file = File.OpenWrite(userConfigFilePath))
|
||||
using (var streamWriter = new StreamWriter(file))
|
||||
{
|
||||
string serializedConfig = JsonConvert.SerializeObject(this.userConfig, Formatting.Indented);
|
||||
streamWriter.Write(serializedConfig);
|
||||
}
|
||||
|
||||
this.dirty = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show($"Unhandled exception saving updated configuration: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetObject(string section, string key, object defaultValue, out object value)
|
||||
{
|
||||
value = defaultValue;
|
||||
|
||||
if (this.userConfig.ContainsKey(section))
|
||||
{
|
||||
dynamic sectionObject = this.userConfig[section];
|
||||
if (sectionObject != null && sectionObject.ContainsKey(key))
|
||||
{
|
||||
return (string)sectionObject[key];
|
||||
value = sectionObject[key];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,14 +83,58 @@
|
||||
dynamic sectionObject = this.defaultConfig[section];
|
||||
if (sectionObject != null && sectionObject.ContainsKey(key))
|
||||
{
|
||||
return (string)sectionObject[key];
|
||||
value = sectionObject[key];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: other accessors unimplemented as we only need master server host name for now
|
||||
public bool TryGetString(string section, string key, string defaultValue, out string value)
|
||||
{
|
||||
value = defaultValue;
|
||||
|
||||
if (this.TryGetObject(section, key, defaultValue, out object objValue))
|
||||
{
|
||||
value = objValue.ToString();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetBool(string section, string key, bool defaultValue, out bool value)
|
||||
{
|
||||
value = defaultValue;
|
||||
|
||||
if (this.TryGetObject(section, key, defaultValue, out object objValue))
|
||||
{
|
||||
return bool.TryParse(objValue.ToString(), out value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetValue(string section, string key, dynamic value)
|
||||
{
|
||||
if (!this.userConfig.ContainsKey(section))
|
||||
{
|
||||
this.userConfig.Add(section, new Dictionary<string, dynamic>());
|
||||
}
|
||||
|
||||
dynamic sectionObject = this.userConfig[section];
|
||||
if (sectionObject != null && sectionObject.ContainsKey(key))
|
||||
{
|
||||
sectionObject[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
sectionObject.Add(key, value);
|
||||
}
|
||||
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
private static IDictionary<string, dynamic> ReadConfig(string filePath)
|
||||
{
|
||||
|
8
Giants.Launcher/ConfigDefaults.cs
Normal file
8
Giants.Launcher/ConfigDefaults.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace Giants.Launcher
|
||||
{
|
||||
public static class ConfigDefaults
|
||||
{
|
||||
public const string BranchNameDefault = "Release";
|
||||
public const string MasterServerHostNameDefault = "https://giants.azurewebsites.net/";
|
||||
}
|
||||
}
|
@ -2,6 +2,11 @@
|
||||
{
|
||||
public static class ConfigKeys
|
||||
{
|
||||
// Update
|
||||
public const string BranchName = "branchName";
|
||||
public const string EnableBranchSelection = "enableBranchSelection";
|
||||
|
||||
// Network
|
||||
public const string MasterServerHostName = "masterServerHostName";
|
||||
public const string BannedPlayers = "bannedPlayers";
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
{
|
||||
public static class ConfigSections
|
||||
{
|
||||
public const string Update = "update";
|
||||
public const string Network = "network";
|
||||
}
|
||||
}
|
||||
|
@ -21,13 +21,15 @@ namespace Giants.Launcher
|
||||
private const string RegistryValue = "DestDir";
|
||||
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly BranchesClient branchHttpClient;
|
||||
private readonly VersionClient versionHttpClient;
|
||||
private readonly CommunityClient communityHttpClient;
|
||||
|
||||
private string commandLine;
|
||||
private string gamePath = null;
|
||||
private Updater updater;
|
||||
private Config config;
|
||||
private readonly Config config;
|
||||
private string branchName;
|
||||
private string communityAppUri;
|
||||
|
||||
public LauncherForm()
|
||||
@ -39,17 +41,29 @@ namespace Giants.Launcher
|
||||
// Set window title
|
||||
this.SetTitle();
|
||||
|
||||
this.updater = new Updater(
|
||||
updateCompletedCallback: this.LauncherForm_DownloadCompletedCallback,
|
||||
updateProgressCallback: this.LauncherForm_DownloadProgressCallback);
|
||||
|
||||
// Read newer file-based game settings
|
||||
this.config = new Config();
|
||||
this.config.Read();
|
||||
|
||||
string baseUrl = this.config.GetString(ConfigSections.Network, ConfigKeys.MasterServerHostName);
|
||||
this.config.TryGetString(ConfigSections.Network, ConfigKeys.MasterServerHostName, ConfigDefaults.MasterServerHostNameDefault, out string baseUrl);
|
||||
this.config.TryGetString(ConfigSections.Update, ConfigKeys.BranchName, defaultValue: ConfigDefaults.BranchNameDefault, out string branchName);
|
||||
|
||||
this.branchName = branchName;
|
||||
|
||||
this.httpClient = new HttpClient(
|
||||
new HttpClientHandler()
|
||||
{
|
||||
UseProxy = false
|
||||
});
|
||||
this.branchHttpClient = new BranchesClient(this.httpClient)
|
||||
{
|
||||
BaseUrl = baseUrl,
|
||||
|
||||
};
|
||||
this.versionHttpClient = new VersionClient(this.httpClient)
|
||||
{
|
||||
BaseUrl = baseUrl
|
||||
@ -62,12 +76,14 @@ namespace Giants.Launcher
|
||||
|
||||
private void btnExit_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.config.Write();
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
private void btnPlay_Click(object sender, EventArgs e)
|
||||
{
|
||||
GameSettings.Save();
|
||||
this.config.Write();
|
||||
|
||||
foreach (string c in Environment.GetCommandLineArgs())
|
||||
{
|
||||
@ -87,19 +103,44 @@ namespace Giants.Launcher
|
||||
gameProcess.Start();
|
||||
Application.Exit();
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(string.Format("Failed to launch game process at: {0}. {1}", this.gamePath, ex.Message),
|
||||
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void btnOptions_Click(object sender, EventArgs e)
|
||||
private async void btnOptions_Click(object sender, EventArgs e)
|
||||
{
|
||||
OptionsForm form = new OptionsForm(Resources.AppName + " Options", this.gamePath);
|
||||
OptionsForm form = new OptionsForm(
|
||||
title: Resources.AppName + " Options",
|
||||
gamePath: this.gamePath,
|
||||
appName: ApplicationNames.Giants,
|
||||
currentBranchName: this.branchName,
|
||||
config: this.config,
|
||||
branchesClient: this.branchHttpClient)
|
||||
{
|
||||
StartPosition = FormStartPosition.CenterParent
|
||||
};
|
||||
|
||||
form.StartPosition = FormStartPosition.CenterParent;
|
||||
form.ShowDialog();
|
||||
|
||||
this.config.TryGetBool(ConfigSections.Update, ConfigKeys.EnableBranchSelection, defaultValue: false, out bool enableBranchSelection);
|
||||
if (enableBranchSelection)
|
||||
{
|
||||
this.config.TryGetString(ConfigSections.Update, ConfigKeys.BranchName, defaultValue: ConfigDefaults.BranchNameDefault, out string branchName);
|
||||
|
||||
if (!this.branchName.Equals(branchName))
|
||||
{
|
||||
this.branchName = branchName;
|
||||
|
||||
VersionInfo gameVersionInfo = await this.GetVersionInfo(
|
||||
GetApplicationName(ApplicationType.Game), this.branchName);
|
||||
|
||||
this.btnPlay.Enabled = false;
|
||||
await this.updater.UpdateApplication(ApplicationType.Game, gameVersionInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void LauncherForm_Load(object sender, EventArgs e)
|
||||
@ -127,29 +168,14 @@ namespace Giants.Launcher
|
||||
|
||||
if (GameSettings.Get<int>("NoAutoUpdate") == 0)
|
||||
{
|
||||
Version gameVersion = VersionHelper.GetGameVersion(this.gamePath);
|
||||
if (gameVersion == null)
|
||||
{
|
||||
string message = string.Format(Resources.AppNotFound, Resources.AppName);
|
||||
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
var appVersions = new Dictionary<ApplicationType, Version>()
|
||||
{
|
||||
[ApplicationType.Game] = gameVersion,
|
||||
[ApplicationType.Launcher] = VersionHelper.GetLauncherVersion()
|
||||
};
|
||||
|
||||
// Check for updates
|
||||
Task updateTask = this.CheckForUpdates(appVersions);
|
||||
Task discordTask = this.CheckDiscordStatus();
|
||||
Task updateTask = this.CheckForUpdates();
|
||||
Task discordTask = this.UpdateDiscordStatus();
|
||||
|
||||
await Task.WhenAll(updateTask, discordTask);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CheckDiscordStatus()
|
||||
private async Task UpdateDiscordStatus()
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -165,27 +191,26 @@ namespace Giants.Launcher
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CheckForUpdates(Dictionary<ApplicationType, Version> appVersions)
|
||||
private async Task CheckForUpdates()
|
||||
{
|
||||
this.updater = new Updater(
|
||||
appVersions: appVersions,
|
||||
updateCompletedCallback: this.LauncherForm_DownloadCompletedCallback,
|
||||
updateProgressCallback: this.LauncherForm_DownloadProgressCallback);
|
||||
|
||||
Task<VersionInfo> gameVersionInfo = this.GetVersionInfo(
|
||||
GetApplicationName(ApplicationType.Game));
|
||||
GetApplicationName(ApplicationType.Game), this.branchName);
|
||||
|
||||
Task<VersionInfo> launcherVersionInfo = this.GetVersionInfo(
|
||||
GetApplicationName(ApplicationType.Launcher));
|
||||
GetApplicationName(ApplicationType.Launcher), this.branchName);
|
||||
|
||||
Version localGameVersion = VersionHelper.GetGameVersion(this.gamePath);
|
||||
Version localLauncherVersion = VersionHelper.GetLauncherVersion();
|
||||
|
||||
await Task.WhenAll(gameVersionInfo, launcherVersionInfo);
|
||||
|
||||
if (this.updater.IsUpdateRequired(ApplicationType.Game, gameVersionInfo.Result))
|
||||
if (this.updater.IsUpdateRequired(ApplicationType.Game, gameVersionInfo.Result, localGameVersion))
|
||||
{
|
||||
this.btnPlay.Enabled = false;
|
||||
await this.updater.UpdateApplication(ApplicationType.Game, gameVersionInfo.Result);
|
||||
}
|
||||
|
||||
if (this.updater.IsUpdateRequired(ApplicationType.Launcher, launcherVersionInfo.Result))
|
||||
if (this.updater.IsUpdateRequired(ApplicationType.Launcher, launcherVersionInfo.Result, localLauncherVersion))
|
||||
{
|
||||
this.btnPlay.Enabled = false;
|
||||
await this.updater.UpdateApplication(ApplicationType.Launcher, launcherVersionInfo.Result);
|
||||
@ -197,28 +222,20 @@ namespace Giants.Launcher
|
||||
switch (applicationType)
|
||||
{
|
||||
case ApplicationType.Game:
|
||||
#if BETA
|
||||
return ApplicationNames.GiantsBeta;
|
||||
#else
|
||||
return ApplicationNames.Giants;
|
||||
#endif
|
||||
case ApplicationType.Launcher:
|
||||
#if BETA
|
||||
return ApplicationNames.GiantsLauncherBeta;
|
||||
#else
|
||||
return ApplicationNames.GiantsLauncher;
|
||||
#endif
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
private async Task<VersionInfo> GetVersionInfo(string appName)
|
||||
private async Task<VersionInfo> GetVersionInfo(string appName, string branchName)
|
||||
{
|
||||
VersionInfo versionInfo;
|
||||
try
|
||||
{
|
||||
versionInfo = await this.versionHttpClient.GetVersionInfoAsync(appName);
|
||||
versionInfo = await this.versionHttpClient.GetVersionInfoAsync(appName, branchName);
|
||||
return versionInfo;
|
||||
}
|
||||
catch (ApiException ex)
|
||||
@ -298,6 +315,14 @@ namespace Giants.Launcher
|
||||
|
||||
updaterProcess.Start();
|
||||
|
||||
this.config.TryGetBool(ConfigSections.Update, ConfigKeys.EnableBranchSelection, defaultValue: false, out bool enableBranchSelection);
|
||||
if (enableBranchSelection)
|
||||
{
|
||||
this.config.SetValue(ConfigSections.Update, ConfigKeys.BranchName, this.branchName);
|
||||
}
|
||||
|
||||
this.config.Write();
|
||||
|
||||
Application.Exit();
|
||||
return;
|
||||
}
|
||||
@ -334,15 +359,6 @@ namespace Giants.Launcher
|
||||
private void SetTitle()
|
||||
{
|
||||
string title = Resources.AppName;
|
||||
|
||||
#if DEBUG
|
||||
title += " DEBUG";
|
||||
#endif
|
||||
|
||||
#if BETA
|
||||
title += " BETA";
|
||||
#endif
|
||||
|
||||
this.Text = title;
|
||||
}
|
||||
}
|
||||
|
115
Giants.Launcher/Forms/OptionsForm.Designer.cs
generated
115
Giants.Launcher/Forms/OptionsForm.Designer.cs
generated
@ -44,18 +44,22 @@
|
||||
this.btnResetDefaults = new System.Windows.Forms.Button();
|
||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
||||
this.chkUpdates = new System.Windows.Forms.CheckBox();
|
||||
this.cmbBranch = new System.Windows.Forms.ComboBox();
|
||||
this.BranchGroupBox = new System.Windows.Forms.GroupBox();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.groupBox3.SuspendLayout();
|
||||
this.BranchGroupBox.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// cmbRenderer
|
||||
//
|
||||
this.cmbRenderer.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbRenderer.FormattingEnabled = true;
|
||||
this.cmbRenderer.Location = new System.Drawing.Point(124, 19);
|
||||
this.cmbRenderer.Location = new System.Drawing.Point(165, 23);
|
||||
this.cmbRenderer.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.cmbRenderer.Name = "cmbRenderer";
|
||||
this.cmbRenderer.Size = new System.Drawing.Size(252, 21);
|
||||
this.cmbRenderer.Size = new System.Drawing.Size(335, 24);
|
||||
this.cmbRenderer.TabIndex = 0;
|
||||
this.cmbRenderer.SelectedIndexChanged += new System.EventHandler(this.cmbRenderer_SelectedIndexChanged);
|
||||
//
|
||||
@ -63,18 +67,20 @@
|
||||
//
|
||||
this.cmbResolution.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbResolution.FormattingEnabled = true;
|
||||
this.cmbResolution.Location = new System.Drawing.Point(124, 50);
|
||||
this.cmbResolution.Location = new System.Drawing.Point(165, 62);
|
||||
this.cmbResolution.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.cmbResolution.Name = "cmbResolution";
|
||||
this.cmbResolution.Size = new System.Drawing.Size(252, 21);
|
||||
this.cmbResolution.Size = new System.Drawing.Size(335, 24);
|
||||
this.cmbResolution.TabIndex = 1;
|
||||
//
|
||||
// cmbAntialiasing
|
||||
//
|
||||
this.cmbAntialiasing.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbAntialiasing.FormattingEnabled = true;
|
||||
this.cmbAntialiasing.Location = new System.Drawing.Point(124, 81);
|
||||
this.cmbAntialiasing.Location = new System.Drawing.Point(165, 100);
|
||||
this.cmbAntialiasing.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.cmbAntialiasing.Name = "cmbAntialiasing";
|
||||
this.cmbAntialiasing.Size = new System.Drawing.Size(252, 21);
|
||||
this.cmbAntialiasing.Size = new System.Drawing.Size(335, 24);
|
||||
this.cmbAntialiasing.TabIndex = 2;
|
||||
//
|
||||
// groupBox1
|
||||
@ -85,9 +91,11 @@
|
||||
this.groupBox1.Controls.Add(this.cmbRenderer);
|
||||
this.groupBox1.Controls.Add(this.cmbResolution);
|
||||
this.groupBox1.Controls.Add(this.cmbAntialiasing);
|
||||
this.groupBox1.Location = new System.Drawing.Point(12, 12);
|
||||
this.groupBox1.Location = new System.Drawing.Point(16, 15);
|
||||
this.groupBox1.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(382, 116);
|
||||
this.groupBox1.Padding = new System.Windows.Forms.Padding(4);
|
||||
this.groupBox1.Size = new System.Drawing.Size(509, 143);
|
||||
this.groupBox1.TabIndex = 4;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "Graphics Settings";
|
||||
@ -95,27 +103,30 @@
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(52, 84);
|
||||
this.label3.Location = new System.Drawing.Point(69, 103);
|
||||
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(66, 13);
|
||||
this.label3.Size = new System.Drawing.Size(83, 16);
|
||||
this.label3.TabIndex = 6;
|
||||
this.label3.Text = "Anti-aliasing:";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(58, 53);
|
||||
this.label2.Location = new System.Drawing.Point(77, 65);
|
||||
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(60, 13);
|
||||
this.label2.Size = new System.Drawing.Size(74, 16);
|
||||
this.label2.TabIndex = 5;
|
||||
this.label2.Text = "Resolution:";
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(64, 22);
|
||||
this.label1.Location = new System.Drawing.Point(85, 27);
|
||||
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(54, 13);
|
||||
this.label1.Size = new System.Drawing.Size(67, 16);
|
||||
this.label1.TabIndex = 4;
|
||||
this.label1.Text = "Renderer:";
|
||||
//
|
||||
@ -124,9 +135,11 @@
|
||||
this.groupBox2.Controls.Add(this.cmbMode);
|
||||
this.groupBox2.Controls.Add(this.chkTripleBuffering);
|
||||
this.groupBox2.Controls.Add(this.chkVSync);
|
||||
this.groupBox2.Location = new System.Drawing.Point(12, 138);
|
||||
this.groupBox2.Location = new System.Drawing.Point(16, 170);
|
||||
this.groupBox2.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(118, 93);
|
||||
this.groupBox2.Padding = new System.Windows.Forms.Padding(4);
|
||||
this.groupBox2.Size = new System.Drawing.Size(157, 114);
|
||||
this.groupBox2.TabIndex = 5;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Mode";
|
||||
@ -139,17 +152,19 @@
|
||||
"Fullscreen",
|
||||
"Windowed",
|
||||
"Borderless"});
|
||||
this.cmbMode.Location = new System.Drawing.Point(12, 19);
|
||||
this.cmbMode.Location = new System.Drawing.Point(16, 23);
|
||||
this.cmbMode.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.cmbMode.Name = "cmbMode";
|
||||
this.cmbMode.Size = new System.Drawing.Size(88, 21);
|
||||
this.cmbMode.Size = new System.Drawing.Size(116, 24);
|
||||
this.cmbMode.TabIndex = 3;
|
||||
//
|
||||
// chkTripleBuffering
|
||||
//
|
||||
this.chkTripleBuffering.AutoSize = true;
|
||||
this.chkTripleBuffering.Location = new System.Drawing.Point(12, 64);
|
||||
this.chkTripleBuffering.Location = new System.Drawing.Point(16, 79);
|
||||
this.chkTripleBuffering.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.chkTripleBuffering.Name = "chkTripleBuffering";
|
||||
this.chkTripleBuffering.Size = new System.Drawing.Size(97, 17);
|
||||
this.chkTripleBuffering.Size = new System.Drawing.Size(119, 20);
|
||||
this.chkTripleBuffering.TabIndex = 2;
|
||||
this.chkTripleBuffering.Text = "Triple Buffering";
|
||||
this.chkTripleBuffering.UseVisualStyleBackColor = true;
|
||||
@ -157,18 +172,20 @@
|
||||
// chkVSync
|
||||
//
|
||||
this.chkVSync.AutoSize = true;
|
||||
this.chkVSync.Location = new System.Drawing.Point(12, 43);
|
||||
this.chkVSync.Location = new System.Drawing.Point(16, 53);
|
||||
this.chkVSync.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.chkVSync.Name = "chkVSync";
|
||||
this.chkVSync.Size = new System.Drawing.Size(88, 17);
|
||||
this.chkVSync.Size = new System.Drawing.Size(107, 20);
|
||||
this.chkVSync.TabIndex = 1;
|
||||
this.chkVSync.Text = "Vertical Sync";
|
||||
this.chkVSync.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnOK
|
||||
//
|
||||
this.btnOK.Location = new System.Drawing.Point(238, 208);
|
||||
this.btnOK.Location = new System.Drawing.Point(317, 272);
|
||||
this.btnOK.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.btnOK.Name = "btnOK";
|
||||
this.btnOK.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnOK.Size = new System.Drawing.Size(100, 28);
|
||||
this.btnOK.TabIndex = 6;
|
||||
this.btnOK.Text = "OK";
|
||||
this.btnOK.UseVisualStyleBackColor = true;
|
||||
@ -177,9 +194,10 @@
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(319, 208);
|
||||
this.btnCancel.Location = new System.Drawing.Point(425, 272);
|
||||
this.btnCancel.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCancel.Size = new System.Drawing.Size(100, 28);
|
||||
this.btnCancel.TabIndex = 7;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
@ -187,9 +205,10 @@
|
||||
//
|
||||
// btnResetDefaults
|
||||
//
|
||||
this.btnResetDefaults.Location = new System.Drawing.Point(300, 138);
|
||||
this.btnResetDefaults.Location = new System.Drawing.Point(400, 170);
|
||||
this.btnResetDefaults.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.btnResetDefaults.Name = "btnResetDefaults";
|
||||
this.btnResetDefaults.Size = new System.Drawing.Size(94, 23);
|
||||
this.btnResetDefaults.Size = new System.Drawing.Size(125, 28);
|
||||
this.btnResetDefaults.TabIndex = 8;
|
||||
this.btnResetDefaults.Text = "Reset Defaults";
|
||||
this.btnResetDefaults.UseVisualStyleBackColor = true;
|
||||
@ -198,9 +217,11 @@
|
||||
// groupBox3
|
||||
//
|
||||
this.groupBox3.Controls.Add(this.chkUpdates);
|
||||
this.groupBox3.Location = new System.Drawing.Point(136, 138);
|
||||
this.groupBox3.Location = new System.Drawing.Point(181, 167);
|
||||
this.groupBox3.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.groupBox3.Name = "groupBox3";
|
||||
this.groupBox3.Size = new System.Drawing.Size(127, 49);
|
||||
this.groupBox3.Padding = new System.Windows.Forms.Padding(4);
|
||||
this.groupBox3.Size = new System.Drawing.Size(169, 54);
|
||||
this.groupBox3.TabIndex = 6;
|
||||
this.groupBox3.TabStop = false;
|
||||
this.groupBox3.Text = "Other";
|
||||
@ -208,22 +229,44 @@
|
||||
// chkUpdates
|
||||
//
|
||||
this.chkUpdates.AutoSize = true;
|
||||
this.chkUpdates.Location = new System.Drawing.Point(8, 22);
|
||||
this.chkUpdates.Location = new System.Drawing.Point(11, 24);
|
||||
this.chkUpdates.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.chkUpdates.Name = "chkUpdates";
|
||||
this.chkUpdates.Size = new System.Drawing.Size(115, 17);
|
||||
this.chkUpdates.Size = new System.Drawing.Size(140, 20);
|
||||
this.chkUpdates.TabIndex = 1;
|
||||
this.chkUpdates.Text = "Check for Updates";
|
||||
this.chkUpdates.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// cmbBranch
|
||||
//
|
||||
this.cmbBranch.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbBranch.FormattingEnabled = true;
|
||||
this.cmbBranch.Location = new System.Drawing.Point(27, 17);
|
||||
this.cmbBranch.Name = "cmbBranch";
|
||||
this.cmbBranch.Size = new System.Drawing.Size(124, 24);
|
||||
this.cmbBranch.TabIndex = 9;
|
||||
//
|
||||
// BranchGroupBox
|
||||
//
|
||||
this.BranchGroupBox.Controls.Add(this.cmbBranch);
|
||||
this.BranchGroupBox.Location = new System.Drawing.Point(181, 222);
|
||||
this.BranchGroupBox.Name = "BranchGroupBox";
|
||||
this.BranchGroupBox.Size = new System.Drawing.Size(169, 49);
|
||||
this.BranchGroupBox.TabIndex = 10;
|
||||
this.BranchGroupBox.TabStop = false;
|
||||
this.BranchGroupBox.Text = "Branch";
|
||||
this.BranchGroupBox.Visible = false;
|
||||
//
|
||||
// OptionsForm
|
||||
//
|
||||
this.AcceptButton = this.btnOK;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoSize = true;
|
||||
this.CancelButton = this.btnCancel;
|
||||
this.ClientSize = new System.Drawing.Size(406, 239);
|
||||
this.ClientSize = new System.Drawing.Size(541, 316);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.BranchGroupBox);
|
||||
this.Controls.Add(this.groupBox3);
|
||||
this.Controls.Add(this.btnResetDefaults);
|
||||
this.Controls.Add(this.btnCancel);
|
||||
@ -231,6 +274,7 @@
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
this.Margin = new System.Windows.Forms.Padding(4);
|
||||
this.Name = "OptionsForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
@ -245,6 +289,7 @@
|
||||
this.groupBox2.PerformLayout();
|
||||
this.groupBox3.ResumeLayout(false);
|
||||
this.groupBox3.PerformLayout();
|
||||
this.BranchGroupBox.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
@ -267,5 +312,7 @@
|
||||
private System.Windows.Forms.GroupBox groupBox3;
|
||||
private System.Windows.Forms.CheckBox chkUpdates;
|
||||
private System.Windows.Forms.ComboBox cmbMode;
|
||||
private System.Windows.Forms.ComboBox cmbBranch;
|
||||
private System.Windows.Forms.GroupBox BranchGroupBox;
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using Giants.WebApi.Clients;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Giants.Launcher
|
||||
@ -9,16 +11,34 @@ namespace Giants.Launcher
|
||||
public partial class OptionsForm : Form
|
||||
{
|
||||
private readonly string gamePath = null;
|
||||
private readonly string appName;
|
||||
private readonly Config config;
|
||||
private readonly string currentBranchName;
|
||||
private readonly bool enableBranchSelection;
|
||||
private readonly BranchesClient branchesClient;
|
||||
|
||||
public OptionsForm(string title, string gamePath)
|
||||
public OptionsForm(
|
||||
string title,
|
||||
string gamePath,
|
||||
string appName,
|
||||
Config config,
|
||||
string currentBranchName,
|
||||
BranchesClient branchesClient)
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
this.Text = title;
|
||||
this.gamePath = gamePath;
|
||||
this.appName = appName;
|
||||
this.config = config;
|
||||
this.currentBranchName = currentBranchName;
|
||||
this.branchesClient = branchesClient;
|
||||
|
||||
this.config.TryGetBool(ConfigSections.Update, ConfigKeys.EnableBranchSelection, defaultValue: false, out bool enableBranchSelection);
|
||||
this.enableBranchSelection = enableBranchSelection;
|
||||
}
|
||||
|
||||
private void OptionsForm_Load(object sender, EventArgs e)
|
||||
private async void OptionsForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
// Must come first as other options depend on it
|
||||
this.PopulateRenderers();
|
||||
@ -28,9 +48,33 @@ namespace Giants.Launcher
|
||||
this.PopulateAnisotropy();
|
||||
this.PopulateAntialiasing();
|
||||
|
||||
await this.PopulateBranches();
|
||||
|
||||
this.SetOptions();
|
||||
}
|
||||
|
||||
private async Task PopulateBranches()
|
||||
{
|
||||
if (this.enableBranchSelection)
|
||||
{
|
||||
try
|
||||
{
|
||||
var branches = await this.branchesClient.GetBranchesAsync(this.appName);
|
||||
|
||||
cmbBranch.Items.AddRange(branches.ToArray());
|
||||
|
||||
cmbBranch.SelectedItem = this.currentBranchName;
|
||||
|
||||
BranchGroupBox.Visible = true;
|
||||
cmbBranch.Visible = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageBox.Show($"Unhandled exception retrieving branch information from the server: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateRenderers()
|
||||
{
|
||||
this.cmbRenderer.Items.Clear();
|
||||
@ -72,12 +116,19 @@ namespace Giants.Launcher
|
||||
this.cmbAntialiasing.SelectedIndex = 0;
|
||||
|
||||
this.chkUpdates.Checked = GameSettings.Get<int>(RegistryKeys.NoAutoUpdate) != 1;
|
||||
|
||||
if (this.enableBranchSelection)
|
||||
{
|
||||
this.cmbBranch.SelectedItem = this.currentBranchName;
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateAntialiasing()
|
||||
{
|
||||
var antialiasingOptions = new List<KeyValuePair<string, int>>();
|
||||
antialiasingOptions.Add(new KeyValuePair<string, int>(Resources.OptionNone, 0));
|
||||
var antialiasingOptions = new List<KeyValuePair<string, int>>
|
||||
{
|
||||
new KeyValuePair<string, int>(Resources.OptionNone, 0)
|
||||
};
|
||||
|
||||
var renderer = (RendererInfo)this.cmbRenderer.SelectedItem;
|
||||
if (renderer != null)
|
||||
@ -228,6 +279,15 @@ namespace Giants.Launcher
|
||||
|
||||
GameSettings.Save();
|
||||
|
||||
if (this.enableBranchSelection)
|
||||
{
|
||||
string newBranch = this.cmbBranch.SelectedItem?.ToString();
|
||||
if (!string.IsNullOrEmpty(newBranch) && !newBranch.Equals(this.currentBranchName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
this.config.SetValue(ConfigSections.Update, ConfigKeys.BranchName, newBranch);
|
||||
}
|
||||
}
|
||||
|
||||
this.Close();
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="ApplicationNames.cs" />
|
||||
<Compile Include="Config.cs" />
|
||||
<Compile Include="ConfigDefaults.cs" />
|
||||
<Compile Include="ConfigKeys.cs" />
|
||||
<Compile Include="ConfigSections.cs" />
|
||||
<Compile Include="Renderer\RendererInfo.cs" />
|
||||
@ -181,7 +182,6 @@
|
||||
<Target Name="PostBuild" AfterTargets="Build">
|
||||
<Copy Condition="$(GameImagePath) != ''" SourceFiles="$(TargetPath)" DestinationFolder="$(GameImagePath)" SkipUnchangedFiles="true" />
|
||||
<Copy Condition="$(GameImagePath) != ''" SourceFiles="@(ReferenceCopyLocalPaths)" DestinationFolder="$(GameImagePath)" SkipUnchangedFiles="true" />
|
||||
<Copy Condition="$(GameImagePath) != ''" SourceFiles="@(_SourceItemsToCopyToOutputDirectory)" DestinationFolder="$(GameImagePath)" SkipUnchangedFiles="true" />
|
||||
<CallTarget Condition="$(GIANTS_PATH) != ''" Targets="CopyTargetToGameFolder" />
|
||||
</Target>
|
||||
</Project>
|
@ -2,6 +2,8 @@
|
||||
{
|
||||
public enum ApplicationType
|
||||
{
|
||||
None = 0,
|
||||
|
||||
Launcher,
|
||||
Game,
|
||||
}
|
||||
|
@ -1,38 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Giants.WebApi.Clients;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Giants.WebApi.Clients;
|
||||
|
||||
namespace Giants.Launcher
|
||||
{
|
||||
public class Updater
|
||||
{
|
||||
private readonly IDictionary<ApplicationType, Version> appVersions;
|
||||
private readonly AsyncCompletedEventHandler updateCompletedCallback;
|
||||
private readonly DownloadProgressChangedEventHandler updateProgressCallback;
|
||||
|
||||
public Updater(
|
||||
IDictionary<ApplicationType, Version> appVersions,
|
||||
AsyncCompletedEventHandler updateCompletedCallback,
|
||||
DownloadProgressChangedEventHandler updateProgressCallback)
|
||||
{
|
||||
this.appVersions = appVersions;
|
||||
this.updateCompletedCallback = updateCompletedCallback;
|
||||
this.updateProgressCallback = updateProgressCallback;
|
||||
}
|
||||
|
||||
public bool IsUpdateRequired(ApplicationType applicationType, VersionInfo versionInfo)
|
||||
public bool IsUpdateRequired(ApplicationType applicationType, VersionInfo remoteVersionInfo, Version localVersion)
|
||||
{
|
||||
if (versionInfo != null && this.ToVersion(versionInfo.Version) > this.appVersions[applicationType])
|
||||
if (remoteVersionInfo?.InstallerUri != null
|
||||
&& this.ToVersion(remoteVersionInfo.Version) > localVersion)
|
||||
{
|
||||
// Display update prompt
|
||||
string updateMsg = applicationType == ApplicationType.Game ?
|
||||
string.Format(Resources.UpdateAvailableText, this.ToVersion(versionInfo.Version).ToString()) :
|
||||
string.Format(Resources.LauncherUpdateAvailableText, this.ToVersion(versionInfo.Version).ToString());
|
||||
string.Format(Resources.UpdateAvailableText, this.ToVersion(remoteVersionInfo.Version).ToString()) :
|
||||
string.Format(Resources.LauncherUpdateAvailableText, this.ToVersion(remoteVersionInfo.Version).ToString());
|
||||
|
||||
if (MessageBox.Show(updateMsg, Resources.UpdateAvailableTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
|
||||
{
|
||||
|
@ -15,6 +15,10 @@
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
string message = string.Format(Resources.AppNotFound, Resources.AppName);
|
||||
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
Application.Exit();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
7
Giants.Services/BranchConstants.cs
Normal file
7
Giants.Services/BranchConstants.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Giants.Services
|
||||
{
|
||||
public static class BranchConstants
|
||||
{
|
||||
public const string DefaultBranchName = "Release";
|
||||
}
|
||||
}
|
@ -1,9 +1,5 @@
|
||||
namespace Giants.Services
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
public static class CacheKeys
|
||||
{
|
||||
public const string ServerInfo = nameof(ServerInfo);
|
||||
|
@ -4,10 +4,10 @@ namespace Giants.Services
|
||||
{
|
||||
public class VersionInfo : DataContract.V1.VersionInfo, IIdentifiable
|
||||
{
|
||||
public string id => GenerateId(this.AppName);
|
||||
public string id => GenerateId(this.AppName, this.BranchName ?? BranchConstants.DefaultBranchName);
|
||||
|
||||
public string DocumentType => nameof(VersionInfo);
|
||||
|
||||
public static string GenerateId(string gameName) => $"{nameof(VersionInfo)}-{gameName}";
|
||||
public static string GenerateId(string appName, string branchName) => $"{nameof(VersionInfo)}-{appName}-{branchName}";
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,75 @@
|
||||
namespace Giants.Services
|
||||
{
|
||||
using System;
|
||||
using System.Net.Http.Headers;
|
||||
using Autofac;
|
||||
using Giants.Services.Core;
|
||||
using Giants.Services.Services;
|
||||
using Giants.Services.Store;
|
||||
using Giants.Services.Utility;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
|
||||
public static class ServicesModule
|
||||
public class ServicesModule : Module
|
||||
{
|
||||
public static void RegisterServices(IServiceCollection services, IConfiguration configuration)
|
||||
private readonly IConfiguration configuration;
|
||||
|
||||
public ServicesModule(IConfiguration configuration)
|
||||
{
|
||||
services.AddSingleton<IServerRegistryService, ServerRegistryService>();
|
||||
services.AddSingleton<IServerRegistryStore, CosmosDbServerRegistryStore>();
|
||||
services.AddSingleton<IDateTimeProvider, DefaultDateTimeProvider>();
|
||||
services.AddSingleton<IMemoryCache, MemoryCache>();
|
||||
services.AddSingleton<IVersioningStore, CosmosDbVersioningStore>();
|
||||
services.AddSingleton<IVersioningService, VersioningService>();
|
||||
services.AddSingleton<ICommunityService, CommunityService>();
|
||||
services.AddSingleton<ICrashReportService, CrashReportService>();
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
services.AddHostedService<InitializerService>();
|
||||
services.AddHostedService<ServerRegistryCleanupService>();
|
||||
|
||||
services.AddHttpClient("Sentry", c =>
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
c.BaseAddress = new Uri(configuration["SentryBaseUri"]);
|
||||
builder.RegisterType<ServerRegistryService>()
|
||||
.As<IServerRegistryService>()
|
||||
.SingleInstance();
|
||||
builder.RegisterType<CosmosDbServerRegistryStore>()
|
||||
.As<IServerRegistryStore>()
|
||||
.SingleInstance();
|
||||
builder.RegisterType<DefaultDateTimeProvider>()
|
||||
.As<IDateTimeProvider>()
|
||||
.SingleInstance();
|
||||
builder.RegisterType<MemoryCache>()
|
||||
.As<IMemoryCache>()
|
||||
.SingleInstance();
|
||||
builder.RegisterType<CosmosDbVersioningStore>()
|
||||
.As<IVersioningStore>()
|
||||
.SingleInstance();
|
||||
builder.RegisterType<VersioningService>()
|
||||
.As<IVersioningService>()
|
||||
.SingleInstance();
|
||||
builder.RegisterType<CommunityService>()
|
||||
.As<ICommunityService>()
|
||||
.SingleInstance();
|
||||
builder.RegisterType<CrashReportService>()
|
||||
.As<ICrashReportService>()
|
||||
.SingleInstance();
|
||||
|
||||
string sentryAuthenticationToken = configuration["SentryAuthenticationToken"];
|
||||
c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", sentryAuthenticationToken);
|
||||
var cosmosClient = new CosmosDbClient(
|
||||
connectionString: this.configuration["CosmosDbEndpoint"],
|
||||
authKeyOrResourceToken: this.configuration["CosmosDbKey"],
|
||||
databaseId: this.configuration["DatabaseId"],
|
||||
containerId: this.configuration["ContainerId"]);
|
||||
|
||||
cosmosClient.Initialize().GetAwaiter().GetResult();
|
||||
|
||||
builder.RegisterInstance(cosmosClient).SingleInstance();
|
||||
|
||||
builder.Register<ISimpleMemoryCache<VersionInfo>>(icc =>
|
||||
{
|
||||
var versionStore = icc.Resolve<IVersioningStore>();
|
||||
|
||||
return new SimpleMemoryCache<VersionInfo>(
|
||||
expirationPeriod: TimeSpan.FromMinutes(5),
|
||||
memoryCache: icc.Resolve<IMemoryCache>(),
|
||||
cacheKey: CacheKeys.VersionInfo,
|
||||
getAllItems: async (cacheEntry) =>
|
||||
{
|
||||
return await versionStore.GetVersions();
|
||||
});
|
||||
})
|
||||
.AsSelf()
|
||||
.SingleInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="6.4.0" />
|
||||
<PackageReference Include="AutoMapper" Version="11.0.1" />
|
||||
<PackageReference Include="Azure.Storage.Blobs" Version="12.13.1" />
|
||||
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.30.1" />
|
||||
|
@ -1,12 +1,15 @@
|
||||
namespace Giants.Services
|
||||
{
|
||||
using Giants.DataContract.V1;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public interface IVersioningService
|
||||
{
|
||||
Task<VersionInfo> GetVersionInfo(string appName);
|
||||
Task<IEnumerable<string>> GetBranches(string appName);
|
||||
|
||||
Task UpdateVersionInfo(string appName, AppVersion appVersion, string fileName);
|
||||
Task<VersionInfo> GetVersionInfo(string appName, string branchName);
|
||||
|
||||
Task UpdateVersionInfo(string appName, AppVersion appVersion, string fileName, string branchName, bool force);
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
namespace Giants.Services
|
||||
{
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
public class InitializerService : IHostedService
|
||||
{
|
||||
private readonly IVersioningStore updaterStore;
|
||||
private readonly IServerRegistryStore serverRegistryStore;
|
||||
|
||||
public InitializerService(
|
||||
IVersioningStore updaterStore,
|
||||
IServerRegistryStore serverRegistryStore)
|
||||
{
|
||||
// TODO: Pick these up from reflection and auto initialize
|
||||
this.updaterStore = updaterStore;
|
||||
this.serverRegistryStore = serverRegistryStore;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await this.serverRegistryStore.Initialize();
|
||||
await this.updaterStore.Initialize();
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
using Giants.DataContract.V1;
|
||||
using Giants.Services.Utility;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Giants.Services
|
||||
@ -11,41 +13,54 @@ namespace Giants.Services
|
||||
{
|
||||
private readonly IVersioningStore versioningStore;
|
||||
private readonly IConfiguration configuration;
|
||||
private readonly ISimpleMemoryCache<VersionInfo> versionCache;
|
||||
private readonly ILogger<VersioningService> logger;
|
||||
|
||||
private const string InstallerContainerName = "public";
|
||||
|
||||
public VersioningService(
|
||||
ILogger<VersioningService> logger,
|
||||
IVersioningStore updaterStore,
|
||||
IConfiguration configuration,
|
||||
ILogger<VersioningService> logger)
|
||||
ISimpleMemoryCache<VersionInfo> versionCache)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.versioningStore = updaterStore;
|
||||
this.configuration = configuration;
|
||||
this.logger = logger;
|
||||
this.versionCache = versionCache;
|
||||
}
|
||||
|
||||
public Task<VersionInfo> GetVersionInfo(string appName)
|
||||
public async Task<VersionInfo> GetVersionInfo(string appName, string branchName)
|
||||
{
|
||||
ArgumentUtility.CheckStringForNullOrEmpty(appName);
|
||||
|
||||
return this.versioningStore.GetVersionInfo(appName);
|
||||
branchName ??= BranchConstants.DefaultBranchName;
|
||||
|
||||
var versions = await this.versionCache.GetItems();
|
||||
|
||||
return versions
|
||||
.Where(x => x.AppName.Equals(appName, StringComparison.Ordinal)
|
||||
&& !string.IsNullOrEmpty(x.BranchName)
|
||||
&& x.BranchName.Equals(branchName, StringComparison.OrdinalIgnoreCase))
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public async Task UpdateVersionInfo(string appName, AppVersion appVersion, string fileName)
|
||||
public async Task UpdateVersionInfo(string appName, AppVersion appVersion, string fileName, string branchName, bool force)
|
||||
{
|
||||
ArgumentUtility.CheckStringForNullOrEmpty(appName);
|
||||
ArgumentUtility.CheckForNull(appVersion);
|
||||
ArgumentUtility.CheckStringForNullOrEmpty(fileName);
|
||||
ArgumentUtility.CheckStringForNullOrEmpty(branchName);
|
||||
|
||||
Uri storageAccountUri = new Uri(this.configuration["StorageAccountUri"]);
|
||||
var storageAccountUri = new Uri(this.configuration["StorageAccountUri"]);
|
||||
|
||||
VersionInfo versionInfo = await this.GetVersionInfo(appName);
|
||||
VersionInfo versionInfo = await this.GetVersionInfo(appName, branchName);
|
||||
if (versionInfo == null)
|
||||
{
|
||||
throw new ArgumentException($"No version information for {appName} found.", nameof(appName));
|
||||
throw new ArgumentException($"No version information for {appName} ({branchName}) found.");
|
||||
}
|
||||
|
||||
if (appVersion < versionInfo.Version)
|
||||
if (!force && (appVersion < versionInfo.Version))
|
||||
{
|
||||
throw new ArgumentException($"Version {appVersion.SerializeToJson()} is less than current version {versionInfo.Version.SerializeToJson()}", nameof(appVersion));
|
||||
}
|
||||
@ -61,11 +76,22 @@ namespace Giants.Services
|
||||
AppName = appName,
|
||||
Version = appVersion,
|
||||
InstallerUri = installerUri,
|
||||
BranchName = branchName,
|
||||
};
|
||||
|
||||
this.logger.LogInformation("Updating version info for {appName}: {versionInfo}", appName, newVersionInfo.SerializeToJson());
|
||||
|
||||
await this.versioningStore.UpdateVersionInfo(newVersionInfo);
|
||||
this.versionCache.Invalidate();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<string>> GetBranches(string appName)
|
||||
{
|
||||
var allVersions = await this.versionCache.GetItems();
|
||||
|
||||
return allVersions
|
||||
.Where(x => x.AppName.Equals(appName, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(x => x.BranchName).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,8 @@
|
||||
private readonly IConfiguration configuration;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
private readonly IDateTimeProvider dateTimeProvider;
|
||||
private readonly CosmosDbClient client;
|
||||
private readonly TimeSpan timeoutPeriod;
|
||||
private CosmosDbClient client;
|
||||
|
||||
private const int ServerRefreshIntervalInMinutes = 1;
|
||||
|
||||
@ -27,12 +27,14 @@
|
||||
ILogger<CosmosDbServerRegistryStore> logger,
|
||||
IConfiguration configuration,
|
||||
IMemoryCache memoryCache,
|
||||
IDateTimeProvider dateTimeProvider)
|
||||
IDateTimeProvider dateTimeProvider,
|
||||
CosmosDbClient client)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.configuration = configuration;
|
||||
this.memoryCache = memoryCache;
|
||||
this.dateTimeProvider = dateTimeProvider;
|
||||
this.client = client;
|
||||
this.timeoutPeriod = TimeSpan.FromMinutes(Convert.ToDouble(this.configuration["ServerTimeoutPeriodInMinutes"]));
|
||||
}
|
||||
|
||||
@ -176,17 +178,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Initialize()
|
||||
{
|
||||
this.client = new CosmosDbClient(
|
||||
connectionString: this.configuration["CosmosDbEndpoint"],
|
||||
authKeyOrResourceToken: this.configuration["CosmosDbKey"],
|
||||
databaseId: this.configuration["DatabaseId"],
|
||||
containerId: this.configuration["ContainerId"]);
|
||||
|
||||
await this.client.Initialize();
|
||||
}
|
||||
|
||||
private async Task<ConcurrentDictionary<string, IList<ServerInfo>>> PopulateCache(ICacheEntry entry)
|
||||
{
|
||||
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
|
||||
|
@ -1,63 +1,26 @@
|
||||
namespace Giants.Services.Store
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public class CosmosDbVersioningStore : IVersioningStore
|
||||
{
|
||||
private readonly ILogger<CosmosDbServerRegistryStore> logger;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
private readonly IConfiguration configuration;
|
||||
private CosmosDbClient client;
|
||||
private readonly CosmosDbClient client;
|
||||
|
||||
public CosmosDbVersioningStore(
|
||||
ILogger<CosmosDbServerRegistryStore> logger,
|
||||
IMemoryCache memoryCache,
|
||||
IConfiguration configuration)
|
||||
CosmosDbClient cosmosDbClient)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.memoryCache = memoryCache;
|
||||
this.configuration = configuration;
|
||||
this.client = cosmosDbClient;
|
||||
}
|
||||
|
||||
public async Task<VersionInfo> GetVersionInfo(string appName)
|
||||
public Task<IEnumerable<VersionInfo>> GetVersions()
|
||||
{
|
||||
VersionInfo versionInfo = await this.memoryCache.GetOrCreateAsync<VersionInfo>(
|
||||
key: GetCacheKey(appName),
|
||||
factory: async (entry) =>
|
||||
{
|
||||
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
|
||||
|
||||
return await this.client.GetItemById<VersionInfo>(
|
||||
VersionInfo.GenerateId(appName),
|
||||
nameof(VersionInfo));
|
||||
});
|
||||
|
||||
return versionInfo;
|
||||
return this.client.GetItems<VersionInfo>();
|
||||
}
|
||||
|
||||
public async Task UpdateVersionInfo(VersionInfo versionInfo)
|
||||
{
|
||||
await this.client.UpsertItem(versionInfo);
|
||||
}
|
||||
|
||||
public async Task Initialize()
|
||||
{
|
||||
this.client = new CosmosDbClient(
|
||||
connectionString: this.configuration["CosmosDbEndpoint"],
|
||||
authKeyOrResourceToken: this.configuration["CosmosDbKey"],
|
||||
databaseId: this.configuration["DatabaseId"],
|
||||
containerId: this.configuration["ContainerId"]);
|
||||
|
||||
await this.client.Initialize();
|
||||
}
|
||||
|
||||
private static string GetCacheKey(string gameName)
|
||||
{
|
||||
return $"{CacheKeys.VersionInfo}-{gameName}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
namespace Giants.Services
|
||||
{
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class FileVersioningStore : IVersioningStore
|
||||
{
|
||||
public Task<VersionInfo> GetVersionInfo(string appName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task UpdateVersionInfo(VersionInfo versionInfo)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task Initialize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -7,8 +7,6 @@
|
||||
|
||||
public interface IServerRegistryStore
|
||||
{
|
||||
Task Initialize();
|
||||
|
||||
Task DeleteServer(string id, string partitionKey = null);
|
||||
|
||||
Task DeleteServers(IEnumerable<string> ids, string partitionKey = null);
|
||||
|
@ -1,13 +1,12 @@
|
||||
namespace Giants.Services
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public interface IVersioningStore
|
||||
{
|
||||
Task<VersionInfo> GetVersionInfo(string appName);
|
||||
Task<IEnumerable<VersionInfo>> GetVersions();
|
||||
|
||||
Task UpdateVersionInfo(VersionInfo versionInfo);
|
||||
|
||||
Task Initialize();
|
||||
}
|
||||
}
|
||||
|
12
Giants.Services/Utility/ISimpleMemoryCache.cs
Normal file
12
Giants.Services/Utility/ISimpleMemoryCache.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Giants.Services.Utility
|
||||
{
|
||||
public interface ISimpleMemoryCache<TRecord>
|
||||
{
|
||||
Task<IEnumerable<TRecord>> GetItems();
|
||||
|
||||
void Invalidate();
|
||||
}
|
||||
}
|
82
Giants.Services/Utility/SimpleMemoryCache.cs
Normal file
82
Giants.Services/Utility/SimpleMemoryCache.cs
Normal file
@ -0,0 +1,82 @@
|
||||
using Microsoft.Extensions.Azure;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Giants.Services.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper around <see cref="MemoryCache"/> that caches all items of the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRecord"></typeparam>
|
||||
public class SimpleMemoryCache<TRecord> : ISimpleMemoryCache<TRecord>, IDisposable
|
||||
{
|
||||
private readonly TimeSpan? expirationPeriod;
|
||||
private IMemoryCache memoryCache;
|
||||
private readonly object cacheKey;
|
||||
private readonly Func<ICacheEntry, Task<IEnumerable<TRecord>>> getAllItems;
|
||||
private CancellationTokenSource resetCacheToken;
|
||||
private bool disposedValue;
|
||||
|
||||
public SimpleMemoryCache(
|
||||
TimeSpan? expirationPeriod,
|
||||
IMemoryCache memoryCache,
|
||||
object cacheKey,
|
||||
Func<ICacheEntry, Task<IEnumerable<TRecord>>> getAllItems)
|
||||
{
|
||||
this.expirationPeriod = expirationPeriod;
|
||||
this.memoryCache = memoryCache;
|
||||
this.cacheKey = cacheKey;
|
||||
this.getAllItems = getAllItems;
|
||||
this.resetCacheToken = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TRecord>> GetItems()
|
||||
{
|
||||
IEnumerable<TRecord> items = await this.memoryCache.GetOrCreateAsync(cacheKey, this.PopulateCache);
|
||||
return items;
|
||||
}
|
||||
|
||||
public void Invalidate()
|
||||
{
|
||||
this.resetCacheToken.Cancel();
|
||||
this.resetCacheToken.Dispose();
|
||||
this.resetCacheToken = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<TRecord>> PopulateCache(ICacheEntry cacheEntry)
|
||||
{
|
||||
if (this.expirationPeriod.HasValue)
|
||||
{
|
||||
cacheEntry.AbsoluteExpirationRelativeToNow = this.expirationPeriod;
|
||||
}
|
||||
|
||||
cacheEntry.AddExpirationToken(new CancellationChangeToken(this.resetCacheToken.Token));
|
||||
|
||||
return await this.getAllItems(cacheEntry);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
this.memoryCache?.Dispose();
|
||||
this.resetCacheToken?.Dispose();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,15 @@
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
"net6.0": {
|
||||
"Autofac": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.4.0, )",
|
||||
"resolved": "6.4.0",
|
||||
"contentHash": "tkFxl6wAPuwVhrlN8wuNADnd+k2tv4ReP7ZZSL0vjfcN0RcfC9v25ogxK6b03HC7D4NwWjSLf1G/zTG8Bw43wQ==",
|
||||
"dependencies": {
|
||||
"System.Diagnostics.DiagnosticSource": "4.7.1"
|
||||
}
|
||||
},
|
||||
"AutoMapper": {
|
||||
"type": "Direct",
|
||||
"requested": "[11.0.1, )",
|
||||
|
@ -52,17 +52,26 @@ namespace Giants.WebApi.Clients
|
||||
partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response);
|
||||
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public virtual System.Threading.Tasks.Task DeleteServerAsync()
|
||||
public virtual System.Threading.Tasks.Task DeleteServerAsync(string gameName, int? port)
|
||||
{
|
||||
return DeleteServerAsync(System.Threading.CancellationToken.None);
|
||||
return DeleteServerAsync(gameName, port, System.Threading.CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public virtual async System.Threading.Tasks.Task DeleteServerAsync(System.Threading.CancellationToken cancellationToken)
|
||||
public virtual async System.Threading.Tasks.Task DeleteServerAsync(string gameName, int? port, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
var urlBuilder_ = new System.Text.StringBuilder();
|
||||
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Servers");
|
||||
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Servers?");
|
||||
if (gameName != null)
|
||||
{
|
||||
urlBuilder_.Append(System.Uri.EscapeDataString("gameName") + "=").Append(System.Uri.EscapeDataString(ConvertToString(gameName, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
|
||||
}
|
||||
if (port != null)
|
||||
{
|
||||
urlBuilder_.Append(System.Uri.EscapeDataString("port") + "=").Append(System.Uri.EscapeDataString(ConvertToString(port, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
|
||||
}
|
||||
urlBuilder_.Length--;
|
||||
|
||||
var client_ = _httpClient;
|
||||
var disposeClient_ = false;
|
||||
@ -364,6 +373,220 @@ namespace Giants.WebApi.Clients
|
||||
}
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v11.0.0.0))")]
|
||||
public partial class BranchesClient
|
||||
{
|
||||
private string _baseUrl = "https://localhost:44304";
|
||||
private System.Net.Http.HttpClient _httpClient;
|
||||
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;
|
||||
|
||||
public BranchesClient(System.Net.Http.HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
|
||||
}
|
||||
|
||||
private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
|
||||
{
|
||||
var settings = new Newtonsoft.Json.JsonSerializerSettings();
|
||||
UpdateJsonSerializerSettings(settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
public string BaseUrl
|
||||
{
|
||||
get { return _baseUrl; }
|
||||
set { _baseUrl = value; }
|
||||
}
|
||||
|
||||
protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } }
|
||||
|
||||
partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings);
|
||||
|
||||
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url);
|
||||
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
|
||||
partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response);
|
||||
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public virtual System.Threading.Tasks.Task<System.Collections.Generic.ICollection<string>> GetBranchesAsync(string appName)
|
||||
{
|
||||
return GetBranchesAsync(appName, System.Threading.CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public virtual async System.Threading.Tasks.Task<System.Collections.Generic.ICollection<string>> GetBranchesAsync(string appName, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
var urlBuilder_ = new System.Text.StringBuilder();
|
||||
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Branches?");
|
||||
if (appName != null)
|
||||
{
|
||||
urlBuilder_.Append(System.Uri.EscapeDataString("appName") + "=").Append(System.Uri.EscapeDataString(ConvertToString(appName, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
|
||||
}
|
||||
urlBuilder_.Length--;
|
||||
|
||||
var client_ = _httpClient;
|
||||
var disposeClient_ = false;
|
||||
try
|
||||
{
|
||||
using (var request_ = new System.Net.Http.HttpRequestMessage())
|
||||
{
|
||||
request_.Method = new System.Net.Http.HttpMethod("GET");
|
||||
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
||||
|
||||
PrepareRequest(client_, request_, urlBuilder_);
|
||||
|
||||
var url_ = urlBuilder_.ToString();
|
||||
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
|
||||
|
||||
PrepareRequest(client_, request_, url_);
|
||||
|
||||
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
|
||||
var disposeResponse_ = true;
|
||||
try
|
||||
{
|
||||
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
|
||||
if (response_.Content != null && response_.Content.Headers != null)
|
||||
{
|
||||
foreach (var item_ in response_.Content.Headers)
|
||||
headers_[item_.Key] = item_.Value;
|
||||
}
|
||||
|
||||
ProcessResponse(client_, response_);
|
||||
|
||||
var status_ = (int)response_.StatusCode;
|
||||
if (status_ == 200)
|
||||
{
|
||||
var objectResponse_ = await ReadObjectResponseAsync<System.Collections.Generic.ICollection<string>>(response_, headers_, cancellationToken).ConfigureAwait(false);
|
||||
if (objectResponse_.Object == null)
|
||||
{
|
||||
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
|
||||
}
|
||||
return objectResponse_.Object;
|
||||
}
|
||||
else
|
||||
{
|
||||
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disposeResponse_)
|
||||
response_.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disposeClient_)
|
||||
client_.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected struct ObjectResponseResult<T>
|
||||
{
|
||||
public ObjectResponseResult(T responseObject, string responseText)
|
||||
{
|
||||
this.Object = responseObject;
|
||||
this.Text = responseText;
|
||||
}
|
||||
|
||||
public T Object { get; }
|
||||
|
||||
public string Text { get; }
|
||||
}
|
||||
|
||||
public bool ReadResponseAsString { get; set; }
|
||||
|
||||
protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>> ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
if (response == null || response.Content == null)
|
||||
{
|
||||
return new ObjectResponseResult<T>(default(T), string.Empty);
|
||||
}
|
||||
|
||||
if (ReadResponseAsString)
|
||||
{
|
||||
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
|
||||
return new ObjectResponseResult<T>(typedBody, responseText);
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonException exception)
|
||||
{
|
||||
var message = "Could not deserialize the response body string as " + typeof(T).FullName + ".";
|
||||
throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
using (var streamReader = new System.IO.StreamReader(responseStream))
|
||||
using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader))
|
||||
{
|
||||
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
|
||||
var typedBody = serializer.Deserialize<T>(jsonTextReader);
|
||||
return new ObjectResponseResult<T>(typedBody, string.Empty);
|
||||
}
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonException exception)
|
||||
{
|
||||
var message = "Could not deserialize the response body stream as " + typeof(T).FullName + ".";
|
||||
throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
if (value is System.Enum)
|
||||
{
|
||||
var name = System.Enum.GetName(value.GetType(), value);
|
||||
if (name != null)
|
||||
{
|
||||
var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name);
|
||||
if (field != null)
|
||||
{
|
||||
var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute))
|
||||
as System.Runtime.Serialization.EnumMemberAttribute;
|
||||
if (attribute != null)
|
||||
{
|
||||
return attribute.Value != null ? attribute.Value : name;
|
||||
}
|
||||
}
|
||||
|
||||
var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
|
||||
return converted == null ? string.Empty : converted;
|
||||
}
|
||||
}
|
||||
else if (value is bool)
|
||||
{
|
||||
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
|
||||
}
|
||||
else if (value is byte[])
|
||||
{
|
||||
return System.Convert.ToBase64String((byte[]) value);
|
||||
}
|
||||
else if (value.GetType().IsArray)
|
||||
{
|
||||
var array = System.Linq.Enumerable.OfType<object>((System.Array) value);
|
||||
return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo)));
|
||||
}
|
||||
|
||||
var result = System.Convert.ToString(value, cultureInfo);
|
||||
return result == null ? "" : result;
|
||||
}
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v11.0.0.0))")]
|
||||
public partial class CommunityClient
|
||||
{
|
||||
@ -573,6 +796,210 @@ namespace Giants.WebApi.Clients
|
||||
}
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v11.0.0.0))")]
|
||||
public partial class CrashReportsClient
|
||||
{
|
||||
private string _baseUrl = "https://localhost:44304";
|
||||
private System.Net.Http.HttpClient _httpClient;
|
||||
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;
|
||||
|
||||
public CrashReportsClient(System.Net.Http.HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
|
||||
}
|
||||
|
||||
private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
|
||||
{
|
||||
var settings = new Newtonsoft.Json.JsonSerializerSettings();
|
||||
UpdateJsonSerializerSettings(settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
public string BaseUrl
|
||||
{
|
||||
get { return _baseUrl; }
|
||||
set { _baseUrl = value; }
|
||||
}
|
||||
|
||||
protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } }
|
||||
|
||||
partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings);
|
||||
|
||||
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url);
|
||||
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
|
||||
partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response);
|
||||
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public virtual System.Threading.Tasks.Task UploadAsync()
|
||||
{
|
||||
return UploadAsync(System.Threading.CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public virtual async System.Threading.Tasks.Task UploadAsync(System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
var urlBuilder_ = new System.Text.StringBuilder();
|
||||
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/CrashReports");
|
||||
|
||||
var client_ = _httpClient;
|
||||
var disposeClient_ = false;
|
||||
try
|
||||
{
|
||||
using (var request_ = new System.Net.Http.HttpRequestMessage())
|
||||
{
|
||||
request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json");
|
||||
request_.Method = new System.Net.Http.HttpMethod("POST");
|
||||
|
||||
PrepareRequest(client_, request_, urlBuilder_);
|
||||
|
||||
var url_ = urlBuilder_.ToString();
|
||||
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
|
||||
|
||||
PrepareRequest(client_, request_, url_);
|
||||
|
||||
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
|
||||
var disposeResponse_ = true;
|
||||
try
|
||||
{
|
||||
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
|
||||
if (response_.Content != null && response_.Content.Headers != null)
|
||||
{
|
||||
foreach (var item_ in response_.Content.Headers)
|
||||
headers_[item_.Key] = item_.Value;
|
||||
}
|
||||
|
||||
ProcessResponse(client_, response_);
|
||||
|
||||
var status_ = (int)response_.StatusCode;
|
||||
if (status_ == 200)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disposeResponse_)
|
||||
response_.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disposeClient_)
|
||||
client_.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected struct ObjectResponseResult<T>
|
||||
{
|
||||
public ObjectResponseResult(T responseObject, string responseText)
|
||||
{
|
||||
this.Object = responseObject;
|
||||
this.Text = responseText;
|
||||
}
|
||||
|
||||
public T Object { get; }
|
||||
|
||||
public string Text { get; }
|
||||
}
|
||||
|
||||
public bool ReadResponseAsString { get; set; }
|
||||
|
||||
protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>> ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
if (response == null || response.Content == null)
|
||||
{
|
||||
return new ObjectResponseResult<T>(default(T), string.Empty);
|
||||
}
|
||||
|
||||
if (ReadResponseAsString)
|
||||
{
|
||||
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
|
||||
return new ObjectResponseResult<T>(typedBody, responseText);
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonException exception)
|
||||
{
|
||||
var message = "Could not deserialize the response body string as " + typeof(T).FullName + ".";
|
||||
throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
using (var streamReader = new System.IO.StreamReader(responseStream))
|
||||
using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader))
|
||||
{
|
||||
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
|
||||
var typedBody = serializer.Deserialize<T>(jsonTextReader);
|
||||
return new ObjectResponseResult<T>(typedBody, string.Empty);
|
||||
}
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonException exception)
|
||||
{
|
||||
var message = "Could not deserialize the response body stream as " + typeof(T).FullName + ".";
|
||||
throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
if (value is System.Enum)
|
||||
{
|
||||
var name = System.Enum.GetName(value.GetType(), value);
|
||||
if (name != null)
|
||||
{
|
||||
var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name);
|
||||
if (field != null)
|
||||
{
|
||||
var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute))
|
||||
as System.Runtime.Serialization.EnumMemberAttribute;
|
||||
if (attribute != null)
|
||||
{
|
||||
return attribute.Value != null ? attribute.Value : name;
|
||||
}
|
||||
}
|
||||
|
||||
var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
|
||||
return converted == null ? string.Empty : converted;
|
||||
}
|
||||
}
|
||||
else if (value is bool)
|
||||
{
|
||||
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
|
||||
}
|
||||
else if (value is byte[])
|
||||
{
|
||||
return System.Convert.ToBase64String((byte[]) value);
|
||||
}
|
||||
else if (value.GetType().IsArray)
|
||||
{
|
||||
var array = System.Linq.Enumerable.OfType<object>((System.Array) value);
|
||||
return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo)));
|
||||
}
|
||||
|
||||
var result = System.Convert.ToString(value, cultureInfo);
|
||||
return result == null ? "" : result;
|
||||
}
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v11.0.0.0))")]
|
||||
public partial class VersionClient
|
||||
{
|
||||
@ -608,14 +1035,14 @@ namespace Giants.WebApi.Clients
|
||||
partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response);
|
||||
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public virtual System.Threading.Tasks.Task<VersionInfo> GetVersionInfoAsync(string appName)
|
||||
public virtual System.Threading.Tasks.Task<VersionInfo> GetVersionInfoAsync(string appName, string branchName)
|
||||
{
|
||||
return GetVersionInfoAsync(appName, System.Threading.CancellationToken.None);
|
||||
return GetVersionInfoAsync(appName, branchName, System.Threading.CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public virtual async System.Threading.Tasks.Task<VersionInfo> GetVersionInfoAsync(string appName, System.Threading.CancellationToken cancellationToken)
|
||||
public virtual async System.Threading.Tasks.Task<VersionInfo> GetVersionInfoAsync(string appName, string branchName, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
var urlBuilder_ = new System.Text.StringBuilder();
|
||||
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Version?");
|
||||
@ -623,6 +1050,10 @@ namespace Giants.WebApi.Clients
|
||||
{
|
||||
urlBuilder_.Append(System.Uri.EscapeDataString("appName") + "=").Append(System.Uri.EscapeDataString(ConvertToString(appName, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
|
||||
}
|
||||
if (branchName != null)
|
||||
{
|
||||
urlBuilder_.Append(System.Uri.EscapeDataString("branchName") + "=").Append(System.Uri.EscapeDataString(ConvertToString(branchName, System.Globalization.CultureInfo.InvariantCulture))).Append("&");
|
||||
}
|
||||
urlBuilder_.Length--;
|
||||
|
||||
var client_ = _httpClient;
|
||||
@ -684,6 +1115,78 @@ namespace Giants.WebApi.Clients
|
||||
}
|
||||
}
|
||||
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public virtual System.Threading.Tasks.Task UpdateVersionInfoAsync(VersionInfoUpdate versionInfoUpdate)
|
||||
{
|
||||
return UpdateVersionInfoAsync(versionInfoUpdate, System.Threading.CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public virtual async System.Threading.Tasks.Task UpdateVersionInfoAsync(VersionInfoUpdate versionInfoUpdate, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
if (versionInfoUpdate == null)
|
||||
throw new System.ArgumentNullException("versionInfoUpdate");
|
||||
|
||||
var urlBuilder_ = new System.Text.StringBuilder();
|
||||
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Version");
|
||||
|
||||
var client_ = _httpClient;
|
||||
var disposeClient_ = false;
|
||||
try
|
||||
{
|
||||
using (var request_ = new System.Net.Http.HttpRequestMessage())
|
||||
{
|
||||
var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(versionInfoUpdate, _settings.Value));
|
||||
content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
|
||||
request_.Content = content_;
|
||||
request_.Method = new System.Net.Http.HttpMethod("POST");
|
||||
|
||||
PrepareRequest(client_, request_, urlBuilder_);
|
||||
|
||||
var url_ = urlBuilder_.ToString();
|
||||
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
|
||||
|
||||
PrepareRequest(client_, request_, url_);
|
||||
|
||||
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
|
||||
var disposeResponse_ = true;
|
||||
try
|
||||
{
|
||||
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
|
||||
if (response_.Content != null && response_.Content.Headers != null)
|
||||
{
|
||||
foreach (var item_ in response_.Content.Headers)
|
||||
headers_[item_.Key] = item_.Value;
|
||||
}
|
||||
|
||||
ProcessResponse(client_, response_);
|
||||
|
||||
var status_ = (int)response_.StatusCode;
|
||||
if (status_ == 200)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disposeResponse_)
|
||||
response_.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disposeClient_)
|
||||
client_.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected struct ObjectResponseResult<T>
|
||||
{
|
||||
public ObjectResponseResult(T responseObject, string responseText)
|
||||
@ -829,7 +1332,7 @@ namespace Giants.WebApi.Clients
|
||||
[Newtonsoft.Json.JsonProperty("numPlayers", Required = Newtonsoft.Json.Required.Always)]
|
||||
public int NumPlayers { get; set; }
|
||||
|
||||
[Newtonsoft.Json.JsonProperty("maxPlayers", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
|
||||
[Newtonsoft.Json.JsonProperty("maxPlayers", Required = Newtonsoft.Json.Required.Always)]
|
||||
public int MaxPlayers { get; set; }
|
||||
|
||||
[Newtonsoft.Json.JsonProperty("gameState", Required = Newtonsoft.Json.Required.Always)]
|
||||
@ -920,6 +1423,30 @@ namespace Giants.WebApi.Clients
|
||||
[System.ComponentModel.DataAnnotations.Required]
|
||||
public System.Uri InstallerUri { get; set; }
|
||||
|
||||
[Newtonsoft.Json.JsonProperty("branchName", Required = Newtonsoft.Json.Required.Always)]
|
||||
[System.ComponentModel.DataAnnotations.Required]
|
||||
public string BranchName { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v11.0.0.0))")]
|
||||
public partial class VersionInfoUpdate
|
||||
{
|
||||
[Newtonsoft.Json.JsonProperty("appName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
|
||||
public string AppName { get; set; }
|
||||
|
||||
[Newtonsoft.Json.JsonProperty("appVersion", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
|
||||
public AppVersion AppVersion { get; set; }
|
||||
|
||||
[Newtonsoft.Json.JsonProperty("fileName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
|
||||
public string FileName { get; set; }
|
||||
|
||||
[Newtonsoft.Json.JsonProperty("branchName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
|
||||
public string BranchName { get; set; }
|
||||
|
||||
[Newtonsoft.Json.JsonProperty("forceUpdate", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
|
||||
public bool ForceUpdate { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"x-generator": "NSwag v13.7.0.0 (NJsonSchema v10.1.24.0 (Newtonsoft.Json v10.0.0.0))",
|
||||
"x-generator": "NSwag v13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v10.0.0.0))",
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "My Title",
|
||||
@ -17,6 +17,26 @@
|
||||
"Servers"
|
||||
],
|
||||
"operationId": "Servers_DeleteServer",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "gameName",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"x-position": 1
|
||||
},
|
||||
{
|
||||
"name": "port",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"x-position": 2
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
@ -68,6 +88,40 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/Branches": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Branches"
|
||||
],
|
||||
"operationId": "Branches_GetBranches",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "appName",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"x-position": 1
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/Community": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@ -88,6 +142,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/CrashReports": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"CrashReports"
|
||||
],
|
||||
"operationId": "CrashReports_Upload",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/Version": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@ -103,6 +170,15 @@
|
||||
"nullable": true
|
||||
},
|
||||
"x-position": 1
|
||||
},
|
||||
{
|
||||
"name": "branchName",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"x-position": 2
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@ -117,6 +193,29 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"Version"
|
||||
],
|
||||
"operationId": "Version_UpdateVersionInfo",
|
||||
"requestBody": {
|
||||
"x-name": "versionInfoUpdate",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/VersionInfoUpdate"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true,
|
||||
"x-position": 1
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -153,6 +252,7 @@
|
||||
"mapName",
|
||||
"gameType",
|
||||
"numPlayers",
|
||||
"maxPlayers",
|
||||
"gameState",
|
||||
"timeLimit",
|
||||
"fragLimit",
|
||||
@ -305,7 +405,8 @@
|
||||
"required": [
|
||||
"appName",
|
||||
"version",
|
||||
"installerUri"
|
||||
"installerUri",
|
||||
"branchName"
|
||||
],
|
||||
"properties": {
|
||||
"appName": {
|
||||
@ -319,6 +420,39 @@
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"minLength": 1
|
||||
},
|
||||
"branchName": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"VersionInfoUpdate": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"appName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"appVersion": {
|
||||
"nullable": true,
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AppVersion"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fileName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"branchName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"forceUpdate": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
46
Giants.WebApi.Tests/BranchesControllerTests.cs
Normal file
46
Giants.WebApi.Tests/BranchesControllerTests.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using Giants.Web;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Text.Json;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace Giants.WebApi.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class BranchesControllerTests
|
||||
{
|
||||
private readonly JsonSerializerOptions options = new(JsonSerializerDefaults.Web);
|
||||
private static WebApplicationFactory<Program>? application;
|
||||
private static HttpClient? client;
|
||||
|
||||
[ClassInitialize]
|
||||
public static void Initialize(TestContext context)
|
||||
{
|
||||
application = new WebApplicationFactory<Program>()
|
||||
.WithWebHostBuilder(builder =>
|
||||
{
|
||||
});
|
||||
|
||||
client = application.CreateClient();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetBranchesReturnsExpectedBranches()
|
||||
{
|
||||
using (var response = await client!.GetAsync("api/branches?appName=Giants"))
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
string responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObject = JsonSerializer.Deserialize<IEnumerable<string>>(responseContent, options);
|
||||
|
||||
Assert.IsNotNull(responseObject);
|
||||
Assert.AreEqual(2, responseObject.Count());
|
||||
Assert.IsTrue(responseObject.Any(x => x == "Release"));
|
||||
Assert.IsTrue(responseObject.Any(x => x == "Beta"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
21
Giants.WebApi.Tests/Giants.WebApi.Tests.csproj
Normal file
21
Giants.WebApi.Tests/Giants.WebApi.Tests.csproj
Normal file
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Giants.WebApi\Giants.WebApi.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
127
Giants.WebApi.Tests/VersionControllerTests.cs
Normal file
127
Giants.WebApi.Tests/VersionControllerTests.cs
Normal file
@ -0,0 +1,127 @@
|
||||
using Giants.DataContract.V1;
|
||||
using Giants.Web;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Giants.WebApi.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class VersionControllerTests
|
||||
{
|
||||
private readonly JsonSerializerOptions options = new(JsonSerializerDefaults.Web);
|
||||
private static WebApplicationFactory<Program>? application;
|
||||
private static HttpClient? client;
|
||||
|
||||
[ClassInitialize]
|
||||
public static void Initialize(TestContext context)
|
||||
{
|
||||
application = new WebApplicationFactory<Program>()
|
||||
.WithWebHostBuilder(builder =>
|
||||
{
|
||||
});
|
||||
|
||||
client = application.CreateClient();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetVersionSupportsApiVersion1_0()
|
||||
{
|
||||
using (var response = await client!.GetAsync("api/version?appName=Giants"))
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
string responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObject = JsonSerializer.Deserialize<VersionInfo>(responseContent, options);
|
||||
Assert.IsNotNull(responseObject);
|
||||
|
||||
Assert.AreEqual("Giants", responseObject.AppName);
|
||||
Assert.IsNotNull(responseObject.Version);
|
||||
Assert.IsTrue(responseObject.InstallerUri.ToString().StartsWith("https://giants.blob.core.windows.net/public/GPatch"));
|
||||
Assert.AreEqual("Release", responseObject.BranchName);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetLauncherVersionSupportsApiVersion1_0()
|
||||
{
|
||||
using (var response = await client!.GetAsync("api/version?appName=GiantsLauncher"))
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
string responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObject = JsonSerializer.Deserialize<VersionInfo>(responseContent, options);
|
||||
Assert.IsNotNull(responseObject);
|
||||
|
||||
Assert.AreEqual("GiantsLauncher", responseObject.AppName);
|
||||
Assert.IsNotNull(responseObject.Version);
|
||||
Assert.IsTrue(responseObject.InstallerUri.ToString().StartsWith("about:blank"));
|
||||
Assert.AreEqual("Release", responseObject.BranchName);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetVersionFiltersByBranchNameCorrectly()
|
||||
{
|
||||
using (var response = await client!.GetAsync("api/version?appName=Giants&branchName=Release&apiVersion=1.1"))
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
string responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObject = JsonSerializer.Deserialize<VersionInfo>(responseContent, options);
|
||||
Assert.IsNotNull(responseObject);
|
||||
|
||||
Assert.AreEqual("Giants", responseObject.AppName);
|
||||
Assert.IsNotNull(responseObject.Version);
|
||||
Assert.IsTrue(responseObject.InstallerUri.ToString().StartsWith("https://giants.blob.core.windows.net/public/GPatch"));
|
||||
Assert.AreEqual("Release", responseObject.BranchName);
|
||||
}
|
||||
|
||||
using (var response = await client!.GetAsync("api/version?appName=Giants&branchName=Beta&apiVersion=1.1"))
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
string responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObject = JsonSerializer.Deserialize<VersionInfo>(responseContent, options);
|
||||
Assert.IsNotNull(responseObject);
|
||||
|
||||
Assert.AreEqual("Giants", responseObject.AppName);
|
||||
Assert.IsNotNull(responseObject.Version);
|
||||
Assert.IsTrue(responseObject.InstallerUri.ToString().StartsWith("https://giants.blob.core.windows.net/public/GPatch"));
|
||||
Assert.AreEqual("Beta", responseObject.BranchName);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetLauncherVersionFiltersByBranchNameCorrectly()
|
||||
{
|
||||
using (var response = await client!.GetAsync("api/version?appName=GiantsLauncher&branchName=Release&apiVersion=1.1"))
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
string responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObject = JsonSerializer.Deserialize<VersionInfo>(responseContent, options);
|
||||
Assert.IsNotNull(responseObject);
|
||||
|
||||
Assert.AreEqual("GiantsLauncher", responseObject.AppName);
|
||||
Assert.IsNotNull(responseObject.Version);
|
||||
Assert.IsTrue(responseObject.InstallerUri.ToString().StartsWith("about:blank"));
|
||||
Assert.AreEqual("Release", responseObject.BranchName);
|
||||
}
|
||||
|
||||
using (var response = await client!.GetAsync("api/version?appName=GiantsLauncher&branchName=Beta&apiVersion=1.1"))
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
string responseContent = await response.Content.ReadAsStringAsync();
|
||||
var responseObject = JsonSerializer.Deserialize<VersionInfo>(responseContent, options);
|
||||
Assert.IsNotNull(responseObject);
|
||||
|
||||
Assert.AreEqual("GiantsLauncher", responseObject.AppName);
|
||||
Assert.IsNotNull(responseObject.Version);
|
||||
Assert.IsTrue(responseObject.InstallerUri.ToString().StartsWith("about:blank"));
|
||||
Assert.AreEqual("Beta", responseObject.BranchName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
Giants.WebApi.Tests/appsettings.json
Normal file
9
Giants.WebApi.Tests/appsettings.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
2223
Giants.WebApi.Tests/packages.lock.json
Normal file
2223
Giants.WebApi.Tests/packages.lock.json
Normal file
File diff suppressed because it is too large
Load Diff
30
Giants.WebApi/Controllers/BranchesController.cs
Normal file
30
Giants.WebApi/Controllers/BranchesController.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using Giants.DataContract.V1;
|
||||
using Giants.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Giants.WebApi.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[Route("api/[controller]")]
|
||||
public class BranchesController : ControllerBase
|
||||
{
|
||||
private readonly IVersioningService versioningService;
|
||||
|
||||
public BranchesController(IVersioningService branchService)
|
||||
{
|
||||
this.versioningService = branchService;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IEnumerable<string>> GetBranches([FromQuery]string appName)
|
||||
{
|
||||
ArgumentUtility.CheckStringForNullOrEmpty(appName);
|
||||
|
||||
return await this.versioningService.GetBranches(appName);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ using Giants.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Identity.Web.Resource;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Giants.WebApi.Controllers
|
||||
@ -27,11 +28,16 @@ namespace Giants.WebApi.Controllers
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<DataContract.V1.VersionInfo> GetVersionInfo(string appName)
|
||||
public async Task<DataContract.V1.VersionInfo> GetVersionInfo(string appName, string branchName)
|
||||
{
|
||||
ArgumentUtility.CheckStringForNullOrEmpty(appName);
|
||||
|
||||
Services.VersionInfo versionInfo = await this.versioningService.GetVersionInfo(appName);
|
||||
VersionInfo versionInfo = await this.versioningService.GetVersionInfo(appName, branchName);
|
||||
|
||||
if (versionInfo == null)
|
||||
{
|
||||
throw new ArgumentException($"No version information for {appName} ({branchName}) found.", appName);
|
||||
}
|
||||
|
||||
return this.mapper.Map<DataContract.V1.VersionInfo>(versionInfo);
|
||||
}
|
||||
@ -44,7 +50,12 @@ namespace Giants.WebApi.Controllers
|
||||
{
|
||||
ArgumentUtility.CheckForNull(versionInfoUpdate);
|
||||
|
||||
await this.versioningService.UpdateVersionInfo(versionInfoUpdate.AppName, versionInfoUpdate.AppVersion, versionInfoUpdate.FileName);
|
||||
await this.versioningService.UpdateVersionInfo(
|
||||
appName: versionInfoUpdate.AppName,
|
||||
appVersion: versionInfoUpdate.AppVersion,
|
||||
fileName: versionInfoUpdate.FileName,
|
||||
branchName: versionInfoUpdate.BranchName,
|
||||
force: versionInfoUpdate.ForceUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="6.4.0" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="AutoMapper" Version="11.0.1" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.0.0" />
|
||||
|
@ -1,5 +1,8 @@
|
||||
namespace Giants.Web
|
||||
{
|
||||
using Autofac;
|
||||
using Autofac.Core;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using AutoMapper;
|
||||
using Giants.Services;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
@ -14,8 +17,10 @@ namespace Giants.Web
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Identity.Web;
|
||||
using Microsoft.IdentityModel.Logging;
|
||||
using NSwag.Generation.Processors;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class Program
|
||||
@ -26,7 +31,11 @@ namespace Giants.Web
|
||||
|
||||
ConfigureServices(builder);
|
||||
|
||||
var app = builder.Build();
|
||||
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
|
||||
builder.Host.ConfigureContainer<ContainerBuilder>((containerBuilder) => ConfigureAutofacServices(containerBuilder, builder.Configuration));
|
||||
|
||||
var app = builder
|
||||
.Build();
|
||||
ConfigureApplication(app, app.Environment);
|
||||
|
||||
app.Run();
|
||||
@ -87,17 +96,40 @@ namespace Giants.Web
|
||||
services.AddHttpContextAccessor();
|
||||
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
|
||||
|
||||
ServicesModule.RegisterServices(services, builder.Configuration);
|
||||
|
||||
IMapper mapper = Services.Mapper.GetMapper();
|
||||
services.AddSingleton(mapper);
|
||||
|
||||
services.AddHealthChecks();
|
||||
|
||||
RegisterHttpClients(services, builder.Configuration);
|
||||
|
||||
RegisterHostedServices(services);
|
||||
|
||||
builder.Logging.AddEventSourceLogger();
|
||||
builder.Logging.AddApplicationInsights();
|
||||
}
|
||||
|
||||
private static void ConfigureAutofacServices(ContainerBuilder containerBuilder, IConfiguration configuration)
|
||||
{
|
||||
containerBuilder.RegisterModule(new ServicesModule(configuration));
|
||||
}
|
||||
|
||||
private static void RegisterHttpClients(IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddHttpClient("Sentry", c =>
|
||||
{
|
||||
c.BaseAddress = new Uri(configuration["SentryBaseUri"]);
|
||||
|
||||
string sentryAuthenticationToken = configuration["SentryAuthenticationToken"];
|
||||
c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", sentryAuthenticationToken);
|
||||
});
|
||||
}
|
||||
|
||||
private static void RegisterHostedServices(IServiceCollection services)
|
||||
{
|
||||
services.AddHostedService<ServerRegistryCleanupService>();
|
||||
}
|
||||
|
||||
private static void ConfigureApplication(WebApplication app, IWebHostEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
|
@ -2,6 +2,25 @@
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
"net6.0": {
|
||||
"Autofac": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.4.0, )",
|
||||
"resolved": "6.4.0",
|
||||
"contentHash": "tkFxl6wAPuwVhrlN8wuNADnd+k2tv4ReP7ZZSL0vjfcN0RcfC9v25ogxK6b03HC7D4NwWjSLf1G/zTG8Bw43wQ==",
|
||||
"dependencies": {
|
||||
"System.Diagnostics.DiagnosticSource": "4.7.1"
|
||||
}
|
||||
},
|
||||
"Autofac.Extensions.DependencyInjection": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "nGrXNpQX2FiZpIBydK9cxZnnoqP/cUd3k/53uRERYEqLtWzKtE15R6L+j5q5ax5Rv/+3wAIkOaPePkahfqrwjg==",
|
||||
"dependencies": {
|
||||
"Autofac": "6.4.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
|
||||
}
|
||||
},
|
||||
"AutoMapper": {
|
||||
"type": "Direct",
|
||||
"requested": "[11.0.1, )",
|
||||
@ -1908,6 +1927,7 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper": "[11.0.1, )",
|
||||
"Autofac": "[6.4.0, )",
|
||||
"Azure.Storage.Blobs": "[12.13.1, )",
|
||||
"Giants.DataContract": "[1.0.0, )",
|
||||
"Microsoft.Azure.Cosmos": "[3.30.1, )",
|
||||
|
230
GiantsTools.sln
230
GiantsTools.sln
@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30320.27
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32811.315
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Giants.Services", "Giants.Services\Giants.Services.csproj", "{0CD61424-4E74-4A48-A726-729FEA32C50C}"
|
||||
EndProject
|
||||
@ -25,8 +25,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{0801
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imp_gbs", "Plugins\imp_gbs\imp_gbs.vcxproj", "{448F061E-AE05-4E06-84A1-C95660FD048C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Giants.Services.Tests", "Giants.Services.Tests\Giants.Services.Tests.csproj", "{2AFB71CA-8313-472E-B242-0517343764B4}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ServerConsole", "ServerConsoleExample\ServerConsole.vcxproj", "{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NavMeshGenerator", "NavMeshGenerator\NavMeshGenerator.vcxproj", "{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}"
|
||||
@ -34,327 +32,107 @@ EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
DebugBeta|Any CPU = DebugBeta|Any CPU
|
||||
DebugBeta|x64 = DebugBeta|x64
|
||||
DebugBeta|x86 = DebugBeta|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
ReleaseBeta|Any CPU = ReleaseBeta|Any CPU
|
||||
ReleaseBeta|x64 = ReleaseBeta|x64
|
||||
ReleaseBeta|x86 = ReleaseBeta|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.DebugBeta|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.DebugBeta|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.DebugBeta|x64.ActiveCfg = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.DebugBeta|x64.Build.0 = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.DebugBeta|x86.ActiveCfg = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.DebugBeta|x86.Build.0 = Debug|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.ReleaseBeta|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.ReleaseBeta|Any CPU.Build.0 = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.ReleaseBeta|x64.ActiveCfg = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.ReleaseBeta|x64.Build.0 = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{0CD61424-4E74-4A48-A726-729FEA32C50C}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.DebugBeta|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.DebugBeta|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.DebugBeta|x64.ActiveCfg = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.DebugBeta|x64.Build.0 = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.DebugBeta|x86.ActiveCfg = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.DebugBeta|x86.Build.0 = Debug|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.ReleaseBeta|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.ReleaseBeta|Any CPU.Build.0 = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.ReleaseBeta|x64.ActiveCfg = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.ReleaseBeta|x64.Build.0 = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{D426FE47-231B-41F0-AC78-293D12EF66A0}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.DebugBeta|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.DebugBeta|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.DebugBeta|x64.ActiveCfg = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.DebugBeta|x64.Build.0 = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.DebugBeta|x86.ActiveCfg = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.DebugBeta|x86.Build.0 = Debug|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.ReleaseBeta|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.ReleaseBeta|Any CPU.Build.0 = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.ReleaseBeta|x64.ActiveCfg = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.ReleaseBeta|x64.Build.0 = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{9A284C34-8F4B-4E20-B74B-1A0AF04EDBD1}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.DebugBeta|Any CPU.ActiveCfg = DebugBeta|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.DebugBeta|Any CPU.Build.0 = DebugBeta|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.DebugBeta|x64.ActiveCfg = Debug|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.DebugBeta|x64.Build.0 = Debug|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.DebugBeta|x86.ActiveCfg = Debug|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.DebugBeta|x86.Build.0 = Debug|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.ReleaseBeta|Any CPU.ActiveCfg = ReleaseBeta|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.ReleaseBeta|Any CPU.Build.0 = ReleaseBeta|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.ReleaseBeta|x64.ActiveCfg = Release|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.ReleaseBeta|x64.Build.0 = Release|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{612FD606-F072-4A04-9054-65BC592E9D3E}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.DebugBeta|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.DebugBeta|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.DebugBeta|x64.ActiveCfg = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.DebugBeta|x64.Build.0 = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.DebugBeta|x86.ActiveCfg = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.DebugBeta|x86.Build.0 = Debug|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.ReleaseBeta|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.ReleaseBeta|Any CPU.Build.0 = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.ReleaseBeta|x64.ActiveCfg = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.ReleaseBeta|x64.Build.0 = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{D4C21170-82D4-4D1F-81EC-036835AC1238}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Debug|x86.Build.0 = Debug|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.DebugBeta|Any CPU.ActiveCfg = Debug|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.DebugBeta|Any CPU.Build.0 = Debug|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.DebugBeta|x64.ActiveCfg = Debug|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.DebugBeta|x86.ActiveCfg = Debug|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.DebugBeta|x86.Build.0 = Debug|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|x64.ActiveCfg = Release|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|x86.ActiveCfg = Release|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.Release|x86.Build.0 = Release|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.ReleaseBeta|Any CPU.ActiveCfg = Release|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.ReleaseBeta|Any CPU.Build.0 = Release|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.ReleaseBeta|x64.ActiveCfg = Release|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.ReleaseBeta|x86.ActiveCfg = Release|Win32
|
||||
{9A0AF60B-3C3B-45B7-B5E1-4C9997A68EBB}.ReleaseBeta|x86.Build.0 = Release|Win32
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.DebugBeta|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.DebugBeta|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.DebugBeta|x64.ActiveCfg = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.DebugBeta|x64.Build.0 = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.DebugBeta|x86.ActiveCfg = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.DebugBeta|x86.Build.0 = Debug|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.ReleaseBeta|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.ReleaseBeta|Any CPU.Build.0 = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.ReleaseBeta|x64.ActiveCfg = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.ReleaseBeta|x64.Build.0 = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{6286A2C7-15F0-4D87-B928-4B012F9E0FFE}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.DebugBeta|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.DebugBeta|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.DebugBeta|x64.ActiveCfg = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.DebugBeta|x64.Build.0 = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.DebugBeta|x86.ActiveCfg = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.DebugBeta|x86.Build.0 = Debug|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.ReleaseBeta|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.ReleaseBeta|Any CPU.Build.0 = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.ReleaseBeta|x64.ActiveCfg = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.ReleaseBeta|x64.Build.0 = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{F5F3D216-9787-4CFF-88DF-8259CF667F88}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.DebugBeta|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.DebugBeta|Any CPU.Build.0 = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.DebugBeta|x64.ActiveCfg = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.DebugBeta|x64.Build.0 = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.DebugBeta|x86.ActiveCfg = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.DebugBeta|x86.Build.0 = Debug|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.ReleaseBeta|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.ReleaseBeta|Any CPU.Build.0 = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.ReleaseBeta|x64.ActiveCfg = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.ReleaseBeta|x64.Build.0 = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{49423BA5-4A9F-47A3-9D2D-E83936272DD0}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Debug|x64.Build.0 = Debug|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Debug|x86.Build.0 = Debug|Win32
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.DebugBeta|Any CPU.ActiveCfg = Debug|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.DebugBeta|Any CPU.Build.0 = Debug|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.DebugBeta|x64.ActiveCfg = Debug|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.DebugBeta|x64.Build.0 = Debug|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.DebugBeta|x86.ActiveCfg = Debug|Win32
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.DebugBeta|x86.Build.0 = Debug|Win32
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Debug|x86.Build.0 = Debug|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Release|Any CPU.Build.0 = Release|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Release|x64.ActiveCfg = Release|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Release|x64.Build.0 = Release|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Release|x86.ActiveCfg = Release|Win32
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.Release|x86.Build.0 = Release|Win32
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.ReleaseBeta|Any CPU.ActiveCfg = Release|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.ReleaseBeta|Any CPU.Build.0 = Release|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.ReleaseBeta|x64.ActiveCfg = Release|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.ReleaseBeta|x64.Build.0 = Release|x64
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.ReleaseBeta|x86.ActiveCfg = Release|Win32
|
||||
{448F061E-AE05-4E06-84A1-C95660FD048C}.ReleaseBeta|x86.Build.0 = Release|Win32
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|x64.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|x64.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|x86.ActiveCfg = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.DebugBeta|x86.Build.0 = Debug|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|Any CPU.Build.0 = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|x64.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|x64.Build.0 = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x64.Build.0 = Debug|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x86.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|Any CPU.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|Any CPU.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|x64.ActiveCfg = Debug|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|x64.Build.0 = Debug|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|x86.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|x86.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x64.ActiveCfg = Release|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x64.Build.0 = Release|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x86.ActiveCfg = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x86.Build.0 = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|Any CPU.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|Any CPU.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|x64.ActiveCfg = Release|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|x64.Build.0 = Release|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|x86.ActiveCfg = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|x86.Build.0 = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|Any CPU.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|x64.ActiveCfg = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|x64.Build.0 = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|x86.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|x86.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x64.Build.0 = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x86.Build.0 = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|Any CPU.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|x64.ActiveCfg = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|x64.Build.0 = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|x86.ActiveCfg = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.ReleaseBeta|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
Loading…
Reference in New Issue
Block a user