[feat] Stalin manager
# Conflicts: # Content.Client/Entry/EntryPoint.cs # Content.Server/Entry/EntryPoint.cs # Content.Server/GameTicking/Commands/JoinGameCommand.cs # Content.Server/GameTicking/GameTicker.Lobby.cs # Content.Server/GameTicking/GameTicker.RoundFlow.cs # Content.Server/GameTicking/GameTicker.Spawning.cs
This commit is contained in:
@@ -22,7 +22,7 @@ namespace Content.Client.Administration.Systems
|
|||||||
// Currently this is only the ViewVariables verb, but more admin-UI related verbs can be added here.
|
// Currently this is only the ViewVariables verb, but more admin-UI related verbs can be added here.
|
||||||
|
|
||||||
// View variables verbs
|
// View variables verbs
|
||||||
if (_clientConGroupController.CanViewVar())
|
if (_clientConGroupController.CanAdminMenu())
|
||||||
{
|
{
|
||||||
var verb = new VvVerb()
|
var verb = new VvVerb()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ namespace Content.Client.Administration.UI
|
|||||||
editButton.OnPressed += _ => OnEditRankPressed(kv);
|
editButton.OnPressed += _ => OnEditRankPressed(kv);
|
||||||
_menu.AdminRanksList.AddChild(editButton);
|
_menu.AdminRanksList.AddChild(editButton);
|
||||||
|
|
||||||
if (!_adminManager.HasFlag(rank.Flags))
|
if (rank.Flags != AdminFlags.Host && !_adminManager.HasFlag(AdminFlags.Permissions) || rank.Flags == AdminFlags.Host && !_adminManager.HasFlag(AdminFlags.Host))
|
||||||
{
|
{
|
||||||
editButton.Disabled = true;
|
editButton.Disabled = true;
|
||||||
editButton.ToolTip = Loc.GetString("permissions-eui-do-not-have-required-flags-to-edit-rank-tooltip");
|
editButton.ToolTip = Loc.GetString("permissions-eui-do-not-have-required-flags-to-edit-rank-tooltip");
|
||||||
@@ -401,7 +401,15 @@ namespace Content.Client.Administration.UI
|
|||||||
{
|
{
|
||||||
// Can only grant out perms you also have yourself.
|
// Can only grant out perms you also have yourself.
|
||||||
// Primarily intended to prevent people giving themselves +HOST with +PERMISSIONS but generalized.
|
// Primarily intended to prevent people giving themselves +HOST with +PERMISSIONS but generalized.
|
||||||
var disable = !ui._adminManager.HasFlag(flag);
|
bool disable;
|
||||||
|
if (flag != AdminFlags.Host)
|
||||||
|
{
|
||||||
|
disable = !ui._adminManager.HasFlag(AdminFlags.Permissions);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
disable = !ui._adminManager.HasFlag(AdminFlags.Host);
|
||||||
|
}
|
||||||
var flagName = flag.ToString().ToUpper();
|
var flagName = flag.ToString().ToUpper();
|
||||||
|
|
||||||
var group = new ButtonGroup();
|
var group = new ButtonGroup();
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ using Content.Client.Voting;
|
|||||||
using Content.Client.White.JoinQueue;
|
using Content.Client.White.JoinQueue;
|
||||||
using Content.Client.White.Sponsors;
|
using Content.Client.White.Sponsors;
|
||||||
using Content.Shared.Ame;
|
using Content.Shared.Ame;
|
||||||
|
using Content.Client.White.Stalin;
|
||||||
using Content.Shared.Gravity;
|
using Content.Shared.Gravity;
|
||||||
using Content.Shared.Localizations;
|
using Content.Shared.Localizations;
|
||||||
using Robust.Client;
|
using Robust.Client;
|
||||||
@@ -76,6 +77,7 @@ namespace Content.Client.Entry
|
|||||||
//WD-EDIT
|
//WD-EDIT
|
||||||
[Dependency] private readonly SponsorsManager _sponsorsManager = default!;
|
[Dependency] private readonly SponsorsManager _sponsorsManager = default!;
|
||||||
[Dependency] private readonly JoinQueueManager _queueManager = default!;
|
[Dependency] private readonly JoinQueueManager _queueManager = default!;
|
||||||
|
[Dependency] private readonly StalinManager _stalinManager = default!;
|
||||||
//WD-EDIT
|
//WD-EDIT
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
@@ -140,6 +142,10 @@ namespace Content.Client.Entry
|
|||||||
_jobRequirements.Initialize();
|
_jobRequirements.Initialize();
|
||||||
_playbackMan.Initialize();
|
_playbackMan.Initialize();
|
||||||
|
|
||||||
|
//WD-EDIT
|
||||||
|
_stalinManager.Initialize();
|
||||||
|
//WD-EDIT
|
||||||
|
|
||||||
//AUTOSCALING default Setup!
|
//AUTOSCALING default Setup!
|
||||||
_configManager.SetCVar("interface.resolutionAutoScaleUpperCutoffX", 1080);
|
_configManager.SetCVar("interface.resolutionAutoScaleUpperCutoffX", 1080);
|
||||||
_configManager.SetCVar("interface.resolutionAutoScaleUpperCutoffY", 720);
|
_configManager.SetCVar("interface.resolutionAutoScaleUpperCutoffY", 720);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Client.Changelog;
|
using Content.Client.Changelog;
|
||||||
using Content.Client.UserInterface.Systems.EscapeMenu;
|
using Content.Client.UserInterface.Systems.EscapeMenu;
|
||||||
using Content.Client.UserInterface.Systems.Guidebook;
|
using Content.Client.UserInterface.Systems.Guidebook;
|
||||||
|
using Content.Client.White.Stalin;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
@@ -11,12 +12,14 @@ namespace Content.Client.Info
|
|||||||
{
|
{
|
||||||
public sealed class LinkBanner : BoxContainer
|
public sealed class LinkBanner : BoxContainer
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly StalinManager _stalinManager = default!;
|
||||||
private readonly IConfigurationManager _cfg;
|
private readonly IConfigurationManager _cfg;
|
||||||
|
|
||||||
private ValueList<(CVarDef<string> cVar, Button button)> _infoLinks;
|
private ValueList<(CVarDef<string> cVar, Button button)> _infoLinks;
|
||||||
|
|
||||||
public LinkBanner()
|
public LinkBanner()
|
||||||
{
|
{
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
var buttons = new BoxContainer
|
var buttons = new BoxContainer
|
||||||
{
|
{
|
||||||
Orientation = LayoutOrientation.Horizontal
|
Orientation = LayoutOrientation.Horizontal
|
||||||
@@ -54,6 +57,15 @@ namespace Content.Client.Info
|
|||||||
buttons.AddChild(button);
|
buttons.AddChild(button);
|
||||||
_infoLinks.Add((cVar, button));
|
_infoLinks.Add((cVar, button));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var saltedYaycaButton = new Button() {Text = "Привязать дискорд"};
|
||||||
|
|
||||||
|
saltedYaycaButton.OnPressed += _ =>
|
||||||
|
{
|
||||||
|
_stalinManager.RequestUri();
|
||||||
|
};
|
||||||
|
|
||||||
|
buttons.AddChild(saltedYaycaButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void EnteredTree()
|
protected override void EnteredTree()
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ using Content.Client.Guidebook;
|
|||||||
using Content.Client.Replay;
|
using Content.Client.Replay;
|
||||||
using Content.Client.White.JoinQueue;
|
using Content.Client.White.JoinQueue;
|
||||||
using Content.Client.White.Sponsors;
|
using Content.Client.White.Sponsors;
|
||||||
|
using Content.Client.White.Stalin;
|
||||||
using Content.Shared.Administration.Managers;
|
using Content.Shared.Administration.Managers;
|
||||||
|
|
||||||
namespace Content.Client.IoC
|
namespace Content.Client.IoC
|
||||||
@@ -51,6 +52,7 @@ namespace Content.Client.IoC
|
|||||||
//WD-EDIT
|
//WD-EDIT
|
||||||
IoCManager.Register<JoinQueueManager>();
|
IoCManager.Register<JoinQueueManager>();
|
||||||
IoCManager.Register<SponsorsManager>();
|
IoCManager.Register<SponsorsManager>();
|
||||||
|
IoCManager.Register<StalinManager>();
|
||||||
//WD-EDIT
|
//WD-EDIT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
Content.Client/White/Stalin/StalinManager.cs
Normal file
26
Content.Client/White/Stalin/StalinManager.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using Content.Shared.White.SaltedYayca;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
namespace Content.Client.White.Stalin;
|
||||||
|
|
||||||
|
public sealed class StalinManager
|
||||||
|
{
|
||||||
|
[Dependency] private readonly INetManager _netManager = default!;
|
||||||
|
[Dependency] private readonly IUriOpener _uriOpener = default!;
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_netManager.RegisterNetMessage<DiscordAuthResponse>(OnStalinResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RequestUri()
|
||||||
|
{
|
||||||
|
_netManager.ClientSendMessage(new DiscordAuthRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStalinResponse(DiscordAuthResponse message)
|
||||||
|
{
|
||||||
|
_uriOpener.OpenUri(message.Uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
var player = actor.PlayerSession;
|
var player = actor.PlayerSession;
|
||||||
|
|
||||||
if (!_adminManager.HasAdminFlag(player, AdminFlags.Fun))
|
if (!_adminManager.HasAdminFlag(player, AdminFlags.MeatyOre) && !_adminManager.HasAdminFlag(player, AdminFlags.Fun))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!TryComp<MindContainerComponent>(args.Target, out var targetMindComp))
|
if (!TryComp<MindContainerComponent>(args.Target, out var targetMindComp))
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
|
|
||||||
var player = actor.PlayerSession;
|
var player = actor.PlayerSession;
|
||||||
|
|
||||||
if (_adminManager.IsAdmin(player))
|
if (_adminManager.HasAdminFlag(player, AdminFlags.Admin))
|
||||||
{
|
{
|
||||||
Verb mark = new();
|
Verb mark = new();
|
||||||
mark.Text = Loc.GetString("toolshed-verb-mark");
|
mark.Text = Loc.GetString("toolshed-verb-mark");
|
||||||
|
|||||||
@@ -429,7 +429,9 @@ namespace Content.Server.Administration.UI
|
|||||||
|
|
||||||
private bool UserAdminFlagCheck(AdminFlags flags)
|
private bool UserAdminFlagCheck(AdminFlags flags)
|
||||||
{
|
{
|
||||||
return _adminManager.HasAdminFlag(Player, flags);
|
if (flags == AdminFlags.Host)
|
||||||
|
return _adminManager.HasAdminFlag(Player, AdminFlags.Host);
|
||||||
|
return _adminManager.HasAdminFlag(Player, AdminFlags.Permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanTouchAdmin(Admin admin)
|
private bool CanTouchAdmin(Admin admin)
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ using Robust.Shared.Utility;
|
|||||||
using Content.Server.UtkaIntegration;
|
using Content.Server.UtkaIntegration;
|
||||||
using Content.Server.White.JoinQueue;
|
using Content.Server.White.JoinQueue;
|
||||||
using Content.Server.White.Sponsors;
|
using Content.Server.White.Sponsors;
|
||||||
|
using Content.Server.White.Stalin;
|
||||||
using Content.Server.White.TTS;
|
using Content.Server.White.TTS;
|
||||||
|
|
||||||
namespace Content.Server.Entry
|
namespace Content.Server.Entry
|
||||||
@@ -111,6 +112,7 @@ namespace Content.Server.Entry
|
|||||||
IoCManager.Resolve<SponsorsManager>().Initialize();
|
IoCManager.Resolve<SponsorsManager>().Initialize();
|
||||||
IoCManager.Resolve<JoinQueueManager>().Initialize();
|
IoCManager.Resolve<JoinQueueManager>().Initialize();
|
||||||
IoCManager.Resolve<TTSManager>().Initialize();
|
IoCManager.Resolve<TTSManager>().Initialize();
|
||||||
|
IoCManager.Resolve<StalinManager>().Initialize();
|
||||||
//WD-EDIT
|
//WD-EDIT
|
||||||
|
|
||||||
_voteManager.Initialize();
|
_voteManager.Initialize();
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
|
using Content.Server.Chat.Managers;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
|
using Content.Server.White.Stalin;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
|
using Content.Shared.White;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
@@ -12,6 +18,8 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly StalinManager _stalinManager = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||||
|
|
||||||
public string Command => "joingame";
|
public string Command => "joingame";
|
||||||
public string Description => "";
|
public string Description => "";
|
||||||
@@ -21,7 +29,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
}
|
}
|
||||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
public async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
if (args.Length != 2)
|
if (args.Length != 2)
|
||||||
{
|
{
|
||||||
@@ -46,6 +54,19 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var chatManager = IoCManager.Resolve<IChatManager>();
|
||||||
|
|
||||||
|
if (_configurationManager.GetCVar(WhiteCVars.StalinEnabled))
|
||||||
|
{
|
||||||
|
var allowEnterRequest = await _stalinManager.AllowEnter(player);
|
||||||
|
|
||||||
|
if (!allowEnterRequest.allow)
|
||||||
|
{
|
||||||
|
chatManager.DispatchServerMessage(player, allowEnterRequest.errorMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ticker.RunLevel == GameRunLevel.PreRoundLobby)
|
if (ticker.RunLevel == GameRunLevel.PreRoundLobby)
|
||||||
{
|
{
|
||||||
shell.WriteLine("Round has not started.");
|
shell.WriteLine("Round has not started.");
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Content.Server.Station.Components;
|
|||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Content.Shared.White;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking
|
namespace Content.Server.GameTicking
|
||||||
{
|
{
|
||||||
@@ -168,6 +169,11 @@ namespace Content.Server.GameTicking
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_configurationManager.GetCVar(WhiteCVars.StalinEnabled))
|
||||||
|
{
|
||||||
|
_chatManager.DispatchServerMessage(player, "Внимание, на сервере включен бункер. Если ваш аккаунт не был привязан к дискорду, то вы не сможете зайти в раунд. Для того чтобы привязать аккаунт - нажмите на кнопку ПРИВЯЗАТЬ АККАУНТ");
|
||||||
|
}
|
||||||
|
|
||||||
var status = ready ? PlayerGameStatus.ReadyToPlay : PlayerGameStatus.NotReadyToPlay;
|
var status = ready ? PlayerGameStatus.ReadyToPlay : PlayerGameStatus.NotReadyToPlay;
|
||||||
_playerGameStatuses[player.UserId] = ready ? PlayerGameStatus.ReadyToPlay : PlayerGameStatus.NotReadyToPlay;
|
_playerGameStatuses[player.UserId] = ready ? PlayerGameStatus.ReadyToPlay : PlayerGameStatus.NotReadyToPlay;
|
||||||
RaiseNetworkEvent(GetStatusMsg(player), player.ConnectedClient);
|
RaiseNetworkEvent(GetStatusMsg(player), player.ConnectedClient);
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ using Robust.Shared.Random;
|
|||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Content.Server.UtkaIntegration;
|
using Content.Server.UtkaIntegration;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.White.Stalin;
|
||||||
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.White;
|
||||||
|
using Robust.Shared.Asynchronous;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking
|
namespace Content.Server.GameTicking
|
||||||
{
|
{
|
||||||
@@ -32,6 +36,7 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
//WD-EDIT
|
//WD-EDIT
|
||||||
[Dependency] private readonly UtkaTCPWrapper _utkaSocketWrapper = default!;
|
[Dependency] private readonly UtkaTCPWrapper _utkaSocketWrapper = default!;
|
||||||
|
[Dependency] private readonly StalinManager _stalinManager = default!;
|
||||||
//WD-EDIT
|
//WD-EDIT
|
||||||
|
|
||||||
private static readonly Counter RoundNumberMetric = Metrics.CreateCounter(
|
private static readonly Counter RoundNumberMetric = Metrics.CreateCounter(
|
||||||
@@ -178,7 +183,7 @@ namespace Content.Server.GameTicking
|
|||||||
return gridUids;
|
return gridUids;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartRound(bool force = false)
|
public async void StartRound(bool force = false)
|
||||||
{
|
{
|
||||||
#if EXCEPTION_TOLERANCE
|
#if EXCEPTION_TOLERANCE
|
||||||
try
|
try
|
||||||
@@ -215,11 +220,25 @@ namespace Content.Server.GameTicking
|
|||||||
RaiseLocalEvent(startingEvent);
|
RaiseLocalEvent(startingEvent);
|
||||||
var readyPlayers = new List<ICommonSession>();
|
var readyPlayers = new List<ICommonSession>();
|
||||||
var readyPlayerProfiles = new Dictionary<NetUserId, HumanoidCharacterProfile>();
|
var readyPlayerProfiles = new Dictionary<NetUserId, HumanoidCharacterProfile>();
|
||||||
|
var stalinBunkerEnabled = _configurationManager.GetCVar(WhiteCVars.StalinEnabled);
|
||||||
|
|
||||||
|
await _stalinManager.RefreshUsersData();
|
||||||
|
|
||||||
foreach (var (userId, status) in _playerGameStatuses)
|
foreach (var (userId, status) in _playerGameStatuses)
|
||||||
{
|
{
|
||||||
if (LobbyEnabled && status != PlayerGameStatus.ReadyToPlay) continue;
|
if (LobbyEnabled && status != PlayerGameStatus.ReadyToPlay) continue;
|
||||||
if (!_playerManager.TryGetSessionById(userId, out var session)) continue;
|
if (!_playerManager.TryGetSessionById(userId, out var session)) continue;
|
||||||
|
|
||||||
|
if (stalinBunkerEnabled)
|
||||||
|
{
|
||||||
|
var playerData = await _stalinManager.AllowEnter(session, false);
|
||||||
|
|
||||||
|
if (!playerData.allow)
|
||||||
|
{
|
||||||
|
_chatManager.DispatchServerMessage(session, $"{playerData.errorMessage}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugTools.Assert(_userDb.IsLoadComplete(session), $"Player was readied up but didn't have user DB data loaded yet??");
|
DebugTools.Assert(_userDb.IsLoadComplete(session), $"Player was readied up but didn't have user DB data loaded yet??");
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using Content.Shared.Players;
|
|||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Content.Shared.Roles.Jobs;
|
using Content.Shared.Roles.Jobs;
|
||||||
|
using Content.Shared.White;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
@@ -307,12 +308,22 @@ namespace Content.Server.GameTicking
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Causes the given player to join the current game as observer ghost. See also <see cref="SpawnObserver"/>
|
/// Causes the given player to join the current game as observer ghost. See also <see cref="SpawnObserver"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void JoinAsObserver(ICommonSession player)
|
public async void JoinAsObserver(ICommonSession player)
|
||||||
{
|
{
|
||||||
// Can't spawn players with a dummy ticker!
|
// Can't spawn players with a dummy ticker!
|
||||||
if (DummyTicker)
|
if (DummyTicker)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (_configurationManager.GetCVar(WhiteCVars.StalinEnabled))
|
||||||
|
{
|
||||||
|
var allowEnterData = await _stalinManager.AllowEnter(player);
|
||||||
|
if (!allowEnterData.allow)
|
||||||
|
{
|
||||||
|
_chatManager.DispatchServerMessage(player, $"Вход в игру запрещен: {allowEnterData.errorMessage}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PlayerJoinGame(player);
|
PlayerJoinGame(player);
|
||||||
SpawnObserver(player);
|
SpawnObserver(player);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ using Content.Server.Worldgen.Tools;
|
|||||||
using Content.Server.UtkaIntegration;
|
using Content.Server.UtkaIntegration;
|
||||||
using Content.Server.White.JoinQueue;
|
using Content.Server.White.JoinQueue;
|
||||||
using Content.Server.White.Sponsors;
|
using Content.Server.White.Sponsors;
|
||||||
|
using Content.Server.White.Stalin;
|
||||||
using Content.Server.White.TTS;
|
using Content.Server.White.TTS;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
@@ -69,6 +70,7 @@ namespace Content.Server.IoC
|
|||||||
IoCManager.Register<JoinQueueManager>();
|
IoCManager.Register<JoinQueueManager>();
|
||||||
IoCManager.Register<UtkaTCPWrapper>();
|
IoCManager.Register<UtkaTCPWrapper>();
|
||||||
IoCManager.Register<TTSManager>();
|
IoCManager.Register<TTSManager>();
|
||||||
|
IoCManager.Register<StalinManager>();
|
||||||
// WD-EDIT
|
// WD-EDIT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
49
Content.Server/White/Stalin/Commands/EnableStalinBunker.cs
Normal file
49
Content.Server/White/Stalin/Commands/EnableStalinBunker.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Server.Chat.Managers;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.White;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
|
||||||
|
namespace Content.Server.White.Stalin.Commands;
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
|
public sealed class EnableStalinBunker : IConsoleCommand
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
|
||||||
|
public string Command => "stalinbunker";
|
||||||
|
public string Description => "Enables the stalin bunker, like PaNIk bunker, but better";
|
||||||
|
public string Help => "stalinBunker <bool>";
|
||||||
|
|
||||||
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length > 1)
|
||||||
|
{
|
||||||
|
shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var enabled = _cfg.GetCVar(CCVars.PanicBunkerEnabled);
|
||||||
|
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
enabled = !enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Length == 1 && !bool.TryParse(args[0], out enabled))
|
||||||
|
{
|
||||||
|
shell.WriteError(Loc.GetString("shell-argument-must-be-boolean"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
|
_cfg.SetCVar(WhiteCVars.StalinEnabled, enabled);
|
||||||
|
|
||||||
|
var announce = Loc.GetString("stalin-panic-bunker", ("enabled", $"{enabled}"));
|
||||||
|
|
||||||
|
IoCManager.Resolve<IChatManager>().DispatchServerAnnouncement(announce, Color.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Content.Server/White/Stalin/DiscordUserData.cs
Normal file
38
Content.Server/White/Stalin/DiscordUserData.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System.Buffers;
|
||||||
|
using System.Buffers.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace Content.Server.White.Stalin;
|
||||||
|
|
||||||
|
public sealed class DiscordUserData
|
||||||
|
{
|
||||||
|
[JsonPropertyName("registered")]
|
||||||
|
public bool Registered { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("created_at")]
|
||||||
|
public double UnixTimestamp { get; set; }
|
||||||
|
|
||||||
|
public DateTime DiscordAge => UnixTimeStampToDateTime(UnixTimestamp);
|
||||||
|
|
||||||
|
public static DateTime UnixTimeStampToDateTime( double unixTimeStamp )
|
||||||
|
{
|
||||||
|
// Unix timestamp is seconds past epoch
|
||||||
|
DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
dateTime = dateTime.AddSeconds(unixTimeStamp).ToLocalTime();
|
||||||
|
return dateTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class DiscordUsersDataRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("uuids")]
|
||||||
|
public List<string> Uids { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class DiscordUsersData
|
||||||
|
{
|
||||||
|
public Dictionary<string, DiscordUserData> Users { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
261
Content.Server/White/Stalin/StalinManager.cs
Normal file
261
Content.Server/White/Stalin/StalinManager.cs
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.Chat.Managers;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.White;
|
||||||
|
using Content.Shared.White.SaltedYayca;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Asynchronous;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||||
|
|
||||||
|
namespace Content.Server.White.Stalin;
|
||||||
|
|
||||||
|
public sealed class StalinManager
|
||||||
|
{
|
||||||
|
[Dependency] private readonly INetManager _netManager = default!;
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||||
|
[Dependency] private readonly ITaskManager _taskManager = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
|
||||||
|
|
||||||
|
private IChatManager _chatManager = default!;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, DiscordUserData> _registeredStalinCache = new();
|
||||||
|
private readonly Dictionary<string, DateTime> _nextStalinAllowedCheck = new();
|
||||||
|
private string _stalinApiUrl = string.Empty;
|
||||||
|
private string _stalinAuthUrl = string.Empty;
|
||||||
|
private float _minimalDiscordAccountAge = 0f;
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_netManager.RegisterNetMessage<DiscordAuthRequest>(OnDiscordAuthRequest);
|
||||||
|
_netManager.RegisterNetMessage<DiscordAuthResponse>();
|
||||||
|
_chatManager = IoCManager.Resolve<IChatManager>();
|
||||||
|
|
||||||
|
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||||
|
_configurationManager.OnValueChanged(WhiteCVars.StalinApiUrl, newValue => _stalinApiUrl = newValue, true);
|
||||||
|
_configurationManager.OnValueChanged(WhiteCVars.StalinAuthUrl, newValue => _stalinAuthUrl = newValue, true);
|
||||||
|
_configurationManager.OnValueChanged(WhiteCVars.StalinDiscordMinimumAge, newValue => _minimalDiscordAccountAge = newValue, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RefreshUsersData()
|
||||||
|
{
|
||||||
|
var players = Filter.GetAllPlayers().Cast<ICommonSession>().ToList();
|
||||||
|
|
||||||
|
var usersData = await RequestDiscordUsersDataAsync(players);
|
||||||
|
|
||||||
|
if(usersData == null) return;
|
||||||
|
|
||||||
|
foreach (var data in usersData.Users)
|
||||||
|
{
|
||||||
|
if(!data.Value.Registered) continue;
|
||||||
|
_registeredStalinCache[data.Key] = data.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(bool allow, string errorMessage)> AllowEnter(ICommonSession session, bool requestIfNull = true)
|
||||||
|
{
|
||||||
|
var userId = session.UserId.ToString();
|
||||||
|
if (_nextStalinAllowedCheck.TryGetValue(userId, out var nextAllowedCheckTime))
|
||||||
|
{
|
||||||
|
if (DateTime.Now < nextAllowedCheckTime)
|
||||||
|
{
|
||||||
|
var timeoutTime = (int) ((nextAllowedCheckTime - DateTime.Now).TotalSeconds);
|
||||||
|
return (false, Loc.GetString("stalin-timeout", ("timeoutTime", timeoutTime)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextCheckTime = DateTime.Now.AddSeconds(_random.NextDouble(3,8));
|
||||||
|
_nextStalinAllowedCheck[userId] = nextCheckTime;
|
||||||
|
|
||||||
|
DiscordUserData responseData = null!;
|
||||||
|
if (!_registeredStalinCache.TryGetValue(userId, out responseData!) && requestIfNull)
|
||||||
|
{
|
||||||
|
responseData = await RequestDiscordUserDataAsync(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseData == null)
|
||||||
|
{
|
||||||
|
return (false, Loc.GetString("stalin-discord-doesnt-link"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var discordAge = GetDiscordAccountAge(responseData);
|
||||||
|
var discordAgeCheck = VerifyDiscordAge(discordAge);
|
||||||
|
|
||||||
|
return (discordAgeCheck.passed, discordAgeCheck.errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private (bool passed, string errorMessage) VerifyDiscordAge(double discordAge)
|
||||||
|
{
|
||||||
|
if(discordAge < _minimalDiscordAccountAge)
|
||||||
|
{
|
||||||
|
long needed = (long)(_minimalDiscordAccountAge - discordAge);
|
||||||
|
return (false, Loc.GetString("stalin-discord-age-check-fail", ("needed", needed)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (true, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double GetDiscordAccountAge(DiscordUserData data)
|
||||||
|
{
|
||||||
|
return (DateTime.Now - data.DiscordAge).TotalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||||
|
{
|
||||||
|
if(!_cfg.GetCVar(WhiteCVars.StalinEnabled)) return;
|
||||||
|
|
||||||
|
if (e.NewStatus != SessionStatus.Connected) return;
|
||||||
|
|
||||||
|
var session = e.Session;
|
||||||
|
|
||||||
|
if(string.IsNullOrEmpty(_stalinApiUrl))
|
||||||
|
{
|
||||||
|
var sawmill = Logger.GetSawmill("stalin");
|
||||||
|
sawmill.Log(LogLevel.Warning, "Stalin API URL is not set, skipping check.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var discordUserData = await RequestDiscordUserDataAsync(session);
|
||||||
|
|
||||||
|
if (discordUserData == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_registeredStalinCache[session.UserId.ToString()] = discordUserData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Запрашивает данные о привязки аккаунта к дискорду. Если аккаунт не привязан, возвращает null.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="session"></param>
|
||||||
|
/// <exception cref="NullReferenceException"></exception>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task<DiscordUserData> RequestDiscordUserDataAsync(ICommonSession session)
|
||||||
|
{
|
||||||
|
using var client = new HttpClient();
|
||||||
|
client.Timeout = TimeSpan.FromSeconds(5);
|
||||||
|
HttpResponseMessage response;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response = await client.GetAsync($"{_stalinApiUrl}isconnected?uuid={session.UserId}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_taskManager.RunOnMainThread(() =>
|
||||||
|
{
|
||||||
|
_chatManager.DispatchServerMessage(session, Loc.GetString("stalin-request-failed",
|
||||||
|
("error", e.InnerException!.ToString())));
|
||||||
|
|
||||||
|
var sawmill = Logger.GetSawmill("yayca");
|
||||||
|
sawmill.Log(LogLevel.Warning, $"API отвалился, звоните Утке...");
|
||||||
|
});
|
||||||
|
|
||||||
|
return null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
_taskManager.RunOnMainThread(() =>
|
||||||
|
{
|
||||||
|
_chatManager.DispatchServerMessage(session,
|
||||||
|
Loc.GetString("stalin-request-failed", ("error", response.StatusCode)));
|
||||||
|
});
|
||||||
|
|
||||||
|
return null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await response.Content.ReadFromJsonAsync<DiscordUserData>();
|
||||||
|
|
||||||
|
if (result!.Registered == false)
|
||||||
|
{
|
||||||
|
return null!;
|
||||||
|
}
|
||||||
|
return result!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<DiscordUsersData> RequestDiscordUsersDataAsync(List<ICommonSession> sessions)
|
||||||
|
{
|
||||||
|
using var client = new HttpClient();
|
||||||
|
client.Timeout = TimeSpan.FromSeconds(5);
|
||||||
|
HttpResponseMessage response;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var request = new DiscordUsersDataRequest()
|
||||||
|
{
|
||||||
|
Uids = sessions.Select(x => x.UserId.ToString()).ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
response = await client.PostAsJsonAsync(_stalinApiUrl + "isconnected", request);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
return null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var responseData = await response.Content.ReadFromJsonAsync<Dictionary<string, DiscordUserData>>();
|
||||||
|
|
||||||
|
var usersData = new DiscordUsersData()
|
||||||
|
{
|
||||||
|
Users = responseData!
|
||||||
|
};
|
||||||
|
|
||||||
|
return usersData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDiscordAuthRequest(DiscordAuthRequest message)
|
||||||
|
{
|
||||||
|
|
||||||
|
var playerSession = _playerManager.GetSessionByChannel(message.MsgChannel);
|
||||||
|
|
||||||
|
var saltedYayca = GenerateDiscordAuthUri(playerSession.Name, playerSession.UserId.ToString());
|
||||||
|
|
||||||
|
var response = new DiscordAuthResponse()
|
||||||
|
{
|
||||||
|
Uri = saltedYayca
|
||||||
|
};
|
||||||
|
|
||||||
|
_netManager.ServerSendMessage(response, message.MsgChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateDiscordAuthUri(string ckey, string uid)
|
||||||
|
{
|
||||||
|
using var sha1 = new SHA1Managed();
|
||||||
|
|
||||||
|
var saltBytes = Encoding.UTF8.GetBytes(_configurationManager.GetCVar(WhiteCVars.StalinSalt));
|
||||||
|
var ckeyBytes = Encoding.UTF8.GetBytes(ckey);
|
||||||
|
var uidBytes = Encoding.UTF8.GetBytes(uid);
|
||||||
|
|
||||||
|
var saltedBytes = ckeyBytes.Concat(uidBytes).Concat(saltBytes).ToArray();
|
||||||
|
var hash = ToHexStr(sha1.ComputeHash(saltedBytes));
|
||||||
|
|
||||||
|
var request = WebUtility.UrlEncode($"{ckey}@{uid}@{hash}");
|
||||||
|
return $"{_stalinAuthUrl}{request}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ToHexStr(byte[] hash)
|
||||||
|
{
|
||||||
|
StringBuilder hex = new StringBuilder(hash.Length * 2);
|
||||||
|
foreach (byte b in hash)
|
||||||
|
hex.AppendFormat("{0:x2}", b);
|
||||||
|
return hex.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -89,6 +89,11 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
EditNotes = 1 << 14,
|
EditNotes = 1 << 14,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Commands for Meaty Ores.
|
||||||
|
/// </summary>
|
||||||
|
MeatyOre = 1 << 15,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dangerous host permissions like scsi.
|
/// Dangerous host permissions like scsi.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
19
Content.Shared/White/SaltedYayca/DiscordAuthRequest.cs
Normal file
19
Content.Shared/White/SaltedYayca/DiscordAuthRequest.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Lidgren.Network;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.White.SaltedYayca;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public sealed class DiscordAuthRequest : NetMessage
|
||||||
|
{
|
||||||
|
public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableUnordered;
|
||||||
|
public override MsgGroups MsgGroup => MsgGroups.Core;
|
||||||
|
|
||||||
|
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
23
Content.Shared/White/SaltedYayca/DiscordAuthResponse.cs
Normal file
23
Content.Shared/White/SaltedYayca/DiscordAuthResponse.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Lidgren.Network;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.White.SaltedYayca;
|
||||||
|
|
||||||
|
public sealed class DiscordAuthResponse : NetMessage
|
||||||
|
{
|
||||||
|
public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableUnordered;
|
||||||
|
public override MsgGroups MsgGroup => MsgGroups.String;
|
||||||
|
|
||||||
|
public string Uri = string.Empty;
|
||||||
|
|
||||||
|
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
|
||||||
|
{
|
||||||
|
Uri = buffer.ReadString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
|
||||||
|
{
|
||||||
|
buffer.Write(Uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -76,7 +76,7 @@ public sealed class WhiteCVars
|
|||||||
/// URL of the TTS server API.
|
/// URL of the TTS server API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly CVarDef<string> TTSApiUrl =
|
public static readonly CVarDef<string> TTSApiUrl =
|
||||||
CVarDef.Create("tts.api_url", "http://127.0.0.1:2386", CVar.SERVERONLY);
|
CVarDef.Create("tts.api_url", "", CVar.SERVERONLY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TTS Volume
|
/// TTS Volume
|
||||||
@@ -90,4 +90,21 @@ public sealed class WhiteCVars
|
|||||||
public static readonly CVarDef<int> TTSMaxCacheSize =
|
public static readonly CVarDef<int> TTSMaxCacheSize =
|
||||||
CVarDef.Create("tts.max_cash_size", 200, CVar.SERVERONLY | CVar.ARCHIVE);
|
CVarDef.Create("tts.max_cash_size", 200, CVar.SERVERONLY | CVar.ARCHIVE);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stalin
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static readonly CVarDef<string> StalinSalt =
|
||||||
|
CVarDef.Create("stalin.salt", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL | CVar.ARCHIVE);
|
||||||
|
public static readonly CVarDef<string> StalinApiUrl =
|
||||||
|
CVarDef.Create("stalin.api_url", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL | CVar.ARCHIVE);
|
||||||
|
public static readonly CVarDef<string> StalinAuthUrl =
|
||||||
|
CVarDef.Create("stalin.auth_url", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL | CVar.ARCHIVE);
|
||||||
|
public static readonly CVarDef<bool> StalinEnabled =
|
||||||
|
CVarDef.Create("stalin.enabled", false, CVar.SERVERONLY | CVar.ARCHIVE);
|
||||||
|
public static readonly CVarDef<float> StalinDiscordMinimumAge =
|
||||||
|
CVarDef.Create("stalin.minimal_discord_age_minutes", 30.0f, CVar.SERVERONLY | CVar.ARCHIVE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user