diff --git a/modtools/build.gradle b/modtools/build.gradle new file mode 100644 index 0000000..3e9ebfc --- /dev/null +++ b/modtools/build.gradle @@ -0,0 +1,25 @@ +plugins { + id 'java-library' +} + +group 'me.jamestmartin' +version '0.1.0' + +sourceCompatibility = 8 + +repositories { + mavenCentral() + maven { url = 'https://oss.sonatype.org/content/repositories/snapshots' } + maven { + url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' + + content { + includeGroup 'org.bukkit' + includeGroup 'org.spigotmc' + } + } +} + +dependencies { + compileOnly 'org.spigotmc:spigot-api:1.16.4-R0.1-SNAPSHOT' +} \ No newline at end of file diff --git a/wasteland/src/main/java/me/jamestmartin/wasteland/manual/CommandManual.java b/modtools/src/main/java/me/jamestmartin/wasteland/manual/CommandManual.java similarity index 98% rename from wasteland/src/main/java/me/jamestmartin/wasteland/manual/CommandManual.java rename to modtools/src/main/java/me/jamestmartin/wasteland/manual/CommandManual.java index 0724deb..f7f3138 100644 --- a/wasteland/src/main/java/me/jamestmartin/wasteland/manual/CommandManual.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/manual/CommandManual.java @@ -6,6 +6,8 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import me.jamestmartin.wasteland.manual.config.ManualSection; + public class CommandManual implements CommandExecutor { private final String manualName; private final ManualSection manual; diff --git a/wasteland/src/main/java/me/jamestmartin/wasteland/manual/ManualState.java b/modtools/src/main/java/me/jamestmartin/wasteland/manual/ManualState.java similarity index 85% rename from wasteland/src/main/java/me/jamestmartin/wasteland/manual/ManualState.java rename to modtools/src/main/java/me/jamestmartin/wasteland/manual/ManualState.java index 43cc938..38e54df 100644 --- a/wasteland/src/main/java/me/jamestmartin/wasteland/manual/ManualState.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/manual/ManualState.java @@ -2,9 +2,9 @@ package me.jamestmartin.wasteland.manual; import org.bukkit.plugin.java.JavaPlugin; -import me.jamestmartin.wasteland.Substate; +import me.jamestmartin.wasteland.manual.config.ManualConfig; -public class ManualState implements Substate { +public class ManualState { private final CommandManual commandRules; private final CommandManual commandFaq; @@ -13,13 +13,11 @@ public class ManualState implements Substate { this.commandFaq = new CommandManual("faq", config.getFaq()); } - @Override public void register(JavaPlugin plugin) { plugin.getCommand("rules").setExecutor(commandRules); plugin.getCommand("faq").setExecutor(commandFaq); } - @Override public void unregister(JavaPlugin plugin) { plugin.getCommand("rules").setExecutor(null); plugin.getCommand("faq").setExecutor(null); diff --git a/wasteland/src/main/java/me/jamestmartin/wasteland/manual/ManualConfig.java b/modtools/src/main/java/me/jamestmartin/wasteland/manual/config/ManualConfig.java similarity index 88% rename from wasteland/src/main/java/me/jamestmartin/wasteland/manual/ManualConfig.java rename to modtools/src/main/java/me/jamestmartin/wasteland/manual/config/ManualConfig.java index 7349b24..6ba9a18 100644 --- a/wasteland/src/main/java/me/jamestmartin/wasteland/manual/ManualConfig.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/manual/config/ManualConfig.java @@ -1,4 +1,4 @@ -package me.jamestmartin.wasteland.manual; +package me.jamestmartin.wasteland.manual.config; public class ManualConfig { private final ManualSection rules; diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/manual/config/ManualConfigParser.java b/modtools/src/main/java/me/jamestmartin/wasteland/manual/config/ManualConfigParser.java new file mode 100644 index 0000000..78d233b --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/manual/config/ManualConfigParser.java @@ -0,0 +1,49 @@ +package me.jamestmartin.wasteland.manual.config; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.bukkit.configuration.ConfigurationSection; + +public class ManualConfigParser { + public static ManualConfig parse(ConfigurationSection c) { + ManualSection rules = new ManualSection( + "The Server Rules", + parseManualSectionList(castToSectionList(c.getMapList("rules")))); + ManualSection faq = new ManualSection( + "Frequently Asked Questions", + parseManualSectionList(castToSectionList(c.getMapList("faq")))); + return new ManualConfig(rules, faq); + } + + private static ManualSection parseManualSection(Map c) { + String summary = (String) c.get("summary"); + Optional details = Optional.ofNullable((String) c.get("details")); + List subsections = parseManualSectionList(castToSectionList(c.get("sections"))); + + return new ManualSection(summary, details, subsections); + } + + private static List> castToSectionList(Object x) { + if (x == null) { + return null; + } + return ((List) x).stream().map(xx -> (Map) xx).collect(Collectors.toUnmodifiableList()); + } + + public static List parseManualSectionList(List> list) { + List sections = new ArrayList<>(); + if (list == null) { + return sections; + } + + for (Map section : list) { + sections.add(parseManualSection(section)); + } + + return sections; + } +} diff --git a/wasteland/src/main/java/me/jamestmartin/wasteland/manual/ManualSection.java b/modtools/src/main/java/me/jamestmartin/wasteland/manual/config/ManualSection.java similarity index 98% rename from wasteland/src/main/java/me/jamestmartin/wasteland/manual/ManualSection.java rename to modtools/src/main/java/me/jamestmartin/wasteland/manual/config/ManualSection.java index 0671de1..49ef928 100644 --- a/wasteland/src/main/java/me/jamestmartin/wasteland/manual/ManualSection.java +++ b/modtools/src/main/java/me/jamestmartin/wasteland/manual/config/ManualSection.java @@ -1,4 +1,4 @@ -package me.jamestmartin.wasteland.manual; +package me.jamestmartin.wasteland.manual.config; import java.util.List; import java.util.Optional; diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/ModToolsState.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/ModToolsState.java new file mode 100644 index 0000000..dc77b8f --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/ModToolsState.java @@ -0,0 +1,96 @@ +package me.jamestmartin.wasteland.modtools; + +import org.bukkit.plugin.java.JavaPlugin; + +import me.jamestmartin.wasteland.manual.ManualState; +import me.jamestmartin.wasteland.modtools.commands.CommandBan; +import me.jamestmartin.wasteland.modtools.commands.CommandBans; +import me.jamestmartin.wasteland.modtools.commands.CommandInfractions; +import me.jamestmartin.wasteland.modtools.commands.CommandKick; +import me.jamestmartin.wasteland.modtools.commands.CommandMute; +import me.jamestmartin.wasteland.modtools.commands.CommandMutes; +import me.jamestmartin.wasteland.modtools.commands.CommandUnban; +import me.jamestmartin.wasteland.modtools.commands.CommandUnmute; +import me.jamestmartin.wasteland.modtools.commands.CommandWarn; +import me.jamestmartin.wasteland.modtools.config.ModToolsConfig; +import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; +import me.jamestmartin.wasteland.modtools.log.CommandModLog; +import me.jamestmartin.wasteland.offlineplayer.CommandLastSeen; +import me.jamestmartin.wasteland.offlineplayer.CommandUUID; + +class ModToolsState { + private final ManualState manualState; + + private final CommandBan commandBan; + private final CommandBans commandBans; + private final CommandInfractions commandInfractions; + private final CommandKick commandKick; + private final CommandLastSeen commandLastSeen; + private final CommandModLog commandModLog; + private final CommandMute commandMute; + private final CommandMutes commandMutes; + private final CommandUnban commandUnban; + private final CommandUnmute commandUnmute; + private final CommandUUID commandUUID; + private final CommandWarn commandWarn; + + public ModToolsState(ModToolsConfig config) { + this.manualState = new ManualState(config.getManuals()); + + // TODO + InfractionStore store = null; + + this.commandBan = new CommandBan(store, config.getDurations().getBansConfig()); + this.commandBans = new CommandBans(); + this.commandInfractions = new CommandInfractions(); + this.commandKick = new CommandKick(store); + this.commandLastSeen = new CommandLastSeen(); + this.commandModLog = new CommandModLog(); + this.commandMute = new CommandMute(store, config.getDurations().getMutesConfig()); + this.commandMutes = new CommandMutes(); + this.commandUnban = new CommandUnban(); + this.commandUnmute = new CommandUnmute(); + this.commandUUID = new CommandUUID(); + this.commandWarn = new CommandWarn(store); + } + + public void register(JavaPlugin plugin) { + manualState.register(plugin); + + plugin.getCommand("ban").setExecutor(commandBan); + plugin.getCommand("bans").setExecutor(commandBans); + plugin.getCommand("infractions").setExecutor(commandInfractions); + plugin.getCommand("kick").setExecutor(commandKick); + plugin.getCommand("lastseen").setExecutor(commandLastSeen); + plugin.getCommand("modlog").setExecutor(commandModLog); + plugin.getCommand("mute").setExecutor(commandMute); + plugin.getCommand("mutes").setExecutor(commandMutes); + plugin.getCommand("unban").setExecutor(commandUnban); + plugin.getCommand("unmute").setExecutor(commandUnmute); + plugin.getCommand("uuid").setExecutor(commandUUID); + plugin.getCommand("warn").setExecutor(commandWarn); + } + + public void unregister(JavaPlugin plugin) { + manualState.unregister(plugin); + + plugin.getCommand("ban").setExecutor(null); + plugin.getCommand("bans").setExecutor(null); + plugin.getCommand("infractions").setExecutor(null); + plugin.getCommand("kick").setExecutor(null); + plugin.getCommand("lastseen").setExecutor(null); + plugin.getCommand("modlog").setExecutor(null); + plugin.getCommand("mute").setExecutor(null); + plugin.getCommand("mutes").setExecutor(null); + plugin.getCommand("unban").setExecutor(null); + plugin.getCommand("unmute").setExecutor(null); + plugin.getCommand("uuid").setExecutor(null); + plugin.getCommand("warn").setExecutor(null); + + disable(plugin); + } + + public void disable(JavaPlugin plugin) { + + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/WastelandModTools.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/WastelandModTools.java new file mode 100644 index 0000000..8f3c865 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/WastelandModTools.java @@ -0,0 +1,53 @@ +package me.jamestmartin.wasteland.modtools; + +import org.bukkit.plugin.java.JavaPlugin; + +import me.jamestmartin.wasteland.modtools.commands.CommandWMT; +import me.jamestmartin.wasteland.modtools.config.ConfigParser; + +public class WastelandModTools extends JavaPlugin { + private static WastelandModTools instance; + + private ModToolsState state; + + public static WastelandModTools getInstance() { + return instance; + } + + @Override + public void onEnable() { + instance = this; + saveDefaultConfig(); + load(); + + // This command doesn't depend on any config, + // so we don't need to register/unregister it when we reload. + getCommand("wmt").setExecutor(new CommandWMT(this)); + } + + @Override + public void onDisable() { + state.disable(this); + instance = null; + } + + private void load() { + state = new ModToolsState(ConfigParser.parse(getConfig())); + state.register(this); + } + + private void unload() { + state.unregister(this); + state = null; + } + + public void reload() { + getLogger().info("Reloading..."); + saveDefaultConfig(); + reloadConfig(); + unload(); + load(); + getLogger().info("Done."); + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBan.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBan.java new file mode 100644 index 0000000..c1dff67 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBan.java @@ -0,0 +1,29 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import me.jamestmartin.wasteland.modtools.config.DurationsConfig; +import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; +import me.jamestmartin.wasteland.modtools.infraction.InfractionType; + +public class CommandBan extends CommandIssueInfraction { + public CommandBan(InfractionStore store, DurationsConfig durations) { + super(store, durations); + } + + @Override + protected InfractionType getType() { + return InfractionType.BAN; + } + + @Override + protected void applyInfraction(CommandSender sender, Infraction infraction) { + Player recipient = infraction.getRecipient().getPlayer(); + if (recipient != null) { + recipient.kickPlayer(infraction.getMessage()); + } + sender.sendMessage(infraction.getRecipient().getName() + " has been banned for " + infraction.getDuration().toStringLong() + "."); + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBans.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBans.java new file mode 100644 index 0000000..f74b620 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandBans.java @@ -0,0 +1,15 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public class CommandBans implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandInfractions.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandInfractions.java new file mode 100644 index 0000000..ff5d5b5 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandInfractions.java @@ -0,0 +1,15 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public class CommandInfractions implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandIssueInfraction.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandIssueInfraction.java new file mode 100644 index 0000000..dd2b404 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandIssueInfraction.java @@ -0,0 +1,72 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import java.util.Optional; + +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import me.jamestmartin.wasteland.modtools.config.DurationsConfig; +import me.jamestmartin.wasteland.modtools.infraction.Duration; +import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; +import me.jamestmartin.wasteland.modtools.infraction.InfractionType; + +abstract class CommandIssueInfraction implements CommandExecutor { + protected final InfractionStore store; + protected final DurationsConfig durations; + + public CommandIssueInfraction(InfractionStore store, DurationsConfig durations) { + this.store = store; + this.durations = durations; + } + + public CommandIssueInfraction(InfractionStore store) { + if (getType().hasDuration()) { + throw new IllegalArgumentException("Must pass durations for infraction type which has duration"); + } + this.store = store; + this.durations = null; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + Duration maxDuration = durations != null ? durations.getMaximumBanDuration(sender) : Duration.INFINITY; + if (maxDuration.getSeconds().map(x -> x == 0).orElse(false)) { + sender.sendMessage("You have permission to issue infractions, but can only issue infractions of duration 0!"); + sender.sendMessage("No infraction will be issued."); + return true; + } + + Player issuer = sender instanceof Player ? (Player) sender : null; + Optional maybe = parseArgs(getType(), issuer, args); + if (maybe.isEmpty()) { + // TOOD: better error messages + sender.sendMessage("Invalid syntax."); + return false; + } + Infraction infraction = maybe.get(); + + if (infraction.getDuration().compareTo(maxDuration) == 1) { + sender.sendMessage("You are not allowed you issue an infraction of duration " + infraction.getDuration() + "."); + sender.sendMessage("The maximum infraction duration you can issue is " + maxDuration + "."); + sender.sendMessage("No infraction will be issued."); + return true; + } + + applyInfraction(sender, infraction); + store.addInfraction(infraction); + return false; + } + + protected abstract InfractionType getType(); + + protected abstract void applyInfraction(CommandSender sender, Infraction infraction); + + private static Optional parseArgs(InfractionType type, OfflinePlayer issuer, String[] args) { + // TODO + return null; + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandKick.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandKick.java new file mode 100644 index 0000000..c494ed6 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandKick.java @@ -0,0 +1,31 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; +import me.jamestmartin.wasteland.modtools.infraction.InfractionType; + +public class CommandKick extends CommandIssueInfraction { + public CommandKick(InfractionStore store) { + super(store); + } + + @Override + protected InfractionType getType() { + return InfractionType.KICK; + } + + @Override + protected void applyInfraction(CommandSender sender, Infraction infraction) { + Player player = infraction.getRecipient().getPlayer(); + if (player == null) { + sender.sendMessage("That player is not online!"); + sender.sendMessage("Infraction logged anyway."); + return; + } + + player.kickPlayer(infraction.getMessage()); + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMute.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMute.java new file mode 100644 index 0000000..bd00b22 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMute.java @@ -0,0 +1,30 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import me.jamestmartin.wasteland.modtools.config.DurationsConfig; +import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; +import me.jamestmartin.wasteland.modtools.infraction.InfractionType; + +public class CommandMute extends CommandIssueInfraction { + public CommandMute(InfractionStore store, DurationsConfig durations) { + super(store, durations); + } + + @Override + protected InfractionType getType() { + return InfractionType.MUTE; + } + + @Override + protected void applyInfraction(CommandSender sender, Infraction infraction) { + Player player = infraction.getRecipient().getPlayer(); + if (player != null) { + player.sendMessage(infraction.getMessage()); + } + + sender.sendMessage(infraction.getRecipient().getName() + " has been muted for " + infraction.getDuration().toStringLong() + "."); + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMutes.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMutes.java new file mode 100644 index 0000000..e1b9597 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandMutes.java @@ -0,0 +1,15 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public class CommandMutes implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandRemoveInfraction.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandRemoveInfraction.java new file mode 100644 index 0000000..19cfdcf --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandRemoveInfraction.java @@ -0,0 +1,46 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import java.util.Optional; + +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; +import me.jamestmartin.wasteland.modtools.infraction.InfractionType; + +public abstract class CommandRemoveInfraction implements CommandExecutor { + protected final InfractionStore store; + + public CommandRemoveInfraction(InfractionStore store) { + this.store = store; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + Player issuer = sender instanceof Player ? (Player) sender : null; + Optional maybe = parseArgs(getType(), issuer, args); + if (maybe.isEmpty()) { + // TOOD: better error messages + sender.sendMessage("Invalid syntax."); + return false; + } + Infraction infraction = maybe.get(); + + applyInfraction(sender, infraction); + store.addInfraction(infraction); + return false; + } + + protected abstract InfractionType getType(); + + protected abstract void applyInfraction(CommandSender sender, Infraction infraction); + + private static Optional parseArgs(InfractionType type, OfflinePlayer issuer, String[] args) { + // TODO + return null; + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnban.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnban.java new file mode 100644 index 0000000..499261b --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnban.java @@ -0,0 +1,15 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public class CommandUnban implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnmute.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnmute.java new file mode 100644 index 0000000..d85337b --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandUnmute.java @@ -0,0 +1,15 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public class CommandUnmute implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandWMT.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandWMT.java new file mode 100644 index 0000000..41aa41f --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandWMT.java @@ -0,0 +1,44 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +import me.jamestmartin.wasteland.modtools.WastelandModTools; + +public class CommandWMT implements CommandExecutor { + private final WastelandModTools instance; + + public CommandWMT(WastelandModTools instance) { + this.instance = instance; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (args.length < 1) { + sender.sendMessage("Not enough arguments."); + return false; + } + + if (args.length > 1) { + sender.sendMessage("Too many arguments."); + return false; + } + + if (!args[0].equals("reload")) { + sender.sendMessage("Unknown subcommand: " + args[0]); + return false; + } + + if (!sender.hasPermission("wasteland.modtools.reload")) { + sender.sendMessage("You do not have permission to reload Wasteland ModTools."); + } + + sender.sendMessage("Reloading..."); + instance.reload(); + sender.sendMessage("Done."); + + return true; + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandWarn.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandWarn.java new file mode 100644 index 0000000..c8ad5f5 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/commands/CommandWarn.java @@ -0,0 +1,29 @@ +package me.jamestmartin.wasteland.modtools.commands; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.InfractionStore; +import me.jamestmartin.wasteland.modtools.infraction.InfractionType; + +public class CommandWarn extends CommandIssueInfraction { + public CommandWarn(InfractionStore store) { + super(store); + } + + @Override + protected InfractionType getType() { + return InfractionType.WARN; + } + + @Override + protected void applyInfraction(CommandSender sender, Infraction infraction) { + Player player = infraction.getRecipient().getPlayer(); + if (player != null) { + player.sendMessage(infraction.getMessage()); + } + + sender.sendMessage(infraction.getRecipient().getName() + " has been warned."); + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/ConfigParser.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/ConfigParser.java new file mode 100644 index 0000000..47febe1 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/ConfigParser.java @@ -0,0 +1,48 @@ +package me.jamestmartin.wasteland.modtools.config; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.bukkit.configuration.ConfigurationSection; + +import me.jamestmartin.wasteland.manual.config.ManualConfig; +import me.jamestmartin.wasteland.manual.config.ManualConfigParser; +import me.jamestmartin.wasteland.modtools.infraction.Duration; + +public class ConfigParser { + public static ModToolsConfig parse(ConfigurationSection c) { + ManualConfig manualConfig = ManualConfigParser.parse(c.getConfigurationSection("manuals")); + DurationsConfigs durationsConfig = parseDurationsConfig(c.getConfigurationSection("permissions")); + + return new ModToolsConfig(manualConfig, durationsConfig); + } + + private static DurationsConfigs parseDurationsConfig(ConfigurationSection c) { + Map maximumBans = new HashMap<>(); + Map maximumMutes = new HashMap<>(); + + if (c.isString("ban")) { + maximumBans.put("", Duration.parse(c.getString("ban")).get()); + } + if (c.isString("mute")) { + maximumMutes.put("", Duration.parse(c.getString("mute")).get()); + } + + for (String key : c.getKeys(false)) { + if (c.isString(key)) { + continue; + } + + DurationsConfigs sub = parseDurationsConfig(c.getConfigurationSection(key)); + for (Entry ban : sub.getBansConfig().getMaximumDurations().entrySet()) { + maximumBans.put(key + "." + ban.getKey(), ban.getValue()); + } + for (Entry mute : sub.getMutesConfig().getMaximumDurations().entrySet()) { + maximumMutes.put(key + "." + mute.getKey(), mute.getValue()); + } + } + + return new DurationsConfigs(new DurationsConfig(maximumBans), new DurationsConfig(maximumMutes)); + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/DurationsConfig.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/DurationsConfig.java new file mode 100644 index 0000000..b63f95e --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/DurationsConfig.java @@ -0,0 +1,29 @@ +package me.jamestmartin.wasteland.modtools.config; + +import java.util.Map; + +import org.bukkit.command.CommandSender; + +import me.jamestmartin.wasteland.modtools.infraction.Duration; + +public class DurationsConfig { + private final Map maxima; + + public DurationsConfig(Map maxima) { + this.maxima = maxima; + } + + public Map getMaximumDurations() { + return maxima; + } + + public Duration getMaximumBanDuration(CommandSender moderator) { + Duration duration = maxima.getOrDefault("default", Duration.ZERO); + for (String perm : maxima.keySet()) { + if (moderator.hasPermission(perm)) { + duration = duration.max(maxima.get(perm)); + } + } + return duration; + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/DurationsConfigs.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/DurationsConfigs.java new file mode 100644 index 0000000..98a5461 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/DurationsConfigs.java @@ -0,0 +1,19 @@ +package me.jamestmartin.wasteland.modtools.config; + +public class DurationsConfigs { + private final DurationsConfig bansConfig; + private final DurationsConfig mutesConfig; + + public DurationsConfigs(DurationsConfig bansConfig, DurationsConfig mutesConfig) { + this.bansConfig = bansConfig; + this.mutesConfig = mutesConfig; + } + + public DurationsConfig getBansConfig() { + return bansConfig; + } + + public DurationsConfig getMutesConfig() { + return mutesConfig; + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/ModToolsConfig.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/ModToolsConfig.java new file mode 100644 index 0000000..623056a --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/config/ModToolsConfig.java @@ -0,0 +1,21 @@ +package me.jamestmartin.wasteland.modtools.config; + +import me.jamestmartin.wasteland.manual.config.ManualConfig; + +public class ModToolsConfig { + private final ManualConfig manuals; + private final DurationsConfigs durations; + + public ModToolsConfig(ManualConfig manuals, DurationsConfigs durations) { + this.manuals = manuals; + this.durations = durations; + } + + public ManualConfig getManuals() { + return manuals; + } + + public DurationsConfigs getDurations() { + return durations; + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Duration.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Duration.java new file mode 100644 index 0000000..fdff271 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Duration.java @@ -0,0 +1,173 @@ +package me.jamestmartin.wasteland.modtools.infraction; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +public class Duration implements Comparable { + public static final Duration ZERO = new Duration(0); + public static final Duration INFINITY = new Duration(); + + /** Durations of "none" are infinite. */ + private final Optional seconds; + + private Duration() { + this.seconds = Optional.empty(); + } + + private Duration(Optional seconds) { + this.seconds = seconds; + } + + public Duration(long seconds) { + this.seconds = Optional.of(seconds); + } + + public Optional getSeconds() { + return seconds; + } + + public Duration max(Duration other) { + return new Duration(this.seconds.flatMap(x -> other.seconds.map(y -> Math.max(x, y)))); + } + + public static Optional parse(String str) { + if (str.equals("0")) { + return Optional.of(ZERO); + } + if (str.equals("forever")) { + return Optional.of(INFINITY); + } + return DurationParts.parse(str).map(DurationParts::toDuration); + } + + private Optional toParts() { + if (seconds.isEmpty()) { + return Optional.empty(); + } + long secs = seconds.get(); + + // Find the greatest prefix that gives an exact value. + List suffixes = List.of(DurationSuffix.values()); + Collections.reverse(suffixes); + DurationSuffix s = null; + for (DurationSuffix suffix : suffixes) { + if (secs % suffix.getSeconds() == 0) { + s = suffix; + } + } + + return Optional.of(new DurationParts(secs / s.getSeconds(), s)); + } + + @Override + public String toString() { + return toParts().map(DurationParts::toString).orElse("forever"); + } + + public String toStringLong() { + return toParts().map(DurationParts::toStringLong).orElse("forever"); + } + + private static class DurationParts { + public final long value; + public final DurationSuffix suffix; + + public DurationParts(long value, DurationSuffix suffix) { + this.value = value; + this.suffix = suffix; + } + + public Duration toDuration() { + return new Duration(value * suffix.getSeconds()); + } + + @Override + public String toString() { + return value + suffix.toString(); + } + + public String toStringLong() { + return value + " " + suffix.toStingLong(); + } + + public static Optional parse(String str) { + if (str.length() < 2) { + return Optional.empty(); + } + + Optional suffix = DurationSuffix.fromChar(str.charAt(str.length() - 1)); + if (suffix.isEmpty()) { + return Optional.empty(); + } + + String valueStr = str.substring(0, str.length() - 1); + if (!valueStr.matches("\\d+")) { + return Optional.empty(); + } + + return Optional.of(new DurationParts(Long.parseLong(valueStr), suffix.get())); + } + } + + private static enum DurationSuffix { + SECONDS('s', "seconds", 1), + MINUTES('m', "minutes", 60), + HOURS('h', "hours", 3600), + DAYS('d', "days", 86400), + WEEKS('w', "weeks", 604800), + MONTHS('M', "months", 2628000), + YEARS('y', "years", 31540000); + + private final char character; + private final String longName; + private final long seconds; + + private DurationSuffix(char character, String longName, long seconds) { + this.character = character; + this.longName = longName; + this.seconds = seconds; + } + + public long getSeconds() { + return seconds; + } + + public char toChar() { + return character; + } + + @Override + public String toString() { + return String.valueOf(toChar()); + } + + public String toStingLong() { + return longName; + } + + public static Optional fromChar(char c) { + for (DurationSuffix suffix : DurationSuffix.values()) { + if (suffix.character == c) { + return Optional.of(suffix); + } + } + return Optional.empty(); + } + } + + @Override + public int compareTo(Duration other) { + if (getSeconds().isEmpty() && other.getSeconds().isEmpty()) { + return 0; + } + if (getSeconds().isEmpty()) { + return 1; + } + if (other.getSeconds().isEmpty()) { + return -1; + } + + return Long.compare(getSeconds().get(), other.getSeconds().get()); + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Infraction.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Infraction.java new file mode 100644 index 0000000..649085e --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/Infraction.java @@ -0,0 +1,58 @@ +package me.jamestmartin.wasteland.modtools.infraction; + +import java.util.Date; + +import org.bukkit.OfflinePlayer; + +public class Infraction { + private final InfractionType type; + private final OfflinePlayer issuer; + private final OfflinePlayer recipient; + private final Date issued; + private final Duration duration; + private final String rule; + private final String reason; + + public Infraction(InfractionType type, OfflinePlayer issuer, OfflinePlayer recipient, Date issued, Duration duration, String rule, String reason) { + this.type = type; + this.issuer = issuer; + this.recipient = recipient; + this.issued = issued; + this.duration = duration; + this.rule = rule; + this.reason = reason; + } + + public InfractionType getType() { + return type; + } + + public OfflinePlayer getIssuer() { + return issuer; + } + + public OfflinePlayer getRecipient() { + return recipient; + } + + public Date getIssued() { + return issued; + } + + public Duration getDuration() { + return duration; + } + + public String getRule() { + return rule; + } + + public String getReason() { + return reason; + } + + public String getMessage() { + // TODO + return null; + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionProvider.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionProvider.java new file mode 100644 index 0000000..663e656 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionProvider.java @@ -0,0 +1,25 @@ +package me.jamestmartin.wasteland.modtools.infraction; + +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +public interface InfractionProvider { + Set getActiveInfractions(Optional player, Optional type); + + default Set getActiveInfractions() { + return getActiveInfractions(Optional.empty(), Optional.empty()); + } + + default Set getActiveInfractions(UUID player) { + return getActiveInfractions(Optional.of(player), Optional.empty()); + } + + default Set getActiveInfractions(UUID player, InfractionType type) { + return getActiveInfractions(Optional.of(player), Optional.of(type)); + } + + default Set getActiveInfractions(InfractionType type) { + return getActiveInfractions(Optional.empty(), Optional.of(type)); + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionStore.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionStore.java new file mode 100644 index 0000000..e250704 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionStore.java @@ -0,0 +1,8 @@ +package me.jamestmartin.wasteland.modtools.infraction; + +import org.bukkit.OfflinePlayer; + +public interface InfractionStore extends InfractionProvider { + void addInfraction(Infraction infraction); + void removeInfractions(OfflinePlayer player, InfractionType type); +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionType.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionType.java new file mode 100644 index 0000000..d5e746b --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/infraction/InfractionType.java @@ -0,0 +1,18 @@ +package me.jamestmartin.wasteland.modtools.infraction; + +public enum InfractionType { + BAN(true), + KICK(false), + MUTE(true), + WARN(false); + + private final boolean hasduration; + + private InfractionType(boolean hasDuration) { + this.hasduration = hasDuration; + } + + public boolean hasDuration() { + return hasduration; + } +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/CommandModLog.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/CommandModLog.java new file mode 100644 index 0000000..a2fffc3 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/CommandModLog.java @@ -0,0 +1,15 @@ +package me.jamestmartin.wasteland.modtools.log; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public class CommandModLog implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogProvider.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogProvider.java new file mode 100644 index 0000000..1e8d870 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogProvider.java @@ -0,0 +1,67 @@ +package me.jamestmartin.wasteland.modtools.log; + +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +import me.jamestmartin.wasteland.modtools.infraction.Duration; +import me.jamestmartin.wasteland.modtools.infraction.Infraction; +import me.jamestmartin.wasteland.modtools.infraction.InfractionType; + +public interface ModLogProvider { + Set getInfractions( + Duration duration, + Optional issuer, + Optional recipient, + Optional type + ); + + default Set getInfractions() { + return getInfractions(Duration.INFINITY); + } + + default Set getInfractions(InfractionType type) { + return getInfractions(Duration.INFINITY, type); + } + + default Set getInfractions(Duration duration) { + return getInfractions(duration, Optional.empty(), Optional.empty(), Optional.empty()); + } + + default Set getInfractions(Duration duration, InfractionType type) { + return getInfractions(duration, Optional.empty(), Optional.empty(), Optional.of(type)); + } + + default Set getInfractionsIssuedTo(UUID player) { + return getInfractionsIssuedTo(Duration.INFINITY, player); + } + + default Set getInfractionsIssuedTo(UUID player, InfractionType type) { + return getInfractionsIssuedTo(Duration.INFINITY, player, type); + } + + default Set getInfractionsIssuedTo(Duration duration, UUID player) { + return getInfractions(duration, Optional.empty(), Optional.of(player), Optional.empty()); + } + + default Set getInfractionsIssuedTo(Duration duration, UUID player, InfractionType type) { + return getInfractions(duration, Optional.empty(), Optional.of(player), Optional.of(type)); + } + + default Set getInfractionsIssuedBy(UUID player) { + return getInfractionsIssuedBy(Duration.INFINITY, player); + } + + default Set getInfractionsIssuedBy(UUID player, InfractionType type) { + return getInfractionsIssuedBy(Duration.INFINITY, player, type); + } + + default Set getInfractionsIssuedBy(Duration duration, UUID player) { + return getInfractions(duration, Optional.of(player), Optional.empty(), Optional.empty()); + } + + default Set getInfractionsIssuedBy(Duration duration, UUID player, InfractionType type) { + return getInfractions(duration, Optional.of(player), Optional.empty(), Optional.of(type)); + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogStore.java b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogStore.java new file mode 100644 index 0000000..a2c53c9 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/modtools/log/ModLogStore.java @@ -0,0 +1,7 @@ +package me.jamestmartin.wasteland.modtools.log; + +import me.jamestmartin.wasteland.modtools.infraction.Infraction; + +public interface ModLogStore extends ModLogProvider { + void addInfraction(Infraction infraction); +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/CommandLastSeen.java b/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/CommandLastSeen.java new file mode 100644 index 0000000..d9b22d5 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/CommandLastSeen.java @@ -0,0 +1,15 @@ +package me.jamestmartin.wasteland.offlineplayer; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public class CommandLastSeen implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/CommandUUID.java b/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/CommandUUID.java new file mode 100644 index 0000000..f6b6dc1 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/CommandUUID.java @@ -0,0 +1,15 @@ +package me.jamestmartin.wasteland.offlineplayer; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public class CommandUUID implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/OfflinePlayerProvider.java b/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/OfflinePlayerProvider.java new file mode 100644 index 0000000..ca99cc1 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/OfflinePlayerProvider.java @@ -0,0 +1,11 @@ +package me.jamestmartin.wasteland.offlineplayer; + +import java.util.Date; +import java.util.Map; +import java.util.UUID; + +public interface OfflinePlayerProvider { + Map getNameUUIDs(String playerName); + Date getFirstSeen(UUID player); + Date getLastSeen(UUID player); +} diff --git a/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/OfflinePlayerStore.java b/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/OfflinePlayerStore.java new file mode 100644 index 0000000..c8f17a2 --- /dev/null +++ b/modtools/src/main/java/me/jamestmartin/wasteland/offlineplayer/OfflinePlayerStore.java @@ -0,0 +1,7 @@ +package me.jamestmartin.wasteland.offlineplayer; + +import org.bukkit.entity.Player; + +public interface OfflinePlayerStore extends OfflinePlayerProvider { + void logPlayer(Player player); +} diff --git a/modtools/src/main/resources/config.yml b/modtools/src/main/resources/config.yml new file mode 100644 index 0000000..57305d7 --- /dev/null +++ b/modtools/src/main/resources/config.yml @@ -0,0 +1,69 @@ +manuals: + rules: + - summary: Be civil and respectful. + sections: + - summary: If you start getting angry or frustrated, take a break! + - summary: Do not harass other players. + - summary: Do not use slurs. + - summary: Do not advertise. + - summary: Do not spam. + - summary: Avoid excessive swearing. + details: 'What is "excessive" is determined by moderator discretion.' + - summary: Be independent and mature. + sections: + - summary: This is a server intended for adults. + details: You will not be banned for being <16 per se, but acting like a child will get you banned no matter how old you are. + - summary: RTFM (Read The Field Manual). + details: Try to answer questions for yourself (e.g. with `/faq`) before asking them. + - summary: Do not whine or beg. + - summary: Do not ask moderators to cheat. + details: They don't have the ability to, anyway. + - summary: Play fairly. + sections: + - summary: Do not use hacks. + details: Hacks are the use of a client or mod designed for cheating. + - summary: Do not use exploits. + details: Exploits are the use of bugs to gain an unfair advantage (e.g. item duplication) or e.g. bypass protection plugins. + - summary: Do not use cheats. + details: Do not use x-ray resource packs or any other form of cheating. + - summary: Use your power appropriately. + details: Use moderator tools and ranks strictly for their intended purpose. + - summary: Only use authorized mods. + details: Refer to the authorized mods list to see which mods are permitted. If you'd like to use a mod not on that list, you **must ask the administrator(s)** before using it. + - summary: Stick to the game. + sections: + - summary: Keep the chat SFW. + - summary: Avoid discussing politics, religion, and the news. + details: This is not strictly forbidden, but these discussions may be shut down by moderator discretion. + - summary: Do not ask for personal information. + details: This includes real name, age, and location. + - summary: Do not share anyone else's personal information. + details: This includes their real name, age, and location. + - summary: Avoid sharing your own personal information. + details: You may share your own real name, age, or location, but not e.g. your address or phone number. + + faq: + - summary: Nothing to see here. + details: The server administrator has not set an FAQ. + +# Set the maximum durations for which moderators are allowed to mute or ban, +# based on their permission nodes. +permissions: + # The default durations for people with permission to mute/ban, but with no specific duration permission set. + # Set this to 0 if you want to require a more specific permission be to set to allow mutes and bans. + wasteland.modtools.ban.issue: + ban: forever + wasteland.modtools.mute.issue: + mute: forever + # You will not want to leave this section here if you will not be using Wasteland's rank system, + # or don't intend to use the officer rank system for staff ranks. + wasteland.rank: + ltcol: + mute: 3h + ban: 3h + col: + mute: 3d + ban: 3d + bgen: + mute: forever + ban: forever \ No newline at end of file diff --git a/modtools/src/main/resources/plugin.yml b/modtools/src/main/resources/plugin.yml new file mode 100644 index 0000000..f172d65 --- /dev/null +++ b/modtools/src/main/resources/plugin.yml @@ -0,0 +1,193 @@ +name: WastelandModTools +author: HuskFodder +main: me.jamestmartin.wasteland.modtools.WastelandModTools +version: 0.1.0 +api-version: 1.16 + +commands: + modlog: + description: See the list of recent actions taken by moderators. + usage: "Usage: / []" + permission: wasteland.modtools.log + permission-message: You do not have permission to view the moderator log. + infractions: + description: See the list of infractions against the rules a player has committed. + usage: "Usage: / []" + permission: wasteland.modtools.infractions + permission-message: You do not have permission to view players' infractions against the rules. + + uuid: + description: Get the UUID(s) of players who have had a name on this server. + usage: "Usage: / " + permission: wasteland.modtools.uuid + permission-message: You do not have permission to view player UUIDs. + lastseen: + description: Get the last time the player with that name or UUID was seen. + usage: "Usage: / " + permission: wasteland.modtools.lastseen + permission-message: You do not have permission to view when a player was last seen. + + rules: + description: "Read the server rules. You can view more information about a specific rule using `/rules #`." + usage: "Usage: / [
] []" + permission: wasteland.manual.rules + permission-message: You do not have permission to read the server rules. + faq: + description: "Read the server FAQ. You can view more information about a specific topic using `/faq #`." + usage: "Usage: / [
] []" + permission: wasteland.manual.faq + permission-message: You do not have permission to read the server FAQ. + + ban: + description: Ban a player from the server, preventing them from joining again. + usage: "Usage: / [] [ ...]" + permission: wasteland.modtools.ban.issue + permission-message: You do not have permission to ban players. + unban: + description: Unban a player, allowing them to join again. + usage: "Usage: / [ ...]" + permission: wasteland.modtools.ban.pardon + permission-message: You do not have permission to unban players. + bans: + description: See the list of all players currently banned from the server. + usage: "Usage: / []" + permission: wasteland.modtools.ban.list + permission-message: You do not have permission to list banned players. + + kick: + description: Kick a player from the server. + usage: "Usage: / [] [ ...]" + permission: wasteland.modtools.kick + permission-message: You do not have permission to kick players. + + mute: + description: Mute a player, preventing them from talking. + usage: "Usage: / [] [ ...]" + permission: wasteland.modtools.mute.issue + permission-message: You do not have permission to mute players. + unmute: + description: Unmute a player, allowing them to talk again. + usage: "Usage: / [ ...]" + permission: wasteland.modtools.mute.pardon + permission-message: You do not have permission to unmute players. + mutes: + description: See the list of all players currently muted on the server. + usage: "Usage: / []" + permission: wasteland.modtools.mutes.list + permission-message: You do not have permission to list muted players. + + warn: + description: Give a player an official (logged) warning. + usage: "Usage: / [] [ ...]" + permission: wasteland.modtools.warn + permission-message: You do not have permission to issue warnings to players. + +permissions: + wasteland.modtools: + description: Allows you full access to the moderator tools. + default: op + children: + wasteland.modtools.uuid: true + wasteland.modtools.lastseen: true + wasteland.modtools.log: true + wasteland.modtools.actions: true + + wasteland.modtools.log: + description: Allows you to view the log of moderator actions. + default: op + children: + wasteland.modtools.infractions: true + wasteland.modtools.ban.list: true + wasteland.modtools.mute.list: true + wasteland.modtools.warn.list: true + wasteland.modtools.infractions: + description: Allows you to see the list of infractions against the rules a player has committed. + default: op + + wasteland.modtools.uuid: + description: Allows you to see the UUIDs of players with a given name on this server. + default: op + wasteland.modtools.lastseen: + description: Allows you to see the first and last time a player was seen on this server. + default: op + + wasteland.modtools.actions: + description: Allows you to perform any moderator action. + default: op + children: + wasteland.manual.show-other: true + wasteland.modtools.ban: true + wasteland.modtools.kick: true + wasteland.modtools.mute: true + wasteland.modtools.warn: true + + wasteland.manual: + description: Allows you to read any manual. + default: op + children: + wasteland.manual.rules: true + wasteland.manual.faq: true + wasteland.manual.show-other: + description: Allows you to forcibly show any manual to someone else. + default: op + children: + wasteland.manual.rules.show-other: true + wasteland.manual.faq.show-other: true + wasteland.manual.rules: + description: Allows you to read the server rules. + default: true + wasteland.manual.rules.show-other: + description: Allows you to forcibly show the server rules to someone else. + default: op + children: + wasteland.manual.rules: true + wasteland.manual.faq: + description: Allows you to read the FAQ. + default: true + wasteland.manual.faq.show-other: + description: Allows you to forcibly show the FAQ to someone else. + default: op + children: + wasteland.manual.faq: true + + wasteland.modtools.ban: + description: Allows you to ban or unban a player, or list active bans. + default: op + children: + wasteland.modtools.ban.issue: true + wasteland.modtools.ban.list: true + wasteland.modtools.ban.pardon: true + wasteland.modtools.ban.issue: + description: Allows you to issue bans. + default: op + wasteland.modtools.ban.list: + description: Allows you to list all active bans. + default: op + wasteland.modtools.ban.pardon: + description: Allows you to remove bans. + default: op + + wasteland.modtools.kick: + desription: Allows you to kick players. + default: op + + wasteland.modtools.mute: + description: Allows you to mute or unmute a player, or list active mutes. + default: op + children: + wasteland.modtools.mute.issue: true + wasteland.modtools.mute.list: true + wasteland.modtools.mute.pardon: true + wasteland.modtools.mute.issue: + description: Allows you to issue mutes. + default: op + wasteland.modtools.mute.list: + description: Allows you to list active mutes. + default: op + wasteland.modtools.mute.pardon: + description: Allows you to remove mutes. + default: op + + wasteland.modtools.warn: + description: Allows you to issue a warning against a player. + default: op diff --git a/permissions/src/main/java/me/jamestmartin/wasteland/permissions/CommandWP.java b/permissions/src/main/java/me/jamestmartin/wasteland/permissions/CommandWP.java index 9d9b3f4..ef61771 100644 --- a/permissions/src/main/java/me/jamestmartin/wasteland/permissions/CommandWP.java +++ b/permissions/src/main/java/me/jamestmartin/wasteland/permissions/CommandWP.java @@ -22,6 +22,10 @@ class CommandWP implements CommandExecutor { return false; } + if (!sender.hasPermission("wasteland.permissions.reload")) { + sender.sendMessage("You do not have permission to reload Wasteland Permissions' config."); + } + WastelandPermissions.getInstance().reload(); sender.sendMessage("Reloaded Wasteland Permissions' configuration."); diff --git a/permissions/src/main/java/me/jamestmartin/wasteland/permissions/config/ConfigParser.java b/permissions/src/main/java/me/jamestmartin/wasteland/permissions/config/ConfigParser.java index f66b7d7..623d83c 100644 --- a/permissions/src/main/java/me/jamestmartin/wasteland/permissions/config/ConfigParser.java +++ b/permissions/src/main/java/me/jamestmartin/wasteland/permissions/config/ConfigParser.java @@ -30,6 +30,10 @@ public class ConfigParser { } private static Map parseGroups(ConfigurationSection c) { + if (c == null) { + return Map.of(); + } + Map groupConfigs = new HashMap<>(); for (String group : c.getKeys(false)) { groupConfigs.put(group, parseGroup(group, c.getConfigurationSection(group))); @@ -88,6 +92,10 @@ public class ConfigParser { private static Map parsePlayers(Map groups, ConfigurationSection c) { Map players = new HashMap<>(); + if (c == null) { + return players; + } + for (String uuidStr : c.getKeys(false)) { UUID uuid = UUID.fromString(uuidStr); players.put(uuid, parsePlayer(groups, uuidStr, c.getConfigurationSection(uuidStr))); @@ -103,11 +111,18 @@ public class ConfigParser { } private static PseudoGroupConfig parsePseudoGroup(List inherits, ConfigurationSection permissions) { + if (inherits == null) { + inherits = List.of(); + } return new PseudoGroupConfig(inherits, parsePermissions(permissions)); } private static Map parsePermissions(ConfigurationSection c) { Map permissions = new HashMap<>(); + if (c == null) { + return permissions; + } + for (String node : c.getKeys(false)) { if (c.isBoolean(node)) { permissions.put(node, c.getBoolean(node)); diff --git a/permissions/src/main/resources/plugin.yml b/permissions/src/main/resources/plugin.yml index ca85300..54e2bae 100644 --- a/permissions/src/main/resources/plugin.yml +++ b/permissions/src/main/resources/plugin.yml @@ -9,7 +9,7 @@ commands: description: Manage the Wasteland Permissions plugin. usage: "Usage: / [reload]" permission: wasteland.permissions - permission-message: You do not have permission to reload Wasteland Permission' config. + permission-message: You do not have permission to manage Wasteland Permissions. permissions: wasteland.permissions: diff --git a/settings.gradle b/settings.gradle index 5d7ccb3..d0e9253 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ rootProject.name = 'wasteland-all' -include 'wasteland', 'permissions' \ No newline at end of file +include 'wasteland', 'permissions', 'modtools' \ No newline at end of file diff --git a/wasteland/src/main/java/me/jamestmartin/wasteland/WastelandConfig.java b/wasteland/src/main/java/me/jamestmartin/wasteland/WastelandConfig.java index dd7706b..7e45cf8 100644 --- a/wasteland/src/main/java/me/jamestmartin/wasteland/WastelandConfig.java +++ b/wasteland/src/main/java/me/jamestmartin/wasteland/WastelandConfig.java @@ -3,7 +3,6 @@ package me.jamestmartin.wasteland; import me.jamestmartin.wasteland.chat.ChatConfig; import me.jamestmartin.wasteland.kills.KillsConfig; import me.jamestmartin.wasteland.kit.KitConfig; -import me.jamestmartin.wasteland.manual.ManualConfig; import me.jamestmartin.wasteland.ranks.AllRanks; import me.jamestmartin.wasteland.spawns.SpawnsConfig; @@ -14,7 +13,6 @@ public class WastelandConfig { private final AllRanks ranks; private final SpawnsConfig spawnsConfig; private final KitConfig kitConfig; - private final ManualConfig manualConfig; public WastelandConfig( String databaseFilename, @@ -22,15 +20,13 @@ public class WastelandConfig { KillsConfig killsConfig, AllRanks ranks, SpawnsConfig spawnsConfig, - KitConfig kitConfig, - ManualConfig manualConfig) { + KitConfig kitConfig) { this.databaseFilename = databaseFilename; this.chatConfig = chatConfig; this.killsConfig = killsConfig; this.ranks = ranks; this.spawnsConfig = spawnsConfig; this.kitConfig = kitConfig; - this.manualConfig = manualConfig; } public String getDatabaseFilename() { @@ -56,8 +52,4 @@ public class WastelandConfig { public KitConfig getKitConfig() { return kitConfig; } - - public ManualConfig getManualConfig() { - return manualConfig; - } } diff --git a/wasteland/src/main/java/me/jamestmartin/wasteland/WastelandState.java b/wasteland/src/main/java/me/jamestmartin/wasteland/WastelandState.java index 82b2b10..5332e7d 100644 --- a/wasteland/src/main/java/me/jamestmartin/wasteland/WastelandState.java +++ b/wasteland/src/main/java/me/jamestmartin/wasteland/WastelandState.java @@ -8,7 +8,6 @@ import org.bukkit.plugin.java.JavaPlugin; import me.jamestmartin.wasteland.chat.ChatState; import me.jamestmartin.wasteland.kills.KillsState; import me.jamestmartin.wasteland.kit.KitState; -import me.jamestmartin.wasteland.manual.ManualState; import me.jamestmartin.wasteland.ranks.PermissionsPlayerRankProvider; import me.jamestmartin.wasteland.ranks.PlayerRankProvider; import me.jamestmartin.wasteland.ranks.RanksState; @@ -25,7 +24,6 @@ public class WastelandState implements Substate { private final RanksState ranksState; private final SpawnsState spawnsState; private final KitState kitState; - private final ManualState manualState; public WastelandState(WastelandConfig config) throws IOException, ClassNotFoundException, SQLException { this.commandWasteland = new CommandWasteland(); @@ -37,7 +35,6 @@ public class WastelandState implements Substate { this.killsState = new KillsState(config.getKillsConfig(), ranksState.getPlayerKillsStore(), rankProvider); this.spawnsState = new SpawnsState(config.getSpawnsConfig()); this.kitState = new KitState(config.getKitConfig(), storeState.getKitStore()); - this.manualState = new ManualState(config.getManualConfig()); } private Substate[] getSubstates() { @@ -48,7 +45,6 @@ public class WastelandState implements Substate { ranksState, spawnsState, kitState, - manualState, }; return substates; } diff --git a/wasteland/src/main/java/me/jamestmartin/wasteland/config/ConfigParser.java b/wasteland/src/main/java/me/jamestmartin/wasteland/config/ConfigParser.java index 375ee12..86f457c 100644 --- a/wasteland/src/main/java/me/jamestmartin/wasteland/config/ConfigParser.java +++ b/wasteland/src/main/java/me/jamestmartin/wasteland/config/ConfigParser.java @@ -9,8 +9,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; - import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; @@ -26,8 +24,6 @@ import me.jamestmartin.wasteland.WastelandConfig; import me.jamestmartin.wasteland.chat.ChatConfig; import me.jamestmartin.wasteland.kills.KillsConfig; import me.jamestmartin.wasteland.kit.KitConfig; -import me.jamestmartin.wasteland.manual.ManualConfig; -import me.jamestmartin.wasteland.manual.ManualSection; import me.jamestmartin.wasteland.ranks.AllRanks; import me.jamestmartin.wasteland.ranks.EnlistedRank; import me.jamestmartin.wasteland.ranks.EnlistedRanks; @@ -51,22 +47,13 @@ public class ConfigParser { ConfigurationSection officerSection = c.getConfigurationSection("officer"); AllRanks ranks = parseRanks(enlistedSection, officerSection); - ManualSection rules = new ManualSection( - "The Server Rules", - parseManualSectionList(castToSectionList(c.getMapList("rules")))); - ManualSection faq = new ManualSection( - "Frequently Asked Questions", - parseManualSectionList(castToSectionList(c.getMapList("faq")))); - ManualConfig manualConfig = new ManualConfig(rules, faq); - return new WastelandConfig( databaseFilename, chatConfig, killsConfig, ranks, spawnsConfig, - kitConfig, - manualConfig); + kitConfig); } private static ChatConfig parseChatConfig(ConfigurationSection c) { @@ -321,34 +308,6 @@ public class ConfigParser { return new KitConfig(kitPeriod, kitTools, kitItems); } - public static ManualSection parseManualSection(Map c) { - String summary = (String) c.get("summary"); - Optional details = Optional.ofNullable((String) c.get("details")); - List subsections = parseManualSectionList(castToSectionList(c.get("sections"))); - - return new ManualSection(summary, details, subsections); - } - - private static List> castToSectionList(Object x) { - if (x == null) { - return null; - } - return ((List) x).stream().map(xx -> (Map) xx).collect(Collectors.toUnmodifiableList()); - } - - public static List parseManualSectionList(List> list) { - List sections = new ArrayList<>(); - if (list == null) { - return sections; - } - - for (Map section : list) { - sections.add(parseManualSection(section)); - } - - return sections; - } - /** Orphaned method. */ private static Optional readColor(ConfigurationSection c, String path) { return (Optional) Optional.ofNullable(c.getString(path)).map(ChatColor::valueOf); diff --git a/wasteland/src/main/resources/config.yml b/wasteland/src/main/resources/config.yml index 48aabaa..e944519 100644 --- a/wasteland/src/main/resources/config.yml +++ b/wasteland/src/main/resources/config.yml @@ -365,51 +365,4 @@ kit: # A random quantity will be chosen depending on how many kits the player has received. # The item type will not be dropped if the quantity chosen is less than one eighth of the maximum. items: - ROTTEN_FLESH: 32 - -rules: - - summary: Be civil and respectful. - sections: - - summary: If you start getting angry or frustrated, take a break! - - summary: Do not harass other players. - - summary: Do not use slurs. - - summary: Do not advertise. - - summary: Do not spam. - - summary: Avoid excessive swearing. - details: 'What is "excessive" is determined by moderator discretion.' - - summary: Be independent and mature. - sections: - - summary: This is a server intended for adults. - details: You will not be banned for being <16 per se, but acting like a child will get you banned no matter how old you are. - - summary: RTFM (Read The Field Manual). - details: Try to answer questions for yourself (e.g. with `/faq`) before asking them. - - summary: Do not whine or beg. - - summary: Do not ask moderators to cheat. - details: They don't have the ability to, anyway. - - summary: Play fairly. - sections: - - summary: Do not use hacks. - details: Hacks are the use of a client or mod designed for cheating. - - summary: Do not use exploits. - details: Exploits are the use of bugs to gain an unfair advantage (e.g. item duplication) or e.g. bypass protection plugins. - - summary: Do not use cheats. - details: Do not use x-ray resource packs or any other form of cheating. - - summary: Use your power appropriately. - details: Use moderator tools and ranks strictly for their intended purpose. - - summary: Only use authorized mods. - details: Refer to the authorized mods list to see which mods are permitted. If you'd like to use a mod not on that list, you **must ask the administrator(s)** before using it. - - summary: Stick to the game. - sections: - - summary: Keep the chat SFW. - - summary: Avoid discussing politics, religion, and the news. - details: This is not strictly forbidden, but these discussions may be shut down by moderator discretion. - - summary: Do not ask for personal information. - details: This includes real name, age, and location. - - summary: Do not share anyone else's personal information. - details: This includes their real name, age, and location. - - summary: Avoid sharing your own personal information. - details: You may share your own real name, age, or location, but not e.g. your address or phone number. - -faq: - - summary: Nothing to see here. - details: The server administrator has not set an FAQ. \ No newline at end of file + ROTTEN_FLESH: 32 \ No newline at end of file diff --git a/wasteland/src/main/resources/plugin.yml b/wasteland/src/main/resources/plugin.yml index cfa4d1a..0184288 100644 --- a/wasteland/src/main/resources/plugin.yml +++ b/wasteland/src/main/resources/plugin.yml @@ -56,17 +56,6 @@ commands: usage: "Usage: /" permission: wasteland.kit permission-message: You do not have permission to receive a starter kit. - - rules: - description: "Read the server rules. You can view more information about a specific rule using `/rules #`." - usage: "Usage: / [
] []" - permission: wasteland.manual.rules - permission-message: You do not have permission to read the server rules. - faq: - description: "Read the server FAQ. You can view more information about a specific topic using `/faq #`." - usage: "Usage: / [
] []" - permission: wasteland.manual.faq - permission-message: You do not have permission to read the server FAQ. permissions: wasteland.reload: @@ -128,32 +117,3 @@ permissions: wasteland.kit: description: Allows you to receive a starter kit. default: true - - wasteland.manual: - description: Allows you to read any manual. - default: op - children: - wasteland.manual.rules: true - wasteland.manual.faq: true - wasteland.manual.show-other: - description: Allows you to forcibly show any manual to someone else. - default: op - children: - wasteland.manual.rules.show-other: true - wasteland.manual.faq.show-other: true - wasteland.manual.rules: - description: Allows you to read the server rules. - default: true - wasteland.manual.rules.show-other: - description: Allows you to forcibly show the server rules to someone else. - default: op - children: - wasteland.manual.rules: true - wasteland.manual.faq: - description: Allows you to read the FAQ. - default: true - wasteland.manual.faq.show-other: - description: Allows you to forcibly show the FAQ to someone else. - default: op - children: - wasteland.manual.faq: true