public static string Help_GetCommandPage(GhostNetCommandEnv env, int page = 0) { const int pageSize = 8; string prefix = GhostNetModule.Settings.ServerCommandPrefix; StringBuilder builder = new StringBuilder(); int pages = (int)Math.Ceiling(env.Server.Commands.Count / (float)pageSize); if (page < 0 || pages <= page) { throw new Exception("Page out of range!"); } for (int i = page * pageSize; i < (page + 1) * pageSize && i < env.Server.Commands.Count; i++) { GhostNetCommand cmd = env.Server.Commands[i]; builder .Append(prefix) .Append(cmd.Name) .Append(" ") .Append(cmd.Args) .AppendLine(); } builder .Append("Page ") .Append(page + 1) .Append("/") .Append(pages); return(builder.ToString().Trim()); }
public static string Help_GetCommandSnippet(GhostNetCommandEnv env, string cmdName) { GhostNetCommand cmd = env.Server.GetCommand(cmdName); if (cmd == null) { throw new Exception($"Command {cmdName} not found!"); } return(Help_GetCommandSnippet(env, cmd)); }
public GhostNetCommand GetCommand(string cmdName) { cmdName = cmdName.ToLowerInvariant(); for (int i = 0; i < Commands.Count; i++) { GhostNetCommand cmd = Commands[i]; if (cmd.Name == cmdName) { return(cmd); } } return(null); }
public static string Help_GetCommandSnippet(GhostNetCommandEnv env, GhostNetCommand cmd) { string prefix = GhostNetModule.Settings.ServerCommandPrefix; StringBuilder builder = new StringBuilder(); builder .Append(prefix) .Append(cmd.Name) .Append(" ") .Append(cmd.Args) .AppendLine() .AppendLine(cmd.Help); return(builder.ToString().Trim()); }
protected virtual void RunCommandRaceChat(GhostNetCommand cmd, GhostNetCommandEnv env, GhostNetCommandArg[] args) { if (args.Length == 0 || string.IsNullOrWhiteSpace(args[0])) { return; } Race race = GetRace(env.PlayerID); if (race == null) { throw new Exception($"You're not in a race!"); } race.Send(env.Frame, args[0], id: env.MChat.ID); }
public void RegisterCommandsFromModule(EverestModule module) { foreach (Type type in module.GetType().Assembly.GetTypes()) { foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.Static)) { if (!typeof(GhostNetCommand).IsAssignableFrom(field.FieldType) || field.GetCustomAttribute <GhostNetCommandFieldAttribute>() == null) { continue; } GhostNetCommand cmd = field.GetValue(null) as GhostNetCommand; if (cmd == null) { continue; } Commands.Add(cmd); } } }
/// <summary> /// Parse everything as one argument and run the command. /// </summary> public static void Everything(GhostNetCommand cmd, GhostNetCommandEnv env) => cmd.Run(env, new GhostNetCommandArg(env).Parse(env.Text, GhostNetModule.Settings.ServerCommandPrefix.Length + cmd.Name.Length + 1));
protected virtual void RunCommandRace(GhostNetCommand cmd, GhostNetCommandEnv env, GhostNetCommandArg[] args) { if (args.Length == 0) { GhostNetCommandsStandard.Help.Run(env, new GhostNetCommandArg(env).Parse(cmd.Name, 0)); return; } Race race; switch (args[0]) { case "add": case "+": race = GetRace(env.PlayerID); if (race != null && race.Players[0] != env.PlayerID) { throw new Exception("You don't own the race!"); } if (race == null) { race = GetOrCreateRace(env.PlayerID); env.Send($"New race created: #{race.ID + 1}"); } if (race.HasStarted) { throw new Exception("The race has already started!"); } if (args.Length == 1) { // Add the area the player currently is in. if (string.IsNullOrEmpty(env.MPlayer.SID)) { throw new Exception("You can't add the menu to the race!"); } lock (race.Areas) { race.Areas.Add(Tuple.Create(env.MPlayer.SID, env.MPlayer.Mode)); } } else if (args.Length < 3) { throw new Exception("Not enough arguments!"); } else if (args.Length > 3) { throw new Exception("Too many arguments!"); } else { int mode = -1; if (args[2].Type == GhostNetCommandArg.EType.Int) { mode = args[2].Int - 1; } else if (args[2].String.Length == 1) { mode = args[2].String.ToLowerInvariant()[0] - 'a'; } if (mode < 0 || 2 < mode) { throw new Exception("Mode must be one of the following: a 1 b 2 c 3"); } string area = args[1].String; if (args[1].Type == GhostNetCommandArg.EType.Int) { ChunkRListAreas areas; env.Server.Request(env.Connection, out areas); if (areas == null) { throw new Exception("Your client didn't respond to the area list request!"); } if (args[1].Int < 1 || areas.Entries.Length < args[1].Int) { throw new Exception("Not a valid ID!"); } area = areas.Entries[args[1].Int - 1]; } lock (race.Areas) { race.Areas.Add(Tuple.Create(area, (AreaMode)mode)); } } env.Send(race.AreaList); return; case "remove": case "-": race = GetRace(env.PlayerID); if (race == null) { throw new Exception($"You're not in a race!"); } if (race.Players[0] != env.PlayerID) { throw new Exception("You don't own the race!"); } if (race.HasStarted) { throw new Exception("The race has already started!"); } if (args.Length < 2) { throw new Exception("Not enough arguments!"); } if (args.Length > 2) { throw new Exception("Too many arguments!"); } lock (race.Areas) { if (args[1].Type != GhostNetCommandArg.EType.Int || args[1].Int < 1 || race.Areas.Count < args[1].Int) { throw new Exception("Not a valid ID!"); } race.Areas.RemoveAt(args[1].Int - 1); } env.Send(race.AreaList); return; case "start": if (args.Length > 1) { throw new Exception("Too many arguments!"); } race = GetRace(env.PlayerID); if (race == null) { throw new Exception($"You're not in a race!"); } if (race.Players[0] != env.PlayerID) { throw new Exception("You don't own the race!"); } race.Start(); return; case "join": race = GetRace(env.PlayerID); if (race != null) { throw new Exception($"You're already in race #{race.ID}!"); } if (args.Length < 2) { throw new Exception("Not enough arguments!"); } if (args.Length > 2) { throw new Exception("Too many arguments!"); } if (args[1].Type != GhostNetCommandArg.EType.Int || args[1].Int < 1 || Races.Count < args[1].Int) { throw new Exception("Not a valid ID!"); } race = Races[args[1].Int - 1]; if (race == null) { throw new Exception("The race has already ended!"); } if (race.HasStarted) { throw new Exception("You're too late, the race has already started without you!"); } lock (race.Players) { race.Players.Add(env.PlayerID); } race.Send(null, $"{env.MPlayer.Name}#{env.HHead.PlayerID} joined."); return; case "leave": if (args.Length > 1) { throw new Exception("Too many arguments!"); } race = GetRace(env.PlayerID); if (race == null) { throw new Exception($"You're not in a race!"); } race.RemovePlayer(env.PlayerID, $"{env.MPlayer.Name}#{env.HHead.PlayerID} left."); return; case "list": if (args.Length > 1) { throw new Exception("Too many arguments!"); } race = GetRace(env.PlayerID); StringBuilder builder = new StringBuilder(); int count = 0; lock (Races) { for (int i = 0; i < Races.Count; i++) { Race raceListed = Races[i]; if (raceListed == null) { continue; } ChunkMPlayer owner; string ownerName = null; if (env.Server.PlayerMap.TryGetValue(raceListed.Players[0], out owner) && owner != null) { ownerName = owner.Name; } builder .Append(race == raceListed ? '>' : raceListed.HasStarted ? 'X' : '#') .Append(raceListed.ID + 1) .Append(" by ") .Append(string.IsNullOrEmpty(ownerName) ? "???" : ownerName) .AppendLine(); count++; } } builder.Append(count).Append(" race"); if (count != 1) { builder.Append('s'); } env.Send(builder.ToString().Trim()); return; case "areas": case "players": if (args.Length == 1) { race = GetRace(env.PlayerID); if (race == null) { throw new Exception($"You're not in a race!"); } } else if (args.Length > 2) { throw new Exception("Too many arguments!"); } else if (args[1].Type != GhostNetCommandArg.EType.Int || args[1].Int <= 0 || Races.Count < args[1].Int) { throw new Exception("Not a valid ID!"); } else { race = Races[args[1].Int - 1]; if (race == null) { throw new Exception("Race already ended!"); } } switch (args[0]) { case "areas": env.Send(race.AreaList); return; case "players": env.Send(race.PlayerList); return; default: throw new Exception($"Can't list {args[0]}!"); } default: throw new Exception($"Unknown subcommand {args[0]}!"); } }
public virtual void HandleMChat(GhostNetConnection con, GhostNetFrame frame) { ChunkMChat msg = frame; msg.Text = msg.Text.TrimEnd(); // Logger.Log(LogLevel.Info, "ghostnet-s", $"#{frame.HHead.PlayerID} said: {frame.MChat.Text}"); if (!msg.Logged) { lock (ChatLog) { msg.ID = (uint)ChatLog.Count; ChatLog.Add(msg); } } // Handle commands if necessary. if (msg.Text.StartsWith(GhostNetModule.Settings.ServerCommandPrefix)) { // Echo the chat chunk separately. msg.Color = GhostNetModule.Settings.ServerColorCommand; con.SendManagement(new GhostNetFrame { frame.HHead, msg }, true); GhostNetCommandEnv env = new GhostNetCommandEnv { Server = this, Connection = con, Frame = frame }; string prefix = GhostNetModule.Settings.ServerCommandPrefix; // TODO: This is basically a port of disbot-neo's Handler. string cmdName = env.Text.Substring(prefix.Length); cmdName = cmdName.Split(GhostNetCommand.CommandNameDelimiters)[0].ToLowerInvariant(); if (cmdName.Length == 0) { return; } GhostNetCommand cmd = GetCommand(cmdName); if (cmd != null) { GhostNetFrame cmdFrame = frame; Task.Run(() => { try { cmd.Parse(env); } catch (Exception e) { SendMChat(con, cmdFrame, $"Command {cmdName} failed: {e.Message}", color: GhostNetModule.Settings.ServerColorError, fillVars: false); if (e.GetType() != typeof(Exception)) { Logger.Log(LogLevel.Warn, "ghostnet-s", $"cmd failed: {env.Text}"); e.LogDetailed(); } } }); } else { SendMChat(con, frame, $"Command {cmdName} not found!", color: GhostNetModule.Settings.ServerColorError, fillVars: false); } return; } if (!msg.CreatedByServer) { msg.Text.Replace("\r", "").Replace("\n", ""); if (msg.Text.Length > GhostNetModule.Settings.ServerMaxChatTextLength) { msg.Text = msg.Text.Substring(0, GhostNetModule.Settings.ServerMaxChatTextLength); } msg.Tag = ""; msg.Color = Color.White; } msg.Date = DateTime.UtcNow; frame.PropagateM = true; }