Merge branch '20-10-30-admins' into 20-11-13-merges
This commit is contained in:
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 =
|
||||
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
|
||||
@@ -130,5 +137,15 @@ namespace Content.Shared
|
||||
|
||||
public static readonly CVarDef<float> NetGasOverlayTickRate =
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user