first commit
This commit is contained in:
64
NitroxServer/ConsoleCommands/Abstract/CallArgs.cs
Normal file
64
NitroxServer/ConsoleCommands/Abstract/CallArgs.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Abstract
|
||||
{
|
||||
public abstract partial class Command
|
||||
{
|
||||
public ref struct CallArgs
|
||||
{
|
||||
public Command Command { get; }
|
||||
public Optional<Player> Sender { get; }
|
||||
public Span<string> Args { get; }
|
||||
|
||||
public bool IsConsole => !Sender.HasValue;
|
||||
public string SenderName => Sender.HasValue ? Sender.Value.Name : "SERVER";
|
||||
|
||||
public CallArgs(Command command, Optional<Player> sender, Span<string> args)
|
||||
{
|
||||
Command = command;
|
||||
Sender = sender;
|
||||
Args = args;
|
||||
}
|
||||
|
||||
public bool IsValid(int index)
|
||||
{
|
||||
return index < Args.Length && index >= 0 && Args.Length != 0;
|
||||
}
|
||||
|
||||
public string GetTillEnd(int startIndex = 0)
|
||||
{
|
||||
// TODO: Proper argument capture/parse instead of this argument join hack
|
||||
if (Args.Length > 0)
|
||||
{
|
||||
return string.Join(" ", Args.Slice(startIndex).ToArray());
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string Get(int index)
|
||||
{
|
||||
return Get<string>(index);
|
||||
}
|
||||
|
||||
public T Get<T>(int index)
|
||||
{
|
||||
IParameter<object> param = Command.Parameters[index];
|
||||
string arg = IsValid(index) ? Args[index] : null;
|
||||
|
||||
if (arg == null)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(string))
|
||||
{
|
||||
return (T)(object)arg;
|
||||
}
|
||||
|
||||
return (T)param.Read(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
149
NitroxServer/ConsoleCommands/Abstract/Command.cs
Normal file
149
NitroxServer/ConsoleCommands/Abstract/Command.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NitroxModel.Core;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Abstract
|
||||
{
|
||||
public abstract partial class Command
|
||||
{
|
||||
private int optional, required;
|
||||
|
||||
public virtual IEnumerable<string> Aliases { get; }
|
||||
|
||||
public string Name { get; }
|
||||
public string Description { get; }
|
||||
public Perms RequiredPermLevel { get; }
|
||||
public PermsFlag Flags { get; }
|
||||
public bool AllowedArgOverflow { get; set; }
|
||||
public List<IParameter<object>> Parameters { get; }
|
||||
|
||||
protected Command(string name, Perms perms, PermsFlag flag, string description) : this(name, perms, description)
|
||||
{
|
||||
Flags = flag;
|
||||
}
|
||||
|
||||
protected Command(string name, Perms perms, string description)
|
||||
{
|
||||
Validate.NotNull(name);
|
||||
|
||||
Name = name;
|
||||
Flags = PermsFlag.NONE;
|
||||
RequiredPermLevel = perms;
|
||||
AllowedArgOverflow = false;
|
||||
Aliases = Array.Empty<string>();
|
||||
Parameters = new List<IParameter<object>>();
|
||||
Description = string.IsNullOrEmpty(description) ? "No description provided" : description;
|
||||
}
|
||||
|
||||
protected abstract void Execute(CallArgs args);
|
||||
|
||||
public void TryExecute(Optional<Player> sender, Span<string> args)
|
||||
{
|
||||
if (args.Length < required)
|
||||
{
|
||||
SendMessage(sender, $"Error: Invalid Parameters\nUsage: {ToHelpText(false, true)}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AllowedArgOverflow && args.Length > optional + required)
|
||||
{
|
||||
SendMessage(sender, $"Error: Too many Parameters\nUsage: {ToHelpText(false, true)}");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Execute(new CallArgs(this, sender, args));
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
SendMessage(sender, $"Error: {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Fatal error while trying to execute the command");
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanExecute(Perms treshold)
|
||||
{
|
||||
return RequiredPermLevel <= treshold;
|
||||
}
|
||||
|
||||
public string ToHelpText(bool singleCommand, bool cropText = false)
|
||||
{
|
||||
StringBuilder cmd = new(Name);
|
||||
|
||||
if (Aliases.Any())
|
||||
{
|
||||
cmd.AppendFormat("/{0}", string.Join("/", Aliases));
|
||||
}
|
||||
|
||||
cmd.AppendFormat(" {0}", string.Join(" ", Parameters));
|
||||
|
||||
if (singleCommand)
|
||||
{
|
||||
string parameterPreText = Parameters.Count == 0 ? "" : Environment.NewLine;
|
||||
string parameterText = $"{parameterPreText}{string.Join("\n", Parameters.Select(p => $"{p,-47} - {p.GetDescription()}"))}";
|
||||
|
||||
return cropText ? $"{cmd}" : $"{cmd,-32} - {Description} {parameterText}";
|
||||
}
|
||||
return cropText ? $"{cmd}" : $"{cmd,-32} - {Description}";
|
||||
}
|
||||
|
||||
protected void AddParameter<T>(T param) where T : IParameter<object>
|
||||
{
|
||||
Validate.NotNull(param as object);
|
||||
Parameters.Add(param);
|
||||
|
||||
if (param.IsRequired)
|
||||
{
|
||||
required++;
|
||||
}
|
||||
else
|
||||
{
|
||||
optional++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to an existing player
|
||||
/// </summary>
|
||||
public static void SendMessageToPlayer(Optional<Player> player, string message)
|
||||
{
|
||||
if (player.HasValue)
|
||||
{
|
||||
player.Value.SendPacket(new ChatMessage(ChatMessage.SERVER_ID, message));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to an existing player and logs it in the console
|
||||
/// </summary>
|
||||
public static void SendMessage(Optional<Player> player, string message)
|
||||
{
|
||||
SendMessageToPlayer(player, message);
|
||||
if (!player.HasValue)
|
||||
{
|
||||
Log.Info(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to all connected players
|
||||
/// </summary>
|
||||
public static void SendMessageToAllPlayers(string message)
|
||||
{
|
||||
PlayerManager playerManager = NitroxServiceLocator.LocateService<PlayerManager>();
|
||||
playerManager.SendPacketToAllPlayers(new ChatMessage(ChatMessage.SERVER_ID, message));
|
||||
Log.Info($"[BROADCAST] {message}");
|
||||
}
|
||||
}
|
||||
}
|
43
NitroxServer/ConsoleCommands/Abstract/Parameter.cs
Normal file
43
NitroxServer/ConsoleCommands/Abstract/Parameter.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using NitroxModel.Helper;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Abstract
|
||||
{
|
||||
public abstract class Parameter<T> : IParameter<T>
|
||||
{
|
||||
public bool IsRequired { get; }
|
||||
public string Name { get; }
|
||||
private string Description { get; }
|
||||
|
||||
protected Parameter(string name, bool isRequired, string description)
|
||||
{
|
||||
Validate.IsFalse(string.IsNullOrEmpty(name));
|
||||
|
||||
Name = name;
|
||||
IsRequired = isRequired;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public abstract bool IsValid(string arg);
|
||||
public abstract T Read(string arg);
|
||||
|
||||
public virtual string GetDescription()
|
||||
{
|
||||
return Description;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{(IsRequired ? '{' : '[')}{Name}{(IsRequired ? '}' : ']')}";
|
||||
}
|
||||
}
|
||||
|
||||
public interface IParameter<out T>
|
||||
{
|
||||
bool IsRequired { get; }
|
||||
string Name { get; }
|
||||
|
||||
bool IsValid(string arg);
|
||||
T Read(string arg);
|
||||
string GetDescription();
|
||||
}
|
||||
}
|
41
NitroxServer/ConsoleCommands/Abstract/Type/TypeBoolean.cs
Normal file
41
NitroxServer/ConsoleCommands/Abstract/Type/TypeBoolean.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NitroxModel.Helper;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Abstract.Type
|
||||
{
|
||||
public class TypeBoolean : Parameter<bool>, IParameter<object>
|
||||
{
|
||||
private static readonly string[] noValues = new string[]
|
||||
{
|
||||
bool.FalseString,
|
||||
"no",
|
||||
"off"
|
||||
};
|
||||
|
||||
private static readonly string[] yesValues = new string[]
|
||||
{
|
||||
bool.TrueString,
|
||||
"yes",
|
||||
"on"
|
||||
};
|
||||
|
||||
public TypeBoolean(string name, bool isRequired, string description) : base(name, isRequired, description) { }
|
||||
|
||||
public override bool IsValid(string arg)
|
||||
{
|
||||
return yesValues.Contains(arg, StringComparer.OrdinalIgnoreCase) || noValues.Contains(arg, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public override bool Read(string arg)
|
||||
{
|
||||
Validate.IsTrue(IsValid(arg), "Invalid boolean value received");
|
||||
return yesValues.Contains(arg, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
object IParameter<object>.Read(string arg)
|
||||
{
|
||||
return Read(arg);
|
||||
}
|
||||
}
|
||||
}
|
29
NitroxServer/ConsoleCommands/Abstract/Type/TypeEnum.cs
Normal file
29
NitroxServer/ConsoleCommands/Abstract/Type/TypeEnum.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using NitroxModel.Helper;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Abstract.Type
|
||||
{
|
||||
public class TypeEnum<T> : Parameter<object> where T : struct, Enum
|
||||
{
|
||||
public TypeEnum(string name, bool required, string description) : base(name, required, description)
|
||||
{
|
||||
Validate.IsTrue(typeof(T).IsEnum, $"Type {typeof(T).FullName} isn't an enum");
|
||||
}
|
||||
|
||||
public override bool IsValid(string arg)
|
||||
{
|
||||
return Enum.TryParse<T>(arg, true, out _);
|
||||
}
|
||||
|
||||
public override object Read(string arg)
|
||||
{
|
||||
Validate.IsTrue(Enum.TryParse(arg, true, out T value), $"Unknown value received (pick from: {string.Join(", ", Enum.GetNames(typeof(T)))})");
|
||||
return value;
|
||||
}
|
||||
|
||||
public override string GetDescription()
|
||||
{
|
||||
return $"{base.GetDescription()} (values: {string.Join(", ", Enum.GetNames(typeof(T)))})";
|
||||
}
|
||||
}
|
||||
}
|
25
NitroxServer/ConsoleCommands/Abstract/Type/TypeFloat.cs
Normal file
25
NitroxServer/ConsoleCommands/Abstract/Type/TypeFloat.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using NitroxModel.Helper;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Abstract.Type
|
||||
{
|
||||
public class TypeFloat : Parameter<float>, IParameter<object>
|
||||
{
|
||||
public TypeFloat(string name, bool isRequired, string description) : base(name, isRequired, description) { }
|
||||
|
||||
public override bool IsValid(string arg)
|
||||
{
|
||||
return float.TryParse(arg, out _);
|
||||
}
|
||||
|
||||
public override float Read(string arg)
|
||||
{
|
||||
Validate.IsTrue(float.TryParse(arg, out float value), "Invalid decimal number received");
|
||||
return value;
|
||||
}
|
||||
|
||||
object IParameter<object>.Read(string arg)
|
||||
{
|
||||
return Read(arg);
|
||||
}
|
||||
}
|
||||
}
|
25
NitroxServer/ConsoleCommands/Abstract/Type/TypeInt.cs
Normal file
25
NitroxServer/ConsoleCommands/Abstract/Type/TypeInt.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using NitroxModel.Helper;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Abstract.Type
|
||||
{
|
||||
public class TypeInt : Parameter<int>, IParameter<object>
|
||||
{
|
||||
public TypeInt(string name, bool isRequired, string description) : base(name, isRequired, description) { }
|
||||
|
||||
public override bool IsValid(string arg)
|
||||
{
|
||||
return int.TryParse(arg, out _);
|
||||
}
|
||||
|
||||
public override int Read(string arg)
|
||||
{
|
||||
Validate.IsTrue(int.TryParse(arg, out int value), "Invalid integer received");
|
||||
return value;
|
||||
}
|
||||
|
||||
object IParameter<object>.Read(string arg)
|
||||
{
|
||||
return Read(arg);
|
||||
}
|
||||
}
|
||||
}
|
24
NitroxServer/ConsoleCommands/Abstract/Type/TypeNitroxId.cs
Normal file
24
NitroxServer/ConsoleCommands/Abstract/Type/TypeNitroxId.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.Helper;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
public class TypeNitroxId(string name, bool isRequired, string description) : Parameter<NitroxId>(name, isRequired, description)
|
||||
{
|
||||
public override bool IsValid(string arg)
|
||||
{
|
||||
return IsValid(arg, out _);
|
||||
}
|
||||
|
||||
private static bool IsValid(string arg, out Guid result)
|
||||
{
|
||||
return Guid.TryParse(arg, out result);
|
||||
}
|
||||
|
||||
public override NitroxId Read(string arg)
|
||||
{
|
||||
Validate.IsTrue(IsValid(arg, out Guid result), "Received an invalid NitroxId");
|
||||
return new NitroxId(result);
|
||||
}
|
||||
}
|
27
NitroxServer/ConsoleCommands/Abstract/Type/TypePlayer.cs
Normal file
27
NitroxServer/ConsoleCommands/Abstract/Type/TypePlayer.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using NitroxModel.Core;
|
||||
using NitroxModel.Helper;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Abstract.Type
|
||||
{
|
||||
public class TypePlayer : Parameter<Player>
|
||||
{
|
||||
private static readonly PlayerManager playerManager = NitroxServiceLocator.LocateService<PlayerManager>();
|
||||
|
||||
public TypePlayer(string name, bool required, string description) : base(name, required, description)
|
||||
{
|
||||
Validate.NotNull(playerManager, "PlayerManager can't be null to resolve the command");
|
||||
}
|
||||
|
||||
public override bool IsValid(string arg)
|
||||
{
|
||||
return playerManager.TryGetPlayerByName(arg, out _);
|
||||
}
|
||||
|
||||
public override Player Read(string arg)
|
||||
{
|
||||
Validate.IsTrue(playerManager.TryGetPlayerByName(arg, out Player player), "Player not found");
|
||||
return player;
|
||||
}
|
||||
}
|
||||
}
|
20
NitroxServer/ConsoleCommands/Abstract/Type/TypeString.cs
Normal file
20
NitroxServer/ConsoleCommands/Abstract/Type/TypeString.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using NitroxModel.Helper;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Abstract.Type
|
||||
{
|
||||
public class TypeString : Parameter<string>
|
||||
{
|
||||
public TypeString(string name, bool isRequired, string description) : base(name, isRequired, description) { }
|
||||
|
||||
public override bool IsValid(string arg)
|
||||
{
|
||||
return !string.IsNullOrEmpty(arg);
|
||||
}
|
||||
|
||||
public override string Read(string arg)
|
||||
{
|
||||
Validate.IsTrue(IsValid(arg), "Received null/empty instead of a valid string");
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
}
|
42
NitroxServer/ConsoleCommands/AuroraCommand.cs
Normal file
42
NitroxServer/ConsoleCommands/AuroraCommand.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands;
|
||||
|
||||
// TODO: When we make the new command system, move this stuff to it
|
||||
public class AuroraCommand : Command
|
||||
{
|
||||
private readonly StoryManager storyManager;
|
||||
|
||||
// We shouldn't let the server use this command because it needs some stuff to happen client-side like goals
|
||||
public AuroraCommand(StoryManager storyManager) : base("aurora", Perms.ADMIN, PermsFlag.NO_CONSOLE, "Manage Aurora's state")
|
||||
{
|
||||
AddParameter(new TypeString("countdown/restore/explode", true, "Which action to apply to Aurora"));
|
||||
|
||||
this.storyManager = storyManager;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
string action = args.Get<string>(0);
|
||||
|
||||
switch (action.ToLower())
|
||||
{
|
||||
case "countdown":
|
||||
storyManager.BroadcastExplodeAurora(true);
|
||||
break;
|
||||
case "restore":
|
||||
storyManager.BroadcastRestoreAurora();
|
||||
break;
|
||||
case "explode":
|
||||
storyManager.BroadcastExplodeAurora(false);
|
||||
break;
|
||||
default:
|
||||
// Same message as in the abstract class, in method TryExecute
|
||||
SendMessage(args.Sender, $"Error: Invalid Parameters\nUsage: {ToHelpText(false, true)}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
43
NitroxServer/ConsoleCommands/AutosaveCommand.cs
Normal file
43
NitroxServer/ConsoleCommands/AutosaveCommand.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.IO;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Serialization;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class AutoSaveCommand : Command
|
||||
{
|
||||
private readonly Server server;
|
||||
private readonly SubnauticaServerConfig serverConfig;
|
||||
|
||||
public AutoSaveCommand(Server server, SubnauticaServerConfig serverConfig) : base("autosave", Perms.ADMIN, "Toggles the map autosave")
|
||||
{
|
||||
AddParameter(new TypeBoolean("on/off", true, "Whether autosave should be on or off"));
|
||||
|
||||
this.server = server;
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
bool toggle = args.Get<bool>(0);
|
||||
|
||||
using (serverConfig.Update(Path.Combine(KeyValueStore.Instance.GetSavesFolderDir(), server.Name)))
|
||||
{
|
||||
if (toggle)
|
||||
{
|
||||
serverConfig.DisableAutoSave = false;
|
||||
Server.Instance.EnablePeriodicSaving();
|
||||
SendMessage(args.Sender, "Enabled periodical saving");
|
||||
}
|
||||
else
|
||||
{
|
||||
serverConfig.DisableAutoSave = true;
|
||||
Server.Instance.DisablePeriodicSaving();
|
||||
SendMessage(args.Sender, "Disabled periodical saving");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
NitroxServer/ConsoleCommands/BackCommand.cs
Normal file
26
NitroxServer/ConsoleCommands/BackCommand.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class BackCommand : Command
|
||||
{
|
||||
public BackCommand() : base("back", Perms.MODERATOR, PermsFlag.NO_CONSOLE, "Teleports you back on your last location")
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Player player = args.Sender.Value;
|
||||
|
||||
if (player.LastStoredPosition == null)
|
||||
{
|
||||
SendMessage(args.Sender, "No previous location...");
|
||||
return;
|
||||
}
|
||||
|
||||
player.Teleport(player.LastStoredPosition.Value, player.LastStoredSubRootID);
|
||||
SendMessage(args.Sender, $"Teleported back to {player.LastStoredPosition.Value}");
|
||||
}
|
||||
}
|
||||
}
|
18
NitroxServer/ConsoleCommands/BackupCommand.cs
Normal file
18
NitroxServer/ConsoleCommands/BackupCommand.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class BackupCommand : Command
|
||||
{
|
||||
public BackupCommand() : base("backup", Perms.ADMIN, "Creates a backup of the save")
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Server.Instance.BackUp();
|
||||
SendMessageToPlayer(args.Sender, "World has been backed up");
|
||||
}
|
||||
}
|
||||
}
|
24
NitroxServer/ConsoleCommands/BroadcastCommand.cs
Normal file
24
NitroxServer/ConsoleCommands/BroadcastCommand.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class BroadcastCommand : Command
|
||||
{
|
||||
public override IEnumerable<string> Aliases { get; } = new[] { "say" };
|
||||
|
||||
public BroadcastCommand() : base("broadcast", Perms.MODERATOR, "Broadcasts a message on the server")
|
||||
{
|
||||
AddParameter(new TypeString("message", true, "The message to be broadcast"));
|
||||
|
||||
AllowedArgOverflow = true;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
SendMessageToAllPlayers(args.GetTillEnd());
|
||||
}
|
||||
}
|
||||
}
|
35
NitroxServer/ConsoleCommands/ChangeAdminPasswordCommand.cs
Normal file
35
NitroxServer/ConsoleCommands/ChangeAdminPasswordCommand.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.IO;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Serialization;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class ChangeAdminPasswordCommand : Command
|
||||
{
|
||||
private readonly Server server;
|
||||
private readonly SubnauticaServerConfig serverConfig;
|
||||
|
||||
public ChangeAdminPasswordCommand(Server server, SubnauticaServerConfig serverConfig) : base("changeadminpassword", Perms.ADMIN, "Changes admin password")
|
||||
{
|
||||
AddParameter(new TypeString("password", true, "The new admin password"));
|
||||
|
||||
this.server = server;
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
string saveDir = Path.Combine(KeyValueStore.Instance.GetSavesFolderDir(), server.Name);
|
||||
using (serverConfig.Update(saveDir))
|
||||
{
|
||||
string newPassword = args.Get(0);
|
||||
serverConfig.AdminPassword = newPassword;
|
||||
Log.InfoSensitive("Admin password changed to {password} by {playername}", newPassword, args.SenderName);
|
||||
}
|
||||
|
||||
SendMessageToPlayer(args.Sender, "Admin password has been updated");
|
||||
}
|
||||
}
|
||||
}
|
50
NitroxServer/ConsoleCommands/ChangeServerGamemodeCommand.cs
Normal file
50
NitroxServer/ConsoleCommands/ChangeServerGamemodeCommand.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.IO;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel.Serialization;
|
||||
using NitroxModel.Server;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands;
|
||||
|
||||
internal class ChangeServerGamemodeCommand : Command
|
||||
{
|
||||
private readonly Server server;
|
||||
private readonly PlayerManager playerManager;
|
||||
private readonly SubnauticaServerConfig serverConfig;
|
||||
|
||||
public ChangeServerGamemodeCommand(Server server, PlayerManager playerManager, SubnauticaServerConfig serverConfig) : base("changeservergamemode", Perms.ADMIN, "Changes server gamemode")
|
||||
{
|
||||
AddParameter(new TypeEnum<NitroxGameMode>("gamemode", true, "Gamemode to change to"));
|
||||
|
||||
this.server = server;
|
||||
this.playerManager = playerManager;
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
NitroxGameMode sgm = args.Get<NitroxGameMode>(0);
|
||||
|
||||
using (serverConfig.Update(Path.Combine(KeyValueStore.Instance.GetSavesFolderDir(), server.Name)))
|
||||
{
|
||||
if (serverConfig.GameMode != sgm)
|
||||
{
|
||||
serverConfig.GameMode = sgm;
|
||||
|
||||
foreach (Player player in playerManager.GetAllPlayers())
|
||||
{
|
||||
player.GameMode = sgm;
|
||||
}
|
||||
playerManager.SendPacketToAllPlayers(GameModeChanged.ForAllPlayers(sgm));
|
||||
SendMessageToAllPlayers($"Server gamemode changed to \"{sgm}\" by {args.SenderName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage(args.Sender, "Server is already using this gamemode");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
NitroxServer/ConsoleCommands/ChangeServerPasswordCommand.cs
Normal file
35
NitroxServer/ConsoleCommands/ChangeServerPasswordCommand.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.IO;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Serialization;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class ChangeServerPasswordCommand : Command
|
||||
{
|
||||
private readonly Server server;
|
||||
private readonly SubnauticaServerConfig serverConfig;
|
||||
|
||||
public ChangeServerPasswordCommand(Server server, SubnauticaServerConfig serverConfig) : base("changeserverpassword", Perms.ADMIN, "Changes server password. Clear it without argument")
|
||||
{
|
||||
AddParameter(new TypeString("password", false, "The new server password"));
|
||||
|
||||
this.server = server;
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
string password = args.Get(0) ?? string.Empty;
|
||||
|
||||
using (serverConfig.Update(Path.Combine(KeyValueStore.Instance.GetSavesFolderDir(), server.Name)))
|
||||
{
|
||||
serverConfig.ServerPassword = password;
|
||||
}
|
||||
|
||||
Log.InfoSensitive("Server password changed to \"{password}\" by {playername}", password, args.SenderName);
|
||||
SendMessageToPlayer(args.Sender, "Server password has been updated");
|
||||
}
|
||||
}
|
||||
}
|
82
NitroxServer/ConsoleCommands/ConfigCommand.cs
Normal file
82
NitroxServer/ConsoleCommands/ConfigCommand.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Platforms.OS.Shared;
|
||||
using NitroxModel.Serialization;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class ConfigCommand : Command
|
||||
{
|
||||
private readonly SemaphoreSlim configOpenLock = new(1);
|
||||
private readonly Server server;
|
||||
private readonly SubnauticaServerConfig serverConfig;
|
||||
|
||||
public ConfigCommand(Server server, SubnauticaServerConfig serverConfig) : base("config", Perms.CONSOLE, "Opens the server configuration file")
|
||||
{
|
||||
this.server = server;
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
if (!configOpenLock.Wait(0))
|
||||
{
|
||||
Log.Warn("Waiting on previous config command to close the configuration file.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Save config file if it doesn't exist yet.
|
||||
string saveDir = Path.Combine(KeyValueStore.Instance.GetSavesFolderDir(), server.Name);
|
||||
string configFile = Path.Combine(saveDir, serverConfig.FileName);
|
||||
if (!File.Exists(configFile))
|
||||
{
|
||||
serverConfig.Serialize(saveDir);
|
||||
}
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await StartWithDefaultProgramAsync(configFile);
|
||||
}
|
||||
finally
|
||||
{
|
||||
configOpenLock.Release();
|
||||
}
|
||||
serverConfig.Deserialize(saveDir); // Notifies user if deserialization failed.
|
||||
Log.Info("If you made changes, restart the server for them to take effect.");
|
||||
})
|
||||
.ContinueWith(t =>
|
||||
{
|
||||
#if DEBUG
|
||||
if (t.Exception != null)
|
||||
{
|
||||
throw t.Exception;
|
||||
}
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
private async Task StartWithDefaultProgramAsync(string fileToOpen)
|
||||
{
|
||||
using Process process = FileSystem.Instance.OpenOrExecuteFile(fileToOpen);
|
||||
await process.WaitForExitAsync();
|
||||
try
|
||||
{
|
||||
while (!process.HasExited)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
NitroxServer/ConsoleCommands/DebugStartMapCommand.cs
Normal file
37
NitroxServer/ConsoleCommands/DebugStartMapCommand.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
#if DEBUG
|
||||
using System.Collections.Generic;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.DataStructures.Unity;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.GameLogic;
|
||||
using NitroxServer.Serialization.World;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
|
||||
internal class DebugStartMapCommand : Command
|
||||
{
|
||||
private readonly RandomStartGenerator nitroxRandomStart;
|
||||
private readonly PlayerManager playerManager;
|
||||
private readonly World world;
|
||||
|
||||
public DebugStartMapCommand(PlayerManager playerManager, RandomStartGenerator nitroxRandomStart, World world) :
|
||||
base("debugstartmap", Perms.ADMIN, "Spawns blocks at spawn positions")
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
this.nitroxRandomStart = nitroxRandomStart;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
List<NitroxVector3> randomStartPositions = nitroxRandomStart.GenerateRandomStartPositions(world.Seed);
|
||||
|
||||
playerManager.SendPacketToAllPlayers(new DebugStartMapPacket(randomStartPositions));
|
||||
SendMessage(args.Sender, $"Rendered {randomStartPositions.Count} spawn positions");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
26
NitroxServer/ConsoleCommands/DeopCommand.cs
Normal file
26
NitroxServer/ConsoleCommands/DeopCommand.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class DeopCommand : Command
|
||||
{
|
||||
public DeopCommand() : base("deop", Perms.ADMIN, "Removes admin rights from user")
|
||||
{
|
||||
AddParameter(new TypePlayer("name", true, "Username to remove admin rights from"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Player targetPlayer = args.Get<Player>(0);
|
||||
targetPlayer.Permissions = Perms.PLAYER;
|
||||
|
||||
// Need to notify him so that he no longer shows admin stuff on client (which would in any way stop working)
|
||||
targetPlayer.SendPacket(new PermsChanged(targetPlayer.Permissions));
|
||||
SendMessage(targetPlayer, "You were demoted to PLAYER");
|
||||
SendMessage(args.Sender, $"Updated {targetPlayer.Name}\'s permissions to PLAYER");
|
||||
}
|
||||
}
|
||||
}
|
33
NitroxServer/ConsoleCommands/DirectoryCommand.cs
Normal file
33
NitroxServer/ConsoleCommands/DirectoryCommand.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class DirectoryCommand : Command
|
||||
{
|
||||
public override IEnumerable<string> Aliases { get; } = new[] { "dir" };
|
||||
|
||||
public DirectoryCommand() : base("directory", Perms.CONSOLE, "Opens the current directory of the server")
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
string path = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Log.ErrorSensitive("Unable to open Nitrox directory {path} because it does not exist", path);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
Log.InfoSensitive("Opening directory {path}", path);
|
||||
Process.Start(new ProcessStartInfo(path) { UseShellExecute = true, Verb = "open" })?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
64
NitroxServer/ConsoleCommands/FastCommand.cs
Normal file
64
NitroxServer/ConsoleCommands/FastCommand.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands;
|
||||
|
||||
public class FastCommand : Command
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
private readonly SessionSettings sessionSettings;
|
||||
|
||||
public FastCommand(PlayerManager playerManager, SessionSettings sessionSettings) : base("fast", Perms.MODERATOR, "Enables/disables a fast cheat command, whether it be \"hatch\" or \"grow\"")
|
||||
{
|
||||
AddParameter(new TypeEnum<FastCheatChanged.FastCheat>("cheat", true, "The name of the fast cheat to change: \"hatch\" or \"grow\""));
|
||||
AddParameter(new TypeBoolean("value", false, "Whether the cheat will be enabled or disabled. Default count as a toggle"));
|
||||
this.playerManager = playerManager;
|
||||
this.sessionSettings = sessionSettings;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
FastCheatChanged.FastCheat cheat = args.Get<FastCheatChanged.FastCheat>(0);
|
||||
|
||||
bool value = cheat switch
|
||||
{
|
||||
FastCheatChanged.FastCheat.HATCH => sessionSettings.FastHatch,
|
||||
FastCheatChanged.FastCheat.GROW => sessionSettings.FastGrow,
|
||||
_ => throw new ArgumentException("Must provide a valid cheat name: \"hatch\" or \"grow\""),
|
||||
};
|
||||
|
||||
|
||||
if (args.IsValid(1))
|
||||
{
|
||||
bool newValue = args.Get<bool>(1);
|
||||
if (newValue == value)
|
||||
{
|
||||
SendMessage(args.Sender, $"Fast {cheat} already set to {newValue}");
|
||||
return;
|
||||
}
|
||||
value = newValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the value wasn't provided then we toggle it
|
||||
value = !value;
|
||||
}
|
||||
|
||||
switch (cheat)
|
||||
{
|
||||
case FastCheatChanged.FastCheat.HATCH:
|
||||
sessionSettings.FastHatch = value;
|
||||
break;
|
||||
case FastCheatChanged.FastCheat.GROW:
|
||||
sessionSettings.FastGrow = value;
|
||||
break;
|
||||
}
|
||||
|
||||
playerManager.SendPacketToAllPlayers(new FastCheatChanged(cheat, value));
|
||||
SendMessageToAllPlayers($"Fast {cheat} changed to {value} by {args.SenderName}");
|
||||
}
|
||||
}
|
50
NitroxServer/ConsoleCommands/GameModeCommand.cs
Normal file
50
NitroxServer/ConsoleCommands/GameModeCommand.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel.Server;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands;
|
||||
|
||||
internal class GameModeCommand : Command
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public GameModeCommand(PlayerManager playerManager) : base("gamemode", Perms.ADMIN, "Changes a player's gamemode")
|
||||
{
|
||||
AddParameter(new TypeEnum<NitroxGameMode>("gamemode", true, "Gamemode to change to"));
|
||||
AddParameter(new TypePlayer("name", false, "Username to whom change the game mode (defaults to self)"));
|
||||
|
||||
this.playerManager = playerManager;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
NitroxGameMode gameMode = args.Get<NitroxGameMode>(0);
|
||||
Player targetPlayer = args.Get<Player>(1);
|
||||
|
||||
if (args.IsConsole && targetPlayer == null)
|
||||
{
|
||||
Log.Error($"Console can't use the gamemode command without providing a player name to it.");
|
||||
return;
|
||||
}
|
||||
// The target player if not set, is the player who sent the command
|
||||
targetPlayer ??= args.Sender.Value;
|
||||
|
||||
targetPlayer.GameMode = gameMode;
|
||||
playerManager.SendPacketToAllPlayers(GameModeChanged.ForPlayer(targetPlayer.Id, gameMode));
|
||||
SendMessage(targetPlayer, $"GameMode changed to {gameMode}");
|
||||
if (args.IsConsole)
|
||||
{
|
||||
Log.Info($"Changed {targetPlayer.Name} [{targetPlayer.Id}]'s gamemode to {gameMode}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targetPlayer != args.Sender.Value)
|
||||
{
|
||||
SendMessage(args.Sender.Value, $"GameMode of {targetPlayer.Name} changed to {gameMode}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
NitroxServer/ConsoleCommands/HelpCommand.cs
Normal file
62
NitroxServer/ConsoleCommands/HelpCommand.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NitroxModel.Core;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class HelpCommand : Command
|
||||
{
|
||||
public override IEnumerable<string> Aliases { get; } = new[] { "?" };
|
||||
|
||||
public HelpCommand() : base("help", Perms.PLAYER, "Displays this")
|
||||
{
|
||||
AddParameter(new TypeString("command", false, "Command to see help information for"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
List<string> cmdsText;
|
||||
if (args.IsConsole)
|
||||
{
|
||||
cmdsText = GetHelpText(Perms.CONSOLE, false, args.IsValid(0) ? args.Get<string>(0) : null);
|
||||
foreach (string cmdText in cmdsText)
|
||||
{
|
||||
Log.Info(cmdText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdsText = GetHelpText(args.Sender.Value.Permissions, true, args.IsValid(0) ? args.Get<string>(0) : null);
|
||||
|
||||
foreach (string cmdText in cmdsText)
|
||||
{
|
||||
SendMessageToPlayer(args.Sender, cmdText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> GetHelpText(Perms permThreshold, bool cropText, string singleCommand)
|
||||
{
|
||||
static bool CanExecuteAndProcess(Command cmd, Perms perms)
|
||||
{
|
||||
return cmd.CanExecute(perms) && !(perms == Perms.CONSOLE && cmd.Flags.HasFlag(PermsFlag.NO_CONSOLE));
|
||||
}
|
||||
|
||||
//Runtime query to avoid circular dependencies
|
||||
IEnumerable<Command> commands = NitroxServiceLocator.LocateService<IEnumerable<Command>>();
|
||||
if (singleCommand != null && !commands.Any(cmd => cmd.Name.Equals(singleCommand)))
|
||||
{
|
||||
return new List<string> { "Command does not exist" };
|
||||
}
|
||||
List<string> cmdsText = new();
|
||||
cmdsText.Add(singleCommand != null ? $"=== Showing help for {singleCommand} ===" : "=== Showing command list ===");
|
||||
cmdsText.AddRange(commands.Where(cmd => CanExecuteAndProcess(cmd, permThreshold) && (singleCommand == null || cmd.Name.Equals(singleCommand)))
|
||||
.OrderByDescending(cmd => cmd.Name)
|
||||
.Select(cmd => cmd.ToHelpText(singleCommand != null, cropText)));
|
||||
return cmdsText;
|
||||
}
|
||||
}
|
||||
}
|
58
NitroxServer/ConsoleCommands/KickCommand.cs
Normal file
58
NitroxServer/ConsoleCommands/KickCommand.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
using NitroxServer.GameLogic.Entities;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class KickCommand : Command
|
||||
{
|
||||
private readonly EntitySimulation entitySimulation;
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public KickCommand(PlayerManager playerManager, EntitySimulation entitySimulation) : base("kick", Perms.MODERATOR, "Kicks a player from the server")
|
||||
{
|
||||
AddParameter(new TypePlayer("name", true, "Name of the player to kick"));
|
||||
AddParameter(new TypeString("reason", false, "Reason for kicking the player"));
|
||||
|
||||
AllowedArgOverflow = true;
|
||||
|
||||
this.playerManager = playerManager;
|
||||
this.entitySimulation = entitySimulation;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Player playerToKick = args.Get<Player>(0);
|
||||
|
||||
if (args.SenderName == playerToKick.Name)
|
||||
{
|
||||
SendMessage(args.Sender, "You can't kick yourself");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.IsConsole && playerToKick.Permissions >= args.Sender.Value.Permissions)
|
||||
{
|
||||
SendMessage(args.Sender, $"You're not allowed to kick {playerToKick.Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
playerToKick.SendPacket(new PlayerKicked(args.GetTillEnd(1)));
|
||||
playerManager.PlayerDisconnected(playerToKick.Connection);
|
||||
|
||||
List<SimulatedEntity> revokedEntities = entitySimulation.CalculateSimulationChangesFromPlayerDisconnect(playerToKick);
|
||||
if (revokedEntities.Count > 0)
|
||||
{
|
||||
SimulationOwnershipChange ownershipChange = new(revokedEntities);
|
||||
playerManager.SendPacketToAllPlayers(ownershipChange);
|
||||
}
|
||||
|
||||
playerManager.SendPacketToOtherPlayers(new Disconnect(playerToKick.Id), playerToKick);
|
||||
SendMessage(args.Sender, $"The player {playerToKick.Name} has been disconnected");
|
||||
}
|
||||
}
|
||||
}
|
32
NitroxServer/ConsoleCommands/ListCommand.cs
Normal file
32
NitroxServer/ConsoleCommands/ListCommand.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Serialization;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class ListCommand : Command
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
private readonly SubnauticaServerConfig serverConfig;
|
||||
|
||||
public ListCommand(SubnauticaServerConfig serverConfig, PlayerManager playerManager) : base("list", Perms.PLAYER, "Shows who's online")
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
IList<string> players = playerManager.GetConnectedPlayers().Select(player => player.Name).ToList();
|
||||
|
||||
StringBuilder builder = new($"List of players ({players.Count}/{serverConfig.MaxConnections}):\n");
|
||||
builder.Append(string.Join(", ", players));
|
||||
|
||||
SendMessage(args.Sender, builder.ToString());
|
||||
}
|
||||
}
|
||||
}
|
33
NitroxServer/ConsoleCommands/LoadBatchCommand.cs
Normal file
33
NitroxServer/ConsoleCommands/LoadBatchCommand.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
#if DEBUG
|
||||
using System.Collections.Generic;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic.Entities.Spawning;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class LoadBatchCommand : Command
|
||||
{
|
||||
private readonly BatchEntitySpawner batchEntitySpawner;
|
||||
|
||||
public LoadBatchCommand(BatchEntitySpawner batchEntitySpawner) : base("loadbatch", Perms.ADMIN, "Loads entities at x y z")
|
||||
{
|
||||
AddParameter(new TypeInt("x", true, "x coordinate"));
|
||||
AddParameter(new TypeInt("y", true, "y coordinate"));
|
||||
AddParameter(new TypeInt("z", true, "z coordinate"));
|
||||
|
||||
this.batchEntitySpawner = batchEntitySpawner;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
NitroxInt3 batchId = new(args.Get<int>(0), args.Get<int>(1), args.Get<int>(2));
|
||||
List<Entity> entities = batchEntitySpawner.LoadUnspawnedEntities(batchId);
|
||||
|
||||
SendMessage(args.Sender, $"Loaded {entities.Count} entities from batch {batchId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
32
NitroxServer/ConsoleCommands/LoginCommand.cs
Normal file
32
NitroxServer/ConsoleCommands/LoginCommand.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Serialization;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class LoginCommand : Command
|
||||
{
|
||||
private readonly SubnauticaServerConfig serverConfig;
|
||||
|
||||
public LoginCommand(SubnauticaServerConfig serverConfig) : base("login", Perms.PLAYER, PermsFlag.NO_CONSOLE, "Log in to server as admin (requires password)")
|
||||
{
|
||||
AddParameter(new TypeString("password", true, "The admin password for the server"));
|
||||
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
if (args.Get<string>(0) == serverConfig.AdminPassword)
|
||||
{
|
||||
args.Sender.Value.Permissions = Perms.ADMIN;
|
||||
SendMessage(args.Sender, $"Updated permissions to ADMIN for {args.SenderName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage(args.Sender, "Incorrect Password");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
NitroxServer/ConsoleCommands/MuteCommand.cs
Normal file
48
NitroxServer/ConsoleCommands/MuteCommand.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class MuteCommand : Command
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public MuteCommand(PlayerManager playerManager) : base("mute", Perms.MODERATOR, "Prevents a user from chatting")
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
AddParameter(new TypePlayer("name", true, "Player to mute"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Player targetPlayer = args.Get<Player>(0);
|
||||
|
||||
if (args.SenderName == targetPlayer.Name)
|
||||
{
|
||||
SendMessage(args.Sender, "You can't mute yourself");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.IsConsole && targetPlayer.Permissions >= args.Sender.Value.Permissions)
|
||||
{
|
||||
SendMessage(args.Sender, $"You're not allowed to mute {targetPlayer.Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetPlayer.PlayerContext.IsMuted)
|
||||
{
|
||||
SendMessage(args.Sender, $"{targetPlayer.Name} is already muted");
|
||||
args.Sender.Value.SendPacket(new MutePlayer(targetPlayer.Id, targetPlayer.PlayerContext.IsMuted));
|
||||
return;
|
||||
}
|
||||
|
||||
targetPlayer.PlayerContext.IsMuted = true;
|
||||
playerManager.SendPacketToAllPlayers(new MutePlayer(targetPlayer.Id, targetPlayer.PlayerContext.IsMuted));
|
||||
SendMessage(targetPlayer, "You're now muted");
|
||||
SendMessage(args.Sender, $"Muted {targetPlayer.Name}");
|
||||
}
|
||||
}
|
||||
}
|
26
NitroxServer/ConsoleCommands/OpCommand.cs
Normal file
26
NitroxServer/ConsoleCommands/OpCommand.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class OpCommand : Command
|
||||
{
|
||||
public OpCommand() : base("op", Perms.ADMIN, "Sets a user as admin")
|
||||
{
|
||||
AddParameter(new TypePlayer("name", true, "The players name to make an admin"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Player targetPlayer = args.Get<Player>(0);
|
||||
targetPlayer.Permissions = Perms.ADMIN;
|
||||
|
||||
// We need to notify this player that he can show all the admin-related stuff
|
||||
targetPlayer.SendPacket(new PermsChanged(targetPlayer.Permissions));
|
||||
SendMessage(targetPlayer, "You were promoted to ADMIN");
|
||||
SendMessage(args.Sender, $"Updated {targetPlayer.Name}\'s permissions to ADMIN");
|
||||
}
|
||||
}
|
||||
}
|
62
NitroxServer/ConsoleCommands/PlayerCommand.cs
Normal file
62
NitroxServer/ConsoleCommands/PlayerCommand.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
#if DEBUG
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NitroxModel.Core;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities;
|
||||
using NitroxModel.DataStructures.Unity;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
using NitroxServer.GameLogic.Entities;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands;
|
||||
|
||||
internal class PlayerCommand : Command
|
||||
{
|
||||
private readonly Lazy<PlayerManager> playerManager = new(NitroxServiceLocator.LocateService<PlayerManager>);
|
||||
private readonly Lazy<WorldEntityManager> worldEntityManager = new(NitroxServiceLocator.LocateService<WorldEntityManager>);
|
||||
private readonly Lazy<SimulationOwnershipData> simulationOwnershipData = new(NitroxServiceLocator.LocateService<SimulationOwnershipData>);
|
||||
|
||||
public PlayerCommand() : base("player", Perms.CONSOLE, "Lists all visible cells of a player, their simulated entities per cell and the player's visible out of cell entities")
|
||||
{
|
||||
AddParameter(new TypeString("player name", true, "name of the target player"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
string playerName = args.Get<string>(0);
|
||||
|
||||
if (playerManager.Value.TryGetPlayerByName(playerName, out Player player))
|
||||
{
|
||||
List<AbsoluteEntityCell> visibleCells = player.GetVisibleCells();
|
||||
|
||||
Log.Info(player);
|
||||
Log.Info($"Visible cells [{visibleCells.Count}]:");
|
||||
foreach (AbsoluteEntityCell visibleCell in visibleCells)
|
||||
{
|
||||
string simulatedEntities = "";
|
||||
foreach (WorldEntity worldEntity in worldEntityManager.Value.GetEntities(visibleCell))
|
||||
{
|
||||
if (simulationOwnershipData.Value.TryGetLock(worldEntity.Id, out SimulationOwnershipData.PlayerLock playerLock) &&
|
||||
playerLock.Player.Id == player.Id)
|
||||
{
|
||||
simulatedEntities += $"[{worldEntity.Id}; {worldEntity.TechType?.ToString() ?? worldEntity.ClassId}], ";
|
||||
}
|
||||
}
|
||||
Log.Info($"{visibleCell}; {NitroxVector3.Distance(visibleCell.Position, player.Position)}");
|
||||
if (simulatedEntities.Length > 0)
|
||||
{
|
||||
// Get everything but the last ", " of the string
|
||||
Log.Info(simulatedEntities[..^2]);
|
||||
}
|
||||
}
|
||||
Log.Info($"\nOut of cell entities:\n{string.Join(", ", player.OutOfCellVisibleEntities)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Player with name {playerName} not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.Exceptions;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands.Processor
|
||||
{
|
||||
public class ConsoleCommandProcessor
|
||||
{
|
||||
private readonly Dictionary<string, Command> commands = new();
|
||||
private readonly char[] splitChar = { ' ' };
|
||||
|
||||
public ConsoleCommandProcessor(IEnumerable<Command> cmds)
|
||||
{
|
||||
foreach (Command cmd in cmds)
|
||||
{
|
||||
if (commands.ContainsKey(cmd.Name))
|
||||
{
|
||||
throw new DuplicateRegistrationException($"Command {cmd.Name} is registered multiple times.");
|
||||
}
|
||||
|
||||
commands[cmd.Name] = cmd;
|
||||
|
||||
foreach (string alias in cmd.Aliases)
|
||||
{
|
||||
if (commands.ContainsKey(alias))
|
||||
{
|
||||
throw new DuplicateRegistrationException($"Command {alias} is registered multiple times.");
|
||||
}
|
||||
|
||||
commands[alias] = cmd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessCommand(string msg, Optional<Player> sender, Perms permissions)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Span<string> parts = msg.Split(splitChar, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (!commands.TryGetValue(parts[0], out Command command))
|
||||
{
|
||||
Command.SendMessage(sender, $"Command not found: {parts[0]}");
|
||||
return;
|
||||
}
|
||||
if (!sender.HasValue && command.Flags.HasFlag(PermsFlag.NO_CONSOLE))
|
||||
{
|
||||
Log.Error("This command cannot be used by CONSOLE");
|
||||
return;
|
||||
}
|
||||
|
||||
if (command.CanExecute(permissions))
|
||||
{
|
||||
command.TryExecute(sender, parts[1..]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Command.SendMessage(sender, "You do not have the required permissions for this command !");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
42
NitroxServer/ConsoleCommands/PromoteCommand.cs
Normal file
42
NitroxServer/ConsoleCommands/PromoteCommand.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class PromoteCommand : Command
|
||||
{
|
||||
public PromoteCommand() : base("promote", Perms.MODERATOR, "Sets specific permissions to a user")
|
||||
{
|
||||
AddParameter(new TypePlayer("name", true, "The username to change the permissions of"));
|
||||
AddParameter(new TypeEnum<Perms>("perms", true, "Permission level"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Player targetPlayer = args.Get<Player>(0);
|
||||
Perms permissions = args.Get<Perms>(1);
|
||||
|
||||
if (args.SenderName == targetPlayer.Name)
|
||||
{
|
||||
SendMessage(args.Sender, "You can't promote yourself");
|
||||
return;
|
||||
}
|
||||
|
||||
//Allows a bounded permission hierarchy
|
||||
if (args.IsConsole || permissions < args.Sender.Value.Permissions)
|
||||
{
|
||||
targetPlayer.Permissions = permissions;
|
||||
|
||||
targetPlayer.SendPacket(new PermsChanged(targetPlayer.Permissions));
|
||||
SendMessage(args.Sender, $"Updated {targetPlayer.Name}\'s permissions to {permissions}");
|
||||
SendMessageToPlayer(targetPlayer, $"You've been promoted to {permissions}");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage(args.Sender, $"You're not allowed to update {targetPlayer.Name}\'s permissions");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
55
NitroxServer/ConsoleCommands/PvpCommand.cs
Normal file
55
NitroxServer/ConsoleCommands/PvpCommand.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.IO;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Serialization;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.Serialization;
|
||||
using NitroxServer.Serialization.World;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands;
|
||||
|
||||
public class PvpCommand : Command
|
||||
{
|
||||
private readonly SubnauticaServerConfig serverConfig;
|
||||
private readonly Server server;
|
||||
|
||||
public PvpCommand(SubnauticaServerConfig serverConfig, Server server) : base("pvp", Perms.ADMIN, "Enables/Disables PvP")
|
||||
{
|
||||
AddParameter(new TypeString("state", true, "on/off"));
|
||||
|
||||
this.serverConfig = serverConfig;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
string state = args.Get<string>(0).ToLower();
|
||||
|
||||
bool pvpEnabled = false;
|
||||
switch (state)
|
||||
{
|
||||
case "on":
|
||||
pvpEnabled = true;
|
||||
break;
|
||||
case "off":
|
||||
break;
|
||||
default:
|
||||
SendMessage(args.Sender, "Parameter must be \"on\" or \"off\"");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
using (serverConfig.Update(Path.Combine(KeyValueStore.Instance.GetSavesFolderDir(), server.Name)))
|
||||
{
|
||||
if (serverConfig.PvPEnabled == pvpEnabled)
|
||||
{
|
||||
SendMessage(args.Sender, $"PvP is already {state}");
|
||||
return;
|
||||
}
|
||||
|
||||
serverConfig.PvPEnabled = pvpEnabled;
|
||||
|
||||
SendMessageToAllPlayers($"PvP is now {state}");
|
||||
}
|
||||
}
|
||||
}
|
50
NitroxServer/ConsoleCommands/QueryCommand.cs
Normal file
50
NitroxServer/ConsoleCommands/QueryCommand.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
#if DEBUG
|
||||
using System;
|
||||
using NitroxModel.Core;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
using NitroxServer.GameLogic.Entities;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands;
|
||||
|
||||
internal class QueryCommand : Command
|
||||
{
|
||||
private readonly Lazy<EntityRegistry> entityRegistry = new(NitroxServiceLocator.LocateService<EntityRegistry>);
|
||||
private readonly Lazy<SimulationOwnershipData> simulationOwnershipData = new(NitroxServiceLocator.LocateService<SimulationOwnershipData>);
|
||||
|
||||
public QueryCommand() : base("query", Perms.CONSOLE, "Query the entity associated with the given NitroxId")
|
||||
{
|
||||
AddParameter(new TypeNitroxId("entityId", true, "NitroxId of the queried entity"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
NitroxId nitroxId = args.Get<NitroxId>(0);
|
||||
|
||||
if (entityRegistry.Value.TryGetEntityById(nitroxId, out Entity entity))
|
||||
{
|
||||
Log.Info(entity);
|
||||
if (entity is WorldEntity worldEntity && worldEntity.Transform != null)
|
||||
{
|
||||
Log.Info(worldEntity.AbsoluteEntityCell);
|
||||
}
|
||||
if (simulationOwnershipData.Value.TryGetLock(nitroxId, out SimulationOwnershipData.PlayerLock playerLock))
|
||||
{
|
||||
Log.Info($"Lock owner: {playerLock.Player.Name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Info("Not locked");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Entity with id {nitroxId} not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
37
NitroxServer/ConsoleCommands/RestartCommand.cs
Normal file
37
NitroxServer/ConsoleCommands/RestartCommand.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Diagnostics;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class RestartCommand : Command
|
||||
{
|
||||
private readonly Server server;
|
||||
|
||||
public RestartCommand(Server server) : base("restart", Perms.CONSOLE, "Restarts the server")
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
Log.Error("Cannot restart server while debugger is attached.");
|
||||
return;
|
||||
}
|
||||
|
||||
string program = Process.GetCurrentProcess().MainModule?.FileName;
|
||||
if (program == null)
|
||||
{
|
||||
Log.Error("Failed to get location of server.");
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessageToAllPlayers("Server is restarting...");
|
||||
|
||||
server.Stop();
|
||||
using Process proc = Process.Start(program);
|
||||
}
|
||||
}
|
||||
}
|
18
NitroxServer/ConsoleCommands/SaveCommand.cs
Normal file
18
NitroxServer/ConsoleCommands/SaveCommand.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class SaveCommand : Command
|
||||
{
|
||||
public SaveCommand() : base("save", Perms.MODERATOR, "Saves the map")
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Server.Instance.Save();
|
||||
SendMessageToPlayer(args.Sender, "World saved");
|
||||
}
|
||||
}
|
||||
}
|
43
NitroxServer/ConsoleCommands/SetKeepInventoryCommand.cs
Normal file
43
NitroxServer/ConsoleCommands/SetKeepInventoryCommand.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.IO;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel.Serialization;
|
||||
using NitroxModel.Server;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
using NitroxServer.Serialization;
|
||||
using NitroxServer.Serialization.World;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands;
|
||||
internal class SetKeepInventoryCommand : Command
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
private readonly SubnauticaServerConfig serverConfig;
|
||||
private readonly Server server;
|
||||
|
||||
public SetKeepInventoryCommand(PlayerManager playerManager, SubnauticaServerConfig serverConfig, Server server) : base("keepinventory", NitroxModel.DataStructures.GameLogic.Perms.ADMIN, "Sets \"keep inventory\" setting to on/off. If \"on\", players won't lose items when they die.")
|
||||
{
|
||||
AddParameter(new TypeBoolean("state", true, "The true/false state to set keep inventory on death to"));
|
||||
this.playerManager = playerManager;
|
||||
this.serverConfig = serverConfig;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
bool newKeepInventoryState = args.Get<bool>(0);
|
||||
using (serverConfig.Update(Path.Combine(KeyValueStore.Instance.GetSavesFolderDir(), server.Name)))
|
||||
{
|
||||
if (serverConfig.KeepInventoryOnDeath != newKeepInventoryState)
|
||||
{
|
||||
serverConfig.KeepInventoryOnDeath = newKeepInventoryState;
|
||||
playerManager.SendPacketToAllPlayers(new KeepInventoryChanged(newKeepInventoryState));
|
||||
SendMessageToAllPlayers($"KeepInventoryOnDeath changed to \"{newKeepInventoryState}\" by {args.SenderName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage(args.Sender, $"KeepInventoryOnDeath already set to {newKeepInventoryState}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
NitroxServer/ConsoleCommands/StopCommand.cs
Normal file
26
NitroxServer/ConsoleCommands/StopCommand.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class StopCommand : Command
|
||||
{
|
||||
public override IEnumerable<string> Aliases { get; } = new[] { "exit", "halt", "quit", "close" };
|
||||
|
||||
public StopCommand() : base("stop", Perms.ADMIN, "Stops the server")
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Server server = Server.Instance;
|
||||
if (!server.IsRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SendMessageToAllPlayers("Server is shutting down...");
|
||||
server.Stop(shouldSave: true);
|
||||
}
|
||||
}
|
||||
}
|
23
NitroxServer/ConsoleCommands/SummaryCommand.cs
Normal file
23
NitroxServer/ConsoleCommands/SummaryCommand.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class SummaryCommand : Command
|
||||
{
|
||||
private readonly Server server;
|
||||
|
||||
public SummaryCommand(Server server) : base("summary", Perms.MODERATOR, "Shows persisted data")
|
||||
{
|
||||
this.server = server;
|
||||
|
||||
AllowedArgOverflow = true;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Perms viewerPerms = args.Sender.OrNull()?.Permissions ?? Perms.PLAYER;
|
||||
SendMessage(args.Sender, server.GetSaveSummary(viewerPerms));
|
||||
}
|
||||
}
|
||||
}
|
48
NitroxServer/ConsoleCommands/SunbeamCommand.cs
Normal file
48
NitroxServer/ConsoleCommands/SunbeamCommand.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands;
|
||||
|
||||
// TODO: When we make the new command system, move this stuff to it
|
||||
public class SunbeamCommand : Command
|
||||
{
|
||||
private readonly StoryManager storyManager;
|
||||
|
||||
// We shouldn't let the server use this command because it needs some stuff to happen client-side like goals
|
||||
public SunbeamCommand(StoryManager storyManager) : base("sunbeam", Perms.ADMIN, PermsFlag.NO_CONSOLE, "Start sunbeam events")
|
||||
{
|
||||
AddParameter(new TypeString("storystart/countdown/gunaim", true, "Which Sunbeam event to start"));
|
||||
|
||||
this.storyManager = storyManager;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
if (!args.Sender.HasValue)
|
||||
{
|
||||
SendMessage(args.Sender, "This command can't be used by CONSOLE");
|
||||
return;
|
||||
}
|
||||
string action = args.Get<string>(0);
|
||||
|
||||
switch (action.ToLower())
|
||||
{
|
||||
case "storystart":
|
||||
storyManager.StartSunbeamEvent(PlaySunbeamEvent.SunbeamEvent.STORYSTART);
|
||||
break;
|
||||
case "countdown":
|
||||
storyManager.StartSunbeamEvent(PlaySunbeamEvent.SunbeamEvent.COUNTDOWN);
|
||||
break;
|
||||
case "gunaim":
|
||||
storyManager.StartSunbeamEvent(PlaySunbeamEvent.SunbeamEvent.GUNAIM);
|
||||
break;
|
||||
default:
|
||||
// Same message as in the abstract class, in method TryExecute
|
||||
SendMessage(args.Sender, $"Error: Invalid Parameters\nUsage: {ToHelpText(false, true)}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
45
NitroxServer/ConsoleCommands/SwapSerializerCommand.cs
Normal file
45
NitroxServer/ConsoleCommands/SwapSerializerCommand.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.IO;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Serialization;
|
||||
using NitroxModel.Server;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.Serialization.World;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class SwapSerializerCommand : Command
|
||||
{
|
||||
private readonly Server server;
|
||||
private readonly WorldPersistence worldPersistence;
|
||||
private readonly SubnauticaServerConfig serverConfig;
|
||||
|
||||
public SwapSerializerCommand(Server server, SubnauticaServerConfig serverConfig, WorldPersistence worldPersistence) : base("swapserializer", Perms.CONSOLE, "Allows to change the save format")
|
||||
{
|
||||
AddParameter(new TypeEnum<ServerSerializerMode>("serializer", true, "Save format to change to"));
|
||||
|
||||
this.server = server;
|
||||
this.worldPersistence = worldPersistence;
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
ServerSerializerMode serializerMode = args.Get<ServerSerializerMode>(0);
|
||||
|
||||
using (serverConfig.Update(Path.Combine(KeyValueStore.Instance.GetSavesFolderDir(), server.Name)))
|
||||
{
|
||||
if (serializerMode != serverConfig.SerializerMode)
|
||||
{
|
||||
serverConfig.SerializerMode = serializerMode;
|
||||
worldPersistence.UpdateSerializer(serializerMode);
|
||||
SendMessage(args.Sender, $"Server save format swapped to {serverConfig.SerializerMode}");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage(args.Sender, "Server is already using this save format");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
NitroxServer/ConsoleCommands/TeleportCommand.cs
Normal file
29
NitroxServer/ConsoleCommands/TeleportCommand.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.DataStructures.Unity;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class TeleportCommand : Command
|
||||
{
|
||||
public override IEnumerable<string> Aliases { get; } = new[] { "tp" };
|
||||
|
||||
public TeleportCommand() : base("teleport", Perms.MODERATOR, PermsFlag.NO_CONSOLE, "Teleports you on a specific location")
|
||||
{
|
||||
AddParameter(new TypeInt("x", true, "x coordinate"));
|
||||
AddParameter(new TypeInt("y", true, "y coordinate"));
|
||||
AddParameter(new TypeInt("z", true, "z coordinate"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
NitroxVector3 position = new(args.Get<int>(0), args.Get<int>(1), args.Get<int>(2));
|
||||
args.Sender.Value.Teleport(position, Optional.Empty);
|
||||
|
||||
SendMessage(args.Sender, $"Teleported to {position}");
|
||||
}
|
||||
}
|
||||
}
|
41
NitroxServer/ConsoleCommands/TimeCommand.cs
Normal file
41
NitroxServer/ConsoleCommands/TimeCommand.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands;
|
||||
|
||||
public class TimeCommand : Command
|
||||
{
|
||||
private readonly TimeKeeper timeKeeper;
|
||||
|
||||
public TimeCommand(TimeKeeper timeKeeper) : base("time", Perms.MODERATOR, "Changes the map time")
|
||||
{
|
||||
AddParameter(new TypeString("day/night", false, "Time to change to"));
|
||||
|
||||
this.timeKeeper = timeKeeper;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
string time = args.Get(0);
|
||||
|
||||
switch (time?.ToLower())
|
||||
{
|
||||
case "day":
|
||||
timeKeeper.ChangeTime(StoryManager.TimeModification.DAY);
|
||||
SendMessageToAllPlayers("Time set to day");
|
||||
break;
|
||||
|
||||
case "night":
|
||||
timeKeeper.ChangeTime(StoryManager.TimeModification.NIGHT);
|
||||
SendMessageToAllPlayers("Time set to night");
|
||||
break;
|
||||
|
||||
default:
|
||||
timeKeeper.ChangeTime(StoryManager.TimeModification.SKIP);
|
||||
SendMessageToAllPlayers("Skipped time");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
48
NitroxServer/ConsoleCommands/UnmuteCommand.cs
Normal file
48
NitroxServer/ConsoleCommands/UnmuteCommand.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
using NitroxServer.GameLogic;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class UnmuteCommand : Command
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public UnmuteCommand(PlayerManager playerManager) : base("unmute", Perms.MODERATOR, "Removes a mute from a player")
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
AddParameter(new TypePlayer("name", true, "Player to unmute"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Player targetPlayer = args.Get<Player>(0);
|
||||
|
||||
if (args.SenderName == targetPlayer.Name)
|
||||
{
|
||||
SendMessage(args.Sender, "You can't unmute yourself");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.IsConsole && targetPlayer.Permissions >= args.Sender.Value.Permissions)
|
||||
{
|
||||
SendMessage(args.Sender, $"You're not allowed to unmute {targetPlayer.Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!targetPlayer.PlayerContext.IsMuted)
|
||||
{
|
||||
SendMessage(args.Sender, $"{targetPlayer.Name} is already unmuted");
|
||||
args.Sender.Value.SendPacket(new MutePlayer(targetPlayer.Id, targetPlayer.PlayerContext.IsMuted));
|
||||
return;
|
||||
}
|
||||
|
||||
targetPlayer.PlayerContext.IsMuted = false;
|
||||
playerManager.SendPacketToAllPlayers(new MutePlayer(targetPlayer.Id, targetPlayer.PlayerContext.IsMuted));
|
||||
SendMessage(targetPlayer, "You're no longer muted");
|
||||
SendMessage(args.Sender, $"Unmuted {targetPlayer.Name}");
|
||||
}
|
||||
}
|
||||
}
|
38
NitroxServer/ConsoleCommands/WarpCommand.cs
Normal file
38
NitroxServer/ConsoleCommands/WarpCommand.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Helper;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class WarpCommand : Command
|
||||
{
|
||||
public WarpCommand() : base("warp", Perms.MODERATOR, "Allows to teleport players")
|
||||
{
|
||||
AddParameter(new TypePlayer("name", true, "Player to teleport to (or a player specified to teleport)"));
|
||||
AddParameter(new TypePlayer("name", false, "The players name to teleport to"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Player destination;
|
||||
Player sender;
|
||||
|
||||
//Allows the console to teleport two players
|
||||
if (args.IsValid(1))
|
||||
{
|
||||
destination = args.Get<Player>(1);
|
||||
sender = args.Get<Player>(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Validate.IsFalse(args.IsConsole, "This command can't be used by CONSOLE");
|
||||
destination = args.Get<Player>(0);
|
||||
sender = args.Sender.Value;
|
||||
}
|
||||
|
||||
sender.Teleport(destination.Position, destination.SubRootId);
|
||||
SendMessage(sender, $"Teleported to {destination.Name}");
|
||||
}
|
||||
}
|
||||
}
|
28
NitroxServer/ConsoleCommands/WhisperCommand.cs
Normal file
28
NitroxServer/ConsoleCommands/WhisperCommand.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class WhisperCommand : Command
|
||||
{
|
||||
public override IEnumerable<string> Aliases { get; } = new[] { "w", "msg", "m" };
|
||||
|
||||
public WhisperCommand() : base("whisper", Perms.PLAYER, "Sends a private message to a player")
|
||||
{
|
||||
AddParameter(new TypePlayer("name", true, "The players name to message"));
|
||||
AddParameter(new TypeString("msg", true, "The message to send"));
|
||||
|
||||
AllowedArgOverflow = true;
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Player foundPlayer = args.Get<Player>(0);
|
||||
string message = $"[{args.SenderName} -> YOU]: {args.GetTillEnd(1)}";
|
||||
|
||||
SendMessageToPlayer(foundPlayer, message);
|
||||
}
|
||||
}
|
||||
}
|
31
NitroxServer/ConsoleCommands/WhoisCommand.cs
Normal file
31
NitroxServer/ConsoleCommands/WhoisCommand.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Text;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxServer.ConsoleCommands.Abstract;
|
||||
using NitroxServer.ConsoleCommands.Abstract.Type;
|
||||
|
||||
namespace NitroxServer.ConsoleCommands
|
||||
{
|
||||
internal class WhoisCommand : Command
|
||||
{
|
||||
public WhoisCommand() : base("whois", Perms.PLAYER, "Shows informations over a player")
|
||||
{
|
||||
AddParameter(new TypePlayer("name", true, "The players name"));
|
||||
}
|
||||
|
||||
protected override void Execute(CallArgs args)
|
||||
{
|
||||
Player player = args.Get<Player>(0);
|
||||
|
||||
StringBuilder builder = new($"==== {player.Name} ====\n");
|
||||
builder.AppendLine($"ID: {player.Id}");
|
||||
builder.AppendLine($"Role: {player.Permissions}");
|
||||
builder.AppendLine($"Position: {player.Position.X}, {player.Position.Y}, {player.Position.Z}");
|
||||
builder.AppendLine($"Oxygen: {player.Stats.Oxygen}/{player.Stats.MaxOxygen}");
|
||||
builder.AppendLine($"Food: {player.Stats.Food}");
|
||||
builder.AppendLine($"Water: {player.Stats.Water}");
|
||||
builder.AppendLine($"Infection: {player.Stats.InfectionAmount}");
|
||||
|
||||
SendMessage(args.Sender, builder.ToString());
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user