Skip to content

Commit

Permalink
Add /tempban, /tempmute and /kick command
Browse files Browse the repository at this point in the history
Also added some nice preview completions that will show you the expiration date and the formatted MiniMessage when hovering over the completion
  • Loading branch information
JvstvsHD committed Jul 27, 2024
1 parent dbf71fc commit a845208
Show file tree
Hide file tree
Showing 13 changed files with 222 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.sql.Timestamp;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
Expand All @@ -43,6 +44,13 @@ public interface PunishmentDuration extends Comparable<PunishmentDuration> {
*
* @param source the source string.
* @return the parsed duration
* @throws Parser.ParseException if... <ul>
* <li>the source string is empty</li>
* <li>the source string does not contain parsable tokens</li>
* <li>the source string does not contain a unit character after a number</li>
* <li>the source string contains an unknown unit character</li>
* <li>the numeric value is negative</li>
* </ul>
* @see Parser#parse()
*/
static PunishmentDuration parse(String source) {
Expand Down Expand Up @@ -94,6 +102,7 @@ static PunishmentDuration fromMillis(long millis) {
/**
* Converts the given {@link Duration} into a {@link PunishmentDuration}. The duration is relative the given length
* into the future from a given point in time. It is absolute as soon as a punishment is enforced.
*
* @param duration how long the punishment should last
* @return the converted duration
*/
Expand Down Expand Up @@ -205,18 +214,23 @@ public void convert() {
int index = 0;
for (String number : numbers) {
index += number.length();
final long numericValue = Long.parseLong(number);
final long numericValue;
try {
numericValue = Long.parseLong(number);
} catch (NumberFormatException e) {
throw new ParseException("Not a number: " + e.getMessage());
}
if (numericValue < 0)
throw new IllegalArgumentException("Illegal numeric value: " + numericValue);
throw new ParseException("Illegal numeric value: " + numericValue);
final char unit;
try {
unit = Character.toLowerCase(source.charAt(index));
} catch (IndexOutOfBoundsException e) {
throw new IllegalArgumentException("Number is not followed by unit marking character.");
throw new ParseException("Number is not followed by unit marking character.");
}
TimeUnit timeUnit = characterMapping.get(unit);
if (timeUnit == null)
throw new IllegalArgumentException("Unknown time unit for character '" + unit + "'");
throw new ParseException("Unknown time unit for character '" + unit + "'");
converted.put(timeUnit, numericValue);
index++;
}
Expand All @@ -231,9 +245,11 @@ public void convert() {
* @return the parsed duration
*/
public PunishmentDuration parse() {
if (source.isEmpty())
throw new ParseException("Source string is empty.");
convert();
if (rawDuration.isEmpty()) {
throw new IllegalArgumentException("Converted map is empty.");
throw new ParseException("Converted map is empty.");
}
return fromMillis(durationToMillis());
}
Expand All @@ -249,5 +265,11 @@ private long durationToMillis() {
}
return total;
}

public static class ParseException extends RuntimeException {
public ParseException(String message) {
super(message);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public interface PunishmentType {
* @since 1.0.1
*/
default boolean isMute() {
return this == StandardPunishmentType.MUTE || this == StandardPunishmentType.PERMANENT_MUTE;
return this == StandardPunishmentType.TEMPORARY_MUTE || this == StandardPunishmentType.PERMANENT_MUTE;
}

/**
Expand All @@ -45,6 +45,6 @@ default boolean isMute() {
* @since 1.0.1
*/
default boolean isBan() {
return this == StandardPunishmentType.BAN || this == StandardPunishmentType.PERMANENT_BAN;
return this == StandardPunishmentType.TEMPORARY_BAN || this == StandardPunishmentType.PERMANENT_BAN;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@

public enum StandardPunishmentType implements PunishmentType {

BAN(false, "BAN", 1),
TEMPORARY_BAN(false, "BAN", 1),
PERMANENT_BAN(true, "PERMANENT_BAN", 2),
MUTE(false, "MUTE", 3),
TEMPORARY_MUTE(false, "MUTE", 3),
PERMANENT_MUTE(true, "PERMANENT_MUTE", 4),
KICK(false, "KICK", 5);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
package de.jvstvshd.necrify.common;

import de.jvstvshd.necrify.api.Necrify;
import de.jvstvshd.necrify.api.duration.PunishmentDuration;
import de.jvstvshd.necrify.api.punishment.StandardPunishmentType;
import de.jvstvshd.necrify.api.user.NecrifyUser;
import de.jvstvshd.necrify.common.commands.NecrifyCommand;
import de.jvstvshd.necrify.common.commands.NecrifyUserParser;
import de.jvstvshd.necrify.common.commands.PunishmentDurationParser;
import de.jvstvshd.necrify.common.punishment.NecrifyKick;
import de.jvstvshd.necrify.common.commands.UserNotFoundParseException;
import net.kyori.adventure.text.Component;
Expand All @@ -47,7 +49,6 @@
import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
Expand Down Expand Up @@ -104,6 +105,7 @@ public final void registerCommands(CommandManager<NecrifyUser> manager, boolean
var parserRegistry = manager.parserRegistry();
parserRegistry.registerParser(ParserDescriptor.of(new NecrifyUserParser(this.getUserManager()), NecrifyUser.class));
parserRegistry.registerParser(ComponentParser.componentParser(MiniMessage.miniMessage(), StringParser.StringMode.GREEDY));
parserRegistry.registerParser(ParserDescriptor.of(new PunishmentDurationParser(), PunishmentDuration.class));
var commands = new NecrifyCommand(this);
parser.parse(commands);
}
Expand All @@ -112,8 +114,8 @@ public final void registerCommands(CommandManager<NecrifyUser> manager, boolean
public String getDefaultReason(StandardPunishmentType type) {
return "<red>You were " + switch (type) {
case KICK -> "kicked from the server.";
case BAN, PERMANENT_BAN -> "banned from the server.";
case MUTE, PERMANENT_MUTE -> "muted.";
case TEMPORARY_BAN, PERMANENT_BAN -> "banned from the server.";
case TEMPORARY_MUTE, PERMANENT_MUTE -> "muted.";
} + "</red>";
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,12 @@

package de.jvstvshd.necrify.common.commands;

import com.mojang.brigadier.LiteralMessage;
import com.mojang.brigadier.Message;
import de.jvstvshd.necrify.api.PunishmentException;
import de.jvstvshd.necrify.api.event.punishment.PunishmentCancelledEvent;
import de.jvstvshd.necrify.api.message.MessageProvider;
import de.jvstvshd.necrify.api.duration.PunishmentDuration;
import de.jvstvshd.necrify.api.punishment.Punishment;
import de.jvstvshd.necrify.api.punishment.StandardPunishmentType;
import de.jvstvshd.necrify.api.user.NecrifyUser;
import de.jvstvshd.necrify.api.user.UserManager;
import de.jvstvshd.necrify.common.AbstractNecrifyPlugin;
import de.jvstvshd.necrify.common.plugin.Util;
import de.jvstvshd.necrify.common.util.PunishmentHelper;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
Expand All @@ -45,25 +40,15 @@
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.incendo.cloud.annotation.specifier.Greedy;
import org.incendo.cloud.annotations.Argument;
import org.incendo.cloud.annotations.Command;
import org.incendo.cloud.annotations.Default;
import org.incendo.cloud.annotations.Permission;
import org.incendo.cloud.annotations.parser.Parser;
import org.incendo.cloud.annotations.processing.CommandContainer;
import org.incendo.cloud.annotations.suggestion.Suggestions;
import org.incendo.cloud.brigadier.suggestion.TooltipSuggestion;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.injection.ParameterInjector;
import org.incendo.cloud.minecraft.extras.suggestion.ComponentTooltipSuggestion;
import org.incendo.cloud.parser.ArgumentParseResult;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.type.Either;
import org.incendo.cloud.util.annotation.AnnotationAccessor;
import org.slf4j.Logger;

import java.util.Collections;
Expand All @@ -88,13 +73,16 @@ public NecrifyCommand(AbstractNecrifyPlugin plugin) {
this.executor = plugin.getExecutor();
}

//COMMANDS
//Punishing

@Command("necrify ban <target> [reason]")
@Command("ban <target> [reason]")
@Permission(value = {"necrify.command.ban", "necrify.admin"}, mode = Permission.Mode.ANY_OF)
public void banCommand(
NecrifyUser sender,
@Argument(value = "target", description = "Player to ban", suggestions = "suggestOnlinePlayers") NecrifyUser target,
@Argument(value = "reason", description = "Reason the user should be banned for") @Greedy String reason
@Argument(value = "reason", description = "Reason the user should be banned for", suggestions = "suggestMiniMessage") @Greedy String reason
) {
var finalReason = reasonOrDefaultTo(reason, StandardPunishmentType.PERMANENT_BAN);
target.banPermanent(finalReason).whenComplete((ban, throwable) -> {
Expand All @@ -115,7 +103,7 @@ public void banCommand(
public void muteCommand(
NecrifyUser sender,
@Argument(value = "target", description = "Player to mute", suggestions = "suggestOnlinePlayers") NecrifyUser target,
@Argument(value = "reason", description = "Reason the user should be muted for") @Greedy String reason
@Argument(value = "reason", description = "Reason the user should be muted for", suggestions = "suggestMiniMessage") @Greedy String reason
) {
var finalReason = reasonOrDefaultTo(reason, StandardPunishmentType.PERMANENT_MUTE);
target.mutePermanent(finalReason).whenComplete((mute, throwable) -> {
Expand All @@ -130,14 +118,83 @@ public void muteCommand(
});
}

@Command("necrify kick <target> [reason]")
@Command("kick <target> [reason]")
@Permission(value = {"necrify.command.kick", "necrify.admin"}, mode = Permission.Mode.ANY_OF)
public void kickCommand(
NecrifyUser sender,
@Argument(value = "target", description = "Player to kick", suggestions = "suggestOnlinePlayers") NecrifyUser target,
@Argument(value = "reason", description = "Reason the user should be kicked for", suggestions = "suggestMiniMessage") @Greedy String reason
) {
var finalReason = reasonOrDefaultTo(reason, StandardPunishmentType.KICK);
target.kick(finalReason).whenComplete((unused, throwable) -> {
if (throwable != null) {
logException(sender, throwable);
return;
}
sender.sendMessage("command.kick.success",
miniMessage(target.getUsername()).color(NamedTextColor.YELLOW),
copyComponent(target.getUuid().toString()).color(NamedTextColor.YELLOW),
finalReason);
});
}

@Command("necrify tempban <target> <duration> [reason]")
@Command("tempban <target> <duration> [reason]")
@Permission(value = {"necrify.command.tempban", "necrify.admin"}, mode = Permission.Mode.ANY_OF)
public void tempbanCommand(
NecrifyUser sender,
@Argument(value = "target", description = "Player to tempban", suggestions = "suggestOnlinePlayers") NecrifyUser target,
@Argument(value = "duration", description = "Duration the user should be banned for") PunishmentDuration duration,
@Argument(value = "reason", description = "Reason the user should be banned for", suggestions = "suggestMiniMessage") @Greedy String reason
) {
var finalReason = reasonOrDefaultTo(reason, StandardPunishmentType.TEMPORARY_BAN);
target.ban(finalReason, duration).whenComplete((ban, throwable) -> {
if (throwable != null) {
logException(sender, throwable);
return;
}
sender.sendMessage("command.tempban.success",
miniMessage(target.getUsername()).color(NamedTextColor.YELLOW),
copyComponent(target.getUuid().toString()).color(NamedTextColor.YELLOW),
finalReason,
miniMessage(duration.expirationAsString()).color(NamedTextColor.YELLOW));
});
}

@Command("necrify tempmute <target> <duration> [reason]")
@Command("tempmute <target> <duration> [reason]")
@Permission(value = {"necrify.command.tempmute", "necrify.admin"}, mode = Permission.Mode.ANY_OF)
public void tempmuteCommand(
NecrifyUser sender,
@Argument(value = "target", description = "Player to tempmute", suggestions = "suggestOnlinePlayers") NecrifyUser target,
@Argument(value = "duration", description = "Duration the user should be muted for") PunishmentDuration duration,
@Argument(value = "reason", description = "Reason the user should be muted for", suggestions = "suggestMiniMessage") @Greedy String reason
) {
var finalReason = reasonOrDefaultTo(reason, StandardPunishmentType.TEMPORARY_MUTE);
target.mute(finalReason, duration).whenComplete((mute, throwable) -> {
if (throwable != null) {
logException(sender, throwable);
return;
}
sender.sendMessage("command.tempmute.success",
miniMessage(target.getUsername()).color(NamedTextColor.YELLOW),
copyComponent(target.getUuid().toString()).color(NamedTextColor.YELLOW),
finalReason,
miniMessage(duration.expirationAsString()).color(NamedTextColor.YELLOW));
});
}

//Removal of punishments

@Command("necrify unban <target>")
@Command("unban <target>")
@Permission(value = {"necrify.command.unban", "necrify.admin"}, mode = Permission.Mode.ANY_OF)
public void unbanCommand(
NecrifyUser sender,
@Argument(value = "target", description = "Player to unban") NecrifyUser target
) {
var punishments = target.getPunishments(StandardPunishmentType.BAN, StandardPunishmentType.PERMANENT_BAN);
var punishments = target.getPunishments(StandardPunishmentType.TEMPORARY_BAN, StandardPunishmentType.PERMANENT_BAN);
try {
removePunishments(sender, "unban", punishments);
} catch (Exception e) {
Expand All @@ -152,10 +209,33 @@ public void unmuteCommand(
NecrifyUser sender,
@Argument(value = "target", description = "Player to unmute", suggestions = "suggestOnlinePlayers") NecrifyUser target
) {
var punishments = target.getPunishments(StandardPunishmentType.MUTE, StandardPunishmentType.PERMANENT_MUTE);
var punishments = target.getPunishments(StandardPunishmentType.TEMPORARY_MUTE, StandardPunishmentType.PERMANENT_MUTE);
removePunishments(sender, "unmute", punishments);
}

//SUGGESTIONS

@Suggestions("suggestOnlinePlayers")
public List<? extends Suggestion> suggestNames(CommandContext<NecrifyUser> context, CommandInput input) {
return plugin
.getOnlinePlayers()
.stream()
.filter(pair -> pair.first().toLowerCase(Locale.ROOT).startsWith(input.peekString().toLowerCase(Locale.ROOT)))
.map(pair -> ComponentTooltipSuggestion.suggestion(pair.first(),
miniMessage("<red>The player <yellow>(<name>/<uuid>)</yellow> you want to select.</red><yellow>",
Placeholder.parsed("name", pair.first()),
Placeholder.parsed("uuid", pair.second().toString()))
)).toList();
}

@Suggestions("suggestMiniMessage")
public List<? extends Suggestion> suggestMiniMessage(CommandContext<NecrifyUser> context, CommandInput input) {
return Collections.singletonList(ComponentTooltipSuggestion.suggestion(input.remainingInput() + " (hover for preview)",
miniMessage(input.remainingInput())));
}

//HELPER METHODS

private void removePunishments(NecrifyUser source, String commandName, List<Punishment> punishments) {
if (punishments.isEmpty()) {
source.sendMessage(plugin.getMessageProvider().provide("command.punishment.not-banned").color(NamedTextColor.RED));
Expand Down Expand Up @@ -184,18 +264,7 @@ private void removePunishments(NecrifyUser source, String commandName, List<Puni
}
}

@Suggestions("suggestOnlinePlayers")
public List<? extends Suggestion> suggestNames(CommandContext<NecrifyUser> context, CommandInput input) {
return plugin
.getOnlinePlayers()
.stream()
.filter(pair -> pair.first().toLowerCase(Locale.ROOT).startsWith(input.peekString().toLowerCase(Locale.ROOT)))
.map(pair -> ComponentTooltipSuggestion.suggestion(pair.first(),
miniMessage("<red>The player <yellow>(<name>/<uuid>)</yellow> you want to select.</red><yellow>",
Placeholder.parsed("name", pair.first()),
Placeholder.parsed("uuid", pair.second().toString()))
)).toList();
}
//Communication, messaging, logging

private Component buildComponent(Component dataComponent, Punishment punishment) {
return dataComponent.clickEvent(ClickEvent.runCommand("/punishment " + punishment.getPunishmentUuid()
Expand Down
Loading

0 comments on commit a845208

Please sign in to comment.