Merge branch '20-10-30-admins' into 20-11-13-merges
This commit is contained in:
87
Content.Client/Administration/ClientAdminManager.cs
Normal file
87
Content.Client/Administration/ClientAdminManager.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.Network.NetMessages;
|
||||||
|
using Robust.Client.Console;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Client.Administration
|
||||||
|
{
|
||||||
|
public class ClientAdminManager : IClientAdminManager, IClientConGroupImplementation, IPostInjectInit
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IClientNetManager _netMgr = default!;
|
||||||
|
[Dependency] private readonly IClientConGroupController _conGroup = default!;
|
||||||
|
|
||||||
|
private AdminData? _adminData;
|
||||||
|
private readonly HashSet<string> _availableCommands = new HashSet<string>();
|
||||||
|
|
||||||
|
public event Action? AdminStatusUpdated;
|
||||||
|
|
||||||
|
public bool HasFlag(AdminFlags flag)
|
||||||
|
{
|
||||||
|
return _adminData?.HasFlag(flag) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanCommand(string cmdName)
|
||||||
|
{
|
||||||
|
return _availableCommands.Contains(cmdName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanViewVar()
|
||||||
|
{
|
||||||
|
return _adminData?.CanViewVar() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanAdminPlace()
|
||||||
|
{
|
||||||
|
return _adminData?.CanAdminPlace() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanScript()
|
||||||
|
{
|
||||||
|
return _adminData?.CanScript() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanAdminMenu()
|
||||||
|
{
|
||||||
|
return _adminData?.CanAdminMenu() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_netMgr.RegisterNetMessage<MsgUpdateAdminStatus>(MsgUpdateAdminStatus.NAME, UpdateMessageRx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateMessageRx(MsgUpdateAdminStatus message)
|
||||||
|
{
|
||||||
|
_availableCommands.Clear();
|
||||||
|
_availableCommands.UnionWith(message.AvailableCommands);
|
||||||
|
Logger.DebugS("admin", $"Have {message.AvailableCommands.Length} commands available");
|
||||||
|
|
||||||
|
_adminData = message.Admin;
|
||||||
|
if (_adminData != null)
|
||||||
|
{
|
||||||
|
var flagsText = string.Join("|", AdminFlagsHelper.FlagsToNames(_adminData.Flags));
|
||||||
|
Logger.InfoS("admin", $"Updated admin status: {_adminData.Active}/{_adminData.Title}/{flagsText}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.InfoS("admin", "Updated admin status: Not admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
AdminStatusUpdated?.Invoke();
|
||||||
|
ConGroupUpdated?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action? ConGroupUpdated;
|
||||||
|
|
||||||
|
void IPostInjectInit.PostInject()
|
||||||
|
{
|
||||||
|
_conGroup.Implementation = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
Content.Client/Administration/IClientAdminManager.cs
Normal file
52
Content.Client/Administration/IClientAdminManager.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Client.Administration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manages server admin permissions for the local player.
|
||||||
|
/// </summary>
|
||||||
|
public interface IClientAdminManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when the admin status of the local player changes, such as losing admin privileges.
|
||||||
|
/// </summary>
|
||||||
|
event Action AdminStatusUpdated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the local player has an admin flag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flag">The flags to check. Multiple flags can be specified, they must all be held.</param>
|
||||||
|
/// <returns>False if the local player is not an admin, inactive, or does not have all the flags specified.</returns>
|
||||||
|
bool HasFlag(AdminFlags flag);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if a player can execute a specified console command.
|
||||||
|
/// </summary>
|
||||||
|
bool CanCommand(string cmdName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the local player can open the VV menu.
|
||||||
|
/// </summary>
|
||||||
|
bool CanViewVar();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the local player can spawn stuff in with the entity/tile spawn panel.
|
||||||
|
/// </summary>
|
||||||
|
bool CanAdminPlace();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the local player can execute server-side C# scripts.
|
||||||
|
/// </summary>
|
||||||
|
bool CanScript();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the local player can open the admin menu.
|
||||||
|
/// </summary>
|
||||||
|
bool CanAdminMenu();
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
using Robust.Client.Console;
|
|
||||||
using Robust.Client.Graphics.Drawing;
|
using Robust.Client.Graphics.Drawing;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Shared.Input;
|
using Robust.Shared.Input;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
@@ -97,29 +95,23 @@ namespace Content.Client.Chat
|
|||||||
ToggleMode = true,
|
ToggleMode = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var groupController = IoCManager.Resolve<IClientConGroupController>();
|
AdminButton = new Button
|
||||||
if(groupController.CanCommand("asay"))
|
|
||||||
{
|
{
|
||||||
AdminButton = new Button
|
Text = Loc.GetString("Admin"),
|
||||||
{
|
Name = "Admin",
|
||||||
Text = Loc.GetString("Admin"),
|
ToggleMode = true,
|
||||||
Name = "Admin",
|
Visible = false
|
||||||
ToggleMode = true,
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
AllButton.OnToggled += OnFilterToggled;
|
AllButton.OnToggled += OnFilterToggled;
|
||||||
LocalButton.OnToggled += OnFilterToggled;
|
LocalButton.OnToggled += OnFilterToggled;
|
||||||
OOCButton.OnToggled += OnFilterToggled;
|
OOCButton.OnToggled += OnFilterToggled;
|
||||||
|
AdminButton.OnToggled += OnFilterToggled;
|
||||||
|
|
||||||
hBox.AddChild(AllButton);
|
hBox.AddChild(AllButton);
|
||||||
hBox.AddChild(LocalButton);
|
hBox.AddChild(LocalButton);
|
||||||
hBox.AddChild(OOCButton);
|
hBox.AddChild(OOCButton);
|
||||||
if(AdminButton != null)
|
hBox.AddChild(AdminButton);
|
||||||
{
|
|
||||||
AdminButton.OnToggled += OnFilterToggled;
|
|
||||||
hBox.AddChild(AdminButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddChild(outerVBox);
|
AddChild(outerVBox);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
using Content.Client.Administration;
|
||||||
using Content.Client.Interfaces.Chat;
|
using Content.Client.Interfaces.Chat;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
using Robust.Client.Console;
|
using Robust.Client.Console;
|
||||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||||
@@ -18,9 +19,11 @@ using Robust.Shared.Network;
|
|||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace Content.Client.Chat
|
namespace Content.Client.Chat
|
||||||
{
|
{
|
||||||
internal sealed class ChatManager : IChatManager
|
internal sealed class ChatManager : IChatManager, IPostInjectInit
|
||||||
{
|
{
|
||||||
private struct SpeechBubbleData
|
private struct SpeechBubbleData
|
||||||
{
|
{
|
||||||
@@ -75,9 +78,10 @@ namespace Content.Client.Chat
|
|||||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||||
[Dependency] private readonly IClientConGroupController _groupController = default!;
|
[Dependency] private readonly IClientConGroupController _groupController = default!;
|
||||||
|
[Dependency] private readonly IClientAdminManager _adminMgr = default!;
|
||||||
|
|
||||||
private ChatBox _currentChatBox;
|
private ChatBox? _currentChatBox;
|
||||||
private Control _speechBubbleRoot;
|
private Control _speechBubbleRoot = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Speech bubbles that are currently visible on screen.
|
/// Speech bubbles that are currently visible on screen.
|
||||||
@@ -103,7 +107,7 @@ namespace Content.Client.Chat
|
|||||||
_speechBubbleRoot.SetPositionFirst();
|
_speechBubbleRoot.SetPositionFirst();
|
||||||
|
|
||||||
// When connexion is achieved, request the max chat message length
|
// When connexion is achieved, request the max chat message length
|
||||||
_netManager.Connected += new EventHandler<NetChannelArgs>(RequestMaxLength);
|
_netManager.Connected += RequestMaxLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FrameUpdate(FrameEventArgs delta)
|
public void FrameUpdate(FrameEventArgs delta)
|
||||||
@@ -157,14 +161,15 @@ namespace Content.Client.Chat
|
|||||||
{
|
{
|
||||||
_currentChatBox.TextSubmitted += _onChatBoxTextSubmitted;
|
_currentChatBox.TextSubmitted += _onChatBoxTextSubmitted;
|
||||||
_currentChatBox.FilterToggled += _onFilterButtonToggled;
|
_currentChatBox.FilterToggled += _onFilterButtonToggled;
|
||||||
|
|
||||||
|
_currentChatBox.AllButton.Pressed = !_allState;
|
||||||
|
_currentChatBox.LocalButton.Pressed = !_localState;
|
||||||
|
_currentChatBox.OOCButton.Pressed = !_oocState;
|
||||||
|
_currentChatBox.AdminButton.Pressed = !_adminState;
|
||||||
|
AdminStatusUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
RepopulateChat(filteredHistory);
|
RepopulateChat(filteredHistory);
|
||||||
_currentChatBox.AllButton.Pressed = !_allState;
|
|
||||||
_currentChatBox.LocalButton.Pressed = !_localState;
|
|
||||||
_currentChatBox.OOCButton.Pressed = !_oocState;
|
|
||||||
if(chatBox.AdminButton != null)
|
|
||||||
_currentChatBox.AdminButton.Pressed = !_adminState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble)
|
public void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble)
|
||||||
@@ -229,9 +234,12 @@ namespace Content.Client.Chat
|
|||||||
// Check if message is longer than the character limit
|
// Check if message is longer than the character limit
|
||||||
if (text.Length > _maxMessageLength)
|
if (text.Length > _maxMessageLength)
|
||||||
{
|
{
|
||||||
string locWarning = Loc.GetString("Your message exceeds {0} character limit", _maxMessageLength);
|
if (_currentChatBox != null)
|
||||||
_currentChatBox?.AddLine(locWarning, ChatChannel.Server, Color.Orange);
|
{
|
||||||
_currentChatBox.ClearOnEnter = false; // The text shouldn't be cleared if it hasn't been sent
|
string locWarning = Loc.GetString("Your message exceeds {0} character limit", _maxMessageLength);
|
||||||
|
_currentChatBox.AddLine(locWarning, ChatChannel.Server, Color.Orange);
|
||||||
|
_currentChatBox.ClearOnEnter = false; // The text shouldn't be cleared if it hasn't been sent
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,13 +265,15 @@ namespace Content.Client.Chat
|
|||||||
var conInput = text.Substring(1);
|
var conInput = text.Substring(1);
|
||||||
if (string.IsNullOrWhiteSpace(conInput))
|
if (string.IsNullOrWhiteSpace(conInput))
|
||||||
return;
|
return;
|
||||||
if (_groupController.CanCommand("asay")){
|
if (_groupController.CanCommand("asay"))
|
||||||
|
{
|
||||||
_console.ProcessCommand($"asay \"{CommandParsing.Escape(conInput)}\"");
|
_console.ProcessCommand($"asay \"{CommandParsing.Escape(conInput)}\"");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\"");
|
_console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MeAlias:
|
case MeAlias:
|
||||||
@@ -276,7 +286,7 @@ namespace Content.Client.Chat
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
var conInput = _currentChatBox.DefaultChatFormat != null
|
var conInput = _currentChatBox?.DefaultChatFormat != null
|
||||||
? string.Format(_currentChatBox.DefaultChatFormat, CommandParsing.Escape(text))
|
? string.Format(_currentChatBox.DefaultChatFormat, CommandParsing.Escape(text))
|
||||||
: text;
|
: text;
|
||||||
_console.ProcessCommand(conInput);
|
_console.ProcessCommand(conInput);
|
||||||
@@ -341,6 +351,11 @@ namespace Content.Client.Chat
|
|||||||
|
|
||||||
private void RepopulateChat(IEnumerable<StoredChatMessage> filteredMessages)
|
private void RepopulateChat(IEnumerable<StoredChatMessage> filteredMessages)
|
||||||
{
|
{
|
||||||
|
if (_currentChatBox == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_currentChatBox.Contents.Clear();
|
_currentChatBox.Contents.Clear();
|
||||||
|
|
||||||
foreach (var msg in filteredMessages)
|
foreach (var msg in filteredMessages)
|
||||||
@@ -463,7 +478,8 @@ namespace Content.Client.Chat
|
|||||||
|
|
||||||
private void CreateSpeechBubble(IEntity entity, SpeechBubbleData speechData)
|
private void CreateSpeechBubble(IEntity entity, SpeechBubbleData speechData)
|
||||||
{
|
{
|
||||||
var bubble = SpeechBubble.CreateSpeechBubble(speechData.Type, speechData.Message, entity, _eyeManager, this);
|
var bubble =
|
||||||
|
SpeechBubble.CreateSpeechBubble(speechData.Type, speechData.Message, entity, _eyeManager, this);
|
||||||
|
|
||||||
if (_activeSpeechBubbles.TryGetValue(entity.Uid, out var existing))
|
if (_activeSpeechBubbles.TryGetValue(entity.Uid, out var existing))
|
||||||
{
|
{
|
||||||
@@ -496,6 +512,19 @@ namespace Content.Client.Chat
|
|||||||
return _allState ^ _filteredChannels.HasFlag(channel);
|
return _allState ^ _filteredChannels.HasFlag(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IPostInjectInit.PostInject()
|
||||||
|
{
|
||||||
|
_adminMgr.AdminStatusUpdated += AdminStatusUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AdminStatusUpdated()
|
||||||
|
{
|
||||||
|
if (_currentChatBox != null)
|
||||||
|
{
|
||||||
|
_currentChatBox.AdminButton.Visible = _adminMgr.HasFlag(AdminFlags.Admin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private sealed class SpeechBubbleQueueData
|
private sealed class SpeechBubbleQueueData
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Content.Client.Chat;
|
using Content.Client.Administration;
|
||||||
|
using Content.Client.Chat;
|
||||||
|
using Content.Client.Eui;
|
||||||
using Content.Client.GameTicking;
|
using Content.Client.GameTicking;
|
||||||
using Content.Client.Interfaces;
|
using Content.Client.Interfaces;
|
||||||
using Content.Client.Interfaces.Chat;
|
using Content.Client.Interfaces.Chat;
|
||||||
@@ -37,6 +39,8 @@ namespace Content.Client
|
|||||||
IoCManager.Register<IStationEventManager, StationEventManager>();
|
IoCManager.Register<IStationEventManager, StationEventManager>();
|
||||||
IoCManager.Register<IAdminMenuManager, AdminMenuManager>();
|
IoCManager.Register<IAdminMenuManager, AdminMenuManager>();
|
||||||
IoCManager.Register<AlertManager, AlertManager>();
|
IoCManager.Register<AlertManager, AlertManager>();
|
||||||
|
IoCManager.Register<IClientAdminManager, ClientAdminManager>();
|
||||||
|
IoCManager.Register<EuiManager, EuiManager>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Content.Client.Administration;
|
||||||
|
using Content.Client.Eui;
|
||||||
using Content.Client.GameObjects.Components.Actor;
|
using Content.Client.GameObjects.Components.Actor;
|
||||||
using Content.Client.Input;
|
using Content.Client.Input;
|
||||||
using Content.Client.Interfaces;
|
using Content.Client.Interfaces;
|
||||||
@@ -88,6 +90,7 @@ namespace Content.Client
|
|||||||
|
|
||||||
IoCManager.BuildGraph();
|
IoCManager.BuildGraph();
|
||||||
|
|
||||||
|
IoCManager.Resolve<IClientAdminManager>().Initialize();
|
||||||
IoCManager.Resolve<IParallaxManager>().LoadParallax();
|
IoCManager.Resolve<IParallaxManager>().LoadParallax();
|
||||||
IoCManager.Resolve<IBaseClient>().PlayerJoinedServer += SubscribePlayerAttachmentEvents;
|
IoCManager.Resolve<IBaseClient>().PlayerJoinedServer += SubscribePlayerAttachmentEvents;
|
||||||
IoCManager.Resolve<IStylesheetManager>().Initialize();
|
IoCManager.Resolve<IStylesheetManager>().Initialize();
|
||||||
@@ -150,6 +153,7 @@ namespace Content.Client
|
|||||||
IoCManager.Resolve<IClientPreferencesManager>().Initialize();
|
IoCManager.Resolve<IClientPreferencesManager>().Initialize();
|
||||||
IoCManager.Resolve<IStationEventManager>().Initialize();
|
IoCManager.Resolve<IStationEventManager>().Initialize();
|
||||||
IoCManager.Resolve<IAdminMenuManager>().Initialize();
|
IoCManager.Resolve<IAdminMenuManager>().Initialize();
|
||||||
|
IoCManager.Resolve<EuiManager>().Initialize();
|
||||||
IoCManager.Resolve<AlertManager>().Initialize();
|
IoCManager.Resolve<AlertManager>().Initialize();
|
||||||
|
|
||||||
_baseClient.RunLevelChanged += (sender, args) =>
|
_baseClient.RunLevelChanged += (sender, args) =>
|
||||||
|
|||||||
68
Content.Client/Eui/BaseEui.cs
Normal file
68
Content.Client/Eui/BaseEui.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using Content.Shared.Eui;
|
||||||
|
using Content.Shared.Network.NetMessages;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Client.Eui
|
||||||
|
{
|
||||||
|
public abstract class BaseEui
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IClientNetManager _netManager = default!;
|
||||||
|
|
||||||
|
public EuiManager Manager { get; private set; } = default!;
|
||||||
|
public uint Id { get; private set; }
|
||||||
|
|
||||||
|
protected BaseEui()
|
||||||
|
{
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Initialize(EuiManager mgr, uint id)
|
||||||
|
{
|
||||||
|
Manager = mgr;
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the EUI is opened by the server.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Opened()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the EUI is closed by the server.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Closed()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a new state comes in from the server.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void HandleState(EuiStateBase state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a message comes in from the server.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void HandleMessage(EuiMessageBase msg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send a message to the server-side implementation.
|
||||||
|
/// </summary>
|
||||||
|
protected void SendMessage(EuiMessageBase msg)
|
||||||
|
{
|
||||||
|
var netMsg = _netManager.CreateNetMessage<MsgEuiMessage>();
|
||||||
|
netMsg.Id = Id;
|
||||||
|
netMsg.Message = msg;
|
||||||
|
|
||||||
|
_netManager.ClientSendMessage(netMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
Content.Client/Eui/EuiManager.cs
Normal file
73
Content.Client/Eui/EuiManager.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Network.NetMessages;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.Interfaces.Reflection;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Client.Eui
|
||||||
|
{
|
||||||
|
public sealed class EuiManager
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IClientNetManager _net = default!;
|
||||||
|
[Dependency] private readonly IReflectionManager _refl = default!;
|
||||||
|
[Dependency] private readonly IDynamicTypeFactory _dtf = default!;
|
||||||
|
|
||||||
|
private readonly Dictionary<uint, EuiData> _openUis = new Dictionary<uint, EuiData>();
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_net.RegisterNetMessage<MsgEuiCtl>(MsgEuiCtl.NAME, RxMsgCtl);
|
||||||
|
_net.RegisterNetMessage<MsgEuiState>(MsgEuiState.NAME, RxMsgState);
|
||||||
|
_net.RegisterNetMessage<MsgEuiMessage>(MsgEuiMessage.NAME, RxMsgMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RxMsgMessage(MsgEuiMessage message)
|
||||||
|
{
|
||||||
|
var ui = _openUis[message.Id].Eui;
|
||||||
|
ui.HandleMessage(message.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RxMsgState(MsgEuiState message)
|
||||||
|
{
|
||||||
|
var ui = _openUis[message.Id].Eui;
|
||||||
|
ui.HandleState(message.State);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RxMsgCtl(MsgEuiCtl message)
|
||||||
|
{
|
||||||
|
switch (message.Type)
|
||||||
|
{
|
||||||
|
case MsgEuiCtl.CtlType.Open:
|
||||||
|
var euiType = _refl.LooseGetType(message.OpenType);
|
||||||
|
var instance = _dtf.CreateInstance<BaseEui>(euiType);
|
||||||
|
instance.Initialize(this, message.Id);
|
||||||
|
instance.Opened();
|
||||||
|
_openUis.Add(message.Id, new EuiData(instance));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MsgEuiCtl.CtlType.Close:
|
||||||
|
var dat = _openUis[message.Id];
|
||||||
|
dat.Eui.Closed();
|
||||||
|
_openUis.Remove(message.Id);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class EuiData
|
||||||
|
{
|
||||||
|
public BaseEui Eui;
|
||||||
|
|
||||||
|
public EuiData(BaseEui eui)
|
||||||
|
{
|
||||||
|
Eui = eui;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,14 +11,14 @@ namespace Content.Client.UserInterface.AdminMenu
|
|||||||
{
|
{
|
||||||
internal class AdminMenuManager : IAdminMenuManager
|
internal class AdminMenuManager : IAdminMenuManager
|
||||||
{
|
{
|
||||||
[Dependency] private INetManager _netManager = default!;
|
[Dependency] private readonly INetManager _netManager = default!;
|
||||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||||
[Dependency] private readonly IClientConGroupController _clientConGroupController = default!;
|
[Dependency] private readonly IClientConGroupController _clientConGroupController = default!;
|
||||||
|
|
||||||
private SS14Window _window;
|
private SS14Window _window;
|
||||||
private List<SS14Window> _commandWindows;
|
private List<SS14Window> _commandWindows;
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
_commandWindows = new List<SS14Window>();
|
_commandWindows = new List<SS14Window>();
|
||||||
// Reset the AdminMenu Window on disconnect
|
// Reset the AdminMenu Window on disconnect
|
||||||
|
|||||||
601
Content.Client/UserInterface/Permissions/PermissionsEui.cs
Normal file
601
Content.Client/UserInterface/Permissions/PermissionsEui.cs
Normal file
@@ -0,0 +1,601 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Client.Administration;
|
||||||
|
using Content.Client.Eui;
|
||||||
|
using Content.Client.UserInterface.Stylesheets;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.Eui;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using static Content.Shared.Administration.PermissionsEuiMsg;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Client.UserInterface.Permissions
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class PermissionsEui : BaseEui
|
||||||
|
{
|
||||||
|
private const int NoRank = -1;
|
||||||
|
|
||||||
|
[Dependency] private readonly IClientAdminManager _adminManager = default!;
|
||||||
|
|
||||||
|
private readonly Menu _menu;
|
||||||
|
private readonly List<SS14Window> _subWindows = new List<SS14Window>();
|
||||||
|
|
||||||
|
private Dictionary<int, PermissionsEuiState.AdminRankData> _ranks =
|
||||||
|
new Dictionary<int, PermissionsEuiState.AdminRankData>();
|
||||||
|
|
||||||
|
public PermissionsEui()
|
||||||
|
{
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
|
_menu = new Menu(this);
|
||||||
|
_menu.AddAdminButton.OnPressed += AddAdminPressed;
|
||||||
|
_menu.AddAdminRankButton.OnPressed += AddAdminRankPressed;
|
||||||
|
_menu.OnClose += CloseEverything;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Closed()
|
||||||
|
{
|
||||||
|
base.Closed();
|
||||||
|
|
||||||
|
CloseEverything();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseEverything()
|
||||||
|
{
|
||||||
|
foreach (var subWindow in _subWindows.ToArray())
|
||||||
|
{
|
||||||
|
subWindow.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
_menu.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddAdminPressed(BaseButton.ButtonEventArgs obj)
|
||||||
|
{
|
||||||
|
OpenEditWindow(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddAdminRankPressed(BaseButton.ButtonEventArgs obj)
|
||||||
|
{
|
||||||
|
OpenRankEditWindow(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnEditPressed(PermissionsEuiState.AdminData admin)
|
||||||
|
{
|
||||||
|
OpenEditWindow(admin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenEditWindow(PermissionsEuiState.AdminData? data)
|
||||||
|
{
|
||||||
|
var window = new EditAdminWindow(this, data);
|
||||||
|
window.SaveButton.OnPressed += _ => SaveAdminPressed(window);
|
||||||
|
window.OpenCentered();
|
||||||
|
window.OnClose += () => _subWindows.Remove(window);
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
window.RemoveButton!.OnPressed += _ => RemoveButtonPressed(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
_subWindows.Add(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OpenRankEditWindow(KeyValuePair<int, PermissionsEuiState.AdminRankData>? rank)
|
||||||
|
{
|
||||||
|
var window = new EditAdminRankWindow(this, rank);
|
||||||
|
window.SaveButton.OnPressed += _ => SaveAdminRankPressed(window);
|
||||||
|
window.OpenCentered();
|
||||||
|
window.OnClose += () => _subWindows.Remove(window);
|
||||||
|
if (rank != null)
|
||||||
|
{
|
||||||
|
window.RemoveButton!.OnPressed += _ => RemoveRankButtonPressed(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
_subWindows.Add(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveButtonPressed(EditAdminWindow window)
|
||||||
|
{
|
||||||
|
SendMessage(new RemoveAdmin {UserId = window.SourceData!.Value.UserId});
|
||||||
|
|
||||||
|
window.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveRankButtonPressed(EditAdminRankWindow window)
|
||||||
|
{
|
||||||
|
SendMessage(new RemoveAdminRank {Id = window.SourceId!.Value});
|
||||||
|
|
||||||
|
window.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveAdminPressed(EditAdminWindow popup)
|
||||||
|
{
|
||||||
|
popup.CollectSetFlags(out var pos, out var neg);
|
||||||
|
|
||||||
|
int? rank = popup.RankButton.SelectedId;
|
||||||
|
if (rank == NoRank)
|
||||||
|
{
|
||||||
|
rank = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var title = string.IsNullOrWhiteSpace(popup.TitleEdit.Text) ? null : popup.TitleEdit.Text;
|
||||||
|
|
||||||
|
if (popup.SourceData is { } src)
|
||||||
|
{
|
||||||
|
SendMessage(new UpdateAdmin
|
||||||
|
{
|
||||||
|
UserId = src.UserId,
|
||||||
|
Title = title,
|
||||||
|
PosFlags = pos,
|
||||||
|
NegFlags = neg,
|
||||||
|
RankId = rank
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugTools.AssertNotNull(popup.NameEdit);
|
||||||
|
|
||||||
|
SendMessage(new AddAdmin
|
||||||
|
{
|
||||||
|
UserNameOrId = popup.NameEdit!.Text,
|
||||||
|
Title = title,
|
||||||
|
PosFlags = pos,
|
||||||
|
NegFlags = neg,
|
||||||
|
RankId = rank
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void SaveAdminRankPressed(EditAdminRankWindow popup)
|
||||||
|
{
|
||||||
|
var flags = popup.CollectSetFlags();
|
||||||
|
var name = popup.NameEdit.Text;
|
||||||
|
|
||||||
|
if (popup.SourceId is { } src)
|
||||||
|
{
|
||||||
|
SendMessage(new UpdateAdminRank
|
||||||
|
{
|
||||||
|
Id = src,
|
||||||
|
Flags = flags,
|
||||||
|
Name = name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SendMessage(new AddAdminRank
|
||||||
|
{
|
||||||
|
Flags = flags,
|
||||||
|
Name = name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Opened()
|
||||||
|
{
|
||||||
|
_menu.OpenCentered();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void HandleState(EuiStateBase state)
|
||||||
|
{
|
||||||
|
var s = (PermissionsEuiState) state;
|
||||||
|
|
||||||
|
if (s.IsLoading)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ranks = s.AdminRanks;
|
||||||
|
|
||||||
|
_menu.AdminsList.RemoveAllChildren();
|
||||||
|
foreach (var admin in s.Admins)
|
||||||
|
{
|
||||||
|
var al = _menu.AdminsList;
|
||||||
|
var name = admin.UserName ?? admin.UserId.ToString();
|
||||||
|
|
||||||
|
al.AddChild(new Label {Text = name});
|
||||||
|
|
||||||
|
var titleControl = new Label {Text = admin.Title ?? Loc.GetString("none")};
|
||||||
|
if (admin.Title == null) // none
|
||||||
|
{
|
||||||
|
titleControl.StyleClasses.Add(StyleBase.StyleClassItalic);
|
||||||
|
}
|
||||||
|
|
||||||
|
al.AddChild(titleControl);
|
||||||
|
|
||||||
|
bool italic;
|
||||||
|
string rank;
|
||||||
|
var combinedFlags = admin.PosFlags;
|
||||||
|
if (admin.RankId is { } rankId)
|
||||||
|
{
|
||||||
|
italic = false;
|
||||||
|
var rankData = s.AdminRanks[rankId];
|
||||||
|
rank = rankData.Name;
|
||||||
|
combinedFlags |= rankData.Flags;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
italic = true;
|
||||||
|
rank = Loc.GetString("none");
|
||||||
|
}
|
||||||
|
|
||||||
|
var rankControl = new Label {Text = rank};
|
||||||
|
if (italic)
|
||||||
|
{
|
||||||
|
rankControl.StyleClasses.Add(StyleBase.StyleClassItalic);
|
||||||
|
}
|
||||||
|
|
||||||
|
al.AddChild(rankControl);
|
||||||
|
|
||||||
|
var flagsText = AdminFlagsHelper.PosNegFlagsText(admin.PosFlags, admin.NegFlags);
|
||||||
|
|
||||||
|
al.AddChild(new Label
|
||||||
|
{
|
||||||
|
Text = flagsText,
|
||||||
|
SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter | Control.SizeFlags.Expand
|
||||||
|
});
|
||||||
|
|
||||||
|
var editButton = new Button {Text = Loc.GetString("Edit")};
|
||||||
|
editButton.OnPressed += _ => OnEditPressed(admin);
|
||||||
|
al.AddChild(editButton);
|
||||||
|
|
||||||
|
if (!_adminManager.HasFlag(combinedFlags))
|
||||||
|
{
|
||||||
|
editButton.Disabled = true;
|
||||||
|
editButton.ToolTip = Loc.GetString("You do not have the required flags to edit this admin.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_menu.AdminRanksList.RemoveAllChildren();
|
||||||
|
foreach (var kv in s.AdminRanks)
|
||||||
|
{
|
||||||
|
var rank = kv.Value;
|
||||||
|
var flagsText = string.Join(' ', AdminFlagsHelper.FlagsToNames(rank.Flags).Select(f => $"+{f}"));
|
||||||
|
_menu.AdminRanksList.AddChild(new Label {Text = rank.Name});
|
||||||
|
_menu.AdminRanksList.AddChild(new Label
|
||||||
|
{
|
||||||
|
Text = flagsText,
|
||||||
|
SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter | Control.SizeFlags.Expand
|
||||||
|
});
|
||||||
|
var editButton = new Button {Text = Loc.GetString("Edit")};
|
||||||
|
editButton.OnPressed += _ => OnEditRankPressed(kv);
|
||||||
|
_menu.AdminRanksList.AddChild(editButton);
|
||||||
|
|
||||||
|
if (!_adminManager.HasFlag(rank.Flags))
|
||||||
|
{
|
||||||
|
editButton.Disabled = true;
|
||||||
|
editButton.ToolTip = Loc.GetString("You do not have the required flags to edit this rank.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEditRankPressed(KeyValuePair<int, PermissionsEuiState.AdminRankData> rank)
|
||||||
|
{
|
||||||
|
OpenRankEditWindow(rank);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class Menu : SS14Window
|
||||||
|
{
|
||||||
|
private readonly PermissionsEui _ui;
|
||||||
|
public readonly GridContainer AdminsList;
|
||||||
|
public readonly GridContainer AdminRanksList;
|
||||||
|
public readonly Button AddAdminButton;
|
||||||
|
public readonly Button AddAdminRankButton;
|
||||||
|
|
||||||
|
public Menu(PermissionsEui ui)
|
||||||
|
{
|
||||||
|
_ui = ui;
|
||||||
|
Title = Loc.GetString("Permissions Panel");
|
||||||
|
|
||||||
|
var tab = new TabContainer();
|
||||||
|
|
||||||
|
AddAdminButton = new Button
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("Add Admin"),
|
||||||
|
SizeFlagsHorizontal = SizeFlags.ShrinkEnd
|
||||||
|
};
|
||||||
|
|
||||||
|
AddAdminRankButton = new Button
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("Add Admin Rank"),
|
||||||
|
SizeFlagsHorizontal = SizeFlags.ShrinkEnd
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminsList = new GridContainer {Columns = 5, SizeFlagsVertical = SizeFlags.FillExpand};
|
||||||
|
var adminVBox = new VBoxContainer
|
||||||
|
{
|
||||||
|
Children = {AdminsList, AddAdminButton},
|
||||||
|
};
|
||||||
|
TabContainer.SetTabTitle(adminVBox, Loc.GetString("Admins"));
|
||||||
|
|
||||||
|
AdminRanksList = new GridContainer {Columns = 3};
|
||||||
|
var rankVBox = new VBoxContainer
|
||||||
|
{
|
||||||
|
Children = { AdminRanksList, AddAdminRankButton}
|
||||||
|
};
|
||||||
|
TabContainer.SetTabTitle(rankVBox, Loc.GetString("Admin Ranks"));
|
||||||
|
|
||||||
|
tab.AddChild(adminVBox);
|
||||||
|
tab.AddChild(rankVBox);
|
||||||
|
|
||||||
|
Contents.AddChild(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Vector2 ContentsMinimumSize => (600, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class EditAdminWindow : SS14Window
|
||||||
|
{
|
||||||
|
public readonly PermissionsEuiState.AdminData? SourceData;
|
||||||
|
public readonly LineEdit? NameEdit;
|
||||||
|
public readonly LineEdit TitleEdit;
|
||||||
|
public readonly OptionButton RankButton;
|
||||||
|
public readonly Button SaveButton;
|
||||||
|
public readonly Button? RemoveButton;
|
||||||
|
|
||||||
|
public readonly Dictionary<AdminFlags, (Button inherit, Button sub, Button plus)> FlagButtons
|
||||||
|
= new Dictionary<AdminFlags, (Button, Button, Button)>();
|
||||||
|
|
||||||
|
public EditAdminWindow(PermissionsEui ui, PermissionsEuiState.AdminData? data)
|
||||||
|
{
|
||||||
|
SourceData = data;
|
||||||
|
|
||||||
|
Control nameControl;
|
||||||
|
|
||||||
|
if (data is { } dat)
|
||||||
|
{
|
||||||
|
var name = dat.UserName ?? dat.UserId.ToString();
|
||||||
|
Title = Loc.GetString("Edit admin {0}", name);
|
||||||
|
|
||||||
|
nameControl = new Label {Text = name};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Title = Loc.GetString("Add admin");
|
||||||
|
|
||||||
|
nameControl = NameEdit = new LineEdit {PlaceHolder = Loc.GetString("Username/User ID")};
|
||||||
|
}
|
||||||
|
|
||||||
|
TitleEdit = new LineEdit {PlaceHolder = Loc.GetString("Custom title, leave blank to inherit rank title.")};
|
||||||
|
RankButton = new OptionButton();
|
||||||
|
SaveButton = new Button {Text = Loc.GetString("Save"), SizeFlagsHorizontal = SizeFlags.ShrinkEnd | SizeFlags.Expand};
|
||||||
|
|
||||||
|
RankButton.AddItem(Loc.GetString("No rank"), NoRank);
|
||||||
|
foreach (var (rId, rank) in ui._ranks)
|
||||||
|
{
|
||||||
|
RankButton.AddItem(rank.Name, rId);
|
||||||
|
}
|
||||||
|
|
||||||
|
RankButton.SelectId(data?.RankId ?? NoRank);
|
||||||
|
RankButton.OnItemSelected += RankSelected;
|
||||||
|
|
||||||
|
var permGrid = new GridContainer
|
||||||
|
{
|
||||||
|
Columns = 4,
|
||||||
|
HSeparationOverride = 0,
|
||||||
|
VSeparationOverride = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var flag in AdminFlagsHelper.AllFlags)
|
||||||
|
{
|
||||||
|
// Can only grant out perms you also have yourself.
|
||||||
|
// Primarily intended to prevent people giving themselves +HOST with +PERMISSIONS but generalized.
|
||||||
|
var disable = !ui._adminManager.HasFlag(flag);
|
||||||
|
var flagName = flag.ToString().ToUpper();
|
||||||
|
|
||||||
|
var group = new ButtonGroup();
|
||||||
|
|
||||||
|
var inherit = new Button
|
||||||
|
{
|
||||||
|
Text = "I",
|
||||||
|
StyleClasses = {StyleBase.ButtonOpenRight},
|
||||||
|
Disabled = disable,
|
||||||
|
Group = group,
|
||||||
|
};
|
||||||
|
var sub = new Button
|
||||||
|
{
|
||||||
|
Text = "-",
|
||||||
|
StyleClasses = {StyleBase.ButtonOpenBoth},
|
||||||
|
Disabled = disable,
|
||||||
|
Group = group
|
||||||
|
};
|
||||||
|
var plus = new Button
|
||||||
|
{
|
||||||
|
Text = "+",
|
||||||
|
StyleClasses = {StyleBase.ButtonOpenLeft},
|
||||||
|
Disabled = disable,
|
||||||
|
Group = group
|
||||||
|
};
|
||||||
|
|
||||||
|
if (data is { } d)
|
||||||
|
{
|
||||||
|
if ((d.NegFlags & flag) != 0)
|
||||||
|
{
|
||||||
|
sub.Pressed = true;
|
||||||
|
}
|
||||||
|
else if ((d.PosFlags & flag) != 0)
|
||||||
|
{
|
||||||
|
plus.Pressed = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inherit.Pressed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inherit.Pressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
permGrid.AddChild(new Label {Text = flagName});
|
||||||
|
permGrid.AddChild(inherit);
|
||||||
|
permGrid.AddChild(sub);
|
||||||
|
permGrid.AddChild(plus);
|
||||||
|
|
||||||
|
FlagButtons.Add(flag, (inherit, sub, plus));
|
||||||
|
}
|
||||||
|
|
||||||
|
var bottomButtons = new HBoxContainer();
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
// show remove button.
|
||||||
|
RemoveButton = new Button {Text = Loc.GetString("Remove")};
|
||||||
|
bottomButtons.AddChild(RemoveButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomButtons.AddChild(SaveButton);
|
||||||
|
|
||||||
|
Contents.AddChild(new VBoxContainer
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new HBoxContainer
|
||||||
|
{
|
||||||
|
SeparationOverride = 2,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new VBoxContainer
|
||||||
|
{
|
||||||
|
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
nameControl,
|
||||||
|
TitleEdit,
|
||||||
|
RankButton
|
||||||
|
}
|
||||||
|
},
|
||||||
|
permGrid
|
||||||
|
},
|
||||||
|
SizeFlagsVertical = SizeFlags.FillExpand
|
||||||
|
},
|
||||||
|
bottomButtons
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RankSelected(OptionButton.ItemSelectedEventArgs obj)
|
||||||
|
{
|
||||||
|
RankButton.SelectId(obj.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CollectSetFlags(out AdminFlags pos, out AdminFlags neg)
|
||||||
|
{
|
||||||
|
pos = default;
|
||||||
|
neg = default;
|
||||||
|
|
||||||
|
foreach (var (flag, (_, s, p)) in FlagButtons)
|
||||||
|
{
|
||||||
|
if (s.Pressed)
|
||||||
|
{
|
||||||
|
neg |= flag;
|
||||||
|
}
|
||||||
|
else if (p.Pressed)
|
||||||
|
{
|
||||||
|
pos |= flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Vector2? CustomSize => (600, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class EditAdminRankWindow : SS14Window
|
||||||
|
{
|
||||||
|
public readonly int? SourceId;
|
||||||
|
public readonly LineEdit NameEdit;
|
||||||
|
public readonly Button SaveButton;
|
||||||
|
public readonly Button? RemoveButton;
|
||||||
|
public readonly Dictionary<AdminFlags, CheckBox> FlagCheckBoxes = new Dictionary<AdminFlags, CheckBox>();
|
||||||
|
|
||||||
|
public EditAdminRankWindow(PermissionsEui ui, KeyValuePair<int, PermissionsEuiState.AdminRankData>? data)
|
||||||
|
{
|
||||||
|
SourceId = data?.Key;
|
||||||
|
|
||||||
|
NameEdit = new LineEdit
|
||||||
|
{
|
||||||
|
PlaceHolder = Loc.GetString("Rank name"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
NameEdit.Text = data.Value.Value.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveButton = new Button {Text = Loc.GetString("Save"), SizeFlagsHorizontal = SizeFlags.ShrinkEnd | SizeFlags.Expand};
|
||||||
|
var flagsBox = new VBoxContainer();
|
||||||
|
|
||||||
|
foreach (var flag in AdminFlagsHelper.AllFlags)
|
||||||
|
{
|
||||||
|
// Can only grant out perms you also have yourself.
|
||||||
|
// Primarily intended to prevent people giving themselves +HOST with +PERMISSIONS but generalized.
|
||||||
|
var disable = !ui._adminManager.HasFlag(flag);
|
||||||
|
var flagName = flag.ToString().ToUpper();
|
||||||
|
|
||||||
|
var checkBox = new CheckBox
|
||||||
|
{
|
||||||
|
Disabled = disable,
|
||||||
|
Text = flagName
|
||||||
|
};
|
||||||
|
|
||||||
|
if (data != null && (data.Value.Value.Flags & flag) != 0)
|
||||||
|
{
|
||||||
|
checkBox.Pressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlagCheckBoxes.Add(flag, checkBox);
|
||||||
|
flagsBox.AddChild(checkBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bottomButtons = new HBoxContainer();
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
// show remove button.
|
||||||
|
RemoveButton = new Button {Text = Loc.GetString("Remove")};
|
||||||
|
bottomButtons.AddChild(RemoveButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomButtons.AddChild(SaveButton);
|
||||||
|
|
||||||
|
Contents.AddChild(new VBoxContainer
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
NameEdit,
|
||||||
|
flagsBox,
|
||||||
|
bottomButtons
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdminFlags CollectSetFlags()
|
||||||
|
{
|
||||||
|
AdminFlags flags = default;
|
||||||
|
foreach (var (flag, chk) in FlagCheckBoxes)
|
||||||
|
{
|
||||||
|
if (chk.Pressed)
|
||||||
|
{
|
||||||
|
flags |= flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Vector2? CustomSize => (600, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ namespace Content.Client.UserInterface.Stylesheets
|
|||||||
public const string ClassHighDivider = "HighDivider";
|
public const string ClassHighDivider = "HighDivider";
|
||||||
public const string StyleClassLabelHeading = "LabelHeading";
|
public const string StyleClassLabelHeading = "LabelHeading";
|
||||||
public const string StyleClassLabelSubText = "LabelSubText";
|
public const string StyleClassLabelSubText = "LabelSubText";
|
||||||
|
public const string StyleClassItalic = "Italic";
|
||||||
|
|
||||||
public const string ButtonOpenRight = "OpenRight";
|
public const string ButtonOpenRight = "OpenRight";
|
||||||
public const string ButtonOpenLeft = "OpenLeft";
|
public const string ButtonOpenLeft = "OpenLeft";
|
||||||
@@ -31,6 +32,7 @@ namespace Content.Client.UserInterface.Stylesheets
|
|||||||
protected StyleBase(IResourceCache resCache)
|
protected StyleBase(IResourceCache resCache)
|
||||||
{
|
{
|
||||||
var notoSans12 = resCache.GetFont("/Fonts/NotoSans/NotoSans-Regular.ttf", 12);
|
var notoSans12 = resCache.GetFont("/Fonts/NotoSans/NotoSans-Regular.ttf", 12);
|
||||||
|
var notoSans12Italic = resCache.GetFont("/Fonts/NotoSans/NotoSans-Italic.ttf", 12);
|
||||||
|
|
||||||
// Button styles.
|
// Button styles.
|
||||||
var buttonTex = resCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
|
var buttonTex = resCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
|
||||||
@@ -77,6 +79,14 @@ namespace Content.Client.UserInterface.Stylesheets
|
|||||||
{
|
{
|
||||||
new StyleProperty("font", notoSans12),
|
new StyleProperty("font", notoSans12),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// Default font.
|
||||||
|
new StyleRule(
|
||||||
|
new SelectorElement(null, new[] {StyleClassItalic}, null, null),
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new StyleProperty("font", notoSans12Italic),
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Client;
|
using Content.Client;
|
||||||
using Content.Client.Interfaces.Parallax;
|
using Content.Client.Interfaces.Parallax;
|
||||||
@@ -13,7 +12,6 @@ using Robust.Shared.Interfaces.Map;
|
|||||||
using Robust.Shared.Interfaces.Network;
|
using Robust.Shared.Interfaces.Network;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.UnitTesting;
|
using Robust.UnitTesting;
|
||||||
using EntryPoint = Content.Client.EntryPoint;
|
using EntryPoint = Content.Client.EntryPoint;
|
||||||
|
|
||||||
|
|||||||
509
Content.Server.Database/Migrations/Postgres/20201028210620_Admins.Designer.cs
generated
Normal file
509
Content.Server.Database/Migrations/Postgres/20201028210620_Admins.Designer.cs
generated
Normal file
@@ -0,0 +1,509 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Postgres
|
||||||
|
{
|
||||||
|
[DbContext(typeof(PostgresServerDbContext))]
|
||||||
|
[Migration("20201028210620_Admins")]
|
||||||
|
partial class Admins
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.4")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int?>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnName("title")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.ToTable("admin");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_flag_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<Guid>("AdminId")
|
||||||
|
.HasColumnName("admin_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("Negative")
|
||||||
|
.HasColumnName("negative")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminId");
|
||||||
|
|
||||||
|
b.ToTable("admin_flag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("admin_rank");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_flag_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.ToTable("admin_rank_flag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("antag_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("AntagName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("antag_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId", "AntagName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("antag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("assigned_user_id_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("UserName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("assigned_user_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("job_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("JobName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("job_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnName("priority")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("job");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresConnectionLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("connection_log_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<IPAddress>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Time")
|
||||||
|
.HasColumnName("time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("connection_log");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresPlayer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("player_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstSeenTime")
|
||||||
|
.HasColumnName("first_seen_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<IPAddress>("LastSeenAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeenTime")
|
||||||
|
.HasColumnName("last_seen_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenUserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerBan", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("server_ban_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<ValueTuple<IPAddress, int>?>("Address")
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("BanTime")
|
||||||
|
.HasColumnName("ban_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("BanningAdmin")
|
||||||
|
.HasColumnName("banning_admin")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpirationTime")
|
||||||
|
.HasColumnName("expiration_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("reason")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Address");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("server_ban");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("HaveEitherAddressOrUserId", "address IS NOT NULL OR user_id IS NOT NULL");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("unban_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("BanId")
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UnbanTime")
|
||||||
|
.HasColumnName("unban_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UnbanningAdmin")
|
||||||
|
.HasColumnName("unbanning_admin")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BanId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("server_unban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("SelectedCharacterSlot")
|
||||||
|
.HasColumnName("selected_character_slot")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("preference");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("Age")
|
||||||
|
.HasColumnName("age")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("CharacterName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("char_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("EyeColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("eye_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("HairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceId")
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceUnavailable")
|
||||||
|
.HasColumnName("pref_unavailable")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Sex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("sex")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("skin_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Slot")
|
||||||
|
.HasColumnName("slot")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PreferenceId");
|
||||||
|
|
||||||
|
b.HasIndex("Slot", "PreferenceId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("profile");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
|
||||||
|
.WithMany("Admins")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Admin", "Admin")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "Rank")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Antags")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Jobs")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.PostgresServerBan", "Ban")
|
||||||
|
.WithOne("Unban")
|
||||||
|
.HasForeignKey("Content.Server.Database.PostgresServerUnban", "BanId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||||
|
.WithMany("Profiles")
|
||||||
|
.HasForeignKey("PreferenceId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Postgres
|
||||||
|
{
|
||||||
|
public partial class Admins : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "admin_rank",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
admin_rank_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
name = table.Column<string>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_admin_rank", x => x.admin_rank_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "admin",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
user_id = table.Column<Guid>(nullable: false),
|
||||||
|
title = table.Column<string>(nullable: true),
|
||||||
|
admin_rank_id = table.Column<int>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_admin", x => x.user_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_admin_admin_rank_admin_rank_id",
|
||||||
|
column: x => x.admin_rank_id,
|
||||||
|
principalTable: "admin_rank",
|
||||||
|
principalColumn: "admin_rank_id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "admin_rank_flag",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
admin_rank_flag_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
flag = table.Column<string>(nullable: false),
|
||||||
|
admin_rank_id = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_admin_rank_flag", x => x.admin_rank_flag_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_admin_rank_flag_admin_rank_admin_rank_id",
|
||||||
|
column: x => x.admin_rank_id,
|
||||||
|
principalTable: "admin_rank",
|
||||||
|
principalColumn: "admin_rank_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "admin_flag",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
admin_flag_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
flag = table.Column<string>(nullable: false),
|
||||||
|
negative = table.Column<bool>(nullable: false),
|
||||||
|
admin_id = table.Column<Guid>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_admin_flag", x => x.admin_flag_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_admin_flag_admin_admin_id",
|
||||||
|
column: x => x.admin_id,
|
||||||
|
principalTable: "admin",
|
||||||
|
principalColumn: "user_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_admin_admin_rank_id",
|
||||||
|
table: "admin",
|
||||||
|
column: "admin_rank_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_admin_flag_admin_id",
|
||||||
|
table: "admin_flag",
|
||||||
|
column: "admin_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_admin_rank_flag_admin_rank_id",
|
||||||
|
table: "admin_rank_flag",
|
||||||
|
column: "admin_rank_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "admin_flag");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "admin_rank_flag");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "admin");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "admin_rank");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
517
Content.Server.Database/Migrations/Postgres/20201109092921_ExtraIndices.Designer.cs
generated
Normal file
517
Content.Server.Database/Migrations/Postgres/20201109092921_ExtraIndices.Designer.cs
generated
Normal file
@@ -0,0 +1,517 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Postgres
|
||||||
|
{
|
||||||
|
[DbContext(typeof(PostgresServerDbContext))]
|
||||||
|
[Migration("20201109092921_ExtraIndices")]
|
||||||
|
partial class ExtraIndices
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.4")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int?>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnName("title")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.ToTable("admin");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_flag_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<Guid>("AdminId")
|
||||||
|
.HasColumnName("admin_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("Negative")
|
||||||
|
.HasColumnName("negative")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminId");
|
||||||
|
|
||||||
|
b.HasIndex("Flag", "AdminId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("admin_flag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("admin_rank");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_flag_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.HasIndex("Flag", "AdminRankId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("admin_rank_flag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("antag_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("AntagName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("antag_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId", "AntagName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("antag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("assigned_user_id_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("UserName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("assigned_user_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("job_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("JobName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("job_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnName("priority")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("job");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresConnectionLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("connection_log_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<IPAddress>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Time")
|
||||||
|
.HasColumnName("time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("connection_log");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresPlayer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("player_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstSeenTime")
|
||||||
|
.HasColumnName("first_seen_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<IPAddress>("LastSeenAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeenTime")
|
||||||
|
.HasColumnName("last_seen_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenUserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LastSeenUserName");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerBan", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("server_ban_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<ValueTuple<IPAddress, int>?>("Address")
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("BanTime")
|
||||||
|
.HasColumnName("ban_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("BanningAdmin")
|
||||||
|
.HasColumnName("banning_admin")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpirationTime")
|
||||||
|
.HasColumnName("expiration_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("reason")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Address");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("server_ban");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("HaveEitherAddressOrUserId", "address IS NOT NULL OR user_id IS NOT NULL");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("unban_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("BanId")
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UnbanTime")
|
||||||
|
.HasColumnName("unban_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UnbanningAdmin")
|
||||||
|
.HasColumnName("unbanning_admin")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BanId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("server_unban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("SelectedCharacterSlot")
|
||||||
|
.HasColumnName("selected_character_slot")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("preference");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("Age")
|
||||||
|
.HasColumnName("age")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("CharacterName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("char_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("EyeColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("eye_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("HairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceId")
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceUnavailable")
|
||||||
|
.HasColumnName("pref_unavailable")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Sex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("sex")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("skin_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Slot")
|
||||||
|
.HasColumnName("slot")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PreferenceId");
|
||||||
|
|
||||||
|
b.HasIndex("Slot", "PreferenceId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("profile");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
|
||||||
|
.WithMany("Admins")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Admin", "Admin")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "Rank")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Antags")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Jobs")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.PostgresServerBan", "Ban")
|
||||||
|
.WithOne("Unban")
|
||||||
|
.HasForeignKey("Content.Server.Database.PostgresServerUnban", "BanId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||||
|
.WithMany("Profiles")
|
||||||
|
.HasForeignKey("PreferenceId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Postgres
|
||||||
|
{
|
||||||
|
public partial class ExtraIndices : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_player_last_seen_user_name",
|
||||||
|
table: "player",
|
||||||
|
column: "last_seen_user_name");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_admin_rank_flag_flag_admin_rank_id",
|
||||||
|
table: "admin_rank_flag",
|
||||||
|
columns: new[] { "flag", "admin_rank_id" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_admin_flag_flag_admin_id",
|
||||||
|
table: "admin_flag",
|
||||||
|
columns: new[] { "flag", "admin_id" },
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_player_last_seen_user_name",
|
||||||
|
table: "player");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_admin_rank_flag_flag_admin_rank_id",
|
||||||
|
table: "admin_rank_flag");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_admin_flag_flag_admin_id",
|
||||||
|
table: "admin_flag");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,104 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||||||
.HasAnnotation("ProductVersion", "3.1.4")
|
.HasAnnotation("ProductVersion", "3.1.4")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int?>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnName("title")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.ToTable("admin");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_flag_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<Guid>("AdminId")
|
||||||
|
.HasColumnName("admin_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("Negative")
|
||||||
|
.HasColumnName("negative")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminId");
|
||||||
|
|
||||||
|
b.HasIndex("Flag", "AdminId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("admin_flag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("admin_rank");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_flag_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.HasIndex("Flag", "AdminRankId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("admin_rank_flag");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -168,6 +266,8 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LastSeenUserName");
|
||||||
|
|
||||||
b.HasIndex("UserId")
|
b.HasIndex("UserId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
@@ -348,6 +448,32 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||||||
b.ToTable("profile");
|
b.ToTable("profile");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
|
||||||
|
.WithMany("Admins")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Admin", "Admin")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "Rank")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Content.Server.Database.Profile", "Profile")
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
|||||||
476
Content.Server.Database/Migrations/Sqlite/20201028210616_Admins.Designer.cs
generated
Normal file
476
Content.Server.Database/Migrations/Sqlite/20201028210616_Admins.Designer.cs
generated
Normal file
@@ -0,0 +1,476 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Sqlite
|
||||||
|
{
|
||||||
|
[DbContext(typeof(SqliteServerDbContext))]
|
||||||
|
[Migration("20201028210616_Admins")]
|
||||||
|
partial class Admins
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.4");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnName("title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("UserId");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.ToTable("admin");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_flag_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("AdminId")
|
||||||
|
.HasColumnName("admin_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Negative")
|
||||||
|
.HasColumnName("negative")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminId");
|
||||||
|
|
||||||
|
b.ToTable("admin_flag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("admin_rank");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_flag_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.ToTable("admin_rank_flag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("antag_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AntagName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("antag_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId", "AntagName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("antag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("assigned_user_id_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("UserName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("assigned_user_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("job_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("JobName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("job_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnName("priority")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("job");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SelectedCharacterSlot")
|
||||||
|
.HasColumnName("selected_character_slot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("preference");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Age")
|
||||||
|
.HasColumnName("age")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("CharacterName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("char_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("EyeColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("eye_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("HairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceId")
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceUnavailable")
|
||||||
|
.HasColumnName("pref_unavailable")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Sex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("sex")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("skin_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Slot")
|
||||||
|
.HasColumnName("slot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PreferenceId");
|
||||||
|
|
||||||
|
b.HasIndex("Slot", "PreferenceId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("profile");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteConnectionLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("connection_log_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Time")
|
||||||
|
.HasColumnName("time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("connection_log");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqlitePlayer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("player_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstSeenTime")
|
||||||
|
.HasColumnName("first_seen_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeenTime")
|
||||||
|
.HasColumnName("last_seen_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenUserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("player");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerBan", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("BanTime")
|
||||||
|
.HasColumnName("ban_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("BanningAdmin")
|
||||||
|
.HasColumnName("banning_admin")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpirationTime")
|
||||||
|
.HasColumnName("expiration_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("reason")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("unban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("BanId")
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UnbanTime")
|
||||||
|
.HasColumnName("unban_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UnbanningAdmin")
|
||||||
|
.HasColumnName("unbanning_admin")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BanId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("unban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
|
||||||
|
.WithMany("Admins")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Admin", "Admin")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "Rank")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Antags")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Jobs")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||||
|
.WithMany("Profiles")
|
||||||
|
.HasForeignKey("PreferenceId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.SqliteServerBan", "Ban")
|
||||||
|
.WithOne("Unban")
|
||||||
|
.HasForeignKey("Content.Server.Database.SqliteServerUnban", "BanId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Sqlite
|
||||||
|
{
|
||||||
|
public partial class Admins : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "admin_rank",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
admin_rank_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
name = table.Column<string>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_admin_rank", x => x.admin_rank_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "admin",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
user_id = table.Column<Guid>(nullable: false),
|
||||||
|
title = table.Column<string>(nullable: true),
|
||||||
|
admin_rank_id = table.Column<int>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_admin", x => x.user_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_admin_admin_rank_admin_rank_id",
|
||||||
|
column: x => x.admin_rank_id,
|
||||||
|
principalTable: "admin_rank",
|
||||||
|
principalColumn: "admin_rank_id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "admin_rank_flag",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
admin_rank_flag_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
flag = table.Column<string>(nullable: false),
|
||||||
|
admin_rank_id = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_admin_rank_flag", x => x.admin_rank_flag_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_admin_rank_flag_admin_rank_admin_rank_id",
|
||||||
|
column: x => x.admin_rank_id,
|
||||||
|
principalTable: "admin_rank",
|
||||||
|
principalColumn: "admin_rank_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "admin_flag",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
admin_flag_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
flag = table.Column<string>(nullable: false),
|
||||||
|
negative = table.Column<bool>(nullable: false),
|
||||||
|
admin_id = table.Column<Guid>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_admin_flag", x => x.admin_flag_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_admin_flag_admin_admin_id",
|
||||||
|
column: x => x.admin_id,
|
||||||
|
principalTable: "admin",
|
||||||
|
principalColumn: "user_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_admin_admin_rank_id",
|
||||||
|
table: "admin",
|
||||||
|
column: "admin_rank_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_admin_flag_admin_id",
|
||||||
|
table: "admin_flag",
|
||||||
|
column: "admin_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_admin_rank_flag_admin_rank_id",
|
||||||
|
table: "admin_rank_flag",
|
||||||
|
column: "admin_rank_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "admin_flag");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "admin_rank_flag");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "admin");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "admin_rank");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
484
Content.Server.Database/Migrations/Sqlite/20201109092917_ExtraIndices.Designer.cs
generated
Normal file
484
Content.Server.Database/Migrations/Sqlite/20201109092917_ExtraIndices.Designer.cs
generated
Normal file
@@ -0,0 +1,484 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Sqlite
|
||||||
|
{
|
||||||
|
[DbContext(typeof(SqliteServerDbContext))]
|
||||||
|
[Migration("20201109092917_ExtraIndices")]
|
||||||
|
partial class ExtraIndices
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.4");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnName("title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("UserId");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.ToTable("admin");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_flag_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("AdminId")
|
||||||
|
.HasColumnName("admin_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Negative")
|
||||||
|
.HasColumnName("negative")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminId");
|
||||||
|
|
||||||
|
b.HasIndex("Flag", "AdminId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("admin_flag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("admin_rank");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_flag_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.HasIndex("Flag", "AdminRankId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("admin_rank_flag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("antag_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AntagName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("antag_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId", "AntagName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("antag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("assigned_user_id_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("UserName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("assigned_user_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("job_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("JobName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("job_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnName("priority")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("job");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SelectedCharacterSlot")
|
||||||
|
.HasColumnName("selected_character_slot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("preference");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Age")
|
||||||
|
.HasColumnName("age")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("CharacterName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("char_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("EyeColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("eye_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("HairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceId")
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceUnavailable")
|
||||||
|
.HasColumnName("pref_unavailable")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Sex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("sex")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("skin_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Slot")
|
||||||
|
.HasColumnName("slot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PreferenceId");
|
||||||
|
|
||||||
|
b.HasIndex("Slot", "PreferenceId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("profile");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteConnectionLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("connection_log_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Time")
|
||||||
|
.HasColumnName("time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("connection_log");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqlitePlayer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("player_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstSeenTime")
|
||||||
|
.HasColumnName("first_seen_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeenTime")
|
||||||
|
.HasColumnName("last_seen_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenUserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LastSeenUserName");
|
||||||
|
|
||||||
|
b.ToTable("player");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerBan", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("BanTime")
|
||||||
|
.HasColumnName("ban_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("BanningAdmin")
|
||||||
|
.HasColumnName("banning_admin")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpirationTime")
|
||||||
|
.HasColumnName("expiration_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("reason")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("unban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("BanId")
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UnbanTime")
|
||||||
|
.HasColumnName("unban_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UnbanningAdmin")
|
||||||
|
.HasColumnName("unbanning_admin")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BanId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("unban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
|
||||||
|
.WithMany("Admins")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Admin", "Admin")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "Rank")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Antags")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Jobs")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||||
|
.WithMany("Profiles")
|
||||||
|
.HasForeignKey("PreferenceId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.SqliteServerBan", "Ban")
|
||||||
|
.WithOne("Unban")
|
||||||
|
.HasForeignKey("Content.Server.Database.SqliteServerUnban", "BanId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Sqlite
|
||||||
|
{
|
||||||
|
public partial class ExtraIndices : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_player_last_seen_user_name",
|
||||||
|
table: "player",
|
||||||
|
column: "last_seen_user_name");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_admin_rank_flag_flag_admin_rank_id",
|
||||||
|
table: "admin_rank_flag",
|
||||||
|
columns: new[] { "flag", "admin_rank_id" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_admin_flag_flag_admin_id",
|
||||||
|
table: "admin_flag",
|
||||||
|
columns: new[] { "flag", "admin_id" },
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_player_last_seen_user_name",
|
||||||
|
table: "player");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_admin_rank_flag_flag_admin_rank_id",
|
||||||
|
table: "admin_rank_flag");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_admin_flag_flag_admin_id",
|
||||||
|
table: "admin_flag");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,101 @@ namespace Content.Server.Database.Migrations.Sqlite
|
|||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "3.1.4");
|
.HasAnnotation("ProductVersion", "3.1.4");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.HasColumnName("title")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("UserId");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.ToTable("admin");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_flag_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("AdminId")
|
||||||
|
.HasColumnName("admin_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Negative")
|
||||||
|
.HasColumnName("negative")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminId");
|
||||||
|
|
||||||
|
b.HasIndex("Flag", "AdminId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("admin_flag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("admin_rank");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("admin_rank_flag_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AdminRankId")
|
||||||
|
.HasColumnName("admin_rank_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Flag")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("flag")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AdminRankId");
|
||||||
|
|
||||||
|
b.HasIndex("Flag", "AdminRankId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("admin_rank_flag");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -251,6 +346,8 @@ namespace Content.Server.Database.Migrations.Sqlite
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LastSeenUserName");
|
||||||
|
|
||||||
b.ToTable("player");
|
b.ToTable("player");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -318,6 +415,32 @@ namespace Content.Server.Database.Migrations.Sqlite
|
|||||||
b.ToTable("unban");
|
b.ToTable("unban");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
|
||||||
|
.WithMany("Admins")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Admin", "Admin")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.AdminRank", "Rank")
|
||||||
|
.WithMany("Flags")
|
||||||
|
.HasForeignKey("AdminRankId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Content.Server.Database.Profile", "Profile")
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
@@ -26,6 +27,8 @@ namespace Content.Server.Database
|
|||||||
public DbSet<Preference> Preference { get; set; } = null!;
|
public DbSet<Preference> Preference { get; set; } = null!;
|
||||||
public DbSet<Profile> Profile { get; set; } = null!;
|
public DbSet<Profile> Profile { get; set; } = null!;
|
||||||
public DbSet<AssignedUserId> AssignedUserId { get; set; } = null!;
|
public DbSet<AssignedUserId> AssignedUserId { get; set; } = null!;
|
||||||
|
public DbSet<Admin> Admin { get; set; } = null!;
|
||||||
|
public DbSet<AdminRank> AdminRank { get; set; } = null!;
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
@@ -49,6 +52,19 @@ namespace Content.Server.Database
|
|||||||
modelBuilder.Entity<AssignedUserId>()
|
modelBuilder.Entity<AssignedUserId>()
|
||||||
.HasIndex(p => p.UserId)
|
.HasIndex(p => p.UserId)
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
|
modelBuilder.Entity<Admin>()
|
||||||
|
.HasOne(p => p.AdminRank)
|
||||||
|
.WithMany(p => p!.Admins)
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
modelBuilder.Entity<AdminFlag>()
|
||||||
|
.HasIndex(f => new {f.Flag, f.AdminId})
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
modelBuilder.Entity<AdminRankFlag>()
|
||||||
|
.HasIndex(f => new {f.Flag, f.AdminRankId})
|
||||||
|
.IsUnique();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,4 +151,46 @@ namespace Content.Server.Database
|
|||||||
|
|
||||||
[Column("user_id")] public Guid UserId { get; set; }
|
[Column("user_id")] public Guid UserId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Table("admin")]
|
||||||
|
public class Admin
|
||||||
|
{
|
||||||
|
[Column("user_id"), Key] public Guid UserId { get; set; }
|
||||||
|
[Column("title")] public string? Title { get; set; }
|
||||||
|
|
||||||
|
[Column("admin_rank_id")] public int? AdminRankId { get; set; }
|
||||||
|
public AdminRank? AdminRank { get; set; }
|
||||||
|
public List<AdminFlag> Flags { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("admin_flag")]
|
||||||
|
public class AdminFlag
|
||||||
|
{
|
||||||
|
[Column("admin_flag_id")] public int Id { get; set; }
|
||||||
|
[Column("flag")] public string Flag { get; set; } = default!;
|
||||||
|
[Column("negative")] public bool Negative { get; set; }
|
||||||
|
|
||||||
|
[Column("admin_id")] public Guid AdminId { get; set; }
|
||||||
|
public Admin Admin { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("admin_rank")]
|
||||||
|
public class AdminRank
|
||||||
|
{
|
||||||
|
[Column("admin_rank_id")] public int Id { get; set; }
|
||||||
|
[Column("name")] public string Name { get; set; } = default!;
|
||||||
|
|
||||||
|
public List<Admin> Admins { get; set; } = default!;
|
||||||
|
public List<AdminRankFlag> Flags { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("admin_rank_flag")]
|
||||||
|
public class AdminRankFlag
|
||||||
|
{
|
||||||
|
[Column("admin_rank_flag_id")] public int Id { get; set; }
|
||||||
|
[Column("flag")] public string Flag { get; set; } = default!;
|
||||||
|
|
||||||
|
[Column("admin_rank_id")] public int AdminRankId { get; set; }
|
||||||
|
public AdminRank Rank { get; set; } = default!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ namespace Content.Server.Database
|
|||||||
.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4",
|
.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4",
|
||||||
"NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
|
"NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
|
||||||
|
|
||||||
|
modelBuilder.Entity<PostgresPlayer>()
|
||||||
|
.HasIndex(p => p.LastSeenUserName);
|
||||||
|
|
||||||
modelBuilder.Entity<PostgresConnectionLog>()
|
modelBuilder.Entity<PostgresConnectionLog>()
|
||||||
.HasIndex(p => p.UserId);
|
.HasIndex(p => p.UserId);
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ namespace Content.Server.Database
|
|||||||
options.UseSqlite("dummy connection string");
|
options.UseSqlite("dummy connection string");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity<SqlitePlayer>()
|
||||||
|
.HasIndex(p => p.LastSeenUserName);
|
||||||
|
}
|
||||||
|
|
||||||
public SqliteServerDbContext(DbContextOptions<ServerDbContext> options) : base(options)
|
public SqliteServerDbContext(DbContextOptions<ServerDbContext> options) : base(options)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
27
Content.Server/Administration/AdminCommandAttribute.cs
Normal file
27
Content.Server/Administration/AdminCommandAttribute.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
|
|
||||||
|
namespace Content.Server.Administration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that a command can only be executed by an admin with the specified flags.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If this attribute is used multiple times, either attribute's flag sets can be used to get access.
|
||||||
|
/// </remarks>
|
||||||
|
/// <seealso cref="AnyCommandAttribute"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||||
|
[BaseTypeRequired(typeof(IClientCommand))]
|
||||||
|
[MeansImplicitUse]
|
||||||
|
public sealed class AdminCommandAttribute : Attribute
|
||||||
|
{
|
||||||
|
public AdminCommandAttribute(AdminFlags flags)
|
||||||
|
{
|
||||||
|
Flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdminFlags Flags { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
478
Content.Server/Administration/AdminManager.cs
Normal file
478
Content.Server/Administration/AdminManager.cs
Normal file
@@ -0,0 +1,478 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Content.Server.Interfaces.Chat;
|
||||||
|
using Content.Server.Players;
|
||||||
|
using Content.Shared;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.Network.NetMessages;
|
||||||
|
using Robust.Server.Console;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Interfaces.Configuration;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.Interfaces.Resources;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using YamlDotNet.RepresentationModel;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Administration
|
||||||
|
{
|
||||||
|
public sealed class AdminManager : IAdminManager, IPostInjectInit, IConGroupControllerImplementation
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly IServerDbManager _dbManager = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
[Dependency] private readonly IServerNetManager _netMgr = default!;
|
||||||
|
[Dependency] private readonly IConGroupController _conGroup = default!;
|
||||||
|
[Dependency] private readonly IResourceManager _res = default!;
|
||||||
|
[Dependency] private readonly IConsoleShell _consoleShell = default!;
|
||||||
|
[Dependency] private readonly IChatManager _chat = default!;
|
||||||
|
|
||||||
|
private readonly Dictionary<IPlayerSession, AdminReg> _admins = new Dictionary<IPlayerSession, AdminReg>();
|
||||||
|
|
||||||
|
public event Action<AdminPermsChangedEventArgs>? OnPermsChanged;
|
||||||
|
|
||||||
|
public IEnumerable<IPlayerSession> ActiveAdmins => _admins
|
||||||
|
.Where(p => p.Value.Data.Active)
|
||||||
|
.Select(p => p.Key);
|
||||||
|
|
||||||
|
// If a command isn't in this list it's server-console only.
|
||||||
|
// if a command is in but the flags value is null it's available to everybody.
|
||||||
|
private readonly HashSet<string> _anyCommands = new HashSet<string>();
|
||||||
|
private readonly Dictionary<string, AdminFlags[]> _adminCommands = new Dictionary<string, AdminFlags[]>();
|
||||||
|
|
||||||
|
public AdminData? GetAdminData(IPlayerSession session, bool includeDeAdmin = false)
|
||||||
|
{
|
||||||
|
if (_admins.TryGetValue(session, out var reg) && (reg.Data.Active || includeDeAdmin))
|
||||||
|
{
|
||||||
|
return reg.Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeAdmin(IPlayerSession session)
|
||||||
|
{
|
||||||
|
if (!_admins.TryGetValue(session, out var reg))
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Player {session} is not an admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reg.Data.Active)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_chat.SendAdminAnnouncement(Loc.GetString("{0} de-adminned themselves.", session.Name));
|
||||||
|
_chat.DispatchServerMessage(session, Loc.GetString("You are now a normal player."));
|
||||||
|
|
||||||
|
var plyData = session.ContentData()!;
|
||||||
|
plyData.ExplicitlyDeadminned = true;
|
||||||
|
reg.Data.Active = false;
|
||||||
|
|
||||||
|
SendPermsChangedEvent(session);
|
||||||
|
UpdateAdminStatus(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReAdmin(IPlayerSession session)
|
||||||
|
{
|
||||||
|
if (!_admins.TryGetValue(session, out var reg))
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Player {session} is not an admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
_chat.DispatchServerMessage(session, Loc.GetString("You are now an admin."));
|
||||||
|
|
||||||
|
var plyData = session.ContentData()!;
|
||||||
|
plyData.ExplicitlyDeadminned = false;
|
||||||
|
reg.Data.Active = true;
|
||||||
|
|
||||||
|
_chat.SendAdminAnnouncement(Loc.GetString("{0} re-adminned themselves.", session.Name));
|
||||||
|
|
||||||
|
SendPermsChangedEvent(session);
|
||||||
|
UpdateAdminStatus(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ReloadAdmin(IPlayerSession player)
|
||||||
|
{
|
||||||
|
var data = await LoadAdminData(player);
|
||||||
|
var curAdmin = _admins.GetValueOrDefault(player);
|
||||||
|
|
||||||
|
if (data == null && curAdmin == null)
|
||||||
|
{
|
||||||
|
// Wasn't admin before or after.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
// No longer admin.
|
||||||
|
_admins.Remove(player);
|
||||||
|
_chat.DispatchServerMessage(player, Loc.GetString("You are no longer an admin."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var (aData, rankId, special) = data.Value;
|
||||||
|
|
||||||
|
if (curAdmin == null)
|
||||||
|
{
|
||||||
|
// Now an admin.
|
||||||
|
var reg = new AdminReg(player, aData)
|
||||||
|
{
|
||||||
|
IsSpecialLogin = special,
|
||||||
|
RankId = rankId
|
||||||
|
};
|
||||||
|
_admins.Add(player, reg);
|
||||||
|
_chat.DispatchServerMessage(player, Loc.GetString("You are now an admin."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Perms changed.
|
||||||
|
curAdmin.IsSpecialLogin = special;
|
||||||
|
curAdmin.RankId = rankId;
|
||||||
|
curAdmin.Data = aData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player.ContentData()!.ExplicitlyDeadminned)
|
||||||
|
{
|
||||||
|
aData.Active = true;
|
||||||
|
|
||||||
|
_chat.DispatchServerMessage(player, Loc.GetString("Your admin permissions have been updated."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SendPermsChangedEvent(player);
|
||||||
|
UpdateAdminStatus(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReloadAdminsWithRank(int rankId)
|
||||||
|
{
|
||||||
|
foreach (var dat in _admins.Values.Where(p => p.RankId == rankId).ToArray())
|
||||||
|
{
|
||||||
|
ReloadAdmin(dat.Session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_netMgr.RegisterNetMessage<MsgUpdateAdminStatus>(MsgUpdateAdminStatus.NAME);
|
||||||
|
|
||||||
|
// Cache permissions for loaded console commands with the requisite attributes.
|
||||||
|
foreach (var (cmdName, cmd) in _consoleShell.AvailableCommands)
|
||||||
|
{
|
||||||
|
var (isAvail, flagsReq) = GetRequiredFlag(cmd);
|
||||||
|
|
||||||
|
if (!isAvail)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flagsReq.Length != 0)
|
||||||
|
{
|
||||||
|
_adminCommands.Add(cmdName, flagsReq);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_anyCommands.Add(cmdName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load flags for engine commands, since those don't have the attributes.
|
||||||
|
if (_res.TryContentFileRead(new ResourcePath("/engineCommandPerms.yml"), out var fs))
|
||||||
|
{
|
||||||
|
using var reader = new StreamReader(fs, EncodingHelpers.UTF8);
|
||||||
|
var yStream = new YamlStream();
|
||||||
|
yStream.Load(reader);
|
||||||
|
var root = (YamlSequenceNode) yStream.Documents[0].RootNode;
|
||||||
|
|
||||||
|
foreach (var child in root)
|
||||||
|
{
|
||||||
|
var map = (YamlMappingNode) child;
|
||||||
|
var commands = map.GetNode<YamlSequenceNode>("Commands").Select(p => p.AsString());
|
||||||
|
if (map.TryGetNode("Flags", out var flagsNode))
|
||||||
|
{
|
||||||
|
var flagNames = flagsNode.AsString().Split(",", StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var flags = AdminFlagsHelper.NamesToFlags(flagNames);
|
||||||
|
foreach (var cmd in commands)
|
||||||
|
{
|
||||||
|
if (!_adminCommands.TryGetValue(cmd, out var exFlags))
|
||||||
|
{
|
||||||
|
_adminCommands.Add(cmd, new[] {flags});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var newArr = new AdminFlags[exFlags.Length + 1];
|
||||||
|
exFlags.CopyTo(newArr, 0);
|
||||||
|
exFlags[^1] = flags;
|
||||||
|
_adminCommands[cmd] = newArr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_anyCommands.UnionWith(commands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPostInjectInit.PostInject()
|
||||||
|
{
|
||||||
|
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
|
||||||
|
_conGroup.Implementation = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Also sends commands list for non admins..
|
||||||
|
private void UpdateAdminStatus(IPlayerSession session)
|
||||||
|
{
|
||||||
|
var msg = _netMgr.CreateNetMessage<MsgUpdateAdminStatus>();
|
||||||
|
|
||||||
|
var commands = new List<string>(_anyCommands);
|
||||||
|
|
||||||
|
if (_admins.TryGetValue(session, out var adminData))
|
||||||
|
{
|
||||||
|
msg.Admin = adminData.Data;
|
||||||
|
|
||||||
|
commands.AddRange(_adminCommands
|
||||||
|
.Where(p => p.Value.Any(f => adminData.Data.HasFlag(f)))
|
||||||
|
.Select(p => p.Key));
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.AvailableCommands = commands.ToArray();
|
||||||
|
|
||||||
|
_netMgr.ServerSendMessage(msg, session.ConnectedClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.NewStatus == SessionStatus.Connected)
|
||||||
|
{
|
||||||
|
// Run this so that available commands list gets sent.
|
||||||
|
UpdateAdminStatus(e.Session);
|
||||||
|
}
|
||||||
|
else if (e.NewStatus == SessionStatus.InGame)
|
||||||
|
{
|
||||||
|
LoginAdminMaybe(e.Session);
|
||||||
|
}
|
||||||
|
else if (e.NewStatus == SessionStatus.Disconnected)
|
||||||
|
{
|
||||||
|
_admins.Remove(e.Session);
|
||||||
|
|
||||||
|
if (_cfg.GetCVar(CCVars.AdminAnnounceLogout))
|
||||||
|
{
|
||||||
|
_chat.SendAdminAnnouncement(Loc.GetString("Admin logout: {0}", e.Session.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void LoginAdminMaybe(IPlayerSession session)
|
||||||
|
{
|
||||||
|
var adminDat = await LoadAdminData(session);
|
||||||
|
if (adminDat == null)
|
||||||
|
{
|
||||||
|
// Not an admin.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (dat, rankId, specialLogin) = adminDat.Value;
|
||||||
|
var reg = new AdminReg(session, dat)
|
||||||
|
{
|
||||||
|
IsSpecialLogin = specialLogin,
|
||||||
|
RankId = rankId
|
||||||
|
};
|
||||||
|
|
||||||
|
_admins.Add(session, reg);
|
||||||
|
|
||||||
|
if (!session.ContentData()!.ExplicitlyDeadminned)
|
||||||
|
{
|
||||||
|
reg.Data.Active = true;
|
||||||
|
|
||||||
|
if (_cfg.GetCVar(CCVars.AdminAnnounceLogin))
|
||||||
|
{
|
||||||
|
_chat.SendAdminAnnouncement(Loc.GetString("Admin login: {0}", session.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
SendPermsChangedEvent(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAdminStatus(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<(AdminData dat, int? rankId, bool specialLogin)?> LoadAdminData(IPlayerSession session)
|
||||||
|
{
|
||||||
|
if (IsLocal(session) && _cfg.GetCVar(CCVars.ConsoleLoginLocal))
|
||||||
|
{
|
||||||
|
var data = new AdminData
|
||||||
|
{
|
||||||
|
Title = Loc.GetString("Host"),
|
||||||
|
Flags = AdminFlagsHelper.Everything,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (data, null, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var dbData = await _dbManager.GetAdminDataForAsync(session.UserId);
|
||||||
|
|
||||||
|
if (dbData == null)
|
||||||
|
{
|
||||||
|
// Not an admin!
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags = AdminFlags.None;
|
||||||
|
|
||||||
|
if (dbData.AdminRank != null)
|
||||||
|
{
|
||||||
|
flags = AdminFlagsHelper.NamesToFlags(dbData.AdminRank.Flags.Select(p => p.Flag));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var dbFlag in dbData.Flags)
|
||||||
|
{
|
||||||
|
var flag = AdminFlagsHelper.NameToFlag(dbFlag.Flag);
|
||||||
|
if (dbFlag.Negative)
|
||||||
|
{
|
||||||
|
flags &= ~flag;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags |= flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = new AdminData
|
||||||
|
{
|
||||||
|
Flags = flags
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dbData.Title != null)
|
||||||
|
{
|
||||||
|
data.Title = dbData.Title;
|
||||||
|
}
|
||||||
|
else if (dbData.AdminRank != null)
|
||||||
|
{
|
||||||
|
data.Title = dbData.AdminRank.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (data, dbData.AdminRankId, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsLocal(IPlayerSession player)
|
||||||
|
{
|
||||||
|
var ep = player.ConnectedClient.RemoteEndPoint;
|
||||||
|
var addr = ep.Address;
|
||||||
|
if (addr.IsIPv4MappedToIPv6)
|
||||||
|
{
|
||||||
|
addr = addr.MapToIPv4();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Equals(addr, IPAddress.Loopback) || Equals(addr, IPAddress.IPv6Loopback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanCommand(IPlayerSession session, string cmdName)
|
||||||
|
{
|
||||||
|
if (_anyCommands.Contains(cmdName))
|
||||||
|
{
|
||||||
|
// Anybody can use this command.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_adminCommands.TryGetValue(cmdName, out var flagsReq))
|
||||||
|
{
|
||||||
|
// Server-console only.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = GetAdminData(session);
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
// Player isn't an admin.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var flagReq in flagsReq)
|
||||||
|
{
|
||||||
|
if (data.HasFlag(flagReq))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (bool isAvail, AdminFlags[] flagsReq) GetRequiredFlag(IClientCommand cmd)
|
||||||
|
{
|
||||||
|
var type = cmd.GetType();
|
||||||
|
if (Attribute.IsDefined(type, typeof(AnyCommandAttribute)))
|
||||||
|
{
|
||||||
|
// Available to everybody.
|
||||||
|
return (true, Array.Empty<AdminFlags>());
|
||||||
|
}
|
||||||
|
|
||||||
|
var attribs = type.GetCustomAttributes(typeof(AdminCommandAttribute))
|
||||||
|
.Cast<AdminCommandAttribute>()
|
||||||
|
.Select(p => p.Flags)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
// If attribs.length == 0 then no access attribute is specified,
|
||||||
|
// and this is a server-only command.
|
||||||
|
return (attribs.Length != 0, attribs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanViewVar(IPlayerSession session)
|
||||||
|
{
|
||||||
|
return GetAdminData(session)?.CanViewVar() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanAdminPlace(IPlayerSession session)
|
||||||
|
{
|
||||||
|
return GetAdminData(session)?.CanAdminPlace() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanScript(IPlayerSession session)
|
||||||
|
{
|
||||||
|
return GetAdminData(session)?.CanScript() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanAdminMenu(IPlayerSession session)
|
||||||
|
{
|
||||||
|
return GetAdminData(session)?.CanAdminMenu() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendPermsChangedEvent(IPlayerSession session)
|
||||||
|
{
|
||||||
|
var flags = GetAdminData(session)?.Flags;
|
||||||
|
OnPermsChanged?.Invoke(new AdminPermsChangedEventArgs(session, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class AdminReg
|
||||||
|
{
|
||||||
|
public IPlayerSession Session;
|
||||||
|
|
||||||
|
public AdminData Data;
|
||||||
|
public int? RankId;
|
||||||
|
|
||||||
|
// Such as console.loginlocal
|
||||||
|
public bool IsSpecialLogin;
|
||||||
|
|
||||||
|
public AdminReg(IPlayerSession session, AdminData data)
|
||||||
|
{
|
||||||
|
Data = data;
|
||||||
|
Session = session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Content.Server/Administration/AdminPermsChangedEventArgs.cs
Normal file
33
Content.Server/Administration/AdminPermsChangedEventArgs.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
|
||||||
|
namespace Content.Server.Administration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sealed when the permissions of an admin on the server change.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class AdminPermsChangedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public AdminPermsChangedEventArgs(IPlayerSession player, AdminFlags? flags)
|
||||||
|
{
|
||||||
|
Player = player;
|
||||||
|
Flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The player that had their admin permissions changed.
|
||||||
|
/// </summary>
|
||||||
|
public IPlayerSession Player { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The admin flags of the player. Null if the player is no longer an admin.
|
||||||
|
/// </summary>
|
||||||
|
public AdminFlags? Flags { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the player is now an admin.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAdmin => Flags.HasValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Content.Server/Administration/AdminRank.cs
Normal file
18
Content.Server/Administration/AdminRank.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using Content.Shared.Administration;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Administration
|
||||||
|
{
|
||||||
|
public sealed class AdminRank
|
||||||
|
{
|
||||||
|
public AdminRank(string name, AdminFlags flags)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public AdminFlags Flags { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Content.Server/Administration/AnyCommandAttribute.cs
Normal file
18
Content.Server/Administration/AnyCommandAttribute.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
|
|
||||||
|
namespace Content.Server.Administration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that a command can be executed by any player.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="AdminCommandAttribute"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
[BaseTypeRequired(typeof(IClientCommand))]
|
||||||
|
[MeansImplicitUse]
|
||||||
|
public sealed class AnyCommandAttribute : Attribute
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
using Content.Server.GameObjects.Components.Observer;
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.Administration
|
namespace Content.Server.Administration.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
public class AGhost : IClientCommand
|
public class AGhost : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "aghost";
|
public string Command => "aghost";
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net;
|
|
||||||
using Content.Server.Database;
|
using Content.Server.Database;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -8,8 +8,9 @@ using Robust.Shared.Network;
|
|||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
namespace Content.Server.Administration
|
namespace Content.Server.Administration.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Ban)]
|
||||||
public sealed class BanCommand : IClientCommand
|
public sealed class BanCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "ban";
|
public string Command => "ban";
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Server.GameObjects.Components.Mobs;
|
using Content.Server.GameObjects.Components.Mobs;
|
||||||
using Content.Server.GameObjects.Components.Observer;
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -8,8 +9,9 @@ using Robust.Shared.Interfaces.GameObjects;
|
|||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
|
|
||||||
namespace Content.Server.Administration
|
namespace Content.Server.Administration.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
class ControlMob : IClientCommand
|
class ControlMob : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "controlmob";
|
public string Command => "controlmob";
|
||||||
31
Content.Server/Administration/Commands/DeAdminCommand.cs
Normal file
31
Content.Server/Administration/Commands/DeAdminCommand.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using Content.Shared.Administration;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Administration.Commands
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
[AdminCommand(AdminFlags.None)]
|
||||||
|
public class DeAdminCommand : IClientCommand
|
||||||
|
{
|
||||||
|
public string Command => "deadmin";
|
||||||
|
public string Description => "Temporarily de-admins you so you can experience the round as a normal player.";
|
||||||
|
public string Help => "Usage: deadmin\nUse readmin to re-admin after using this.";
|
||||||
|
|
||||||
|
public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
|
||||||
|
{
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
shell.SendText(player, "You cannot use this command from the server console.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mgr = IoCManager.Resolve<IAdminManager>();
|
||||||
|
mgr.DeAdmin(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -7,8 +8,9 @@ using Robust.Shared.Interfaces.GameObjects;
|
|||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
|
|
||||||
namespace Content.Server.Administration
|
namespace Content.Server.Administration.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
class DeleteEntitiesWithComponent : IClientCommand
|
class DeleteEntitiesWithComponent : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "deleteewc";
|
public string Command => "deleteewc";
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.Administration
|
namespace Content.Server.Administration.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
public class DeleteEntitiesWithId : IClientCommand
|
public class DeleteEntitiesWithId : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "deleteewi";
|
public string Command => "deleteewi";
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Content.Server.Eui;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Administration.Commands
|
||||||
|
{
|
||||||
|
[AdminCommand(AdminFlags.Permissions)]
|
||||||
|
public sealed class OpenPermissionsCommand : IClientCommand
|
||||||
|
{
|
||||||
|
public string Command => "permissions";
|
||||||
|
public string Description => "Opens the admin permissions panel.";
|
||||||
|
public string Help => "Usage: permissions";
|
||||||
|
|
||||||
|
public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
|
||||||
|
{
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
shell.SendText(player, "This does not work from the server console.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var eui = IoCManager.Resolve<EuiManager>();
|
||||||
|
var ui = new PermissionsEui();
|
||||||
|
eui.OpenEui(ui, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
Content.Server/Administration/Commands/ReAdminCommand.cs
Normal file
35
Content.Server/Administration/Commands/ReAdminCommand.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Administration.Commands
|
||||||
|
{
|
||||||
|
[AnyCommand]
|
||||||
|
public class ReAdminCommand : IClientCommand
|
||||||
|
{
|
||||||
|
public string Command => "readmin";
|
||||||
|
public string Description => "Re-admins you if you previously de-adminned.";
|
||||||
|
public string Help => "Usage: readmin";
|
||||||
|
|
||||||
|
public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
|
||||||
|
{
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
shell.SendText(player, "You cannot use this command from the server console.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mgr = IoCManager.Resolve<IAdminManager>();
|
||||||
|
|
||||||
|
if (mgr.GetAdminData(player, includeDeAdmin: true) == null)
|
||||||
|
{
|
||||||
|
shell.SendText(player, "You're not an admin.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr.ReAdmin(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using Content.Server.Interfaces.GameTicking;
|
using Content.Server.Interfaces.GameTicking;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.Administration
|
namespace Content.Server.Administration.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Server)]
|
||||||
public class ReadyAll : IClientCommand
|
public class ReadyAll : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "readyall";
|
public string Command => "readyall";
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.GlobalVerbs;
|
using Content.Server.GlobalVerbs;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -6,8 +7,9 @@ using Robust.Shared.Interfaces.GameObjects;
|
|||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
|
|
||||||
namespace Content.Server.Administration
|
namespace Content.Server.Administration.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
class Rejuvenate : IClientCommand
|
class Rejuvenate : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "rejuvenate";
|
public string Command => "rejuvenate";
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameObjects.Components.Markers;
|
using Content.Server.GameObjects.Components.Markers;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
@@ -10,8 +11,9 @@ using Robust.Shared.Interfaces.Map;
|
|||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
namespace Content.Server.Administration
|
namespace Content.Server.Administration.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
public class WarpCommand : IClientCommand
|
public class WarpCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "warp";
|
public string Command => "warp";
|
||||||
76
Content.Server/Administration/IAdminManager.cs
Normal file
76
Content.Server/Administration/IAdminManager.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Administration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manages server administrators and their permission flags.
|
||||||
|
/// </summary>
|
||||||
|
public interface IAdminManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when the permissions of an admin on the server changed.
|
||||||
|
/// </summary>
|
||||||
|
event Action<AdminPermsChangedEventArgs> OnPermsChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all active admins currently on the server.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This does not include admins that are de-adminned.
|
||||||
|
/// </remarks>
|
||||||
|
IEnumerable<IPlayerSession> ActiveAdmins { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the admin data for a player, if they are an admin.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="session">The player to get admin data for.</param>
|
||||||
|
/// <param name="includeDeAdmin">
|
||||||
|
/// Whether to return admin data for admins that are current de-adminned.
|
||||||
|
/// </param>
|
||||||
|
/// <returns><see langword="null" /> if the player is not an admin.</returns>
|
||||||
|
AdminData? GetAdminData(IPlayerSession session, bool includeDeAdmin = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// See if a player has an admin flag.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the player is and admin and has the specified flags.</returns>
|
||||||
|
bool HasAdminFlag(IPlayerSession player, AdminFlags flag)
|
||||||
|
{
|
||||||
|
var data = GetAdminData(player);
|
||||||
|
return data != null && data.HasFlag(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// De-admins an admin temporarily so they are effectively a normal player.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// De-adminned admins are able to re-admin at any time if they so desire.
|
||||||
|
/// </remarks>
|
||||||
|
void DeAdmin(IPlayerSession session);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Re-admins a de-adminned admin.
|
||||||
|
/// </summary>
|
||||||
|
void ReAdmin(IPlayerSession session);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Re-loads the permissions of an player in case their admin data changed DB-side.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="ReloadAdminsWithRank"/>
|
||||||
|
void ReloadAdmin(IPlayerSession player);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reloads admin permissions for all admins with a certain rank.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rankId">The database ID of the rank.</param>
|
||||||
|
/// <seealso cref="ReloadAdmin"/>
|
||||||
|
void ReloadAdminsWithRank(int rankId);
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
460
Content.Server/Administration/PermissionsEui.cs
Normal file
460
Content.Server/Administration/PermissionsEui.cs
Normal file
@@ -0,0 +1,460 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Content.Server.Eui;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.Eui;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using DbAdminRank = Content.Server.Database.AdminRank;
|
||||||
|
using static Content.Shared.Administration.PermissionsEuiMsg;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Administration
|
||||||
|
{
|
||||||
|
public sealed class PermissionsEui : BaseEui
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly IServerDbManager _db = default!;
|
||||||
|
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||||
|
|
||||||
|
private bool _isLoading;
|
||||||
|
|
||||||
|
private readonly List<(Admin a, string? lastUserName)> _admins = new List<(Admin, string? lastUserName)>();
|
||||||
|
private readonly List<DbAdminRank> _adminRanks = new List<DbAdminRank>();
|
||||||
|
|
||||||
|
public PermissionsEui()
|
||||||
|
{
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Opened()
|
||||||
|
{
|
||||||
|
base.Opened();
|
||||||
|
|
||||||
|
StateDirty();
|
||||||
|
LoadFromDb();
|
||||||
|
_adminManager.OnPermsChanged += AdminManagerOnPermsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Closed()
|
||||||
|
{
|
||||||
|
base.Closed();
|
||||||
|
|
||||||
|
_adminManager.OnPermsChanged -= AdminManagerOnPermsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AdminManagerOnPermsChanged(AdminPermsChangedEventArgs obj)
|
||||||
|
{
|
||||||
|
// Close UI if user loses +PERMISSIONS.
|
||||||
|
if (obj.Player == Player && !UserAdminFlagCheck(AdminFlags.Permissions))
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override EuiStateBase GetNewState()
|
||||||
|
{
|
||||||
|
if (_isLoading)
|
||||||
|
{
|
||||||
|
return new PermissionsEuiState
|
||||||
|
{
|
||||||
|
IsLoading = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PermissionsEuiState
|
||||||
|
{
|
||||||
|
Admins = _admins.Select(p => new PermissionsEuiState.AdminData
|
||||||
|
{
|
||||||
|
PosFlags = AdminFlagsHelper.NamesToFlags(p.a.Flags.Where(f => !f.Negative).Select(f => f.Flag)),
|
||||||
|
NegFlags = AdminFlagsHelper.NamesToFlags(p.a.Flags.Where(f => f.Negative).Select(f => f.Flag)),
|
||||||
|
Title = p.a.Title,
|
||||||
|
RankId = p.a.AdminRankId,
|
||||||
|
UserId = new NetUserId(p.a.UserId),
|
||||||
|
UserName = p.lastUserName
|
||||||
|
}).ToArray(),
|
||||||
|
|
||||||
|
AdminRanks = _adminRanks.ToDictionary(a => a.Id, a => new PermissionsEuiState.AdminRankData
|
||||||
|
{
|
||||||
|
Flags = AdminFlagsHelper.NamesToFlags(a.Flags.Select(p => p.Flag)),
|
||||||
|
Name = a.Name
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async void HandleMessage(EuiMessageBase msg)
|
||||||
|
{
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
|
case Close _:
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AddAdmin ca:
|
||||||
|
{
|
||||||
|
await HandleCreateAdmin(ca);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case UpdateAdmin ua:
|
||||||
|
{
|
||||||
|
await HandleUpdateAdmin(ua);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RemoveAdmin ra:
|
||||||
|
{
|
||||||
|
await HandleRemoveAdmin(ra);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AddAdminRank ar:
|
||||||
|
{
|
||||||
|
await HandleAddAdminRank(ar);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case UpdateAdminRank ur:
|
||||||
|
{
|
||||||
|
await HandleUpdateAdminRank(ur);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RemoveAdminRank ra:
|
||||||
|
{
|
||||||
|
await HandleRemoveAdminRank(ra);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsShutDown)
|
||||||
|
{
|
||||||
|
LoadFromDb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleRemoveAdminRank(RemoveAdminRank rr)
|
||||||
|
{
|
||||||
|
var rank = await _db.GetAdminRankAsync(rr.Id);
|
||||||
|
if (rank == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanTouchRank(rank))
|
||||||
|
{
|
||||||
|
Logger.WarningS("admin.perms", $"{Player} tried to remove higher-ranked admin rank {rank.Name}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _db.RemoveAdminRankAsync(rr.Id);
|
||||||
|
|
||||||
|
_adminManager.ReloadAdminsWithRank(rr.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleUpdateAdminRank(UpdateAdminRank ur)
|
||||||
|
{
|
||||||
|
var rank = await _db.GetAdminRankAsync(ur.Id);
|
||||||
|
if (rank == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanTouchRank(rank))
|
||||||
|
{
|
||||||
|
Logger.WarningS("admin.perms", $"{Player} tried to update higher-ranked admin rank {rank.Name}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UserAdminFlagCheck(ur.Flags))
|
||||||
|
{
|
||||||
|
Logger.WarningS("admin.perms", $"{Player} tried to give a rank permissions above their authorization.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rank.Flags = GenRankFlagList(ur.Flags);
|
||||||
|
rank.Name = ur.Name;
|
||||||
|
|
||||||
|
await _db.UpdateAdminRankAsync(rank);
|
||||||
|
|
||||||
|
var flagText = string.Join(' ', AdminFlagsHelper.FlagsToNames(ur.Flags).Select(f => $"+{f}"));
|
||||||
|
Logger.InfoS("admin.perms", $"{Player} updated admin rank {rank.Name}/{flagText}.");
|
||||||
|
|
||||||
|
_adminManager.ReloadAdminsWithRank(ur.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleAddAdminRank(AddAdminRank ar)
|
||||||
|
{
|
||||||
|
if (!UserAdminFlagCheck(ar.Flags))
|
||||||
|
{
|
||||||
|
Logger.WarningS("admin.perms", $"{Player} tried to give a rank permissions above their authorization.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rank = new DbAdminRank
|
||||||
|
{
|
||||||
|
Name = ar.Name,
|
||||||
|
Flags = GenRankFlagList(ar.Flags)
|
||||||
|
};
|
||||||
|
|
||||||
|
await _db.AddAdminRankAsync(rank);
|
||||||
|
|
||||||
|
var flagText = string.Join(' ', AdminFlagsHelper.FlagsToNames(ar.Flags).Select(f => $"+{f}"));
|
||||||
|
Logger.InfoS("admin.perms", $"{Player} added admin rank {rank.Name}/{flagText}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleRemoveAdmin(RemoveAdmin ra)
|
||||||
|
{
|
||||||
|
var admin = await _db.GetAdminDataForAsync(ra.UserId);
|
||||||
|
if (admin == null)
|
||||||
|
{
|
||||||
|
// Doesn't exist.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanTouchAdmin(admin))
|
||||||
|
{
|
||||||
|
Logger.WarningS("admin.perms", $"{Player} tried to remove higher-ranked admin {ra.UserId.ToString()}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _db.RemoveAdminAsync(ra.UserId);
|
||||||
|
|
||||||
|
var record = await _db.GetPlayerRecordByUserId(ra.UserId);
|
||||||
|
Logger.InfoS("admin.perms", $"{Player} removed admin {record?.LastSeenUserName ?? ra.UserId.ToString()}");
|
||||||
|
|
||||||
|
if (_playerManager.TryGetSessionById(ra.UserId, out var player))
|
||||||
|
{
|
||||||
|
_adminManager.ReloadAdmin(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleUpdateAdmin(UpdateAdmin ua)
|
||||||
|
{
|
||||||
|
if (!CheckCreatePerms(ua.PosFlags, ua.NegFlags))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var admin = await _db.GetAdminDataForAsync(ua.UserId);
|
||||||
|
if (admin == null)
|
||||||
|
{
|
||||||
|
// Was removed in the mean time I guess?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanTouchAdmin(admin))
|
||||||
|
{
|
||||||
|
Logger.WarningS("admin.perms", $"{Player} tried to modify higher-ranked admin {ua.UserId.ToString()}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
admin.Title = ua.Title;
|
||||||
|
admin.AdminRankId = ua.RankId;
|
||||||
|
admin.Flags = GenAdminFlagList(ua.PosFlags, ua.NegFlags);
|
||||||
|
|
||||||
|
await _db.UpdateAdminAsync(admin);
|
||||||
|
|
||||||
|
var playerRecord = await _db.GetPlayerRecordByUserId(ua.UserId);
|
||||||
|
var (bad, rankName) = await FetchAndCheckRank(ua.RankId);
|
||||||
|
if (bad)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = playerRecord?.LastSeenUserName ?? ua.UserId.ToString();
|
||||||
|
var title = ua.Title ?? "<no title>";
|
||||||
|
var flags = AdminFlagsHelper.PosNegFlagsText(ua.PosFlags, ua.NegFlags);
|
||||||
|
|
||||||
|
Logger.InfoS("admin.perms", $"{Player} updated admin {name} to {title}/{rankName}/{flags}");
|
||||||
|
|
||||||
|
if (_playerManager.TryGetSessionById(ua.UserId, out var player))
|
||||||
|
{
|
||||||
|
_adminManager.ReloadAdmin(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleCreateAdmin(AddAdmin ca)
|
||||||
|
{
|
||||||
|
if (!CheckCreatePerms(ca.PosFlags, ca.NegFlags))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string name;
|
||||||
|
NetUserId userId;
|
||||||
|
if (Guid.TryParse(ca.UserNameOrId, out var guid))
|
||||||
|
{
|
||||||
|
userId = new NetUserId(guid);
|
||||||
|
var playerRecord = await _db.GetPlayerRecordByUserId(userId);
|
||||||
|
if (playerRecord == null)
|
||||||
|
{
|
||||||
|
name = userId.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = playerRecord.LastSeenUserName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Username entered, resolve user ID from DB.
|
||||||
|
var dbPlayer = await _db.GetPlayerRecordByUserName(ca.UserNameOrId);
|
||||||
|
if (dbPlayer == null)
|
||||||
|
{
|
||||||
|
// username not in DB.
|
||||||
|
// TODO: Notify user.
|
||||||
|
Logger.WarningS("admin.perms",
|
||||||
|
$"{Player} tried to add admin with unknown username {ca.UserNameOrId}.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
userId = dbPlayer.UserId;
|
||||||
|
name = ca.UserNameOrId;
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = await _db.GetAdminDataForAsync(userId);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
// Already exists.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (bad, rankName) = await FetchAndCheckRank(ca.RankId);
|
||||||
|
if (bad)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rankName ??= "<no rank>";
|
||||||
|
|
||||||
|
var admin = new Admin
|
||||||
|
{
|
||||||
|
Flags = GenAdminFlagList(ca.PosFlags, ca.NegFlags),
|
||||||
|
AdminRankId = ca.RankId,
|
||||||
|
UserId = userId.UserId,
|
||||||
|
Title = ca.Title
|
||||||
|
};
|
||||||
|
|
||||||
|
await _db.AddAdminAsync(admin);
|
||||||
|
|
||||||
|
var title = ca.Title ?? "<no title>";
|
||||||
|
var flags = AdminFlagsHelper.PosNegFlagsText(ca.PosFlags, ca.NegFlags);
|
||||||
|
|
||||||
|
Logger.InfoS("admin.perms", $"{Player} added admin {name} as {title}/{rankName}/{flags}");
|
||||||
|
|
||||||
|
if (_playerManager.TryGetSessionById(userId, out var player))
|
||||||
|
{
|
||||||
|
_adminManager.ReloadAdmin(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
|
||||||
|
private bool CheckCreatePerms(AdminFlags posFlags, AdminFlags negFlags)
|
||||||
|
{
|
||||||
|
if ((posFlags & negFlags) != 0)
|
||||||
|
{
|
||||||
|
// Can't have overlapping pos and neg flags.
|
||||||
|
// Just deny the entire message.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UserAdminFlagCheck(posFlags))
|
||||||
|
{
|
||||||
|
// Can't create an admin with higher perms than yourself, obviously.
|
||||||
|
Logger.WarningS("admin.perms", $"{Player} tried to grant admin powers above their authorization.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<(bool bad, string?)> FetchAndCheckRank(int? rankId)
|
||||||
|
{
|
||||||
|
string? ret = null;
|
||||||
|
if (rankId is { } r)
|
||||||
|
{
|
||||||
|
var rank = await _db.GetAdminRankAsync(r);
|
||||||
|
if (rank == null)
|
||||||
|
{
|
||||||
|
// Tried to set to nonexistent rank.
|
||||||
|
Logger.WarningS("admin.perms", $"{Player} tried to assign nonexistent admin rank.");
|
||||||
|
return (true, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rank.Name;
|
||||||
|
|
||||||
|
var rankFlags = AdminFlagsHelper.NamesToFlags(rank.Flags.Select(p => p.Flag));
|
||||||
|
if (!UserAdminFlagCheck(rankFlags))
|
||||||
|
{
|
||||||
|
// Can't assign a rank with flags you don't have yourself.
|
||||||
|
Logger.WarningS("admin.perms", $"{Player} tried to assign admin rank above their authorization.");
|
||||||
|
return (true, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void LoadFromDb()
|
||||||
|
{
|
||||||
|
StateDirty();
|
||||||
|
_isLoading = true;
|
||||||
|
var (admins, ranks) = await _db.GetAllAdminAndRanksAsync();
|
||||||
|
|
||||||
|
_admins.Clear();
|
||||||
|
_admins.AddRange(admins);
|
||||||
|
_adminRanks.Clear();
|
||||||
|
_adminRanks.AddRange(ranks);
|
||||||
|
|
||||||
|
_isLoading = false;
|
||||||
|
StateDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<AdminFlag> GenAdminFlagList(AdminFlags posFlags, AdminFlags negFlags)
|
||||||
|
{
|
||||||
|
var posFlagList = AdminFlagsHelper.FlagsToNames(posFlags);
|
||||||
|
var negFlagList = AdminFlagsHelper.FlagsToNames(negFlags);
|
||||||
|
|
||||||
|
return posFlagList
|
||||||
|
.Select(f => new AdminFlag {Negative = false, Flag = f})
|
||||||
|
.Concat(negFlagList.Select(f => new AdminFlag {Negative = true, Flag = f}))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<AdminRankFlag> GenRankFlagList(AdminFlags flags)
|
||||||
|
{
|
||||||
|
return AdminFlagsHelper.FlagsToNames(flags).Select(f => new AdminRankFlag {Flag = f}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool UserAdminFlagCheck(AdminFlags flags)
|
||||||
|
{
|
||||||
|
return _adminManager.HasAdminFlag(Player, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CanTouchAdmin(Admin admin)
|
||||||
|
{
|
||||||
|
var posFlags = AdminFlagsHelper.NamesToFlags(admin.Flags.Where(f => !f.Negative).Select(f => f.Flag));
|
||||||
|
var rankFlags = AdminFlagsHelper.NamesToFlags(
|
||||||
|
admin.AdminRank?.Flags.Select(f => f.Flag) ?? Array.Empty<string>());
|
||||||
|
|
||||||
|
var totalFlags = posFlags | rankFlags;
|
||||||
|
return UserAdminFlagCheck(totalFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CanTouchRank(DbAdminRank rank)
|
||||||
|
{
|
||||||
|
var rankFlags = AdminFlagsHelper.NamesToFlags(rank.Flags.Select(f => f.Flag));
|
||||||
|
|
||||||
|
return UserAdminFlagCheck(rankFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.Atmos;
|
using Content.Server.GameObjects.Components.Atmos;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.GameObjects.EntitySystems.Atmos;
|
using Content.Server.GameObjects.EntitySystems.Atmos;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
@@ -15,6 +17,7 @@ using Robust.Shared.Maths;
|
|||||||
|
|
||||||
namespace Content.Server.Atmos
|
namespace Content.Server.Atmos
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public class AddAtmos : IClientCommand
|
public class AddAtmos : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "addatmos";
|
public string Command => "addatmos";
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.GUI;
|
using Content.Server.GameObjects.Components.GUI;
|
||||||
using Content.Server.GameObjects.Components.Items.Storage;
|
using Content.Server.GameObjects.Components.Items.Storage;
|
||||||
using Content.Server.GameObjects.Components.Observer;
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
@@ -8,6 +9,7 @@ using Content.Server.Interfaces.GameObjects;
|
|||||||
using Content.Server.Observer;
|
using Content.Server.Observer;
|
||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Content.Server.Utility;
|
using Content.Server.Utility;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.GameObjects.Components.Damage;
|
using Content.Shared.GameObjects.Components.Damage;
|
||||||
using Content.Shared.Interfaces;
|
using Content.Shared.Interfaces;
|
||||||
@@ -20,6 +22,7 @@ using Robust.Shared.Localization;
|
|||||||
|
|
||||||
namespace Content.Server.Chat
|
namespace Content.Server.Chat
|
||||||
{
|
{
|
||||||
|
[AnyCommand]
|
||||||
internal class SayCommand : IClientCommand
|
internal class SayCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "say";
|
public string Command => "say";
|
||||||
@@ -51,6 +54,7 @@ namespace Content.Server.Chat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AnyCommand]
|
||||||
internal class MeCommand : IClientCommand
|
internal class MeCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "me";
|
public string Command => "me";
|
||||||
@@ -76,6 +80,7 @@ namespace Content.Server.Chat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AnyCommand]
|
||||||
internal class OOCCommand : IClientCommand
|
internal class OOCCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "ooc";
|
public string Command => "ooc";
|
||||||
@@ -96,6 +101,7 @@ namespace Content.Server.Chat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
internal class AdminChatCommand : IClientCommand
|
internal class AdminChatCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "asay";
|
public string Command => "asay";
|
||||||
@@ -116,6 +122,7 @@ namespace Content.Server.Chat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AnyCommand]
|
||||||
internal class SuicideCommand : IClientCommand
|
internal class SuicideCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "suicide";
|
public string Command => "suicide";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameObjects.Components;
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.GUI;
|
using Content.Server.GameObjects.Components.GUI;
|
||||||
using Content.Server.GameObjects.Components.Headset;
|
using Content.Server.GameObjects.Components.Headset;
|
||||||
using Content.Server.GameObjects.Components.Items.Storage;
|
using Content.Server.GameObjects.Components.Items.Storage;
|
||||||
@@ -12,7 +12,6 @@ using Content.Shared.Chat;
|
|||||||
using Content.Shared.GameObjects.Components.Inventory;
|
using Content.Shared.GameObjects.Components.Inventory;
|
||||||
using Content.Shared.GameObjects.EntitySystems;
|
using Content.Shared.GameObjects.EntitySystems;
|
||||||
using Content.Shared.Interfaces;
|
using Content.Shared.Interfaces;
|
||||||
using Robust.Server.Console;
|
|
||||||
using Robust.Server.Interfaces.GameObjects;
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
@@ -47,7 +46,7 @@ namespace Content.Server.Chat
|
|||||||
[Dependency] private readonly IServerNetManager _netManager = default!;
|
[Dependency] private readonly IServerNetManager _netManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IMoMMILink _mommiLink = default!;
|
[Dependency] private readonly IMoMMILink _mommiLink = default!;
|
||||||
[Dependency] private readonly IConGroupController _conGroupController = default!;
|
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
@@ -125,7 +124,7 @@ namespace Content.Server.Chat
|
|||||||
|
|
||||||
// Capitalize first letter
|
// Capitalize first letter
|
||||||
message = message[0].ToString().ToUpper() +
|
message = message[0].ToString().ToUpper() +
|
||||||
message.Remove(0,1);
|
message.Remove(0, 1);
|
||||||
|
|
||||||
if (source.TryGetComponent(out InventoryComponent inventory) &&
|
if (source.TryGetComponent(out InventoryComponent inventory) &&
|
||||||
inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.EARS, out ItemComponent item) &&
|
inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.EARS, out ItemComponent item) &&
|
||||||
@@ -142,7 +141,7 @@ namespace Content.Server.Chat
|
|||||||
{
|
{
|
||||||
// Capitalize first letter
|
// Capitalize first letter
|
||||||
message = message[0].ToString().ToUpper() +
|
message = message[0].ToString().ToUpper() +
|
||||||
message.Remove(0,1);
|
message.Remove(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var listeners = EntitySystem.Get<ListeningSystem>();
|
var listeners = EntitySystem.Get<ListeningSystem>();
|
||||||
@@ -212,7 +211,9 @@ namespace Content.Server.Chat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var clients = _playerManager.GetPlayersBy(x => x.AttachedEntity != null && x.AttachedEntity.HasComponent<GhostComponent>()).Select(p => p.ConnectedClient);;
|
var clients = _playerManager
|
||||||
|
.GetPlayersBy(x => x.AttachedEntity != null && x.AttachedEntity.HasComponent<GhostComponent>())
|
||||||
|
.Select(p => p.ConnectedClient);
|
||||||
|
|
||||||
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
||||||
msg.Channel = ChatChannel.Dead;
|
msg.Channel = ChatChannel.Dead;
|
||||||
@@ -231,12 +232,7 @@ namespace Content.Server.Chat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_conGroupController.CanCommand(player, "asay"))
|
var clients = _adminManager.ActiveAdmins.Select(p => p.ConnectedClient);
|
||||||
{
|
|
||||||
SendOOC(player, message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var clients = _playerManager.GetPlayersBy(x => _conGroupController.CanCommand(x, "asay")).Select(p => p.ConnectedClient);;
|
|
||||||
|
|
||||||
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
||||||
|
|
||||||
@@ -246,6 +242,19 @@ namespace Content.Server.Chat
|
|||||||
_netManager.ServerSendToMany(msg, clients.ToList());
|
_netManager.ServerSendToMany(msg, clients.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SendAdminAnnouncement(string message)
|
||||||
|
{
|
||||||
|
var clients = _adminManager.ActiveAdmins.Select(p => p.ConnectedClient);
|
||||||
|
|
||||||
|
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
||||||
|
|
||||||
|
msg.Channel = ChatChannel.AdminChat;
|
||||||
|
msg.Message = message;
|
||||||
|
msg.MessageWrap = $"{Loc.GetString("ADMIN")}: {{0}}";
|
||||||
|
|
||||||
|
_netManager.ServerSendToMany(msg, clients.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
public void SendHookOOC(string sender, string message)
|
public void SendHookOOC(string sender, string message)
|
||||||
{
|
{
|
||||||
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.Body.Part;
|
using Content.Server.GameObjects.Components.Body.Part;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.GameObjects.Components.Body;
|
using Content.Shared.GameObjects.Components.Body;
|
||||||
using Content.Shared.GameObjects.Components.Body.Part;
|
using Content.Shared.GameObjects.Components.Body.Part;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
@@ -10,6 +12,7 @@ using Robust.Shared.IoC;
|
|||||||
|
|
||||||
namespace Content.Server.Commands
|
namespace Content.Server.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
public class AttachBodyPartCommand : IClientCommand
|
public class AttachBodyPartCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "attachbodypart";
|
public string Command => "attachbodypart";
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
|
||||||
namespace Content.Server.Commands
|
namespace Content.Server.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public class HideContainedContextCommand : IClientCommand
|
public class HideContainedContextCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "hidecontainedcontext";
|
public string Command => "hidecontainedcontext";
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.Nutrition;
|
using Content.Server.GameObjects.Components.Nutrition;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.GameObjects.Components.Nutrition;
|
using Content.Shared.GameObjects.Components.Nutrition;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
|
|
||||||
namespace Content.Server.Commands
|
namespace Content.Server.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public class Hungry : IClientCommand
|
public class Hungry : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "hungry";
|
public string Command => "hungry";
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
|
||||||
namespace Content.Server.Commands
|
namespace Content.Server.Commands
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public class ShowContainedContextCommand : IClientCommand
|
public class ShowContainedContextCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public const string CommandName = "showcontainedcontext";
|
public const string CommandName = "showcontainedcontext";
|
||||||
|
|||||||
29
Content.Server/Database/PlayerRecord.cs
Normal file
29
Content.Server/Database/PlayerRecord.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
namespace Content.Server.Database
|
||||||
|
{
|
||||||
|
public sealed class PlayerRecord
|
||||||
|
{
|
||||||
|
public NetUserId UserId { get; }
|
||||||
|
public DateTimeOffset FirstSeenTime { get; }
|
||||||
|
public string LastSeenUserName { get; }
|
||||||
|
public DateTimeOffset LastSeenTime { get; }
|
||||||
|
public IPAddress LastSeenAddress { get; }
|
||||||
|
|
||||||
|
public PlayerRecord(
|
||||||
|
NetUserId userId,
|
||||||
|
DateTimeOffset firstSeenTime,
|
||||||
|
string lastSeenUserName,
|
||||||
|
DateTimeOffset lastSeenTime,
|
||||||
|
IPAddress lastSeenAddress)
|
||||||
|
{
|
||||||
|
UserId = userId;
|
||||||
|
FirstSeenTime = firstSeenTime;
|
||||||
|
LastSeenUserName = lastSeenUserName;
|
||||||
|
LastSeenTime = lastSeenTime;
|
||||||
|
LastSeenAddress = lastSeenAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -211,12 +212,95 @@ namespace Content.Server.Database
|
|||||||
* PLAYER RECORDS
|
* PLAYER RECORDS
|
||||||
*/
|
*/
|
||||||
public abstract Task UpdatePlayerRecord(NetUserId userId, string userName, IPAddress address);
|
public abstract Task UpdatePlayerRecord(NetUserId userId, string userName, IPAddress address);
|
||||||
|
public abstract Task<PlayerRecord?> GetPlayerRecordByUserName(string userName, CancellationToken cancel);
|
||||||
|
public abstract Task<PlayerRecord?> GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CONNECTION LOG
|
* CONNECTION LOG
|
||||||
*/
|
*/
|
||||||
public abstract Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address);
|
public abstract Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ADMIN STUFF
|
||||||
|
*/
|
||||||
|
public async Task<Admin?> GetAdminDataForAsync(NetUserId userId, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
return await db.DbContext.Admin
|
||||||
|
.Include(p => p.Flags)
|
||||||
|
.Include(p => p.AdminRank)
|
||||||
|
.ThenInclude(p => p!.Flags)
|
||||||
|
.SingleOrDefaultAsync(p => p.UserId == userId.UserId, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task<((Admin, string? lastUserName)[] admins, AdminRank[])>
|
||||||
|
GetAllAdminAndRanksAsync(CancellationToken cancel);
|
||||||
|
|
||||||
|
public async Task<AdminRank?> GetAdminRankDataForAsync(int id, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
return await db.DbContext.AdminRank
|
||||||
|
.Include(r => r.Flags)
|
||||||
|
.SingleOrDefaultAsync(r => r.Id == id, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemoveAdminAsync(NetUserId userId, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
var admin = await db.DbContext.Admin.SingleAsync(a => a.UserId == userId.UserId, cancel);
|
||||||
|
db.DbContext.Admin.Remove(admin);
|
||||||
|
|
||||||
|
await db.DbContext.SaveChangesAsync(cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddAdminAsync(Admin admin, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
db.DbContext.Admin.Add(admin);
|
||||||
|
|
||||||
|
await db.DbContext.SaveChangesAsync(cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateAdminAsync(Admin admin, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
db.DbContext.Admin.Update(admin);
|
||||||
|
|
||||||
|
await db.DbContext.SaveChangesAsync(cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemoveAdminRankAsync(int rankId, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
var admin = await db.DbContext.AdminRank.SingleAsync(a => a.Id == rankId, cancel);
|
||||||
|
db.DbContext.AdminRank.Remove(admin);
|
||||||
|
|
||||||
|
await db.DbContext.SaveChangesAsync(cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddAdminRankAsync(AdminRank rank, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
db.DbContext.AdminRank.Add(rank);
|
||||||
|
|
||||||
|
await db.DbContext.SaveChangesAsync(cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateAdminRankAsync(AdminRank rank, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
db.DbContext.AdminRank.Update(rank);
|
||||||
|
|
||||||
|
await db.DbContext.SaveChangesAsync(cancel);
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract Task<DbGuard> GetDb();
|
protected abstract Task<DbGuard> GetDb();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Shared;
|
using Content.Shared;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
@@ -27,7 +28,9 @@ namespace Content.Server.Database
|
|||||||
// Preferences
|
// Preferences
|
||||||
Task<PlayerPreferences> InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile);
|
Task<PlayerPreferences> InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile);
|
||||||
Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index);
|
Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index);
|
||||||
|
|
||||||
Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile? profile, int slot);
|
Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile? profile, int slot);
|
||||||
|
|
||||||
// Single method for two operations for transaction.
|
// Single method for two operations for transaction.
|
||||||
Task DeleteSlotAndSetSelectedIndex(NetUserId userId, int deleteSlot, int newSlot);
|
Task DeleteSlotAndSetSelectedIndex(NetUserId userId, int deleteSlot, int newSlot);
|
||||||
Task<PlayerPreferences?> GetPlayerPreferencesAsync(NetUserId userId);
|
Task<PlayerPreferences?> GetPlayerPreferencesAsync(NetUserId userId);
|
||||||
@@ -42,9 +45,26 @@ namespace Content.Server.Database
|
|||||||
|
|
||||||
// Player records
|
// Player records
|
||||||
Task UpdatePlayerRecordAsync(NetUserId userId, string userName, IPAddress address);
|
Task UpdatePlayerRecordAsync(NetUserId userId, string userName, IPAddress address);
|
||||||
|
Task<PlayerRecord?> GetPlayerRecordByUserName(string userName, CancellationToken cancel = default);
|
||||||
|
Task<PlayerRecord?> GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel = default);
|
||||||
|
|
||||||
// Connection log
|
// Connection log
|
||||||
Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address);
|
Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address);
|
||||||
|
|
||||||
|
// Admins
|
||||||
|
Task<Admin?> GetAdminDataForAsync(NetUserId userId, CancellationToken cancel = default);
|
||||||
|
Task<AdminRank?> GetAdminRankAsync(int id, CancellationToken cancel = default);
|
||||||
|
|
||||||
|
Task<((Admin, string? lastUserName)[] admins, AdminRank[])> GetAllAdminAndRanksAsync(
|
||||||
|
CancellationToken cancel = default);
|
||||||
|
|
||||||
|
Task RemoveAdminAsync(NetUserId userId, CancellationToken cancel = default);
|
||||||
|
Task AddAdminAsync(Admin admin, CancellationToken cancel = default);
|
||||||
|
Task UpdateAdminAsync(Admin admin, CancellationToken cancel = default);
|
||||||
|
|
||||||
|
Task RemoveAdminRankAsync(int rankId, CancellationToken cancel = default);
|
||||||
|
Task AddAdminRankAsync(AdminRank rank, CancellationToken cancel = default);
|
||||||
|
Task UpdateAdminRankAsync(AdminRank rank, CancellationToken cancel = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class ServerDbManager : IServerDbManager
|
public sealed class ServerDbManager : IServerDbManager
|
||||||
@@ -132,11 +152,67 @@ namespace Content.Server.Database
|
|||||||
return _db.UpdatePlayerRecord(userId, userName, address);
|
return _db.UpdatePlayerRecord(userId, userName, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<PlayerRecord?> GetPlayerRecordByUserName(string userName, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.GetPlayerRecordByUserName(userName, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PlayerRecord?> GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.GetPlayerRecordByUserId(userId, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
public Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address)
|
public Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address)
|
||||||
{
|
{
|
||||||
return _db.AddConnectionLogAsync(userId, userName, address);
|
return _db.AddConnectionLogAsync(userId, userName, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<Admin?> GetAdminDataForAsync(NetUserId userId, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.GetAdminDataForAsync(userId, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AdminRank?> GetAdminRankAsync(int id, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.GetAdminRankDataForAsync(id, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<((Admin, string? lastUserName)[] admins, AdminRank[])> GetAllAdminAndRanksAsync(
|
||||||
|
CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.GetAllAdminAndRanksAsync(cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task RemoveAdminAsync(NetUserId userId, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.RemoveAdminAsync(userId, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task AddAdminAsync(Admin admin, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.AddAdminAsync(admin, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task UpdateAdminAsync(Admin admin, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.UpdateAdminAsync(admin, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task RemoveAdminRankAsync(int rankId, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.RemoveAdminRankAsync(rankId, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task AddAdminRankAsync(AdminRank rank, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.AddAdminRankAsync(rank, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task UpdateAdminRankAsync(AdminRank rank, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
return _db.UpdateAdminRankAsync(rank, cancel);
|
||||||
|
}
|
||||||
|
|
||||||
private DbContextOptions<ServerDbContext> CreatePostgresOptions()
|
private DbContextOptions<ServerDbContext> CreatePostgresOptions()
|
||||||
{
|
{
|
||||||
var host = _cfg.GetCVar(CCVars.DatabasePgHost);
|
var host = _cfg.GetCVar(CCVars.DatabasePgHost);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
@@ -138,6 +140,45 @@ namespace Content.Server.Database
|
|||||||
await db.PgDbContext.SaveChangesAsync();
|
await db.PgDbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<PlayerRecord?> GetPlayerRecordByUserName(string userName, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
// Sort by descending last seen time.
|
||||||
|
// So if, due to account renames, we have two people with the same username in the DB,
|
||||||
|
// the most recent one is picked.
|
||||||
|
var record = await db.PgDbContext.Player
|
||||||
|
.OrderByDescending(p => p.LastSeenTime)
|
||||||
|
.FirstOrDefaultAsync(p => p.LastSeenUserName == userName, cancel);
|
||||||
|
|
||||||
|
return MakePlayerRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<PlayerRecord?> GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
var record = await db.PgDbContext.Player
|
||||||
|
.SingleOrDefaultAsync(p => p.UserId == userId.UserId, cancel);
|
||||||
|
|
||||||
|
return MakePlayerRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PlayerRecord? MakePlayerRecord(PostgresPlayer? record)
|
||||||
|
{
|
||||||
|
if (record == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PlayerRecord(
|
||||||
|
new NetUserId(record.UserId),
|
||||||
|
new DateTimeOffset(record.FirstSeenTime, TimeSpan.Zero),
|
||||||
|
record.LastSeenUserName,
|
||||||
|
new DateTimeOffset(record.LastSeenTime, TimeSpan.Zero),
|
||||||
|
record.LastSeenAddress);
|
||||||
|
}
|
||||||
|
|
||||||
public override async Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address)
|
public override async Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address)
|
||||||
{
|
{
|
||||||
await using var db = await GetDbImpl();
|
await using var db = await GetDbImpl();
|
||||||
@@ -153,6 +194,27 @@ namespace Content.Server.Database
|
|||||||
await db.PgDbContext.SaveChangesAsync();
|
await db.PgDbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<((Admin, string? lastUserName)[] admins, AdminRank[])>
|
||||||
|
GetAllAdminAndRanksAsync(CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
// Honestly this probably doesn't even matter but whatever.
|
||||||
|
await using var tx =
|
||||||
|
await db.DbContext.Database.BeginTransactionAsync(IsolationLevel.RepeatableRead, cancel);
|
||||||
|
|
||||||
|
// Join with the player table to find their last seen username, if they have one.
|
||||||
|
var admins = await db.PgDbContext.Admin
|
||||||
|
.Include(a => a.Flags)
|
||||||
|
.GroupJoin(db.PgDbContext.Player, a => a.UserId, p => p.UserId, (a, grouping) => new {a, grouping})
|
||||||
|
.SelectMany(t => t.grouping.DefaultIfEmpty(), (t, p) => new {t.a, p.LastSeenUserName})
|
||||||
|
.ToArrayAsync(cancel);
|
||||||
|
|
||||||
|
var adminRanks = await db.DbContext.AdminRank.Include(a => a.Flags).ToArrayAsync(cancel);
|
||||||
|
|
||||||
|
return (admins.Select(p => (p.a, p.LastSeenUserName)).ToArray(), adminRanks)!;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<DbGuardImpl> GetDbImpl()
|
private async Task<DbGuardImpl> GetDbImpl()
|
||||||
{
|
{
|
||||||
await _dbReadyTask;
|
await _dbReadyTask;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
@@ -105,6 +106,44 @@ namespace Content.Server.Database
|
|||||||
await db.SqliteDbContext.SaveChangesAsync();
|
await db.SqliteDbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<PlayerRecord?> GetPlayerRecordByUserName(string userName, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
// Sort by descending last seen time.
|
||||||
|
// So if due to account renames we have two people with the same username in the DB,
|
||||||
|
// the most recent one is picked.
|
||||||
|
var record = await db.SqliteDbContext.Player
|
||||||
|
.OrderByDescending(p => p.LastSeenTime)
|
||||||
|
.FirstOrDefaultAsync(p => p.LastSeenUserName == userName, cancel);
|
||||||
|
|
||||||
|
return MakePlayerRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<PlayerRecord?> GetPlayerRecordByUserId(NetUserId userId, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
var record = await db.SqliteDbContext.Player
|
||||||
|
.SingleOrDefaultAsync(p => p.UserId == userId.UserId, cancel);
|
||||||
|
|
||||||
|
return MakePlayerRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PlayerRecord? MakePlayerRecord(SqlitePlayer? record)
|
||||||
|
{
|
||||||
|
if (record == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PlayerRecord(
|
||||||
|
new NetUserId(record.UserId),
|
||||||
|
new DateTimeOffset(record.FirstSeenTime, TimeSpan.Zero),
|
||||||
|
record.LastSeenUserName,
|
||||||
|
new DateTimeOffset(record.LastSeenTime, TimeSpan.Zero),
|
||||||
|
IPAddress.Parse(record.LastSeenAddress));
|
||||||
|
}
|
||||||
private static ServerBanDef? ConvertBan(SqliteServerBan? ban)
|
private static ServerBanDef? ConvertBan(SqliteServerBan? ban)
|
||||||
{
|
{
|
||||||
if (ban == null)
|
if (ban == null)
|
||||||
@@ -156,6 +195,21 @@ namespace Content.Server.Database
|
|||||||
await db.SqliteDbContext.SaveChangesAsync();
|
await db.SqliteDbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<((Admin, string? lastUserName)[] admins, AdminRank[])> GetAllAdminAndRanksAsync(
|
||||||
|
CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
var admins = await db.SqliteDbContext.Admin
|
||||||
|
.Include(a => a.Flags)
|
||||||
|
.GroupJoin(db.SqliteDbContext.Player, a => a.UserId, p => p.UserId, (a, grouping) => new {a, grouping})
|
||||||
|
.SelectMany(t => t.grouping.DefaultIfEmpty(), (t, p) => new {t.a, p.LastSeenUserName})
|
||||||
|
.ToArrayAsync(cancel);
|
||||||
|
|
||||||
|
var adminRanks = await db.DbContext.AdminRank.Include(a => a.Flags).ToArrayAsync(cancel);
|
||||||
|
|
||||||
|
return (admins.Select(p => (p.a, p.LastSeenUserName)).ToArray(), adminRanks)!;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<DbGuardImpl> GetDbImpl()
|
private async Task<DbGuardImpl> GetDbImpl()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Content.Server.AI.Utility.Considerations;
|
using Content.Server.Administration;
|
||||||
|
using Content.Server.AI.Utility.Considerations;
|
||||||
using Content.Server.AI.WorldState;
|
using Content.Server.AI.WorldState;
|
||||||
using Content.Server.Database;
|
using Content.Server.Database;
|
||||||
|
using Content.Server.Eui;
|
||||||
using Content.Server.GameObjects.Components.Mobs.Speech;
|
using Content.Server.GameObjects.Components.Mobs.Speech;
|
||||||
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
@@ -23,6 +25,7 @@ namespace Content.Server
|
|||||||
public class EntryPoint : GameServer
|
public class EntryPoint : GameServer
|
||||||
{
|
{
|
||||||
private IGameTicker _gameTicker;
|
private IGameTicker _gameTicker;
|
||||||
|
private EuiManager _euiManager;
|
||||||
private StatusShell _statusShell;
|
private StatusShell _statusShell;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -50,6 +53,7 @@ namespace Content.Server
|
|||||||
IoCManager.BuildGraph();
|
IoCManager.BuildGraph();
|
||||||
|
|
||||||
_gameTicker = IoCManager.Resolve<IGameTicker>();
|
_gameTicker = IoCManager.Resolve<IGameTicker>();
|
||||||
|
_euiManager = IoCManager.Resolve<EuiManager>();
|
||||||
|
|
||||||
IoCManager.Resolve<IServerNotifyManager>().Initialize();
|
IoCManager.Resolve<IServerNotifyManager>().Initialize();
|
||||||
IoCManager.Resolve<IChatManager>().Initialize();
|
IoCManager.Resolve<IChatManager>().Initialize();
|
||||||
@@ -79,6 +83,8 @@ namespace Content.Server
|
|||||||
IoCManager.Resolve<BlackboardManager>().Initialize();
|
IoCManager.Resolve<BlackboardManager>().Initialize();
|
||||||
IoCManager.Resolve<ConsiderationsManager>().Initialize();
|
IoCManager.Resolve<ConsiderationsManager>().Initialize();
|
||||||
IoCManager.Resolve<IPDAUplinkManager>().Initialize();
|
IoCManager.Resolve<IPDAUplinkManager>().Initialize();
|
||||||
|
IoCManager.Resolve<IAdminManager>().Initialize();
|
||||||
|
_euiManager.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(ModUpdateLevel level, FrameEventArgs frameEventArgs)
|
public override void Update(ModUpdateLevel level, FrameEventArgs frameEventArgs)
|
||||||
@@ -92,6 +98,11 @@ namespace Content.Server
|
|||||||
_gameTicker.Update(frameEventArgs);
|
_gameTicker.Update(frameEventArgs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ModUpdateLevel.PostEngine:
|
||||||
|
{
|
||||||
|
_euiManager.SendUpdates();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
131
Content.Server/Eui/BaseEui.cs
Normal file
131
Content.Server/Eui/BaseEui.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.Eui;
|
||||||
|
using Content.Shared.Network.NetMessages;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Eui
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class to implement server-side for an EUI.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// An EUI is a system for making a relatively-easy connection between client and server
|
||||||
|
/// for the purposes of UIs.
|
||||||
|
/// </remarks>
|
||||||
|
/// <remarks>
|
||||||
|
/// An equivalently named class much exist server side for an EUI to work.
|
||||||
|
/// It will be instantiated, opened and closed automatically.
|
||||||
|
/// </remarks>
|
||||||
|
public abstract class BaseEui
|
||||||
|
{
|
||||||
|
private bool _isStateDirty = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The player that this EUI is open for.
|
||||||
|
/// </summary>
|
||||||
|
public IPlayerSession Player { get; private set; } = default!;
|
||||||
|
public bool IsShutDown { get; private set; }
|
||||||
|
public EuiManager Manager { get; private set; } = default!;
|
||||||
|
public uint Id { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the UI has been opened. Do initializing logic here.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Opened()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the UI has been closed.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Closed()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a message comes in from the client.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void HandleMessage(EuiMessageBase msg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mark the current UI state as dirty and queue for an update.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="GetNewState"/>
|
||||||
|
public void StateDirty()
|
||||||
|
{
|
||||||
|
if (_isStateDirty)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isStateDirty = true;
|
||||||
|
Manager.QueueStateUpdate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called some time after <see cref="StateDirty"/> has been called
|
||||||
|
/// to get a new UI state that can be sent to the client.
|
||||||
|
/// </summary>
|
||||||
|
public virtual EuiStateBase GetNewState()
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send a message to the client-side EUI.
|
||||||
|
/// </summary>
|
||||||
|
public void SendMessage(EuiMessageBase message)
|
||||||
|
{
|
||||||
|
var netMgr = IoCManager.Resolve<IServerNetManager>();
|
||||||
|
var msg = netMgr.CreateNetMessage<MsgEuiMessage>();
|
||||||
|
msg.Id = Id;
|
||||||
|
msg.Message = message;
|
||||||
|
|
||||||
|
netMgr.ServerSendMessage(msg, Player.ConnectedClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Close the EUI, breaking the connection between client and server.
|
||||||
|
/// </summary>
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
Manager.CloseEui(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Shutdown()
|
||||||
|
{
|
||||||
|
Closed();
|
||||||
|
IsShutDown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void DoStateUpdate()
|
||||||
|
{
|
||||||
|
_isStateDirty = false;
|
||||||
|
|
||||||
|
var state = GetNewState();
|
||||||
|
|
||||||
|
var netMgr = IoCManager.Resolve<IServerNetManager>();
|
||||||
|
var msg = netMgr.CreateNetMessage<MsgEuiState>();
|
||||||
|
msg.Id = Id;
|
||||||
|
msg.State = state;
|
||||||
|
|
||||||
|
netMgr.ServerSendMessage(msg, Player.ConnectedClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Initialize(EuiManager manager, IPlayerSession player, uint id)
|
||||||
|
{
|
||||||
|
Manager = manager;
|
||||||
|
Player = player;
|
||||||
|
Id = id;
|
||||||
|
Opened();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
144
Content.Server/Eui/EuiManager.cs
Normal file
144
Content.Server/Eui/EuiManager.cs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Network.NetMessages;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Eui
|
||||||
|
{
|
||||||
|
public sealed class EuiManager : IPostInjectInit
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPlayerManager _players = default!;
|
||||||
|
[Dependency] private readonly IServerNetManager _net = default!;
|
||||||
|
|
||||||
|
private readonly Dictionary<IPlayerSession, PlayerEuiData> _playerData =
|
||||||
|
new Dictionary<IPlayerSession, PlayerEuiData>();
|
||||||
|
|
||||||
|
private readonly Queue<(IPlayerSession player, uint id)> _stateUpdateQueue =
|
||||||
|
new Queue<(IPlayerSession, uint id)>();
|
||||||
|
|
||||||
|
private sealed class PlayerEuiData
|
||||||
|
{
|
||||||
|
public uint NextId = 1;
|
||||||
|
public readonly Dictionary<uint, BaseEui> OpenUIs = new Dictionary<uint, BaseEui>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPostInjectInit.PostInject()
|
||||||
|
{
|
||||||
|
_players.PlayerStatusChanged += PlayerStatusChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_net.RegisterNetMessage<MsgEuiCtl>(MsgEuiCtl.NAME);
|
||||||
|
_net.RegisterNetMessage<MsgEuiState>(MsgEuiState.NAME);
|
||||||
|
_net.RegisterNetMessage<MsgEuiMessage>(MsgEuiMessage.NAME, RxMsgMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendUpdates()
|
||||||
|
{
|
||||||
|
while (_stateUpdateQueue.TryDequeue(out var tuple))
|
||||||
|
{
|
||||||
|
var (player, id) = tuple;
|
||||||
|
|
||||||
|
// Check that UI and player still exist.
|
||||||
|
// COULD have been removed in the mean time.
|
||||||
|
if (!_playerData.TryGetValue(player, out var plyDat) || !plyDat.OpenUIs.TryGetValue(id, out var ui))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.DoStateUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenEui(BaseEui eui, IPlayerSession player)
|
||||||
|
{
|
||||||
|
if (eui.Id != 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("That EUI is already open!");
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = _playerData[player];
|
||||||
|
var newId = data.NextId++;
|
||||||
|
eui.Initialize(this, player, newId);
|
||||||
|
|
||||||
|
data.OpenUIs.Add(newId, eui);
|
||||||
|
|
||||||
|
var msg = _net.CreateNetMessage<MsgEuiCtl>();
|
||||||
|
msg.Id = newId;
|
||||||
|
msg.Type = MsgEuiCtl.CtlType.Open;
|
||||||
|
msg.OpenType = eui.GetType().Name;
|
||||||
|
|
||||||
|
_net.ServerSendMessage(msg, player.ConnectedClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseEui(BaseEui eui)
|
||||||
|
{
|
||||||
|
eui.Shutdown();
|
||||||
|
_playerData[eui.Player].OpenUIs.Remove(eui.Id);
|
||||||
|
|
||||||
|
var msg = _net.CreateNetMessage<MsgEuiCtl>();
|
||||||
|
msg.Id = eui.Id;
|
||||||
|
msg.Type = MsgEuiCtl.CtlType.Close;
|
||||||
|
_net.ServerSendMessage(msg, eui.Player.ConnectedClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RxMsgMessage(MsgEuiMessage message)
|
||||||
|
{
|
||||||
|
if (!_players.TryGetSessionByChannel(message.MsgChannel, out var ply))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_playerData.TryGetValue(ply, out var dat))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dat.OpenUIs.TryGetValue(message.Id, out var eui))
|
||||||
|
{
|
||||||
|
Logger.WarningS("eui", $"Got EUI message from player {ply} for non-existing UI {message.Id}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
eui.HandleMessage(message.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.NewStatus == SessionStatus.Connected)
|
||||||
|
{
|
||||||
|
_playerData.Add(e.Session, new PlayerEuiData());
|
||||||
|
}
|
||||||
|
else if (e.NewStatus == SessionStatus.Disconnected)
|
||||||
|
{
|
||||||
|
if (_playerData.TryGetValue(e.Session, out var plyDat))
|
||||||
|
{
|
||||||
|
// Gracefully close all open UIs.
|
||||||
|
foreach (var ui in plyDat.OpenUIs.Values)
|
||||||
|
{
|
||||||
|
ui.Closed();
|
||||||
|
}
|
||||||
|
|
||||||
|
_playerData.Remove(e.Session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void QueueStateUpdate(BaseEui eui)
|
||||||
|
{
|
||||||
|
DebugTools.Assert(eui.Id != 0, "EUI has not been opened yet.");
|
||||||
|
DebugTools.Assert(!eui.IsShutDown, "EUI has been closed.");
|
||||||
|
|
||||||
|
_stateUpdateQueue.Enqueue((eui.Player, eui.Id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.GameObjects.Components.Body;
|
using Content.Shared.GameObjects.Components.Body;
|
||||||
using Content.Shared.GameObjects.Components.Body.Part;
|
using Content.Shared.GameObjects.Components.Body.Part;
|
||||||
@@ -16,6 +18,7 @@ using Robust.Shared.Random;
|
|||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Body
|
namespace Content.Server.GameObjects.Components.Body
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
class AddHandCommand : IClientCommand
|
class AddHandCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public const string DefaultHandPrototype = "LeftHandHuman";
|
public const string DefaultHandPrototype = "LeftHandHuman";
|
||||||
@@ -149,6 +152,7 @@ namespace Content.Server.GameObjects.Components.Body
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
class RemoveHandCommand : IClientCommand
|
class RemoveHandCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "removehand";
|
public string Command => "removehand";
|
||||||
@@ -190,6 +194,7 @@ namespace Content.Server.GameObjects.Components.Body
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
class DestroyMechanismCommand : IClientCommand
|
class DestroyMechanismCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "destroymechanism";
|
public string Command => "destroymechanism";
|
||||||
@@ -242,6 +247,7 @@ namespace Content.Server.GameObjects.Components.Body
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
class HurtCommand : IClientCommand
|
class HurtCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "hurt";
|
public string Command => "hurt";
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.Atmos;
|
using Content.Server.GameObjects.Components.Atmos;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.GameObjects.Components.Damage;
|
using Content.Shared.GameObjects.Components.Damage;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
@@ -115,6 +117,7 @@ namespace Content.Server.GameObjects.Components.Damage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
public class AddDamageFlagCommand : DamageFlagCommand
|
public class AddDamageFlagCommand : DamageFlagCommand
|
||||||
{
|
{
|
||||||
public override string Command => "adddamageflag";
|
public override string Command => "adddamageflag";
|
||||||
@@ -133,6 +136,7 @@ namespace Content.Server.GameObjects.Components.Damage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
public class RemoveDamageFlagCommand : DamageFlagCommand
|
public class RemoveDamageFlagCommand : DamageFlagCommand
|
||||||
{
|
{
|
||||||
public override string Command => "removedamageflag";
|
public override string Command => "removedamageflag";
|
||||||
@@ -151,6 +155,7 @@ namespace Content.Server.GameObjects.Components.Damage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
public class GodModeCommand : IClientCommand
|
public class GodModeCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "godmode";
|
public string Command => "godmode";
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -8,6 +10,7 @@ using Robust.Shared.Localization;
|
|||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Disposal
|
namespace Content.Server.GameObjects.Components.Disposal
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public class TubeConnectionsCommand : IClientCommand
|
public class TubeConnectionsCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "tubeconnections";
|
public string Command => "tubeconnections";
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
@@ -14,7 +16,7 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="TilePryingComponent.TryPryTile"/>
|
/// <see cref="TilePryingComponent.TryPryTile"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
class TilePryCommand : IClientCommand
|
class TilePryCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "tilepry";
|
public string Command => "tilepry";
|
||||||
@@ -69,7 +71,7 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[UsedImplicitly]
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
class AnchorCommand : IClientCommand
|
class AnchorCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "anchor";
|
public string Command => "anchor";
|
||||||
@@ -114,7 +116,7 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[UsedImplicitly]
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
class UnAnchorCommand : IClientCommand
|
class UnAnchorCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "unanchor";
|
public string Command => "unanchor";
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.Commands;
|
using Content.Server.Commands;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.GameObjects.Components.Mobs;
|
using Content.Shared.GameObjects.Components.Mobs;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
@@ -88,6 +90,7 @@ namespace Content.Server.GameObjects.Components.Mobs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public sealed class ShowAlert : IClientCommand
|
public sealed class ShowAlert : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "showalert";
|
public string Command => "showalert";
|
||||||
@@ -129,6 +132,7 @@ namespace Content.Server.GameObjects.Components.Mobs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public sealed class ClearAlert : IClientCommand
|
public sealed class ClearAlert : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "clearalert";
|
public string Command => "clearalert";
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
@@ -17,6 +19,7 @@ namespace Content.Server.GameObjects.Components.Mobs.Speech
|
|||||||
public string Accentuate(string message);
|
public string Accentuate(string message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
public class AddAccent : IClientCommand
|
public class AddAccent : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "addaccent";
|
public string Command => "addaccent";
|
||||||
@@ -38,12 +41,12 @@ namespace Content.Server.GameObjects.Components.Mobs.Speech
|
|||||||
shell.SendText(player, "You don't have a player!");
|
shell.SendText(player, "You don't have a player!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var compFactory = IoCManager.Resolve<IComponentFactory>();
|
var compFactory = IoCManager.Resolve<IComponentFactory>();
|
||||||
|
|
||||||
if (args[0] == "?")
|
if (args[0] == "?")
|
||||||
{
|
{
|
||||||
// Get all components that implement the ISpeechComponent except
|
// Get all components that implement the ISpeechComponent except
|
||||||
var speeches = compFactory.GetAllRefTypes()
|
var speeches = compFactory.GetAllRefTypes()
|
||||||
.Where(c => typeof(IAccentComponent).IsAssignableFrom(c) && c.IsClass);
|
.Where(c => typeof(IAccentComponent).IsAssignableFrom(c) && c.IsClass);
|
||||||
var msg = "";
|
var msg = "";
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.AI;
|
using Content.Server.GameObjects.Components.AI;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
@@ -19,12 +21,12 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
|||||||
* Currently factions are implicitly friendly if they are not hostile.
|
* Currently factions are implicitly friendly if they are not hostile.
|
||||||
* This may change where specified friendly factions are listed. (e.g. to get number of friendlies in area).
|
* This may change where specified friendly factions are listed. (e.g. to get number of friendlies in area).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public Faction GetHostileFactions(Faction faction) => _hostileFactions.TryGetValue(faction, out var hostiles) ? hostiles : Faction.None;
|
public Faction GetHostileFactions(Faction faction) => _hostileFactions.TryGetValue(faction, out var hostiles) ? hostiles : Faction.None;
|
||||||
|
|
||||||
private Dictionary<Faction, Faction> _hostileFactions = new Dictionary<Faction, Faction>
|
private Dictionary<Faction, Faction> _hostileFactions = new Dictionary<Faction, Faction>
|
||||||
{
|
{
|
||||||
{Faction.NanoTransen,
|
{Faction.NanoTransen,
|
||||||
Faction.SimpleHostile | Faction.Syndicate | Faction.Xeno},
|
Faction.SimpleHostile | Faction.Syndicate | Faction.Xeno},
|
||||||
{Faction.SimpleHostile,
|
{Faction.SimpleHostile,
|
||||||
Faction.NanoTransen | Faction.Syndicate
|
Faction.NanoTransen | Faction.Syndicate
|
||||||
@@ -35,11 +37,11 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
|||||||
},
|
},
|
||||||
{Faction.Syndicate,
|
{Faction.Syndicate,
|
||||||
Faction.NanoTransen | Faction.SimpleHostile | Faction.Xeno},
|
Faction.NanoTransen | Faction.SimpleHostile | Faction.Xeno},
|
||||||
{Faction.Xeno,
|
{Faction.Xeno,
|
||||||
Faction.NanoTransen | Faction.Syndicate},
|
Faction.NanoTransen | Faction.Syndicate},
|
||||||
};
|
};
|
||||||
|
|
||||||
public Faction GetFactions(IEntity entity) =>
|
public Faction GetFactions(IEntity entity) =>
|
||||||
entity.TryGetComponent(out AiFactionTagComponent factionTags)
|
entity.TryGetComponent(out AiFactionTagComponent factionTags)
|
||||||
? factionTags.Factions
|
? factionTags.Factions
|
||||||
: Faction.None;
|
: Faction.None;
|
||||||
@@ -76,7 +78,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
|||||||
hostileFactions &= ~target;
|
hostileFactions &= ~target;
|
||||||
_hostileFactions[source] = hostileFactions;
|
_hostileFactions[source] = hostileFactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MakeHostile(Faction source, Faction target)
|
public void MakeHostile(Faction source, Faction target)
|
||||||
{
|
{
|
||||||
if (!_hostileFactions.TryGetValue(source, out var hostileFactions))
|
if (!_hostileFactions.TryGetValue(source, out var hostileFactions))
|
||||||
@@ -89,12 +91,13 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
|||||||
_hostileFactions[source] = hostileFactions;
|
_hostileFactions[source] = hostileFactions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
public sealed class FactionCommand : IClientCommand
|
public sealed class FactionCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "factions";
|
public string Command => "factions";
|
||||||
public string Description => "Update / list factional relationships for NPCs.";
|
public string Description => "Update / list factional relationships for NPCs.";
|
||||||
public string Help => "faction <source> <friendly/hostile> target\n" +
|
public string Help => "faction <source> <friendly/hostile> target\n" +
|
||||||
"faction <source> list: hostile factions";
|
"faction <source> list: hostile factions";
|
||||||
|
|
||||||
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
|
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
|
||||||
@@ -108,11 +111,11 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
|||||||
continue;
|
continue;
|
||||||
result.Append(value + "\n");
|
result.Append(value + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
shell.SendText(player, result.ToString());
|
shell.SendText(player, result.ToString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.Length < 2)
|
if (args.Length < 2)
|
||||||
{
|
{
|
||||||
shell.SendText(player, Loc.GetString("Need more args"));
|
shell.SendText(player, Loc.GetString("Need more args"));
|
||||||
@@ -141,7 +144,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
|||||||
shell.SendText(player, Loc.GetString("Invalid target faction"));
|
shell.SendText(player, Loc.GetString("Invalid target faction"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntitySystem.Get<AiFactionTagSystem>().MakeFriendly(faction, targetFaction);
|
EntitySystem.Get<AiFactionTagSystem>().MakeFriendly(faction, targetFaction);
|
||||||
shell.SendText(player, Loc.GetString("Command successful"));
|
shell.SendText(player, Loc.GetString("Command successful"));
|
||||||
break;
|
break;
|
||||||
@@ -157,7 +160,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
|||||||
shell.SendText(player, Loc.GetString("Invalid target faction"));
|
shell.SendText(player, Loc.GetString("Invalid target faction"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntitySystem.Get<AiFactionTagSystem>().MakeHostile(faction, targetFaction);
|
EntitySystem.Get<AiFactionTagSystem>().MakeHostile(faction, targetFaction);
|
||||||
shell.SendText(player, Loc.GetString("Command successful"));
|
shell.SendText(player, Loc.GetString("Command successful"));
|
||||||
break;
|
break;
|
||||||
@@ -172,4 +175,4 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.Movement;
|
using Content.Server.GameObjects.Components.Movement;
|
||||||
using Content.Shared;
|
using Content.Shared;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.GameObjects.Components.Movement;
|
using Content.Shared.GameObjects.Components.Movement;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.AI;
|
using Robust.Server.AI;
|
||||||
@@ -145,6 +146,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
|||||||
public bool ProcessorTypeExists(string name) => _processorTypes.ContainsKey(name);
|
public bool ProcessorTypeExists(string name) => _processorTypes.ContainsKey(name);
|
||||||
|
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
private class AddAiCommand : IClientCommand
|
private class AddAiCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "addai";
|
public string Command => "addai";
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.MachineLinking;
|
using Content.Server.GameObjects.Components.MachineLinking;
|
||||||
using Content.Server.GameObjects.EntitySystems.Click;
|
using Content.Server.GameObjects.EntitySystems.Click;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -98,6 +100,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public class SignalLinkerCommand : IClientCommand
|
public class SignalLinkerCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "signallink";
|
public string Command => "signallink";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.Access;
|
using Content.Server.GameObjects.Components.Access;
|
||||||
using Content.Server.GameObjects.Components.GUI;
|
using Content.Server.GameObjects.Components.GUI;
|
||||||
using Content.Server.GameObjects.Components.Items.Storage;
|
using Content.Server.GameObjects.Components.Items.Storage;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.Interfaces.GameTicking;
|
using Content.Server.Interfaces.GameTicking;
|
||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
@@ -18,6 +20,7 @@ using Robust.Shared.Utility;
|
|||||||
|
|
||||||
namespace Content.Server.GameTicking
|
namespace Content.Server.GameTicking
|
||||||
{
|
{
|
||||||
|
[AdminCommand(AdminFlags.Server)]
|
||||||
class DelayStartCommand : IClientCommand
|
class DelayStartCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "delaystart";
|
public string Command => "delaystart";
|
||||||
@@ -60,6 +63,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Server)]
|
||||||
class StartRoundCommand : IClientCommand
|
class StartRoundCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "startround";
|
public string Command => "startround";
|
||||||
@@ -80,6 +84,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Server)]
|
||||||
class EndRoundCommand : IClientCommand
|
class EndRoundCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "endround";
|
public string Command => "endround";
|
||||||
@@ -100,6 +105,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Server)]
|
||||||
public class NewRoundCommand : IClientCommand
|
public class NewRoundCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "restartround";
|
public string Command => "restartround";
|
||||||
@@ -165,6 +171,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AnyCommand]
|
||||||
class ObserveCommand : IClientCommand
|
class ObserveCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "observe";
|
public string Command => "observe";
|
||||||
@@ -183,6 +190,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AnyCommand]
|
||||||
class JoinGameCommand : IClientCommand
|
class JoinGameCommand : IClientCommand
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
@@ -228,6 +236,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AnyCommand]
|
||||||
class ToggleReadyCommand : IClientCommand
|
class ToggleReadyCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "toggleready";
|
public string Command => "toggleready";
|
||||||
@@ -246,6 +255,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Server)]
|
||||||
class ToggleDisallowLateJoinCommand: IClientCommand
|
class ToggleDisallowLateJoinCommand: IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "toggledisallowlatejoin";
|
public string Command => "toggledisallowlatejoin";
|
||||||
@@ -274,6 +284,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Server)]
|
||||||
class SetGamePresetCommand : IClientCommand
|
class SetGamePresetCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "setgamepreset";
|
public string Command => "setgamepreset";
|
||||||
@@ -294,6 +305,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Server)]
|
||||||
class ForcePresetCommand : IClientCommand
|
class ForcePresetCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "forcepreset";
|
public string Command => "forcepreset";
|
||||||
@@ -327,6 +339,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Server | AdminFlags.Mapping)]
|
||||||
class MappingCommand : IClientCommand
|
class MappingCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "mapping";
|
public string Command => "mapping";
|
||||||
@@ -383,6 +396,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Mapping)]
|
||||||
class TileWallsCommand : IClientCommand
|
class TileWallsCommand : IClientCommand
|
||||||
{
|
{
|
||||||
// ReSharper disable once StringLiteralTypo
|
// ReSharper disable once StringLiteralTypo
|
||||||
|
|||||||
@@ -31,5 +31,6 @@ namespace Content.Server.Interfaces.Chat
|
|||||||
|
|
||||||
delegate string TransformChat(IEntity speaker, string message);
|
delegate string TransformChat(IEntity speaker, string message);
|
||||||
void RegisterChatTransform(TransformChat handler);
|
void RegisterChatTransform(TransformChat handler);
|
||||||
|
void SendAdminAnnouncement(string message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.Mobs;
|
using Content.Server.GameObjects.Components.Mobs;
|
||||||
using Content.Server.Mobs.Roles;
|
using Content.Server.Mobs.Roles;
|
||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
@@ -12,6 +14,7 @@ using Robust.Shared.Prototypes;
|
|||||||
namespace Content.Server.Mobs
|
namespace Content.Server.Mobs
|
||||||
{
|
{
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Admin)]
|
||||||
public class MindInfoCommand : IClientCommand
|
public class MindInfoCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "mindinfo";
|
public string Command => "mindinfo";
|
||||||
@@ -49,6 +52,7 @@ namespace Content.Server.Mobs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
public class AddRoleCommand : IClientCommand
|
public class AddRoleCommand : IClientCommand
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
@@ -81,6 +85,7 @@ namespace Content.Server.Mobs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
public class RemoveRoleCommand : IClientCommand
|
public class RemoveRoleCommand : IClientCommand
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
@@ -113,6 +118,7 @@ namespace Content.Server.Mobs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public class AddOverlayCommand : IClientCommand
|
public class AddOverlayCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "addoverlay";
|
public string Command => "addoverlay";
|
||||||
@@ -137,6 +143,7 @@ namespace Content.Server.Mobs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public class RemoveOverlayCommand : IClientCommand
|
public class RemoveOverlayCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "rmoverlay";
|
public string Command => "rmoverlay";
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.Components.Mobs;
|
using Content.Server.GameObjects.Components.Mobs;
|
||||||
using Content.Server.GameObjects.Components.Observer;
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
using Content.Server.Interfaces.GameTicking;
|
using Content.Server.Interfaces.GameTicking;
|
||||||
@@ -12,6 +13,7 @@ using Robust.Shared.IoC;
|
|||||||
|
|
||||||
namespace Content.Server.Observer
|
namespace Content.Server.Observer
|
||||||
{
|
{
|
||||||
|
[AnyCommand]
|
||||||
public class Ghost : IClientCommand
|
public class Ghost : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "ghost";
|
public string Command => "ghost";
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ namespace Content.Server.Players
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public Mind? Mind { get; set; }
|
public Mind? Mind { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, the player is an admin and they explicitly de-adminned mid-game,
|
||||||
|
/// so they should not regain admin if they reconnect.
|
||||||
|
/// </summary>
|
||||||
|
public bool ExplicitlyDeadminned { get; set; }
|
||||||
|
|
||||||
public void WipeMind()
|
public void WipeMind()
|
||||||
{
|
{
|
||||||
Mind?.ChangeOwningPlayer(null);
|
Mind?.ChangeOwningPlayer(null);
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using Content.Server.AI.Utility.Considerations;
|
using Content.Server.Administration;
|
||||||
|
using Content.Server.AI.Utility.Considerations;
|
||||||
using Content.Server.AI.WorldState;
|
using Content.Server.AI.WorldState;
|
||||||
using Content.Server.Cargo;
|
using Content.Server.Cargo;
|
||||||
using Content.Server.Chat;
|
using Content.Server.Chat;
|
||||||
using Content.Server.Database;
|
using Content.Server.Database;
|
||||||
|
using Content.Server.Eui;
|
||||||
using Content.Server.GameObjects.Components.Mobs.Speech;
|
using Content.Server.GameObjects.Components.Mobs.Speech;
|
||||||
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
||||||
@@ -47,7 +49,9 @@ namespace Content.Server
|
|||||||
IoCManager.Register<ConsiderationsManager, ConsiderationsManager>();
|
IoCManager.Register<ConsiderationsManager, ConsiderationsManager>();
|
||||||
IoCManager.Register<IAccentManager, AccentManager>();
|
IoCManager.Register<IAccentManager, AccentManager>();
|
||||||
IoCManager.Register<IConnectionManager, ConnectionManager>();
|
IoCManager.Register<IConnectionManager, ConnectionManager>();
|
||||||
|
IoCManager.Register<IAdminManager, AdminManager>();
|
||||||
IoCManager.Register<IDeviceNetwork, DeviceNetwork>();
|
IoCManager.Register<IDeviceNetwork, DeviceNetwork>();
|
||||||
|
IoCManager.Register<EuiManager, EuiManager>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
using Content.Shared;
|
using Content.Shared;
|
||||||
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Interfaces;
|
using Content.Shared.Interfaces;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.GameObjects;
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
@@ -71,6 +73,7 @@ namespace Content.Server
|
|||||||
_netManager.ServerSendMessage(netMessage, actor.playerSession.ConnectedClient);
|
_netManager.ServerSendMessage(netMessage, actor.playerSession.ConnectedClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Debug)]
|
||||||
public class PopupMsgCommand : IClientCommand
|
public class PopupMsgCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "srvpopupmsg";
|
public string Command => "srvpopupmsg";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
using Content.Server.Administration;
|
||||||
using Content.Server.GameObjects.EntitySystems.StationEvents;
|
using Content.Server.GameObjects.EntitySystems.StationEvents;
|
||||||
using JetBrains.Annotations;
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
@@ -8,7 +9,7 @@ using Robust.Shared.Localization;
|
|||||||
|
|
||||||
namespace Content.Server.StationEvents
|
namespace Content.Server.StationEvents
|
||||||
{
|
{
|
||||||
[UsedImplicitly]
|
[AdminCommand(AdminFlags.Server)]
|
||||||
public sealed class StationEventCommand : IClientCommand
|
public sealed class StationEventCommand : IClientCommand
|
||||||
{
|
{
|
||||||
public string Command => "events";
|
public string Command => "events";
|
||||||
|
|||||||
68
Content.Shared/Administration/AdminData.cs
Normal file
68
Content.Shared/Administration/AdminData.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Shared.Administration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents data for a single server admin.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class AdminData
|
||||||
|
{
|
||||||
|
// Can be false if they're de-adminned with the ability to re-admin.
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the admin is currently active. This can be false if they have de-adminned mid-round.
|
||||||
|
/// </summary>
|
||||||
|
public bool Active;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The admin's title.
|
||||||
|
/// </summary>
|
||||||
|
public string? Title;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The admin's permission flags.
|
||||||
|
/// </summary>
|
||||||
|
public AdminFlags Flags;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether this admin has an admin flag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flag">The flags to check. Multiple flags can be specified, they must all be held.</param>
|
||||||
|
/// <returns>False if this admin is not <see cref="Active"/> or does not have all the flags specified.</returns>
|
||||||
|
public bool HasFlag(AdminFlags flag)
|
||||||
|
{
|
||||||
|
return Active && (Flags & flag) == flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if this admin can open the VV menu.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanViewVar()
|
||||||
|
{
|
||||||
|
return HasFlag(AdminFlags.VarEdit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if this admin can spawn stuff in with the entity/tile spawn panel.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanAdminPlace()
|
||||||
|
{
|
||||||
|
return HasFlag(AdminFlags.Spawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if this admin can execute server-side C# scripts.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanScript()
|
||||||
|
{
|
||||||
|
return HasFlag(AdminFlags.Host);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if this admin can open the admin menu.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanAdminMenu()
|
||||||
|
{
|
||||||
|
return HasFlag(AdminFlags.Admin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
Content.Shared/Administration/AdminFlags.cs
Normal file
68
Content.Shared/Administration/AdminFlags.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.Administration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Permissions that admins can have.
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum AdminFlags : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Basic admin verbs.
|
||||||
|
/// </summary>
|
||||||
|
Admin = 1 << 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ability to ban people.
|
||||||
|
/// </summary>
|
||||||
|
Ban = 1 << 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Debug commands for coders.
|
||||||
|
/// </summary>
|
||||||
|
Debug = 1 << 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// !!FUN!!
|
||||||
|
/// </summary>
|
||||||
|
Fun = 1 << 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ability to edit permissions for other administrators.
|
||||||
|
/// </summary>
|
||||||
|
Permissions = 1 << 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ability to control teh server like restart it or change the round type.
|
||||||
|
/// </summary>
|
||||||
|
Server = 1 << 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ability to spawn stuff in.
|
||||||
|
/// </summary>
|
||||||
|
Spawn = 1 << 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ability to use VV.
|
||||||
|
/// </summary>
|
||||||
|
VarEdit = 1 << 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Large mapping operations.
|
||||||
|
/// </summary>
|
||||||
|
Mapping = 1 << 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes you british.
|
||||||
|
/// </summary>
|
||||||
|
//Piss = 1 << 9,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dangerous host permissions like scsi.
|
||||||
|
/// </summary>
|
||||||
|
Host = 1u << 31,
|
||||||
|
}
|
||||||
|
}
|
||||||
124
Content.Shared/Administration/AdminFlagsHelper.cs
Normal file
124
Content.Shared/Administration/AdminFlagsHelper.cs
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace Content.Shared.Administration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains various helper methods for working with admin flags.
|
||||||
|
/// </summary>
|
||||||
|
public static class AdminFlagsHelper
|
||||||
|
{
|
||||||
|
// As you can tell from the boatload of bitwise ops,
|
||||||
|
// writing this class was genuinely fun.
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, AdminFlags> NameFlagsMap = new Dictionary<string, AdminFlags>();
|
||||||
|
private static readonly string[] FlagsNameMap = new string[32];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Every admin flag in the game, at once!
|
||||||
|
/// </summary>
|
||||||
|
public static readonly AdminFlags Everything;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of all individual admin flags.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly IReadOnlyList<AdminFlags> AllFlags;
|
||||||
|
|
||||||
|
static AdminFlagsHelper()
|
||||||
|
{
|
||||||
|
var t = typeof(AdminFlags);
|
||||||
|
var flags = (AdminFlags[]) Enum.GetValues(t);
|
||||||
|
var allFlags = new List<AdminFlags>();
|
||||||
|
|
||||||
|
foreach (var value in flags)
|
||||||
|
{
|
||||||
|
var name = value.ToString().ToUpper();
|
||||||
|
|
||||||
|
// If, in the future, somebody adds a combined admin flag or something for convenience,
|
||||||
|
// ignore it.
|
||||||
|
if (BitOperations.PopCount((uint) value) != 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
allFlags.Add(value);
|
||||||
|
Everything |= value;
|
||||||
|
NameFlagsMap.Add(name, value);
|
||||||
|
FlagsNameMap[BitOperations.Log2((uint) value)] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
AllFlags = allFlags.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an enumerable of admin flag names to a bitfield.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The flags must all be uppercase.
|
||||||
|
/// </remarks>
|
||||||
|
/// <exception cref="ArgumentException">
|
||||||
|
/// Thrown if a string that is not a valid admin flag is contained in <paramref name="names"/>.
|
||||||
|
/// </exception>
|
||||||
|
public static AdminFlags NamesToFlags(IEnumerable<string> names)
|
||||||
|
{
|
||||||
|
var flags = AdminFlags.None;
|
||||||
|
foreach (var name in names)
|
||||||
|
{
|
||||||
|
if (!NameFlagsMap.TryGetValue(name, out var value))
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Invalid admin flag name: {name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
flags |= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the flag bit for an admin flag name.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The flag name must be all uppercase.
|
||||||
|
/// </remarks>
|
||||||
|
/// <exception cref="KeyNotFoundException">
|
||||||
|
/// Thrown if <paramref name="name"/> is not a valid admin flag name.
|
||||||
|
/// </exception>
|
||||||
|
public static AdminFlags NameToFlag(string name)
|
||||||
|
{
|
||||||
|
return NameFlagsMap[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a bitfield of admin flags to an array of all the flag names set.
|
||||||
|
/// </summary>
|
||||||
|
public static string[] FlagsToNames(AdminFlags flags)
|
||||||
|
{
|
||||||
|
var array = new string[BitOperations.PopCount((uint) flags)];
|
||||||
|
var highest = BitOperations.LeadingZeroCount((uint) flags);
|
||||||
|
|
||||||
|
var ai = 0;
|
||||||
|
for (var i = 0; i < 32 - highest; i++)
|
||||||
|
{
|
||||||
|
var flagValue = (AdminFlags) (1u << i);
|
||||||
|
if ((flags & flagValue) != 0)
|
||||||
|
{
|
||||||
|
array[ai++] = FlagsNameMap[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string PosNegFlagsText(AdminFlags posFlags, AdminFlags negFlags)
|
||||||
|
{
|
||||||
|
var posFlagNames = FlagsToNames(posFlags).Select(f => (flag: f, fText: $"+{f}"));
|
||||||
|
var negFlagNames = FlagsToNames(negFlags).Select(f => (flag: f, fText: $"-{f}"));
|
||||||
|
|
||||||
|
var flagsText = string.Join(' ', posFlagNames.Concat(negFlagNames).OrderBy(f => f.flag).Select(p => p.fText));
|
||||||
|
return flagsText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
92
Content.Shared/Administration/PermissionsEuiState.cs
Normal file
92
Content.Shared/Administration/PermissionsEuiState.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Eui;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Administration
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class PermissionsEuiState : EuiStateBase
|
||||||
|
{
|
||||||
|
public bool IsLoading;
|
||||||
|
|
||||||
|
public AdminData[] Admins;
|
||||||
|
public Dictionary<int, AdminRankData> AdminRanks;
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public struct AdminData
|
||||||
|
{
|
||||||
|
public NetUserId UserId;
|
||||||
|
public string UserName;
|
||||||
|
public string Title;
|
||||||
|
public AdminFlags PosFlags;
|
||||||
|
public AdminFlags NegFlags;
|
||||||
|
public int? RankId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public struct AdminRankData
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public AdminFlags Flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PermissionsEuiMsg
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class Close : EuiMessageBase
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class AddAdmin : EuiMessageBase
|
||||||
|
{
|
||||||
|
public string UserNameOrId;
|
||||||
|
public string Title;
|
||||||
|
public AdminFlags PosFlags;
|
||||||
|
public AdminFlags NegFlags;
|
||||||
|
public int? RankId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class RemoveAdmin : EuiMessageBase
|
||||||
|
{
|
||||||
|
public NetUserId UserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class UpdateAdmin : EuiMessageBase
|
||||||
|
{
|
||||||
|
public NetUserId UserId;
|
||||||
|
public string Title;
|
||||||
|
public AdminFlags PosFlags;
|
||||||
|
public AdminFlags NegFlags;
|
||||||
|
public int? RankId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class AddAdminRank : EuiMessageBase
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public AdminFlags Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class RemoveAdminRank : EuiMessageBase
|
||||||
|
{
|
||||||
|
public int Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class UpdateAdminRank : EuiMessageBase
|
||||||
|
{
|
||||||
|
public int Id;
|
||||||
|
|
||||||
|
public string Name;
|
||||||
|
public AdminFlags Flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -67,6 +67,13 @@ namespace Content.Shared
|
|||||||
public static readonly CVarDef<bool> GameDiagonalMovement =
|
public static readonly CVarDef<bool> GameDiagonalMovement =
|
||||||
CVarDef.Create("game.diagonalmovement", true, CVar.ARCHIVE);
|
CVarDef.Create("game.diagonalmovement", true, CVar.ARCHIVE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Console
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static readonly CVarDef<bool>
|
||||||
|
ConsoleLoginLocal = CVarDef.Create("console.loginlocal", true, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Database stuff
|
* Database stuff
|
||||||
@@ -130,5 +137,15 @@ namespace Content.Shared
|
|||||||
|
|
||||||
public static readonly CVarDef<float> NetGasOverlayTickRate =
|
public static readonly CVarDef<float> NetGasOverlayTickRate =
|
||||||
CVarDef.Create("net.gasoverlaytickrate", 3.0f);
|
CVarDef.Create("net.gasoverlaytickrate", 3.0f);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Admin stuff
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static readonly CVarDef<bool> AdminAnnounceLogin =
|
||||||
|
CVarDef.Create("admin.announce_login", true, CVar.SERVERONLY);
|
||||||
|
|
||||||
|
public static readonly CVarDef<bool> AdminAnnounceLogout =
|
||||||
|
CVarDef.Create("admin.announce_logout", true, CVar.SERVERONLY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
Content.Shared/Eui/EuiMessageBase.cs
Normal file
10
Content.Shared/Eui/EuiMessageBase.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.Eui
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public abstract class EuiMessageBase
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Content.Shared/Eui/EuiStateBase.cs
Normal file
11
Content.Shared/Eui/EuiStateBase.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Eui
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public abstract class EuiStateBase
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
55
Content.Shared/Network/NetMessages/MsgEuiCtl.cs
Normal file
55
Content.Shared/Network/NetMessages/MsgEuiCtl.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using Lidgren.Network;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
namespace Content.Shared.Network.NetMessages
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sent server -> client to signal that the client should open an EUI.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MsgEuiCtl : NetMessage
|
||||||
|
{
|
||||||
|
#region REQUIRED
|
||||||
|
|
||||||
|
public const MsgGroups GROUP = MsgGroups.Command;
|
||||||
|
public const string NAME = nameof(MsgEuiCtl);
|
||||||
|
|
||||||
|
public MsgEuiCtl(INetChannel channel) : base(NAME, GROUP) { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public CtlType Type;
|
||||||
|
public string OpenType;
|
||||||
|
public uint Id;
|
||||||
|
|
||||||
|
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
||||||
|
{
|
||||||
|
Id = buffer.ReadUInt32();
|
||||||
|
Type = (CtlType) buffer.ReadByte();
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case CtlType.Open:
|
||||||
|
OpenType = buffer.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||||
|
{
|
||||||
|
buffer.Write(Id);
|
||||||
|
buffer.Write((byte) Type);
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case CtlType.Open:
|
||||||
|
buffer.Write(OpenType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CtlType : byte
|
||||||
|
{
|
||||||
|
Open,
|
||||||
|
Close
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Content.Shared/Network/NetMessages/MsgEuiMessage.cs
Normal file
48
Content.Shared/Network/NetMessages/MsgEuiMessage.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Content.Shared.Eui;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.Interfaces.Serialization;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
namespace Content.Shared.Network.NetMessages
|
||||||
|
{
|
||||||
|
public sealed class MsgEuiMessage : NetMessage
|
||||||
|
{
|
||||||
|
#region REQUIRED
|
||||||
|
|
||||||
|
public const MsgGroups GROUP = MsgGroups.Command;
|
||||||
|
public const string NAME = nameof(MsgEuiMessage);
|
||||||
|
|
||||||
|
public MsgEuiMessage(INetChannel channel) : base(NAME, GROUP) { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public uint Id;
|
||||||
|
public EuiMessageBase Message;
|
||||||
|
|
||||||
|
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
||||||
|
{
|
||||||
|
Id = buffer.ReadUInt32();
|
||||||
|
|
||||||
|
var ser = IoCManager.Resolve<IRobustSerializer>();
|
||||||
|
var len = buffer.ReadVariableInt32();
|
||||||
|
var stream = buffer.ReadAlignedMemory(len);
|
||||||
|
Message = ser.Deserialize<EuiMessageBase>(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||||
|
{
|
||||||
|
buffer.Write(Id);
|
||||||
|
var stream = new MemoryStream();
|
||||||
|
|
||||||
|
var ser = IoCManager.Resolve<IRobustSerializer>();
|
||||||
|
ser.Serialize(stream, Message);
|
||||||
|
var length = (int)stream.Length;
|
||||||
|
buffer.WriteVariableInt32(length);
|
||||||
|
buffer.Write(stream.GetBuffer().AsSpan(0, length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Content.Shared/Network/NetMessages/MsgEuiState.cs
Normal file
48
Content.Shared/Network/NetMessages/MsgEuiState.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Content.Shared.Eui;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.Interfaces.Serialization;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
namespace Content.Shared.Network.NetMessages
|
||||||
|
{
|
||||||
|
public sealed class MsgEuiState : NetMessage
|
||||||
|
{
|
||||||
|
#region REQUIRED
|
||||||
|
|
||||||
|
public const MsgGroups GROUP = MsgGroups.Command;
|
||||||
|
public const string NAME = nameof(MsgEuiState);
|
||||||
|
|
||||||
|
public MsgEuiState(INetChannel channel) : base(NAME, GROUP) { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public uint Id;
|
||||||
|
public EuiStateBase State;
|
||||||
|
|
||||||
|
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
||||||
|
{
|
||||||
|
Id = buffer.ReadUInt32();
|
||||||
|
|
||||||
|
var ser = IoCManager.Resolve<IRobustSerializer>();
|
||||||
|
var len = buffer.ReadVariableInt32();
|
||||||
|
var stream = buffer.ReadAlignedMemory(len);
|
||||||
|
State = ser.Deserialize<EuiStateBase>(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||||
|
{
|
||||||
|
buffer.Write(Id);
|
||||||
|
var stream = new MemoryStream();
|
||||||
|
|
||||||
|
var ser = IoCManager.Resolve<IRobustSerializer>();
|
||||||
|
ser.Serialize(stream, State);
|
||||||
|
var length = (int)stream.Length;
|
||||||
|
buffer.WriteVariableInt32(length);
|
||||||
|
buffer.Write(stream.GetBuffer().AsSpan(0, length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
Content.Shared/Network/NetMessages/MsgUpdateAdminStatus.cs
Normal file
73
Content.Shared/Network/NetMessages/MsgUpdateAdminStatus.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using Content.Shared.Administration;
|
||||||
|
using Lidgren.Network;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
namespace Content.Shared.Network.NetMessages
|
||||||
|
{
|
||||||
|
public sealed class MsgUpdateAdminStatus : NetMessage
|
||||||
|
{
|
||||||
|
#region REQUIRED
|
||||||
|
|
||||||
|
public const MsgGroups GROUP = MsgGroups.Command;
|
||||||
|
public const string NAME = nameof(MsgUpdateAdminStatus);
|
||||||
|
|
||||||
|
public MsgUpdateAdminStatus(INetChannel channel) : base(NAME, GROUP) { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public AdminData Admin;
|
||||||
|
public string[] AvailableCommands;
|
||||||
|
|
||||||
|
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
||||||
|
{
|
||||||
|
var count = buffer.ReadVariableInt32();
|
||||||
|
|
||||||
|
AvailableCommands = new string[count];
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
AvailableCommands[i] = buffer.ReadString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.ReadBoolean())
|
||||||
|
{
|
||||||
|
var active = buffer.ReadBoolean();
|
||||||
|
buffer.ReadPadBits();
|
||||||
|
var flags = (AdminFlags) buffer.ReadUInt32();
|
||||||
|
var title = buffer.ReadString();
|
||||||
|
|
||||||
|
Admin = new AdminData
|
||||||
|
{
|
||||||
|
Active = active,
|
||||||
|
Title = title,
|
||||||
|
Flags = flags,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||||
|
{
|
||||||
|
buffer.WriteVariableInt32(AvailableCommands.Length);
|
||||||
|
|
||||||
|
foreach (var cmd in AvailableCommands)
|
||||||
|
{
|
||||||
|
buffer.Write(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
var isAdmin = Admin != null;
|
||||||
|
buffer.Write(isAdmin);
|
||||||
|
|
||||||
|
if (isAdmin)
|
||||||
|
{
|
||||||
|
buffer.Write(Admin.Active);
|
||||||
|
buffer.WritePadBits();
|
||||||
|
buffer.Write((uint) Admin.Flags);
|
||||||
|
buffer.Write(Admin.Title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableOrdered;
|
||||||
|
}
|
||||||
|
}
|
||||||
35
Content.Tests/Shared/Administration/AdminFlagsExtTest.cs
Normal file
35
Content.Tests/Shared/Administration/AdminFlagsExtTest.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Content.Tests.Shared.Administration
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
[Parallelizable(ParallelScope.All)]
|
||||||
|
public class AdminFlagsExtTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
[TestCase("ADMIN", AdminFlags.Admin)]
|
||||||
|
[TestCase("ADMIN,DEBUG", AdminFlags.Admin | AdminFlags.Debug)]
|
||||||
|
[TestCase("ADMIN,DEBUG,HOST", AdminFlags.Admin | AdminFlags.Debug | AdminFlags.Host)]
|
||||||
|
[TestCase("", AdminFlags.None)]
|
||||||
|
public void TestNamesToFlags(string namesConcat, AdminFlags flags)
|
||||||
|
{
|
||||||
|
var names = namesConcat.Split(",", StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
Assert.That(AdminFlagsHelper.NamesToFlags(names), Is.EqualTo(flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase("ADMIN", AdminFlags.Admin)]
|
||||||
|
[TestCase("ADMIN,DEBUG", AdminFlags.Admin | AdminFlags.Debug)]
|
||||||
|
[TestCase("ADMIN,DEBUG,HOST", AdminFlags.Admin | AdminFlags.Debug | AdminFlags.Host)]
|
||||||
|
[TestCase("", AdminFlags.None)]
|
||||||
|
public void TestFlagsToNames(string namesConcat, AdminFlags flags)
|
||||||
|
{
|
||||||
|
var names = namesConcat.Split(",", StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
Assert.That(AdminFlagsHelper.FlagsToNames(flags), Is.EquivalentTo(names));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
- Index: 1
|
|
||||||
Name: Player
|
|
||||||
Commands:
|
|
||||||
- login
|
|
||||||
- joingame
|
|
||||||
- help
|
|
||||||
- list
|
|
||||||
- say
|
|
||||||
- whisper
|
|
||||||
- me
|
|
||||||
- ooc
|
|
||||||
- observe
|
|
||||||
- toggleready
|
|
||||||
- ghost
|
|
||||||
- suicide
|
|
||||||
- hostlogin
|
|
||||||
|
|
||||||
- Index: 50
|
|
||||||
Name: Moderator
|
|
||||||
Commands:
|
|
||||||
- login
|
|
||||||
- logout
|
|
||||||
- joingame
|
|
||||||
- help
|
|
||||||
- list
|
|
||||||
- say
|
|
||||||
- whisper
|
|
||||||
- me
|
|
||||||
- ooc
|
|
||||||
- showtime
|
|
||||||
- observe
|
|
||||||
- toggleready
|
|
||||||
- ghost
|
|
||||||
- suicide
|
|
||||||
- kick
|
|
||||||
- listplayers
|
|
||||||
- loc
|
|
||||||
- hostlogin
|
|
||||||
- events
|
|
||||||
- factions
|
|
||||||
CanAdminMenu: true
|
|
||||||
|
|
||||||
- Index: 100
|
|
||||||
Name: Administrator
|
|
||||||
Commands:
|
|
||||||
- logout
|
|
||||||
- joingame
|
|
||||||
- help
|
|
||||||
- list
|
|
||||||
- say
|
|
||||||
- whisper
|
|
||||||
- me
|
|
||||||
- ooc
|
|
||||||
- showtime
|
|
||||||
- aghost
|
|
||||||
- observe
|
|
||||||
- toggleready
|
|
||||||
- ghost
|
|
||||||
- suicide
|
|
||||||
- spawn
|
|
||||||
- delete
|
|
||||||
- tp
|
|
||||||
- tpto
|
|
||||||
- tpgrid
|
|
||||||
- setgamepreset
|
|
||||||
- forcepreset
|
|
||||||
- delaystart
|
|
||||||
- startround
|
|
||||||
- endround
|
|
||||||
- restartround
|
|
||||||
- respawn
|
|
||||||
- rejuvenate
|
|
||||||
- addcomp
|
|
||||||
- rmcomp
|
|
||||||
- controlmob
|
|
||||||
- kick
|
|
||||||
- listplayers
|
|
||||||
- loc
|
|
||||||
- lsmap
|
|
||||||
- lsgrid
|
|
||||||
- mindinfo
|
|
||||||
- addrole
|
|
||||||
- rmrole
|
|
||||||
- addoverlay
|
|
||||||
- rmoverlay
|
|
||||||
- showtime
|
|
||||||
- group
|
|
||||||
- addai
|
|
||||||
- warp
|
|
||||||
- hostlogin
|
|
||||||
- deleteewc
|
|
||||||
- asay
|
|
||||||
- mapping
|
|
||||||
- addhand
|
|
||||||
- removehand
|
|
||||||
- tilepry
|
|
||||||
- anchor
|
|
||||||
- unanchor
|
|
||||||
- tubeconnections
|
|
||||||
- tilewalls
|
|
||||||
- events
|
|
||||||
- destroymechanism
|
|
||||||
- addaccent
|
|
||||||
- readyall
|
|
||||||
- factions
|
|
||||||
- signallink
|
|
||||||
- adddamageflag
|
|
||||||
- removedamageflag
|
|
||||||
- godmode
|
|
||||||
- deleteewi
|
|
||||||
- hurt
|
|
||||||
- toggledisallowlatejoin
|
|
||||||
- showcontainedcontext
|
|
||||||
- hidecontainedcontext
|
|
||||||
- showmechanisms
|
|
||||||
- hidemechanisms
|
|
||||||
- attachbodypart
|
|
||||||
- attachtoself
|
|
||||||
- attachtogrid
|
|
||||||
- attachtograndparent
|
|
||||||
- inrangeunoccluded
|
|
||||||
- hungry
|
|
||||||
CanViewVar: true
|
|
||||||
CanAdminPlace: true
|
|
||||||
CanAdminMenu: true
|
|
||||||
|
|
||||||
- Index: 200
|
|
||||||
Name: Host
|
|
||||||
Commands:
|
|
||||||
- logout
|
|
||||||
- joingame
|
|
||||||
- help
|
|
||||||
- list
|
|
||||||
- say
|
|
||||||
- whisper
|
|
||||||
- me
|
|
||||||
- ooc
|
|
||||||
- showtime
|
|
||||||
- aghost
|
|
||||||
- observe
|
|
||||||
- toggleready
|
|
||||||
- ghost
|
|
||||||
- suicide
|
|
||||||
- spawn
|
|
||||||
- delete
|
|
||||||
- tp
|
|
||||||
- tpto
|
|
||||||
- tpgrid
|
|
||||||
- setgamepreset
|
|
||||||
- forcepreset
|
|
||||||
- delaystart
|
|
||||||
- startround
|
|
||||||
- endround
|
|
||||||
- restartround
|
|
||||||
- respawn
|
|
||||||
- rejuvenate
|
|
||||||
- addcomp
|
|
||||||
- controlmob
|
|
||||||
- kick
|
|
||||||
- listplayers
|
|
||||||
- loc
|
|
||||||
- lsmap
|
|
||||||
- lsgrid
|
|
||||||
- mindinfo
|
|
||||||
- addrole
|
|
||||||
- rmrole
|
|
||||||
- addoverlay
|
|
||||||
- rmoverlay
|
|
||||||
- srvpopupmsg
|
|
||||||
- group
|
|
||||||
- showtime
|
|
||||||
- restart
|
|
||||||
- cvar
|
|
||||||
- netaudit
|
|
||||||
- szr_stats
|
|
||||||
- mem
|
|
||||||
- addai
|
|
||||||
- loglevel
|
|
||||||
- testlog
|
|
||||||
- addmap
|
|
||||||
- rmmap
|
|
||||||
- savebp
|
|
||||||
- loadbp
|
|
||||||
- savemap
|
|
||||||
- loadmap
|
|
||||||
- pausemap
|
|
||||||
- unpausemap
|
|
||||||
- querymappaused
|
|
||||||
- mapinit
|
|
||||||
- saveconfig
|
|
||||||
- gc
|
|
||||||
- gc_mode
|
|
||||||
- warp
|
|
||||||
- deleteewc
|
|
||||||
- sudo
|
|
||||||
- asay
|
|
||||||
- mapping
|
|
||||||
- addhand
|
|
||||||
- removehand
|
|
||||||
- tilepry
|
|
||||||
- anchor
|
|
||||||
- unanchor
|
|
||||||
- tubeconnections
|
|
||||||
- addatmos
|
|
||||||
- addgas
|
|
||||||
- fillgas
|
|
||||||
- listgases
|
|
||||||
- removegas
|
|
||||||
- settemp
|
|
||||||
- setatmostemp
|
|
||||||
- deletegas
|
|
||||||
- showatmos
|
|
||||||
- tilewalls
|
|
||||||
- events
|
|
||||||
- destroymechanism
|
|
||||||
- addaccent
|
|
||||||
- readyall
|
|
||||||
- factions
|
|
||||||
- signallink
|
|
||||||
- adddamageflag
|
|
||||||
- removedamageflag
|
|
||||||
- godmode
|
|
||||||
- deleteewi
|
|
||||||
- hurt
|
|
||||||
- toggledisallowlatejoin
|
|
||||||
- showcontainedcontext
|
|
||||||
- hidecontainedcontext
|
|
||||||
- showmechanisms
|
|
||||||
- hidemechanisms
|
|
||||||
- attachbodypart
|
|
||||||
- attachtoself
|
|
||||||
- attachtogrid
|
|
||||||
- attachtograndparent
|
|
||||||
- inrangeunoccluded
|
|
||||||
- showalert
|
|
||||||
- clearalert
|
|
||||||
- hungry
|
|
||||||
CanViewVar: true
|
|
||||||
CanAdminPlace: true
|
|
||||||
CanScript: true
|
|
||||||
CanAdminMenu: true
|
|
||||||
65
Resources/engineCommandPerms.yml
Normal file
65
Resources/engineCommandPerms.yml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# Available to everybody
|
||||||
|
- Commands:
|
||||||
|
- help
|
||||||
|
- list
|
||||||
|
|
||||||
|
- Flags: FUN
|
||||||
|
Commands:
|
||||||
|
- addcomp
|
||||||
|
- rmcomp
|
||||||
|
|
||||||
|
- Flags: DEBUG
|
||||||
|
Commands:
|
||||||
|
- delete
|
||||||
|
- lsgrid
|
||||||
|
- lsmap
|
||||||
|
- listplayers
|
||||||
|
- loc
|
||||||
|
- mem
|
||||||
|
- netaudit
|
||||||
|
- querymappaused
|
||||||
|
- showtime
|
||||||
|
- inrangeunoccluded
|
||||||
|
|
||||||
|
- Flags: MAPPING
|
||||||
|
Commands:
|
||||||
|
- addmap
|
||||||
|
- loadbp
|
||||||
|
- loadmap
|
||||||
|
- pausemap
|
||||||
|
- querymappaused
|
||||||
|
- rmgrid
|
||||||
|
- rmmap
|
||||||
|
- mapinit
|
||||||
|
- savebp
|
||||||
|
- savemap
|
||||||
|
- tpgrid
|
||||||
|
|
||||||
|
- Flags: ADMIN
|
||||||
|
Commands:
|
||||||
|
- delete
|
||||||
|
- kick
|
||||||
|
- listplayers
|
||||||
|
- tp
|
||||||
|
- tpto
|
||||||
|
|
||||||
|
- Flags: SERVER
|
||||||
|
Commands:
|
||||||
|
- delete
|
||||||
|
- pausemap
|
||||||
|
- unpausemap
|
||||||
|
- restart
|
||||||
|
- shutdown
|
||||||
|
|
||||||
|
- Flags: SPAWN
|
||||||
|
Commands:
|
||||||
|
- spawn
|
||||||
|
|
||||||
|
- Flags: HOST
|
||||||
|
Commands:
|
||||||
|
- gc_mode
|
||||||
|
- gc
|
||||||
|
- loglevel
|
||||||
|
- saveconfig
|
||||||
|
- testlog
|
||||||
|
- sudo
|
||||||
@@ -64,6 +64,7 @@
|
|||||||
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue"><data /></s:String>
|
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue"><data /></s:String>
|
||||||
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue"><data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="*.UnitTesting" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data></s:String>
|
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue"><data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="*.UnitTesting" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data></s:String>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=adminbus/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=adminbus/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=adminned/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Aghost/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Aghost/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=akms/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=akms/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Anchorable/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Anchorable/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|||||||
Reference in New Issue
Block a user