command yay!

This commit is contained in:
rfi
2023-11-13 19:10:02 +07:00
parent 21856d353b
commit 6c5aca3c3a
12 changed files with 335 additions and 36 deletions

View File

@@ -0,0 +1,132 @@
using System.Reflection;
using System.Text.RegularExpressions;
using AscNet.Logging;
namespace AscNet.GameServer.Commands
{
public abstract class Command
{
protected Session session;
protected string[] args;
public abstract string Help { get; }
/// <summary>
/// Make sure to handle me well...
/// </summary>
/// <param name="session"></param>
/// <param name="args"></param>
/// <exception cref="ArgumentException"></exception>
public Command(Session session, string[] args, bool validate = true)
{
this.session = session;
this.args = args;
string? ret = Validate();
if (ret is not null && validate)
throw new ArgumentException(ret);
}
public string? Validate()
{
List<PropertyInfo> argsProperties = GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(x => x.GetCustomAttribute(typeof(ArgumentAttribute)) is not null).ToList();
if (argsProperties.Count != args.Length)
return "Invalid args length!";
foreach (var argProp in argsProperties)
{
ArgumentAttribute attr = (ArgumentAttribute)argProp.GetCustomAttribute(typeof(ArgumentAttribute))!;
if (!attr.Pattern.IsMatch(args[attr.Position]))
return $"Argument {argProp.Name} is invalid!";
argProp.SetValue(this, args[attr.Position]);
}
return null;
}
public abstract void Execute();
}
[AttributeUsage(AttributeTargets.Property)]
public class ArgumentAttribute : Attribute
{
public int Position { get; }
public Regex Pattern { get; }
public string? Description { get; }
public ArgumentAttribute(int position, string pattern, string? description = null)
{
Position = position;
Pattern = new(pattern);
Description = description;
}
}
[AttributeUsage(AttributeTargets.Class)]
public class CommandNameAttribute : Attribute
{
public string Name { get; }
public CommandNameAttribute(string name)
{
Name = name;
}
}
[CommandName("help")]
internal class HelpCommand : Command
{
public HelpCommand(Session session, string[] args, bool validate = true) : base(session, args, validate) { }
public override string Help => "Show this help.";
public override void Execute()
{
string helpText = string.Empty;
foreach (var command in CommandFactory.commands.Keys)
{
Command? cmd = CommandFactory.CreateCommand(command, session, args, false);
if (cmd is not null)
helpText += $"{command}\n\t└─{cmd.Help}\n";
}
}
}
public static class CommandFactory
{
public static readonly Dictionary<string, Type> commands = new();
internal static readonly Logger log = new(typeof(CommandFactory), LogLevel.DEBUG, LogLevel.DEBUG);
public static void LoadCommands()
{
log.LogLevelColor[LogLevel.INFO] = ConsoleColor.White;
log.Info("Loading commands...");
IEnumerable<Type> classes = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass && t.GetCustomAttribute<CommandNameAttribute>() is not null
select t;
foreach (var command in classes)
{
CommandNameAttribute nameAttr = command.GetCustomAttribute<CommandNameAttribute>()!;
commands.Add(nameAttr.Name, command);
#if DEBUG
log.Info($"Loaded {nameAttr.Name} command");
#endif
}
log.Info("Finished loading commands");
}
public static Command? CreateCommand(string name, Session session, string[] args, bool validate = true)
{
Type? command = commands.GetValueOrDefault(name);
if (command is null)
return null;
return (Command)Activator.CreateInstance(command, new object[] { session, args, validate })!;
}
}
}

View File

@@ -0,0 +1,73 @@
using AscNet.Common.MsgPack;
using AscNet.Table.share.fuben;
namespace AscNet.GameServer.Commands
{
[CommandName("stage")]
internal class StageCommand : Command
{
public StageCommand(Session session, string[] args, bool validate = true) : base(session, args, validate) { }
[Argument(0, @"^[0-9]+$|^all$", "The target stage, value is stage id or 'all'")]
string TargetStage { get; set; } = string.Empty;
public override string Help => "Modify the stage completion status of the account.";
public override void Execute()
{
if (TargetStage == "all")
{
session.stage.Stages.Clear();
foreach (var stageData in StageTableReader.Instance.All)
{
session.stage.Stages.Add(stageData.StageId, new()
{
StageId = stageData.StageId,
StarsMark = 7,
Passed = true,
PassTimesToday = 0,
PassTimesTotal = 1,
BuyCount = 0,
Score = 0,
LastPassTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
RefreshTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
CreateTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
BestRecordTime = 0,
LastRecordTime = 0,
BestCardIds = new List<long> { 1021001 },
LastCardIds = new List<long> { 1021001 }
});
}
session.SendPush(new NotifyStageData() { StageList = session.stage.Stages.Select(x => x.Value).ToList() });
}
else
{
StageTable? stageData = StageTableReader.Instance.FromStageId(int.Parse(TargetStage));
if (stageData is not null && !session.stage.Stages.ContainsKey(stageData.StageId))
{
StageDatum stage = new()
{
StageId = stageData.StageId,
StarsMark = 7,
Passed = true,
PassTimesToday = 0,
PassTimesTotal = 1,
BuyCount = 0,
Score = 0,
LastPassTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
RefreshTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
CreateTime = DateTimeOffset.Now.ToUnixTimeSeconds(),
BestRecordTime = 0,
LastRecordTime = 0,
BestCardIds = new List<long> { 1021001 },
LastCardIds = new List<long> { 1021001 }
};
session.stage.Stages.Add(stageData.StageId, stage);
session.SendPush(new NotifyStageData() { StageList = new() { stage } });
}
}
}
}
}

View File

@@ -1,5 +1,6 @@
using AscNet.Common.Database;
using AscNet.Common.MsgPack;
using AscNet.Table.share.fuben;
using AscNet.Table.share.guide;
using MessagePack;
using Newtonsoft.Json;
@@ -103,7 +104,7 @@ namespace AscNet.GameServer.Handlers
BaseEquipLoginData = new(),
FubenData = new()
{
StageData = session.stage.Stages,
StageData = session.stage.Stages.ToDictionary(x => x.Key, x => x.Value),
FubenBaseData = new()
},
FubenMainLineData = new(),
@@ -116,7 +117,6 @@ namespace AscNet.GameServer.Handlers
notifyLogin.FashionList.AddRange(session.character.Fashions);
#if DEBUG
// Per account settings flag(?)
notifyLogin.PlayerData.GuideData = GuideGroupTableReader.Instance.All.Select(x => (long)x.Id).ToList();
#endif

File diff suppressed because one or more lines are too long

View File

@@ -120,7 +120,7 @@ namespace AscNet.GameServer
#endif
}
log.Info("Finished Loading Packet Handlers");
log.Info("Finished loading packet handlers");
}
public static RequestPacketHandlerDelegate? GetRequestPacketHandler(string name)

View File

@@ -19,12 +19,16 @@ namespace AscNet.GameServer
}
}
public Server()
static Server()
{
// TODO: add loglevel based on appsettings
LogLevel logLevel = LogLevel.DEBUG;
LogLevel fileLogLevel = LogLevel.DEBUG;
log = new(typeof(Server), logLevel, fileLogLevel);
}
public Server()
{
listener = new(IPAddress.Parse("0.0.0.0"), Common.Common.config.GameServer.Port);
}
@@ -54,5 +58,10 @@ namespace AscNet.GameServer
}
}
}
public Session? SessionFromUID(long uid)
{
return Sessions.FirstOrDefault(x => x.Value.player.PlayerData.Id == uid).Value;
}
}
}