Allow custom categories for /cmd

This commit is contained in:
UnknownShadow200 2018-12-07 09:28:20 +11:00
parent 589050848a
commit 3d2441eb4f
5 changed files with 279 additions and 53 deletions

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{6AAEC8C6-6A45-4490-8A60-937F287E3D78}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Library</OutputType>
<RootNamespace>CmdPruneDB</RootNamespace>
<AssemblyName>CmdPruneDB</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<AppDesignerFolder>Properties</AppDesignerFolder>
<NoWin32Manifest>False</NoWin32Manifest>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<BaseAddress>4194304</BaseAddress>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>True</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="MyClass.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MCGalaxy\MCGalaxy_.csproj">
<Project>{12597DB0-7C34-4DE1-88EA-9250FF3372EB}</Project>
<Name>MCGalaxy_</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

147
CmdPruneDB/MyClass.cs Normal file
View File

@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.IO;
using MCGalaxy.DB;
using MCGalaxy.Maths;
using MCGalaxy.Util;
namespace MCGalaxy.Commands.Moderation {
public class CmdPruneDB : Command2 {
public override string name { get { return "PruneDB"; } }
public override string type { get { return CommandTypes.Moderation; } }
public override LevelPermission defaultRank { get { return LevelPermission.Admin; } }
public override bool SuperUseable { get { return false; } }
public unsafe override void Use(Player p, string message, CommandData data) {
if (message.Length == 0) { Player.Message(p, "You need to provide a player name."); return; }
string[] parts = message.SplitSpaces(), names = null;
int[] ids = GetIds(p, data, parts, out names);
if (ids == null) return;
TimeSpan delta = GetDelta(p, parts[0], parts, 1);
if (delta == TimeSpan.MinValue) return;
BlockDB db = p.level.BlockDB;
DateTime startTime = DateTime.UtcNow - delta;
Vec3U16 dims;
FastList<BlockDBEntry> entries = new FastList<BlockDBEntry>(4096);
byte[] bulk = new byte[BlockDBFile.BulkEntries * BlockDBFile.EntrySize];
int start = (int)((startTime - BlockDB.Epoch).TotalSeconds);
long total;
int changed = 0;
using (IDisposable locker = db.Locker.AccquireWrite()) {
if (!File.Exists(db.FilePath)) {
Player.Message(p, "BlockDB file for this map doesn't exist.");
return;
}
using (Stream src = OpenRead(db.FilePath), dst = OpenWrite(db.FilePath + ".tmp")) {
BlockDBFile format = BlockDBFile.ReadHeader(src, out dims);
BlockDBFile.WriteHeader(dst, dims);
total = format.CountEntries(src);
src.Position = src.Length;
fixed (byte* ptr = bulk) {
while (true) {
BlockDBEntry* entry = (BlockDBEntry*)ptr;
int count = format.ReadBackward(src, bulk, entry);
if (count == 0) break;
entry += (count - 1);
for (int i = count - 1; i >= 0; i--, entry--) {
if (entry->TimeDelta < start) goto finished;
for (int j = 0; j < ids.Length; j++) {
if (entry->PlayerID != ids[j]) continue;
changed++;
entries.Add(*entry);
if (entries.Count == 4096) {
format.WriteEntries(dst, entries);
entries.Count = 0;
}
}
}
}
}
finished:
// flush remaining few entries
if (entries.Count > 0) format.WriteEntries(dst, entries);
}
string namesStr = names.Join(name => PlayerInfo.GetColoredName(p, name));
if (changed > 0) {
File.Delete(db.FilePath);
File.Move(db.FilePath + ".tmp", db.FilePath);
p.Message("Pruned {2} changes by {1}%S's in the past &b{0} %S({3} entries left)",
delta.Shorten(true), namesStr, changed, total - changed);
} else {
File.Delete(db.FilePath + ".tmp");
p.Message("No changes found by {1} %Sin the past &b{0}",
delta.Shorten(true), namesStr);
}
}
}
// all this copy paste makes me sad
static FileStream OpenWrite(string path) {
return new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
}
static FileStream OpenRead(string path) {
return new FileStream(path, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite);
}
static int[] GetIds(Player p, CommandData data, string[] parts, out string[] names) {
int count = Math.Max(1, parts.Length - 1);
List<int> ids = new List<int>();
names = new string[count];
for (int i = 0; i < names.Length; i++) {
p.Message("Searching PlayerDB for \"{0}\"..", parts[i]);
names[i] = PlayerDB.MatchNames(p, parts[i]);
if (names[i] == null) return null;
if (!p.name.CaselessEq(names[i])) {
Group grp = Group.GroupIn(names[i]);
if (!CheckRank(p, data, grp.Permission, "undo", false)) return null;
}
ids.AddRange(NameConverter.FindIds(names[i]));
}
return ids.ToArray();
}
static TimeSpan GetDelta(Player p, string name, string[] parts, int offset) {
TimeSpan delta = TimeSpan.Zero;
string timespan = parts.Length > offset ? parts[parts.Length - 1] : "30m";
bool self = p.name.CaselessEq(name);
if (timespan.CaselessEq("all")) {
return self ? TimeSpan.FromSeconds(int.MaxValue) : p.group.MaxUndo;
} else if (!CommandParser.GetTimespan(p, timespan, ref delta, "undo the past", "s")) {
return TimeSpan.MinValue;
}
if (delta.TotalSeconds == 0)
delta = TimeSpan.FromMinutes(90);
if (!self && delta > p.group.MaxUndo) {
p.Message("{0}%Ss may only undo up to {1}",
p.group.ColoredName, p.group.MaxUndo.Shorten(true, true));
return p.group.MaxUndo;
}
return delta;
}
public override void Help(Player p) {
p.Message("%T/PruneDB [player1] <player2..> <timespan>");
p.Message("%HDeletes the block changes of [players] in the past <timespan> from BlockDB.");
p.Message("&cSlow and dangerous. Use with care.");
}
}
}

View File

@ -0,0 +1,31 @@
#region Using directives
using System;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CmdPruneDB")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CmdPruneDB")]
[assembly: AssemblyCopyright("Copyright 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// This sets the default COM visibility of types in the assembly to invisible.
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all the values or you can use the default the Revision and
// Build Numbers by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]

View File

@ -43,47 +43,21 @@ namespace MCGalaxy.Commands.Info {
}
}
switch (args[0].ToLower()) {
case "build":
case "building":
PrintHelpForGroup(p, sort, modifier, "build", "Building"); break;
case "chat":
PrintHelpForGroup(p, sort, modifier, "chat", "Chat"); break;
case "eco":
case "economy":
PrintHelpForGroup(p, sort, modifier, "eco", "Economy"); break;
case "mod":
case "moderation":
PrintHelpForGroup(p, sort, modifier, "mod", "Moderation"); break;
case "info":
case "information":
PrintHelpForGroup(p, sort, modifier, "info", "Information"); break;
case "game":
case "games":
PrintHelpForGroup(p, sort, modifier, "game", "Game"); break;
case "other":
case "others":
PrintHelpForGroup(p, sort, modifier, "other", "Other"); break;
case "maps":
case "world":
PrintHelpForGroup(p, sort, modifier, "world", "World"); break;
case "short":
case "shortcut":
case "shortcuts":
PrintShortcuts(p, sort); break;
case "old":
case "oldmenu":
case "command":
case "":
PrintRankCommands(p, sort, modifier, p.group, true); break;
case "commandsall":
case "commandall":
case "all":
PrintAllCommands(p, sort, modifier); break;
default:
Group grp = Group.Find(args[0]);
if (grp == null) return false;
PrintRankCommands(p, sort, modifier, grp, false); break;
string type = args[0].ToLower();
if (type == "short" || type == "shortcut" || type == "shortcuts") {
PrintShortcuts(p, sort);
} else if (type == "old" || type == "oldmenu" || type == "" || type == "command") {
PrintRankCommands(p, sort, modifier, p.group, true);
} else if (type == "all" || type == "commandall" || type == "commandsall") {
PrintAllCommands(p, sort, modifier);
} else {
bool any = PrintCategoryCommands(p, sort, modifier, type);
if (any) return true;
// list commands a rank can use
Group grp = Group.Find(type);
if (grp == null) return false;
PrintRankCommands(p, sort, modifier, grp, false);
}
return true;
}
@ -105,9 +79,7 @@ namespace MCGalaxy.Commands.Info {
List<Command> cmds = new List<Command>();
foreach (Command c in Command.allCmds) {
string disabled = Command.GetDisabledReason(c.Enabled);
if (disabled != null || c.name == null) continue;
if (!group.Commands.Contains(c)) continue;
cmds.Add(c);
if (disabled == null && group.Commands.Contains(c)) cmds.Add(c);
}
if (cmds.Count == 0) {
@ -140,29 +112,44 @@ namespace MCGalaxy.Commands.Info {
p.Message("Type %T/Help <command> %Sfor more help on a command.");
}
static void PrintHelpForGroup(Player p, string sort, string modifier,
string type, string category) {
static string GetCategory(string type) {
if (type.CaselessEq("building")) return CommandTypes.Building;
if (type.CaselessEq("eco")) return CommandTypes.Economy;
if (type.CaselessEq("games")) return CommandTypes.Games;
if (type.CaselessEq("info")) return CommandTypes.Information;
if (type.CaselessEq("moderation")) return CommandTypes.Moderation;
if (type.CaselessEq("others")) return CommandTypes.Other;
if (type.CaselessEq("maps")) return CommandTypes.World;
return type;
}
static bool PrintCategoryCommands(Player p, string sort, string modifier, string type) {
List<Command> cmds = new List<Command>();
string category = GetCategory(type);
bool any = false;
foreach (Command c in Command.allCmds) {
string disabled = Command.GetDisabledReason(c.Enabled);
if (p.CanUse(c) && disabled == null) {
if (!c.type.CaselessContains(type) || c.name == null) continue;
cmds.Add(c);
}
if (!c.type.CaselessContains(category)) continue;
if (disabled == null && p.CanUse(c)) cmds.Add(c);
any = true;
}
if (cmds.Count == 0) {
p.Message("You cannot use any of the " + category + " commands."); return;
p.Message("You cannot use any of the " + category + " commands."); return any;
}
SortCommands(cmds, sort);
p.Message(category + " commands you may use:");
type = "Commands " + category;
type = "Commands " + type;
if (sort.Length > 0) type += " " + sort;
MultiPageOutput.Output(p, cmds,
(cmd) => CmdHelp.GetColor(cmd) + cmd.name,
type, "commands", modifier, false);
p.Message("Type %T/Help <command> %Sfor more help on a command.");
return any;
}
static void SortCommands(List<Command> cmds, string sort) {

View File

@ -133,7 +133,7 @@ namespace MCGalaxy.Commands.World {
#region Help messages
static string[] blockPropsHelp = new string[] {
"%T/os blockprops [id] [action] <args> %H- Manages properties for custom blocks on your map.",
"%T/os blockprops [id] [action] <args> %H- Changes properties of blocks in your map.",
"%H See %T/Help blockprops %Hfor a list of actions",
};