From 7219816376d5466d231048022d0891949c6b45b2 Mon Sep 17 00:00:00 2001
From: Morb0 <14136326+Morb0@users.noreply.github.com>
Date: Tue, 9 Apr 2024 18:56:15 +0300
Subject: [PATCH] Add corvax Secrets
---
Content.Client/Content.Client.csproj | 2 +
Content.Client/Humanoid/MarkingPicker.xaml.cs | 7 +++
.../Humanoid/SingleMarkingPicker.xaml.cs | 7 +++
.../Preferences/ClientPreferencesManager.cs | 8 +++-
.../Preferences/UI/CharacterSetupGui.xaml | 6 +++
.../Preferences/UI/CharacterSetupGui.xaml.cs | 8 ++++
Content.Server/Chat/Managers/ChatManager.cs | 10 ++++
.../Connection/ConnectionManager.cs | 28 ++++++++++-
Content.Server/Content.Server.csproj | 1 +
.../GameTicking/GameTicker.Player.cs | 9 +++-
.../GameTicking/GameTicker.StatusShell.cs | 9 +++-
.../Managers/ServerPreferencesManager.cs | 46 +++++++++++++++----
Content.Shared/Content.Shared.csproj | 1 +
.../Humanoid/HumanoidCharacterAppearance.cs | 21 ++++++++-
.../Humanoid/Markings/MarkingPrototype.cs | 5 ++
.../Humanoid/Markings/MarkingsSet.cs | 37 +++++++++++++++
.../Preferences/HumanoidCharacterProfile.cs | 16 +++++--
.../Preferences/ICharacterProfile.cs | 4 +-
.../Content.Corvax.Interfaces.Client.csproj | 13 ++++++
.../IClientDiscordAuthManager.cs | 8 ++++
.../IClientJoinQueueManager.cs | 6 +++
.../IClientSponsorsManager.cs | 8 ++++
.../ISponsorWindowCreator.cs | 6 +++
.../Content.Corvax.Interfaces.Server.csproj | 13 ++++++
.../IServerDiscordAuthManager.cs | 13 ++++++
.../IServerJoinQueueManager.cs | 10 ++++
.../IServerLoadoutManager.cs | 10 ++++
.../IServerSponsorsManager.cs | 14 ++++++
.../IServerVPNGuardManager.cs | 9 ++++
.../Content.Corvax.Interfaces.Shared.csproj | 10 ++++
.../ISharedDiscordAuthManager.cs | 6 +++
.../ISharedSponsorsManager.cs | 6 +++
Secrets | 1 +
SpaceStation14.sln | 35 ++++++++++++++
34 files changed, 371 insertions(+), 22 deletions(-)
create mode 100644 Corvax/Content.Corvax.Interfaces.Client/Content.Corvax.Interfaces.Client.csproj
create mode 100644 Corvax/Content.Corvax.Interfaces.Client/IClientDiscordAuthManager.cs
create mode 100644 Corvax/Content.Corvax.Interfaces.Client/IClientJoinQueueManager.cs
create mode 100644 Corvax/Content.Corvax.Interfaces.Client/IClientSponsorsManager.cs
create mode 100644 Corvax/Content.Corvax.Interfaces.Client/ISponsorWindowCreator.cs
create mode 100644 Corvax/Content.Corvax.Interfaces.Server/Content.Corvax.Interfaces.Server.csproj
create mode 100644 Corvax/Content.Corvax.Interfaces.Server/IServerDiscordAuthManager.cs
create mode 100644 Corvax/Content.Corvax.Interfaces.Server/IServerJoinQueueManager.cs
create mode 100644 Corvax/Content.Corvax.Interfaces.Server/IServerLoadoutManager.cs
create mode 100644 Corvax/Content.Corvax.Interfaces.Server/IServerSponsorsManager.cs
create mode 100644 Corvax/Content.Corvax.Interfaces.Server/IServerVPNGuardManager.cs
create mode 100644 Corvax/Content.Corvax.Interfaces.Shared/Content.Corvax.Interfaces.Shared.csproj
create mode 100644 Corvax/Content.Corvax.Interfaces.Shared/ISharedDiscordAuthManager.cs
create mode 100644 Corvax/Content.Corvax.Interfaces.Shared/ISharedSponsorsManager.cs
create mode 160000 Secrets
diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj
index 956f2fd0351..125bbac00df 100644
--- a/Content.Client/Content.Client.csproj
+++ b/Content.Client/Content.Client.csproj
@@ -22,6 +22,8 @@
+
+
diff --git a/Content.Client/Humanoid/MarkingPicker.xaml.cs b/Content.Client/Humanoid/MarkingPicker.xaml.cs
index 43333439f08..64fcde98657 100644
--- a/Content.Client/Humanoid/MarkingPicker.xaml.cs
+++ b/Content.Client/Humanoid/MarkingPicker.xaml.cs
@@ -1,4 +1,5 @@
using System.Linq;
+using Content.Corvax.Interfaces.Client;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes;
@@ -18,6 +19,7 @@ public sealed partial class MarkingPicker : Control
{
[Dependency] private readonly MarkingManager _markingManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ private IClientSponsorsManager? _sponsorsManager; // Corvax-Sponsors
public Action? OnMarkingAdded;
public Action? OnMarkingRemoved;
@@ -123,6 +125,7 @@ public MarkingPicker()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
+ IoCManager.Instance!.TryResolveType(out _sponsorsManager); // Corvax-Sponsors
SetupCategoryButtons();
CMarkingCategoryButton.OnItemSelected += OnCategoryChange;
@@ -202,6 +205,10 @@ public void Populate(string filter)
var item = CMarkingsUnused.AddItem($"{GetMarkingName(marking)}", marking.Sprites[0].Frame0());
item.Metadata = marking;
+ // Corvax-Sponsors-Start
+ if (marking.SponsorOnly && _sponsorsManager != null)
+ item.Disabled = !_sponsorsManager.Prototypes.Contains(marking.ID);
+ // Corvax-Sponsors-End
}
CMarkingPoints.Visible = _currentMarkings.PointsLeft(_selectedMarkingCategory) != -1;
diff --git a/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs b/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
index be3130a58bd..9e072ea4e02 100644
--- a/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
+++ b/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
@@ -1,4 +1,5 @@
using System.Linq;
+using Content.Corvax.Interfaces.Client;
using Content.Shared.Humanoid.Markings;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
@@ -11,6 +12,7 @@ namespace Content.Client.Humanoid;
public sealed partial class SingleMarkingPicker : BoxContainer
{
[Dependency] private readonly MarkingManager _markingManager = default!;
+ private IClientSponsorsManager? _sponsorsManager; // Corvax-Sponsors
///
/// What happens if a marking is selected.
@@ -122,6 +124,7 @@ public SingleMarkingPicker()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
+ IoCManager.Instance!.TryResolveType(out _sponsorsManager); // Corvax-Sponsors
MarkingList.OnItemSelected += SelectMarking;
AddButton.OnPressed += _ =>
@@ -190,6 +193,10 @@ public void PopulateList(string filter)
{
var item = MarkingList.AddItem(Loc.GetString($"marking-{id}"), marking.Sprites[0].Frame0());
item.Metadata = marking.ID;
+ // Corvax-Sponsors-Start
+ if (marking.SponsorOnly && _sponsorsManager != null)
+ item.Disabled = !_sponsorsManager.Prototypes.Contains(marking.ID);
+ // Corvax-Sponsors-End
if (_markings[Slot].MarkingId == id)
{
diff --git a/Content.Client/Preferences/ClientPreferencesManager.cs b/Content.Client/Preferences/ClientPreferencesManager.cs
index b518493c9d4..18b855e3cb5 100644
--- a/Content.Client/Preferences/ClientPreferencesManager.cs
+++ b/Content.Client/Preferences/ClientPreferencesManager.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Content.Corvax.Interfaces.Client;
using Content.Shared.Preferences;
using Robust.Client;
using Robust.Shared.Configuration;
@@ -22,6 +23,7 @@ public sealed class ClientPreferencesManager : IClientPreferencesManager
[Dependency] private readonly IBaseClient _baseClient = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IPrototypeManager _prototypes = default!;
+ private IClientSponsorsManager? _sponsorsManager; // Corvax-Sponsors
public event Action? OnServerDataLoaded;
@@ -30,6 +32,7 @@ public sealed class ClientPreferencesManager : IClientPreferencesManager
public void Initialize()
{
+ IoCManager.Instance!.TryResolveType(out _sponsorsManager); // Corvax-Sponsors
_netManager.RegisterNetMessage(HandlePreferencesAndSettings);
_netManager.RegisterNetMessage();
_netManager.RegisterNetMessage();
@@ -64,7 +67,10 @@ public void SelectCharacter(int slot)
public void UpdateCharacter(ICharacterProfile profile, int slot)
{
- profile.EnsureValid(_cfg, _prototypes);
+ // Corvax-Sponsors-Start
+ var sponsorPrototypes = _sponsorsManager?.Prototypes.ToArray() ?? [];
+ profile.EnsureValid(_cfg, _prototypes, sponsorPrototypes);
+ // Corvax-Sponsors-End
var characters = new Dictionary(Preferences.Characters) {[slot] = profile};
Preferences = new PlayerPreferences(characters, Preferences.SelectedCharacterIndex, Preferences.AdminOOCColor);
var msg = new MsgUpdateCharacter
diff --git a/Content.Client/Preferences/UI/CharacterSetupGui.xaml b/Content.Client/Preferences/UI/CharacterSetupGui.xaml
index 9a76029ce0b..40aa24cd15b 100644
--- a/Content.Client/Preferences/UI/CharacterSetupGui.xaml
+++ b/Content.Client/Preferences/UI/CharacterSetupGui.xaml
@@ -14,6 +14,12 @@
Text="{Loc 'character-setup-gui-character-setup-stats-button'}"
StyleClasses="ButtonBig"
HorizontalAlignment="Right" />
+
+
+
diff --git a/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs b/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs
index f41fd792054..12285645483 100644
--- a/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs
+++ b/Content.Client/Preferences/UI/CharacterSetupGui.xaml.cs
@@ -6,6 +6,7 @@
using Content.Client.Lobby.UI;
using Content.Client.Resources;
using Content.Client.Stylesheets;
+using Content.Corvax.Interfaces.Client;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Preferences;
@@ -79,6 +80,13 @@ public CharacterSetupGui(
StatsButton.OnPressed += _ => new PlaytimeStatsWindow().OpenCentered();
preferencesManager.OnServerDataLoaded += UpdateUI;
+ // Corvax-Sponsors-Start
+ if (IoCManager.Instance!.TryResolveType(out var creator))
+ {
+ SponsorButton.Visible = true;
+ SponsorButton.OnPressed += _ => creator.OpenWindow();
+ }
+ // Corvax-Sponsors-End
}
protected override void Dispose(bool disposing)
diff --git a/Content.Server/Chat/Managers/ChatManager.cs b/Content.Server/Chat/Managers/ChatManager.cs
index 19e5208e3fa..3be71426e94 100644
--- a/Content.Server/Chat/Managers/ChatManager.cs
+++ b/Content.Server/Chat/Managers/ChatManager.cs
@@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.InteropServices;
+using Content.Corvax.Interfaces.Server;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
using Content.Server.Administration.Systems;
@@ -45,6 +46,7 @@ internal sealed partial class ChatManager : IChatManager
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
+ private IServerSponsorsManager? _sponsorsManager; // Corvax-Sponsors
///
/// The maximum length a player-sent message can be sent
@@ -58,6 +60,7 @@ internal sealed partial class ChatManager : IChatManager
public void Initialize()
{
+ IoCManager.Instance!.TryResolveType(out _sponsorsManager); // Corvax-Sponsors
_netManager.RegisterNetMessage();
_netManager.RegisterNetMessage();
@@ -236,6 +239,13 @@ private void SendOOC(ICommonSession player, string message)
wrappedMessage = Loc.GetString("chat-manager-send-ooc-patron-wrap-message", ("patronColor", patronColor), ("playerName", player.Name), ("message", FormattedMessage.EscapeText(message)));
}
+ // Corvax-Sponsors-Start
+ if (_sponsorsManager != null && _sponsorsManager.TryGetOocColor(player.UserId, out var oocColor))
+ {
+ wrappedMessage = Loc.GetString("chat-manager-send-ooc-patron-wrap-message", ("patronColor", oocColor),("playerName", player.Name), ("message", FormattedMessage.EscapeText(message)));
+ }
+ // Corvax-Sponsors-End
+
//TODO: player.Name color, this will need to change the structure of the MsgChatMessage
ChatMessageToAll(ChatChannel.OOC, message, wrappedMessage, EntityUid.Invalid, hideChat: false, recordReplay: true, colorOverride: colorOverride, author: player.UserId);
_mommiLink.SendOOCMessage(player.Name, message);
diff --git a/Content.Server/Connection/ConnectionManager.cs b/Content.Server/Connection/ConnectionManager.cs
index 2fbc6f23593..79dcfd9504c 100644
--- a/Content.Server/Connection/ConnectionManager.cs
+++ b/Content.Server/Connection/ConnectionManager.cs
@@ -1,5 +1,6 @@
using System.Collections.Immutable;
using System.Threading.Tasks;
+using Content.Corvax.Interfaces.Server;
using Content.Server.Database;
using Content.Server.GameTicking;
using Content.Server.Preferences.Managers;
@@ -16,6 +17,7 @@ namespace Content.Server.Connection
public interface IConnectionManager
{
void Initialize();
+ Task HavePrivilegedJoin(NetUserId userId); // Corvax-Queue
}
///
@@ -30,9 +32,11 @@ public sealed class ConnectionManager : IConnectionManager
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly ILocalizationManager _loc = default!;
[Dependency] private readonly ServerDbEntryManager _serverDbEntry = default!;
+ private IServerSponsorsManager? _sponsorsMgr; // Corvax-Sponsors
public void Initialize()
{
+ IoCManager.Instance!.TryResolveType(out _sponsorsMgr); // Corvax-Sponsors
_netMgr.Connecting += NetMgrOnConnecting;
_netMgr.AssignUserIdCallback = AssignUserIdCallback;
// Approval-based IP bans disabled because they don't play well with Happy Eyeballs.
@@ -106,7 +110,10 @@ private async Task NetMgrOnConnecting(NetConnectingArgs e)
var adminData = await _dbManager.GetAdminDataForAsync(e.UserId);
- if (_cfg.GetCVar(CCVars.PanicBunkerEnabled) && adminData == null)
+ // Corvax-Start: Allow privileged players bypass bunker
+ var isPrivileged = await HavePrivilegedJoin(e.UserId);
+ if (_cfg.GetCVar(CCVars.PanicBunkerEnabled) && adminData == null && !isPrivileged)
+ // Corvax-End
{
var showReason = _cfg.GetCVar(CCVars.PanicBunkerShowReason);
var customReason = _cfg.GetCVar(CCVars.PanicBunkerCustomReason);
@@ -156,7 +163,10 @@ private async Task NetMgrOnConnecting(NetConnectingArgs e)
var wasInGame = EntitySystem.TryGet(out var ticker) &&
ticker.PlayerGameStatuses.TryGetValue(userId, out var status) &&
status == PlayerGameStatus.JoinedGame;
- if ((_plyMgr.PlayerCount >= _cfg.GetCVar(CCVars.SoftMaxPlayers) && adminData is null) && !wasInGame)
+ // Corvax-Queue-Start
+ var isQueueEnabled = IoCManager.Instance!.TryResolveType(out var mgr) && mgr.IsEnabled;
+ if (_plyMgr.PlayerCount >= _cfg.GetCVar(CCVars.SoftMaxPlayers) && !isPrivileged && !isQueueEnabled)
+ // Corvax-Queue-End
{
return (ConnectionDenyReason.Full, Loc.GetString("soft-player-cap-full"), null);
}
@@ -206,5 +216,19 @@ private async Task NetMgrOnConnecting(NetConnectingArgs e)
await _db.AssignUserIdAsync(name, assigned);
return assigned;
}
+
+ // Corvax-Queue-Start: Make these conditions in one place, for checks in the connection and in the queue
+ public async Task HavePrivilegedJoin(NetUserId userId)
+ {
+ var adminBypass = await _dbManager.GetAdminDataForAsync(userId) != null;
+ var havePriorityJoin = _sponsorsMgr != null && _sponsorsMgr.HavePriorityJoin(userId); // Corvax-Sponsors
+ var wasInGame = EntitySystem.TryGet(out var ticker) &&
+ ticker.PlayerGameStatuses.TryGetValue(userId, out var status) &&
+ status == PlayerGameStatus.JoinedGame;
+ return adminBypass ||
+ havePriorityJoin || // Corvax-Sponsors
+ wasInGame;
+ }
+ // Corvax-Queue-End
}
}
diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj
index e398773d54f..320196ea0fb 100644
--- a/Content.Server/Content.Server.csproj
+++ b/Content.Server/Content.Server.csproj
@@ -24,6 +24,7 @@
+
diff --git a/Content.Server/GameTicking/GameTicker.Player.cs b/Content.Server/GameTicking/GameTicker.Player.cs
index 7cacac679a3..6eb3ef5ba82 100644
--- a/Content.Server/GameTicking/GameTicker.Player.cs
+++ b/Content.Server/GameTicking/GameTicker.Player.cs
@@ -1,3 +1,4 @@
+using Content.Corvax.Interfaces.Server;
using Content.Server.Database;
using Content.Shared.GameTicking;
using Content.Shared.GameWindow;
@@ -59,7 +60,10 @@ private async void PlayerStatusChanged(object? sender, SessionStatusEventArgs ar
// Make the player actually join the game.
// timer time must be > tick length
- Timer.Spawn(0, () => _playerManager.JoinGame(args.Session));
+ // Corvax-Queue-Start
+ if (!IoCManager.Instance!.TryResolveType(out _))
+ Timer.Spawn(0, () => _playerManager.JoinGame(args.Session));
+ // Corvax-Queue-End
var record = await _dbManager.GetPlayerRecordByUserId(args.Session.UserId);
var firstConnection = record != null &&
@@ -129,7 +133,8 @@ private async void PlayerStatusChanged(object? sender, SessionStatusEventArgs ar
mind.Session = null;
}
- _userDb.ClientDisconnected(session);
+ if (_playerGameStatuses.ContainsKey(args.Session.UserId)) // Corvax-Queue: Delete data only if player was in game
+ _userDb.ClientDisconnected(session);
break;
}
}
diff --git a/Content.Server/GameTicking/GameTicker.StatusShell.cs b/Content.Server/GameTicking/GameTicker.StatusShell.cs
index fcf5b1c25cd..5009b127b53 100644
--- a/Content.Server/GameTicking/GameTicker.StatusShell.cs
+++ b/Content.Server/GameTicking/GameTicker.StatusShell.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Nodes;
+using Content.Corvax.Interfaces.Server;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Robust.Server.ServerStatus;
@@ -40,10 +41,16 @@ private void GetStatusResponse(JsonNode jObject)
// This method is raised from another thread, so this better be thread safe!
lock (_statusShellLock)
{
+ // Corvax-Queue-Start
+ var players = IoCManager.Instance?.TryResolveType(out var joinQueueManager) ?? false
+ ? joinQueueManager.ActualPlayersCount
+ : _playerManager.PlayerCount;
+ // Corvax-Queue-End
+
jObject["name"] = _baseServer.ServerName;
jObject["map"] = _gameMapManager.GetSelectedMap()?.MapName;
jObject["round_id"] = _gameTicker.RoundId;
- jObject["players"] = _playerManager.PlayerCount;
+ jObject["players"] = players; // Corvax-Queue
jObject["soft_max_players"] = _cfg.GetCVar(CCVars.SoftMaxPlayers);
jObject["panic_bunker"] = _cfg.GetCVar(CCVars.PanicBunkerEnabled);
jObject["run_level"] = (int) _runLevel;
diff --git a/Content.Server/Preferences/Managers/ServerPreferencesManager.cs b/Content.Server/Preferences/Managers/ServerPreferencesManager.cs
index e489ae28d58..b4c73936d91 100644
--- a/Content.Server/Preferences/Managers/ServerPreferencesManager.cs
+++ b/Content.Server/Preferences/Managers/ServerPreferencesManager.cs
@@ -2,6 +2,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Content.Corvax.Interfaces.Server;
using Content.Server.Database;
using Content.Server.Humanoid;
using Content.Shared.CCVar;
@@ -26,6 +27,7 @@ public sealed class ServerPreferencesManager : IServerPreferencesManager
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IServerDbManager _db = default!;
[Dependency] private readonly IPrototypeManager _protos = default!;
+ private IServerSponsorsManager? _sponsors; // Corvax-Sponsors
// Cache player prefs on the server so we don't need as much async hell related to them.
private readonly Dictionary _cachedPlayerPrefs =
@@ -35,6 +37,7 @@ public sealed class ServerPreferencesManager : IServerPreferencesManager
public void Init()
{
+ IoCManager.Instance!.TryResolveType(out _sponsors); // Corvax-Sponsors
_netManager.RegisterNetMessage();
_netManager.RegisterNetMessage(HandleSelectCharacterMessage);
_netManager.RegisterNetMessage(HandleUpdateCharacterMessage);
@@ -52,7 +55,7 @@ private async void HandleSelectCharacterMessage(MsgSelectCharacter message)
return;
}
- if (index < 0 || index >= MaxCharacterSlots)
+ if (index < 0 || index >= GetMaxUserCharacterSlots(userId)) // Corvax-Sponsors
{
return;
}
@@ -92,15 +95,20 @@ private async void HandleUpdateCharacterMessage(MsgUpdateCharacter message)
return;
}
- if (slot < 0 || slot >= MaxCharacterSlots)
+ if (slot < 0 || slot >= GetMaxUserCharacterSlots(userId)) // Corvax-Sponsors
{
return;
}
var curPrefs = prefsData.Prefs!;
- profile.EnsureValid(_cfg, _protos);
-
+ // Corvax-Sponsors-Start: Ensure removing sponsor markings if client somehow bypassed client filtering
+ // WARN! It's not removing markings from DB!
+ var sponsorPrototypes = _sponsors != null && _sponsors.TryGetPrototypes(message.MsgChannel.UserId, out var prototypes)
+ ? prototypes.ToArray()
+ : [];
+ profile.EnsureValid(_cfg, _protos, sponsorPrototypes);
+ // Corvax-Sponsors-End
var profiles = new Dictionary(curPrefs.Characters)
{
[slot] = profile
@@ -125,7 +133,7 @@ private async void HandleDeleteCharacterMessage(MsgDeleteCharacter message)
return;
}
- if (slot < 0 || slot >= MaxCharacterSlots)
+ if (slot < 0 || slot >= GetMaxUserCharacterSlots(userId)) // Corvax-Sponsors
{
return;
}
@@ -193,6 +201,15 @@ public async Task LoadData(ICommonSession session, CancellationToken cancel)
async Task LoadPrefs()
{
var prefs = await GetOrCreatePreferencesAsync(session.UserId);
+ // Corvax-Sponsors-Start: Remove sponsor markings from expired sponsors
+ foreach (var (_, profile) in prefs.Characters)
+ {
+ var sponsorPrototypes = _sponsors != null && _sponsors.TryGetPrototypes(session.UserId, out var prototypes)
+ ? prototypes.ToArray()
+ : [];
+ profile.EnsureValid(_cfg, _protos, sponsorPrototypes);
+ }
+ // Corvax-Sponsors-End
prefsData.Prefs = prefs;
prefsData.PrefsLoaded = true;
@@ -200,7 +217,7 @@ async Task LoadPrefs()
msg.Preferences = prefs;
msg.Settings = new GameSettings
{
- MaxCharacterSlots = MaxCharacterSlots
+ MaxCharacterSlots = GetMaxUserCharacterSlots(session.UserId), // Corvax-Sponsors
};
_netManager.ServerSendMessage(msg, session.Channel);
}
@@ -217,6 +234,14 @@ public bool HavePreferencesLoaded(ICommonSession session)
return _cachedPlayerPrefs.ContainsKey(session.UserId);
}
+ // Corvax-Sponsors-Start: Calculate total available users slots with sponsors
+ private int GetMaxUserCharacterSlots(NetUserId userId)
+ {
+ var maxSlots = _cfg.GetCVar(CCVars.GameMaxCharacterSlots);
+ var extraSlots = _sponsors?.GetExtraCharSlots(userId) ?? 0;
+ return maxSlots + extraSlots;
+ }
+ // Corvax-Sponsors-End
///
/// Tries to get the preferences from the cache
@@ -260,17 +285,20 @@ private async Task GetOrCreatePreferencesAsync(NetUserId user
return await _db.InitPrefsAsync(userId, HumanoidCharacterProfile.Random());
}
- return SanitizePreferences(prefs);
+ // Corvax-Sponsors-Start
+ var sponsorPrototypes = _sponsors != null && _sponsors.TryGetPrototypes(userId, out var prototypes) ? prototypes.ToArray() : []; // Corvax-Sponsors
+ return SanitizePreferences(prefs, sponsorPrototypes);
+ // Corvax-Sponsors-End
}
- private PlayerPreferences SanitizePreferences(PlayerPreferences prefs)
+ private PlayerPreferences SanitizePreferences(PlayerPreferences prefs, string[] sponsorPrototypes)
{
// Clean up preferences in case of changes to the game,
// such as removed jobs still being selected.
return new PlayerPreferences(prefs.Characters.Select(p =>
{
- return new KeyValuePair(p.Key, p.Value.Validated(_cfg, _protos));
+ return new KeyValuePair(p.Key, p.Value.Validated(_cfg, _protos, sponsorPrototypes));
}), prefs.SelectedCharacterIndex, prefs.AdminOOCColor);
}
diff --git a/Content.Shared/Content.Shared.csproj b/Content.Shared/Content.Shared.csproj
index 4cca399b28b..88e338ffd2d 100644
--- a/Content.Shared/Content.Shared.csproj
+++ b/Content.Shared/Content.Shared.csproj
@@ -22,6 +22,7 @@
false
+
diff --git a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs
index 1ffcd1870be..2ca263c60dd 100644
--- a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs
+++ b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs
@@ -188,7 +188,7 @@ public static Color ClampColor(Color color)
return new(color.RByte, color.GByte, color.BByte);
}
- public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex)
+ public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex, string[] sponsorPrototypes)
{
var hairStyleId = appearance.HairStyleId;
var facialHairStyleId = appearance.FacialHairStyleId;
@@ -205,11 +205,29 @@ public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearanc
hairStyleId = HairStyles.DefaultHairStyle;
}
+ // Corvax-Sponsors-Start
+ if (proto.TryIndex(hairStyleId, out MarkingPrototype? hairProto) &&
+ hairProto.SponsorOnly &&
+ !sponsorPrototypes.Contains(hairStyleId))
+ {
+ hairStyleId = HairStyles.DefaultHairStyle;
+ }
+ // Corvax-Sponsors-End
+
if (!markingManager.MarkingsByCategory(MarkingCategories.FacialHair).ContainsKey(facialHairStyleId))
{
facialHairStyleId = HairStyles.DefaultFacialHairStyle;
}
+ // Corvax-Sponsors-Start
+ if (proto.TryIndex(facialHairStyleId, out MarkingPrototype? facialHairProto) &&
+ facialHairProto.SponsorOnly &&
+ !sponsorPrototypes.Contains(facialHairStyleId))
+ {
+ facialHairStyleId = HairStyles.DefaultFacialHairStyle;
+ }
+ // Corvax-Sponsors-End
+
var markingSet = new MarkingSet();
var skinColor = appearance.SkinColor;
if (proto.TryIndex(species, out SpeciesPrototype? speciesProto))
@@ -224,6 +242,7 @@ public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearanc
markingSet.EnsureSpecies(species, skinColor, markingManager);
markingSet.EnsureSexes(sex, markingManager);
+ markingSet.FilterSponsor(sponsorPrototypes, markingManager); // Corvax-Sponsors
}
return new HumanoidCharacterAppearance(
diff --git a/Content.Shared/Humanoid/Markings/MarkingPrototype.cs b/Content.Shared/Humanoid/Markings/MarkingPrototype.cs
index dfb594db5f9..7711881d0ee 100644
--- a/Content.Shared/Humanoid/Markings/MarkingPrototype.cs
+++ b/Content.Shared/Humanoid/Markings/MarkingPrototype.cs
@@ -23,6 +23,11 @@ public sealed partial class MarkingPrototype : IPrototype
[DataField("sexRestriction")]
public Sex? SexRestriction { get; private set; }
+ // Corvax-Sponsors-Start
+ [DataField("sponsorOnly")]
+ public bool SponsorOnly = false;
+ // Corvax-Sponsors-End
+
[DataField("followSkinColor")]
public bool FollowSkinColor { get; private set; } = false;
diff --git a/Content.Shared/Humanoid/Markings/MarkingsSet.cs b/Content.Shared/Humanoid/Markings/MarkingsSet.cs
index d389e194150..66f36cdfc9c 100644
--- a/Content.Shared/Humanoid/Markings/MarkingsSet.cs
+++ b/Content.Shared/Humanoid/Markings/MarkingsSet.cs
@@ -199,6 +199,43 @@ public void EnsureSpecies(string species, Color? skinColor, MarkingManager? mark
}
}
+ // Corvax-Sponsors-Start
+ ///
+ /// Filters sponsor markings unavailable for not sponsors check that from their prototype and allowed param
+ ///
+ /// Sponsor markings that allowed to have.
+ /// Markings manager.
+ /// Prototype manager.
+ public void FilterSponsor(string[] sponsorMarkings, MarkingManager? markingManager = null, IPrototypeManager? prototypeManager = null)
+ {
+ IoCManager.Resolve(ref markingManager);
+ IoCManager.Resolve(ref prototypeManager);
+
+ var toRemove = new List<(MarkingCategories category, string id)>();
+ foreach (var (category, list) in Markings)
+ {
+ foreach (var marking in list)
+ {
+ if (prototypeManager.TryIndex(marking.MarkingId, out var proto) && !proto.SponsorOnly)
+ {
+ return;
+ }
+
+ var allowedToHave = sponsorMarkings.Contains(marking.MarkingId);
+ if (!allowedToHave)
+ {
+ toRemove.Add((category, marking.MarkingId));
+ }
+ }
+ }
+
+ foreach (var marking in toRemove)
+ {
+ Remove(marking.category, marking.id);
+ }
+ }
+ // Corvax-Sponsors-End
+
///
/// Filters markings based on sex and it's restrictions in the marking's prototype from this marking set.
///
diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs
index 812a70d326d..ae1b56490a8 100644
--- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs
+++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs
@@ -381,7 +381,7 @@ public bool MemberwiseEquals(ICharacterProfile maybeOther)
return Appearance.MemberwiseEquals(other.Appearance);
}
- public void EnsureValid(IConfigurationManager configManager, IPrototypeManager prototypeManager)
+ public void EnsureValid(IConfigurationManager configManager, IPrototypeManager prototypeManager, string[] sponsorPrototypes)
{
if (!prototypeManager.TryIndex(Species, out var speciesPrototype) || speciesPrototype.RoundStart == false)
{
@@ -389,6 +389,14 @@ public void EnsureValid(IConfigurationManager configManager, IPrototypeManager p
speciesPrototype = prototypeManager.Index(Species);
}
+ // Corvax-Sponsors-Start: Reset to human if player not sponsor
+ if (speciesPrototype.SponsorOnly && !sponsorPrototypes.Contains(Species))
+ {
+ Species = SharedHumanoidAppearanceSystem.DefaultSpecies;
+ speciesPrototype = prototypeManager.Index(Species);
+ }
+ // Corvax-Sponsors-End
+
var sex = Sex switch
{
Sex.Male => Sex.Male,
@@ -463,7 +471,7 @@ public void EnsureValid(IConfigurationManager configManager, IPrototypeManager p
bankBalance = 0;
}
- var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex);
+ var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex, sponsorPrototypes);
var prefsUnavailableMode = PreferenceUnavailable switch
{
@@ -541,10 +549,10 @@ public void EnsureValid(IConfigurationManager configManager, IPrototypeManager p
_traitPreferences.AddRange(traits);
}
- public ICharacterProfile Validated(IConfigurationManager configManager, IPrototypeManager prototypeManager)
+ public ICharacterProfile Validated(IConfigurationManager configManager, IPrototypeManager prototypeManager, string[] sponsorPrototypes)
{
var profile = new HumanoidCharacterProfile(this);
- profile.EnsureValid(configManager, prototypeManager);
+ profile.EnsureValid(configManager, prototypeManager, sponsorPrototypes); // Corvax-Sponsors
return profile;
}
diff --git a/Content.Shared/Preferences/ICharacterProfile.cs b/Content.Shared/Preferences/ICharacterProfile.cs
index a9d30639bb3..0cfef50c01f 100644
--- a/Content.Shared/Preferences/ICharacterProfile.cs
+++ b/Content.Shared/Preferences/ICharacterProfile.cs
@@ -15,11 +15,11 @@ public interface ICharacterProfile
///
/// Makes this profile valid so there's no bad data like negative ages.
///
- void EnsureValid(IConfigurationManager configManager, IPrototypeManager prototypeManager);
+ void EnsureValid(IConfigurationManager configManager, IPrototypeManager prototypeManager, string[] sponsorPrototypes); // Corvax-Sponsors: Integrated filtering for sponsor prototypes (markings/species/etc)
///
/// Gets a copy of this profile that has applied, i.e. no invalid data.
///
- ICharacterProfile Validated(IConfigurationManager configManager, IPrototypeManager prototypeManager);
+ ICharacterProfile Validated(IConfigurationManager configManager, IPrototypeManager prototypeManager, string[] sponsorPrototypes);
}
}
diff --git a/Corvax/Content.Corvax.Interfaces.Client/Content.Corvax.Interfaces.Client.csproj b/Corvax/Content.Corvax.Interfaces.Client/Content.Corvax.Interfaces.Client.csproj
new file mode 100644
index 00000000000..3a819f9ea1b
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Client/Content.Corvax.Interfaces.Client.csproj
@@ -0,0 +1,13 @@
+
+
+ net8.0
+ enable
+ enable
+
+
+
+ false
+
+
+
+
diff --git a/Corvax/Content.Corvax.Interfaces.Client/IClientDiscordAuthManager.cs b/Corvax/Content.Corvax.Interfaces.Client/IClientDiscordAuthManager.cs
new file mode 100644
index 00000000000..aa78731ee36
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Client/IClientDiscordAuthManager.cs
@@ -0,0 +1,8 @@
+using Content.Corvax.Interfaces.Shared;
+
+namespace Content.Corvax.Interfaces.Client;
+
+public interface IClientDiscordAuthManager : ISharedDiscordAuthManager
+{
+ public string AuthUrl { get; }
+}
diff --git a/Corvax/Content.Corvax.Interfaces.Client/IClientJoinQueueManager.cs b/Corvax/Content.Corvax.Interfaces.Client/IClientJoinQueueManager.cs
new file mode 100644
index 00000000000..04a7eaa2782
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Client/IClientJoinQueueManager.cs
@@ -0,0 +1,6 @@
+namespace Content.Corvax.Interfaces.Client;
+
+public interface IClientJoinQueueManager
+{
+ public void Initialize();
+}
diff --git a/Corvax/Content.Corvax.Interfaces.Client/IClientSponsorsManager.cs b/Corvax/Content.Corvax.Interfaces.Client/IClientSponsorsManager.cs
new file mode 100644
index 00000000000..f2814999ded
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Client/IClientSponsorsManager.cs
@@ -0,0 +1,8 @@
+using Content.Corvax.Interfaces.Shared;
+
+namespace Content.Corvax.Interfaces.Client;
+
+public interface IClientSponsorsManager : ISharedSponsorsManager
+{
+ public List Prototypes { get; }
+}
diff --git a/Corvax/Content.Corvax.Interfaces.Client/ISponsorWindowCreator.cs b/Corvax/Content.Corvax.Interfaces.Client/ISponsorWindowCreator.cs
new file mode 100644
index 00000000000..0eecad4385a
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Client/ISponsorWindowCreator.cs
@@ -0,0 +1,6 @@
+namespace Content.Corvax.Interfaces.Client;
+
+public interface ISponsorWindowCreator
+{
+ public void OpenWindow();
+}
diff --git a/Corvax/Content.Corvax.Interfaces.Server/Content.Corvax.Interfaces.Server.csproj b/Corvax/Content.Corvax.Interfaces.Server/Content.Corvax.Interfaces.Server.csproj
new file mode 100644
index 00000000000..22447b44c7f
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Server/Content.Corvax.Interfaces.Server.csproj
@@ -0,0 +1,13 @@
+
+
+ net8.0
+ enable
+ enable
+
+
+
+ false
+
+
+
+
diff --git a/Corvax/Content.Corvax.Interfaces.Server/IServerDiscordAuthManager.cs b/Corvax/Content.Corvax.Interfaces.Server/IServerDiscordAuthManager.cs
new file mode 100644
index 00000000000..95660f69c18
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Server/IServerDiscordAuthManager.cs
@@ -0,0 +1,13 @@
+using Content.Corvax.Interfaces.Shared;
+using Robust.Server.Player;
+using Robust.Shared.Network;
+using Robust.Shared.Player;
+
+namespace Content.Corvax.Interfaces.Server;
+
+public interface IServerDiscordAuthManager : ISharedDiscordAuthManager
+{
+ public event EventHandler? PlayerVerified;
+ public Task GenerateAuthLink(NetUserId userId, CancellationToken cancel);
+ public Task IsVerified(NetUserId userId, CancellationToken cancel);
+}
diff --git a/Corvax/Content.Corvax.Interfaces.Server/IServerJoinQueueManager.cs b/Corvax/Content.Corvax.Interfaces.Server/IServerJoinQueueManager.cs
new file mode 100644
index 00000000000..ef62ec55b5f
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Server/IServerJoinQueueManager.cs
@@ -0,0 +1,10 @@
+namespace Content.Corvax.Interfaces.Server;
+
+public interface IServerJoinQueueManager
+{
+ public bool IsEnabled { get; }
+ public int PlayerInQueueCount { get; }
+ public int ActualPlayersCount { get; }
+ public void Initialize();
+ public void PostInitialize();
+}
diff --git a/Corvax/Content.Corvax.Interfaces.Server/IServerLoadoutManager.cs b/Corvax/Content.Corvax.Interfaces.Server/IServerLoadoutManager.cs
new file mode 100644
index 00000000000..706ff51e2c7
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Server/IServerLoadoutManager.cs
@@ -0,0 +1,10 @@
+using System.Diagnostics.CodeAnalysis;
+using Content.Corvax.Interfaces.Shared;
+using Robust.Shared.Network;
+
+namespace Content.Corvax.Interfaces.Server;
+
+public interface IServerLoadoutManager : ISharedSponsorsManager
+{
+ public bool TryGetPrototypes(NetUserId userId, [NotNullWhen(true)] out List? prototypes);
+}
diff --git a/Corvax/Content.Corvax.Interfaces.Server/IServerSponsorsManager.cs b/Corvax/Content.Corvax.Interfaces.Server/IServerSponsorsManager.cs
new file mode 100644
index 00000000000..fa5cacc0510
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Server/IServerSponsorsManager.cs
@@ -0,0 +1,14 @@
+using System.Diagnostics.CodeAnalysis;
+using Content.Corvax.Interfaces.Shared;
+using Robust.Shared.Maths;
+using Robust.Shared.Network;
+
+namespace Content.Corvax.Interfaces.Server;
+
+public interface IServerSponsorsManager : ISharedSponsorsManager
+{
+ public bool TryGetPrototypes(NetUserId userId, [NotNullWhen(true)] out List? prototypes);
+ public bool TryGetOocColor(NetUserId userId, [NotNullWhen(true)] out Color? color);
+ public int GetExtraCharSlots(NetUserId userId);
+ public bool HavePriorityJoin(NetUserId userId);
+}
diff --git a/Corvax/Content.Corvax.Interfaces.Server/IServerVPNGuardManager.cs b/Corvax/Content.Corvax.Interfaces.Server/IServerVPNGuardManager.cs
new file mode 100644
index 00000000000..fc41e57e074
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Server/IServerVPNGuardManager.cs
@@ -0,0 +1,9 @@
+using System.Net;
+
+namespace Content.Corvax.Interfaces.Server;
+
+public interface IServerVPNGuardManager
+{
+ public void Initialize();
+ public Task IsConnectionVpn(IPAddress ip);
+}
diff --git a/Corvax/Content.Corvax.Interfaces.Shared/Content.Corvax.Interfaces.Shared.csproj b/Corvax/Content.Corvax.Interfaces.Shared/Content.Corvax.Interfaces.Shared.csproj
new file mode 100644
index 00000000000..5c1a9adff90
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Shared/Content.Corvax.Interfaces.Shared.csproj
@@ -0,0 +1,10 @@
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
diff --git a/Corvax/Content.Corvax.Interfaces.Shared/ISharedDiscordAuthManager.cs b/Corvax/Content.Corvax.Interfaces.Shared/ISharedDiscordAuthManager.cs
new file mode 100644
index 00000000000..3b6770108f8
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Shared/ISharedDiscordAuthManager.cs
@@ -0,0 +1,6 @@
+namespace Content.Corvax.Interfaces.Shared;
+
+public interface ISharedDiscordAuthManager
+{
+ public void Initialize();
+}
diff --git a/Corvax/Content.Corvax.Interfaces.Shared/ISharedSponsorsManager.cs b/Corvax/Content.Corvax.Interfaces.Shared/ISharedSponsorsManager.cs
new file mode 100644
index 00000000000..475ff481f2b
--- /dev/null
+++ b/Corvax/Content.Corvax.Interfaces.Shared/ISharedSponsorsManager.cs
@@ -0,0 +1,6 @@
+namespace Content.Corvax.Interfaces.Shared;
+
+public interface ISharedSponsorsManager
+{
+ public void Initialize();
+}
diff --git a/Secrets b/Secrets
new file mode 160000
index 00000000000..936cdd67f1e
--- /dev/null
+++ b/Secrets
@@ -0,0 +1 @@
+Subproject commit 936cdd67f1e5c3ae43d559700a0b11ff2a1463fb
diff --git a/SpaceStation14.sln b/SpaceStation14.sln
index e0cb455a6db..e8f03df64a0 100644
--- a/SpaceStation14.sln
+++ b/SpaceStation14.sln
@@ -134,6 +134,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Roslyn", "Roslyn", "{7844DA
RobustToolbox\Robust.Roslyn.Shared\Robust.Roslyn.Shared.props = RobustToolbox\Robust.Roslyn.Shared\Robust.Roslyn.Shared.props
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Corvax Interfaces", "Corvax Interfaces", "{29CC4B64-2E8C-4211-9CBE-6BE578B21BAC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.Corvax.Interfaces.Client", "Corvax\Content.Corvax.Interfaces.Client\Content.Corvax.Interfaces.Client.csproj", "{C4886F9E-D0C7-454D-AFE6-8A939C9D84B7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.Corvax.Interfaces.Server", "Corvax\Content.Corvax.Interfaces.Server\Content.Corvax.Interfaces.Server.csproj", "{628D24EC-08D0-4707-9243-8A9892DE09CB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.Corvax.Interfaces.Shared", "Corvax\Content.Corvax.Interfaces.Shared\Content.Corvax.Interfaces.Shared.csproj", "{A2AE8893-F230-4201-8275-191530017A0C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -445,6 +453,30 @@ Global
{83F510FE-9B50-4D96-AFAB-CC13998D6AFE}.Release|Any CPU.Build.0 = Release|Any CPU
{83F510FE-9B50-4D96-AFAB-CC13998D6AFE}.Tools|Any CPU.ActiveCfg = Tools|Any CPU
{83F510FE-9B50-4D96-AFAB-CC13998D6AFE}.Tools|Any CPU.Build.0 = Tools|Any CPU
+ {C4886F9E-D0C7-454D-AFE6-8A939C9D84B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C4886F9E-D0C7-454D-AFE6-8A939C9D84B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C4886F9E-D0C7-454D-AFE6-8A939C9D84B7}.DebugOpt|Any CPU.ActiveCfg = Debug|Any CPU
+ {C4886F9E-D0C7-454D-AFE6-8A939C9D84B7}.DebugOpt|Any CPU.Build.0 = Debug|Any CPU
+ {C4886F9E-D0C7-454D-AFE6-8A939C9D84B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C4886F9E-D0C7-454D-AFE6-8A939C9D84B7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C4886F9E-D0C7-454D-AFE6-8A939C9D84B7}.Tools|Any CPU.ActiveCfg = Debug|Any CPU
+ {C4886F9E-D0C7-454D-AFE6-8A939C9D84B7}.Tools|Any CPU.Build.0 = Debug|Any CPU
+ {628D24EC-08D0-4707-9243-8A9892DE09CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {628D24EC-08D0-4707-9243-8A9892DE09CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {628D24EC-08D0-4707-9243-8A9892DE09CB}.DebugOpt|Any CPU.ActiveCfg = Debug|Any CPU
+ {628D24EC-08D0-4707-9243-8A9892DE09CB}.DebugOpt|Any CPU.Build.0 = Debug|Any CPU
+ {628D24EC-08D0-4707-9243-8A9892DE09CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {628D24EC-08D0-4707-9243-8A9892DE09CB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {628D24EC-08D0-4707-9243-8A9892DE09CB}.Tools|Any CPU.ActiveCfg = Debug|Any CPU
+ {628D24EC-08D0-4707-9243-8A9892DE09CB}.Tools|Any CPU.Build.0 = Debug|Any CPU
+ {A2AE8893-F230-4201-8275-191530017A0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2AE8893-F230-4201-8275-191530017A0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A2AE8893-F230-4201-8275-191530017A0C}.DebugOpt|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2AE8893-F230-4201-8275-191530017A0C}.DebugOpt|Any CPU.Build.0 = Debug|Any CPU
+ {A2AE8893-F230-4201-8275-191530017A0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A2AE8893-F230-4201-8275-191530017A0C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A2AE8893-F230-4201-8275-191530017A0C}.Tools|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2AE8893-F230-4201-8275-191530017A0C}.Tools|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -477,6 +509,9 @@ Global
{07CA34A1-1D37-4771-A2E3-495A1044AE0B} = {7844DA69-B0F0-49FB-A05E-ECA37372277A}
{88B0FC0F-7209-40E2-AF16-EB90AF727C5B} = {7844DA69-B0F0-49FB-A05E-ECA37372277A}
{83F510FE-9B50-4D96-AFAB-CC13998D6AFE} = {7844DA69-B0F0-49FB-A05E-ECA37372277A}
+ {C4886F9E-D0C7-454D-AFE6-8A939C9D84B7} = {29CC4B64-2E8C-4211-9CBE-6BE578B21BAC}
+ {628D24EC-08D0-4707-9243-8A9892DE09CB} = {29CC4B64-2E8C-4211-9CBE-6BE578B21BAC}
+ {A2AE8893-F230-4201-8275-191530017A0C} = {29CC4B64-2E8C-4211-9CBE-6BE578B21BAC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AA37ED9F-F8D6-468E-A101-658AD605B09A}