1
mirror of https://github.com/Shiewk/SModeration.git synced 2026-04-28 05:54:16 +02:00

Add permanent punishments

This commit is contained in:
Shy
2026-04-12 17:53:30 +02:00
parent 24da79642a
commit 2bccf45439
6 changed files with 81 additions and 26 deletions
@@ -49,6 +49,9 @@ public final class ModLogsCommand implements CommandProvider {
List<Punishment> punishments = punishmentManager.byTargetUUID(uuid); List<Punishment> punishments = punishmentManager.byTargetUUID(uuid);
for (Punishment punishment : punishments) { for (Punishment punishment : punishments) {
if (punishment instanceof TimedPunishment timed && timed.isActive()){ if (punishment instanceof TimedPunishment timed && timed.isActive()){
if (timed.isPermanent()){
sender.sendMessage(translatable("smod.command.modlogs." + punishment.getType() + ".permanent", text(punishment.getReason())));
} else {
sender.sendMessage(translatable("smod.command.modlogs." + punishment.getType(), sender.sendMessage(translatable("smod.command.modlogs." + punishment.getType(),
TimeUtil.calendarTimestamp(timed.getExpiry()), TimeUtil.calendarTimestamp(timed.getExpiry()),
TimeUtil.formatTimeLong(timed.getExpiry() - System.currentTimeMillis()), TimeUtil.formatTimeLong(timed.getExpiry() - System.currentTimeMillis()),
@@ -56,6 +59,7 @@ public final class ModLogsCommand implements CommandProvider {
)); ));
} }
} }
}
if (punishments.isEmpty()){ if (punishments.isEmpty()){
sender.sendMessage(translatable("smod.command.modlogs.none")); sender.sendMessage(translatable("smod.command.modlogs.none"));
} }
@@ -21,9 +21,13 @@ public final class DurationArgument implements CustomArgumentType.Converted<Long
public static final Pattern DURATION_PATTERN = Pattern.compile("([0-9]{1,9})(ms|s|min|h|d|w|mo|y)"); public static final Pattern DURATION_PATTERN = Pattern.compile("([0-9]{1,9})(ms|s|min|h|d|w|mo|y)");
public static final Pattern VALIDATION_PATTERN = Pattern.compile("(([0-9]{1,9})(ms|s|min|h|d|w|mo|y))+"); public static final Pattern VALIDATION_PATTERN = Pattern.compile("(([0-9]{1,9})(ms|s|min|h|d|w|mo|y))+");
public static final long INFINITE_DURATION = -1L;
@Override @Override
public @NotNull Long convert(@NotNull String nativeType) throws CommandSyntaxException { public @NotNull Long convert(@NotNull String nativeType) throws CommandSyntaxException {
if (nativeType.startsWith("perm") || nativeType.startsWith("inf")) {
return INFINITE_DURATION;
}
if (!VALIDATION_PATTERN.matcher(nativeType).matches()){ if (!VALIDATION_PATTERN.matcher(nativeType).matches()){
CommandUtil.errorTranslatable("smod.argument.duration.fail.pattern"); CommandUtil.errorTranslatable("smod.argument.duration.fail.pattern");
} }
@@ -58,6 +62,8 @@ public final class DurationArgument implements CustomArgumentType.Converted<Long
public @NotNull <S> CompletableFuture<Suggestions> listSuggestions(@NotNull CommandContext<S> context, @NotNull SuggestionsBuilder builder) { public @NotNull <S> CompletableFuture<Suggestions> listSuggestions(@NotNull CommandContext<S> context, @NotNull SuggestionsBuilder builder) {
if (builder.getRemaining().isBlank()){ if (builder.getRemaining().isBlank()){
List.of( List.of(
"infinite", "inf",
"permanent", "perm",
"100ms", "100ms",
"15s", "15s",
"2min", "2min",
@@ -58,7 +58,7 @@ public class SModMenu extends PageableCustomInventory {
} }
public enum Sort { public enum Sort {
EXPIRY(translatable("smod.menu.sort.expiry"), Comparator.comparingLong(p -> p instanceof TimedPunishment timed ? p.getTimestamp() + timed.getDuration() : p.getTimestamp())), EXPIRY(translatable("smod.menu.sort.expiry"), Comparator.comparingLong(p -> p instanceof TimedPunishment timed ? timed.getExpiry() : p.getTimestamp())),
TIME(translatable("smod.menu.sort.time"), Comparator.comparingLong(Punishment::getTimestamp)), TIME(translatable("smod.menu.sort.time"), Comparator.comparingLong(Punishment::getTimestamp)),
PLAYER_NAME(translatable("smod.menu.sort.playerName"), (p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(PlayerUtil.offlinePlayerName(p1.getTargetID()), PlayerUtil.offlinePlayerName(p2.getTargetID()))), PLAYER_NAME(translatable("smod.menu.sort.playerName"), (p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(PlayerUtil.offlinePlayerName(p1.getTargetID()), PlayerUtil.offlinePlayerName(p2.getTargetID()))),
MODERATOR_NAME(translatable("smod.menu.sort.moderatorName"), (p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(PlayerUtil.offlinePlayerName(p1.getIssuerID()), PlayerUtil.offlinePlayerName(p2.getIssuerID()))); MODERATOR_NAME(translatable("smod.menu.sort.moderatorName"), (p1, p2) -> String.CASE_INSENSITIVE_ORDER.compare(PlayerUtil.offlinePlayerName(p1.getIssuerID()), PlayerUtil.offlinePlayerName(p2.getIssuerID())));
@@ -330,6 +330,10 @@ public class SModMenu extends PageableCustomInventory {
lore.addLine(renderComponent(player, applyFormatting(translatable("smod.menu.info.timestamp", TimeUtil.calendarTimestamp(punishment.getTimestamp()))))); lore.addLine(renderComponent(player, applyFormatting(translatable("smod.menu.info.timestamp", TimeUtil.calendarTimestamp(punishment.getTimestamp())))));
if (punishment instanceof TimedPunishment timed){ if (punishment instanceof TimedPunishment timed){
if (timed.isPermanent()){
lore.addLine(renderComponent(player, applyFormatting(translatable("smod.menu.info.duration", translatable("smod.time.permanent")))));
lore.addLine(renderComponent(player, applyFormatting(translatable("smod.menu.info.expiry.never"))));
} else {
lore.addLine(renderComponent(player, applyFormatting(translatable("smod.menu.info.duration", TimeUtil.formatTimeLong(timed.getExpiry() - punishment.getTimestamp()))))); lore.addLine(renderComponent(player, applyFormatting(translatable("smod.menu.info.duration", TimeUtil.formatTimeLong(timed.getExpiry() - punishment.getTimestamp())))));
long remainingTime = timed.getExpiry() - System.currentTimeMillis(); long remainingTime = timed.getExpiry() - System.currentTimeMillis();
if (remainingTime > 0){ if (remainingTime > 0){
@@ -338,6 +342,7 @@ public class SModMenu extends PageableCustomInventory {
lore.addLine(renderComponent(player, applyFormatting(translatable("smod.menu.info.expiry.past", TimeUtil.formatTimeLong(-remainingTime))))); lore.addLine(renderComponent(player, applyFormatting(translatable("smod.menu.info.expiry.past", TimeUtil.formatTimeLong(-remainingTime)))));
} }
} }
}
lore.addLine(renderComponent(player, applyFormatting(translatable("smod.menu.info.reason", text(punishment.getReason()))))); lore.addLine(renderComponent(player, applyFormatting(translatable("smod.menu.info.reason", text(punishment.getReason())))));
@@ -1,5 +1,6 @@
package de.shiewk.smoderation.paper.punishments; package de.shiewk.smoderation.paper.punishments;
import de.shiewk.smoderation.paper.command.argument.DurationArgument;
import de.shiewk.smoderation.paper.util.PlayerUtil; import de.shiewk.smoderation.paper.util.PlayerUtil;
import de.shiewk.smoderation.paper.util.SerializationHelper; import de.shiewk.smoderation.paper.util.SerializationHelper;
import de.shiewk.smoderation.paper.util.TimeUtil; import de.shiewk.smoderation.paper.util.TimeUtil;
@@ -35,7 +36,7 @@ public abstract class TimedPunishment extends Punishment {
} }
public boolean isActive(){ public boolean isActive(){
return !wasCancelled() && System.currentTimeMillis() < timestamp + duration; return !wasCancelled() && (isPermanent() || System.currentTimeMillis() < getExpiry());
} }
@Override @Override
@@ -55,6 +56,13 @@ public abstract class TimedPunishment extends Punishment {
@Override @Override
public Component infoMessage(){ public Component infoMessage(){
if (isPermanent()){
return translatable(
"smod.punishment.playerMessage." + type + ".permanent",
text(PlayerUtil.offlinePlayerName(this.issuer)),
text(reason)
);
} else {
return translatable( return translatable(
"smod.punishment.playerMessage." + type, "smod.punishment.playerMessage." + type,
text(PlayerUtil.offlinePlayerName(this.issuer)), text(PlayerUtil.offlinePlayerName(this.issuer)),
@@ -62,9 +70,18 @@ public abstract class TimedPunishment extends Punishment {
TimeUtil.formatTimeLong(this.timestamp + this.duration - System.currentTimeMillis()) TimeUtil.formatTimeLong(this.timestamp + this.duration - System.currentTimeMillis())
); );
} }
}
@Override @Override
public Component adminMessage(){ public Component adminMessage(){
if (isPermanent()){
return translatable(
"smod.punishment.broadcast." + type + ".permanent",
text(PlayerUtil.offlinePlayerName(target)),
text(PlayerUtil.offlinePlayerName(issuer)),
text(reason)
);
} else {
return translatable( return translatable(
"smod.punishment.broadcast." + type, "smod.punishment.broadcast." + type,
text(PlayerUtil.offlinePlayerName(target)), text(PlayerUtil.offlinePlayerName(target)),
@@ -73,6 +90,7 @@ public abstract class TimedPunishment extends Punishment {
TimeUtil.formatTimeLong(this.duration) TimeUtil.formatTimeLong(this.duration)
); );
} }
}
public Component cancelMessage(){ public Component cancelMessage(){
return translatable( return translatable(
@@ -83,7 +101,11 @@ public abstract class TimedPunishment extends Punishment {
} }
public long getExpiry() { public long getExpiry() {
return getTimestamp() + getDuration(); return isPermanent() ? Long.MAX_VALUE : getTimestamp() + getDuration();
}
public boolean isPermanent() {
return getDuration() == DurationArgument.INFINITE_DURATION;
} }
protected void cancel(UUID canceller) { protected void cancel(UUID canceller) {
@@ -19,8 +19,10 @@
"smod.command.kick.fail.protect": "Dieser Spieler kann nicht gekickt werden.", "smod.command.kick.fail.protect": "Dieser Spieler kann nicht gekickt werden.",
"smod.command.kick.fail.self": "Du kannst dich nicht selbst kicken.", "smod.command.kick.fail.self": "Du kannst dich nicht selbst kicken.",
"smod.command.modlogs.ban": "<primary>- ist bis <secondary><arg:0></secondary> <gray>(in <arg:1>)</gray> gebannt. Grund: <secondary><arg:2>", "smod.command.modlogs.ban": "<primary>- ist bis <secondary><arg:0></secondary> <gray>(in <arg:1>)</gray> gebannt. Grund: <secondary><arg:2>",
"smod.command.modlogs.ban.permanent": "<primary>- ist <secondary>permanent</secondary> gebannt. Grund: <secondary><arg:0>",
"smod.command.modlogs.heading": "<primary>Spieler <secondary><arg:0> <gray>(<arg:1>)", "smod.command.modlogs.heading": "<primary>Spieler <secondary><arg:0> <gray>(<arg:1>)",
"smod.command.modlogs.mute": "<primary>- ist bis <secondary><arg:0></secondary> <gray>(in <arg:1>)</gray> stummgeschaltet. Grund: <secondary><arg:2>", "smod.command.modlogs.mute": "<primary>- ist bis <secondary><arg:0></secondary> <gray>(in <arg:1>)</gray> stummgeschaltet. Grund: <secondary><arg:2>",
"smod.command.modlogs.mute.permanent": "<primary>- ist <secondary>permanent</secondary> stummgeschaltet. Grund: <secondary><arg:0>",
"smod.command.modlogs.none": "<primary>- ist momentan nicht gebannt oder stummgeschaltet.", "smod.command.modlogs.none": "<primary>- ist momentan nicht gebannt oder stummgeschaltet.",
"smod.command.mute.fail.alreadyMuted": "Dieser Spieler ist schon stummgeschaltet.", "smod.command.mute.fail.alreadyMuted": "Dieser Spieler ist schon stummgeschaltet.",
"smod.command.mute.fail.forceReason": "Bitte gib einen Grund an.", "smod.command.mute.fail.forceReason": "Bitte gib einen Grund an.",
@@ -56,6 +58,7 @@
"smod.menu.info.click": "\u00BB Klicke, um die Strafe aufzuheben", "smod.menu.info.click": "\u00BB Klicke, um die Strafe aufzuheben",
"smod.menu.info.duration": "<secondary>Dauer: <primary><arg:0>", "smod.menu.info.duration": "<secondary>Dauer: <primary><arg:0>",
"smod.menu.info.expiry.future": "<secondary>Läuft ab: <primary>In <arg:0>", "smod.menu.info.expiry.future": "<secondary>Läuft ab: <primary>In <arg:0>",
"smod.menu.info.expiry.never": "<secondary>Läuft ab: <primary>Nie",
"smod.menu.info.expiry.past": "<secondary>Ist abgelaufen: <primary><arg:0> ago", "smod.menu.info.expiry.past": "<secondary>Ist abgelaufen: <primary><arg:0> ago",
"smod.menu.info.player": "<secondary>Spieler: <primary><arg:0>", "smod.menu.info.player": "<secondary>Spieler: <primary><arg:0>",
"smod.menu.info.punishedBy": "<secondary>Bestraft von: <primary><arg:0>", "smod.menu.info.punishedBy": "<secondary>Bestraft von: <primary><arg:0>",
@@ -77,16 +80,20 @@
"smod.menu.type.all": "Alle", "smod.menu.type.all": "Alle",
"smod.menu.type.switch": "\u00BB Klicke, um den Typ zu ändern", "smod.menu.type.switch": "\u00BB Klicke, um den Typ zu ändern",
"smod.punishment.broadcast.ban": "<primary><secondary><arg:0></secondary> wurde von <secondary><arg:1></secondary> für <secondary><arg:3></secondary> gebannt.<newline>Grund: <secondary><arg:2>", "smod.punishment.broadcast.ban": "<primary><secondary><arg:0></secondary> wurde von <secondary><arg:1></secondary> für <secondary><arg:3></secondary> gebannt.<newline>Grund: <secondary><arg:2>",
"smod.punishment.broadcast.ban.permanent": "<primary><secondary><arg:0></secondary> wurde von <secondary><arg:1></secondary> <secondary>permanent</secondary> gebannt.<newline>Grund: <secondary><arg:2>",
"smod.punishment.broadcast.kick": "<primary><secondary><arg:0></secondary> wurde von <secondary><arg:1></secondary> gekickt.<newline>Grund: <secondary><arg:2>", "smod.punishment.broadcast.kick": "<primary><secondary><arg:0></secondary> wurde von <secondary><arg:1></secondary> gekickt.<newline>Grund: <secondary><arg:2>",
"smod.punishment.broadcast.mute": "<primary><secondary><arg:0></secondary> wurde von <secondary><arg:1></secondary> für <secondary><arg:3></secondary> stummgeschaltet.<newline>Grund: <secondary><arg:2>", "smod.punishment.broadcast.mute": "<primary><secondary><arg:0></secondary> wurde von <secondary><arg:1></secondary> für <secondary><arg:3></secondary> stummgeschaltet.<newline>Grund: <secondary><arg:2>",
"smod.punishment.broadcast.mute.permanent": "<primary><secondary><arg:0></secondary> wurde von <secondary><arg:1></secondary> <secondary>permanent</secondary> stummgeschaltet.<newline>Grund: <secondary><arg:2>",
"smod.punishment.cancel.ban": "<primary><secondary><arg:0></secondary> wurde von <secondary><arg:1></secondary> entbannt.", "smod.punishment.cancel.ban": "<primary><secondary><arg:0></secondary> wurde von <secondary><arg:1></secondary> entbannt.",
"smod.punishment.cancel.mute": "<primary><secondary><arg:0></secondary>s Stummschaltung wurde von <secondary><arg:1></secondary> aufgehoben.", "smod.punishment.cancel.mute": "<primary><secondary><arg:0></secondary>s Stummschaltung wurde von <secondary><arg:1></secondary> aufgehoben.",
"smod.punishment.name.ban": "Bann", "smod.punishment.name.ban": "Bann",
"smod.punishment.name.kick": "Kick", "smod.punishment.name.kick": "Kick",
"smod.punishment.name.mute": "Stummschaltung", "smod.punishment.name.mute": "Stummschaltung",
"smod.punishment.playerMessage.ban": "<primary>Du wurdest von <secondary><arg:0></secondary> vom Server gebannt.<newline>Grund: <secondary><arg:1></secondary><newline>Dein Bann läuft in <secondary><arg:2></secondary> ab.", "smod.punishment.playerMessage.ban": "<primary>Du wurdest von <secondary><arg:0></secondary> vom Server gebannt.<newline>Grund: <secondary><arg:1></secondary><newline>Dein Bann läuft in <secondary><arg:2></secondary> ab.",
"smod.punishment.playerMessage.ban.permanent": "<primary>Du wurdest von <secondary><arg:0></secondary> vom Server gebannt.<newline>Grund: <secondary><arg:1></secondary><newline>Dein Bann läuft <secondary>nicht</secondary> ab.",
"smod.punishment.playerMessage.kick": "<primary>Du wurdest von <secondary><arg:0></secondary> vom Server gekickt.<newline>Grund: <secondary><arg:1>", "smod.punishment.playerMessage.kick": "<primary>Du wurdest von <secondary><arg:0></secondary> vom Server gekickt.<newline>Grund: <secondary><arg:1>",
"smod.punishment.playerMessage.mute": "<primary>Du wurdest von <secondary><arg:0></secondary> stummgeschaltet.<newline>Grund: <secondary><arg:1></secondary><newline>Du kannst in <secondary><arg:2></secondary> wieder schreiben.", "smod.punishment.playerMessage.mute": "<primary>Du wurdest von <secondary><arg:0></secondary> stummgeschaltet.<newline>Grund: <secondary><arg:1></secondary><newline>Du kannst in <secondary><arg:2></secondary> wieder schreiben.",
"smod.punishment.playerMessage.mute.permanent": "<primary>Du wurdest von <secondary><arg:0></secondary> stummgeschaltet.<newline>Grund: <secondary><arg:1></secondary><newline>Du kannst <secondary>nie</secondary> wieder schreiben.",
"smod.punishment.playerMessage.mute.chat": "<primary>Du kannst diesen Befehl nicht ausführen, während du stummgeschaltet bist.", "smod.punishment.playerMessage.mute.chat": "<primary>Du kannst diesen Befehl nicht ausführen, während du stummgeschaltet bist.",
"smod.socialspy.command": "<primary>[<secondary>SocialSpy</secondary>] <arg:0>: <secondary><arg:1>", "smod.socialspy.command": "<primary>[<secondary>SocialSpy</secondary>] <arg:0>: <secondary><arg:1>",
"smod.time.days": "<arg:0> Tage", "smod.time.days": "<arg:0> Tage",
@@ -106,6 +113,8 @@
"smod.time.month.8": "September", "smod.time.month.8": "September",
"smod.time.month.9": "Oktober", "smod.time.month.9": "Oktober",
"smod.time.months": "<arg:0> Monate", "smod.time.months": "<arg:0> Monate",
"smod.time.never": "Nie",
"smod.time.permanent": "Permanent",
"smod.time.seconds": "<arg:0> Sekunden", "smod.time.seconds": "<arg:0> Sekunden",
"smod.time.timestamp": "<arg:2>. <arg:1> <arg:0> <arg:3>:<arg:4>:<arg:5> <arg:6>", "smod.time.timestamp": "<arg:2>. <arg:1> <arg:0> <arg:3>:<arg:4>:<arg:5> <arg:6>",
"smod.time.weeks": "<arg:0> Wochen", "smod.time.weeks": "<arg:0> Wochen",
@@ -19,8 +19,10 @@
"smod.command.kick.fail.protect": "This player can't be kicked.", "smod.command.kick.fail.protect": "This player can't be kicked.",
"smod.command.kick.fail.self": "You can't kick yourself.", "smod.command.kick.fail.self": "You can't kick yourself.",
"smod.command.modlogs.ban": "<primary>- is banned until <secondary><arg:0></secondary> <gray>(in <arg:1>)</gray>. Reason: <secondary><arg:2>", "smod.command.modlogs.ban": "<primary>- is banned until <secondary><arg:0></secondary> <gray>(in <arg:1>)</gray>. Reason: <secondary><arg:2>",
"smod.command.modlogs.ban.permanent": "<primary>- is banned <secondary>permanently</secondary>. Reason: <secondary><arg:0>",
"smod.command.modlogs.heading": "<primary>Player <secondary><arg:0> <gray>(<arg:1>)", "smod.command.modlogs.heading": "<primary>Player <secondary><arg:0> <gray>(<arg:1>)",
"smod.command.modlogs.mute": "<primary>- is muted until <secondary><arg:0></secondary> <gray>(in <arg:1>)</gray>. Reason: <secondary><arg:2>", "smod.command.modlogs.mute": "<primary>- is muted until <secondary><arg:0></secondary> <gray>(in <arg:1>)</gray>. Reason: <secondary><arg:2>",
"smod.command.modlogs.mute.permanent": "<primary>- is muted <secondary>permanently</secondary>. Reason: <secondary><arg:0>",
"smod.command.modlogs.none": "<primary>- is not currently muted or banned.", "smod.command.modlogs.none": "<primary>- is not currently muted or banned.",
"smod.command.mute.fail.alreadyMuted": "This player is already muted.", "smod.command.mute.fail.alreadyMuted": "This player is already muted.",
"smod.command.mute.fail.forceReason": "Please provide a reason.", "smod.command.mute.fail.forceReason": "Please provide a reason.",
@@ -56,6 +58,7 @@
"smod.menu.info.click": "\u00BB Click to cancel punishment", "smod.menu.info.click": "\u00BB Click to cancel punishment",
"smod.menu.info.duration": "<secondary>Duration: <primary><arg:0>", "smod.menu.info.duration": "<secondary>Duration: <primary><arg:0>",
"smod.menu.info.expiry.future": "<secondary>Expires: <primary>In <arg:0>", "smod.menu.info.expiry.future": "<secondary>Expires: <primary>In <arg:0>",
"smod.menu.info.expiry.never": "<secondary>Expires: <primary>Never",
"smod.menu.info.expiry.past": "<secondary>Expired: <primary><arg:0> ago", "smod.menu.info.expiry.past": "<secondary>Expired: <primary><arg:0> ago",
"smod.menu.info.player": "<secondary>Player: <primary><arg:0>", "smod.menu.info.player": "<secondary>Player: <primary><arg:0>",
"smod.menu.info.punishedBy": "<secondary>Punished by: <primary><arg:0>", "smod.menu.info.punishedBy": "<secondary>Punished by: <primary><arg:0>",
@@ -77,16 +80,20 @@
"smod.menu.type.all": "All", "smod.menu.type.all": "All",
"smod.menu.type.switch": "» Click to switch type", "smod.menu.type.switch": "» Click to switch type",
"smod.punishment.broadcast.ban": "<primary><secondary><arg:0></secondary> was banned by <secondary><arg:1></secondary> for <secondary><arg:3></secondary>.<newline>Reason: <secondary><arg:2>", "smod.punishment.broadcast.ban": "<primary><secondary><arg:0></secondary> was banned by <secondary><arg:1></secondary> for <secondary><arg:3></secondary>.<newline>Reason: <secondary><arg:2>",
"smod.punishment.broadcast.ban.permanent": "<primary><secondary><arg:0></secondary> was banned <secondary>permanently</secondary> by <secondary><arg:1></secondary>.<newline>Reason: <secondary><arg:2>",
"smod.punishment.broadcast.kick": "<primary><secondary><arg:0></secondary> was kicked by <secondary><arg:1></secondary>.<newline>Reason: <secondary><arg:2>", "smod.punishment.broadcast.kick": "<primary><secondary><arg:0></secondary> was kicked by <secondary><arg:1></secondary>.<newline>Reason: <secondary><arg:2>",
"smod.punishment.broadcast.mute": "<primary><secondary><arg:0></secondary> was muted by <secondary><arg:1></secondary> for <secondary><arg:3></secondary>.<newline>Reason: <secondary><arg:2>", "smod.punishment.broadcast.mute": "<primary><secondary><arg:0></secondary> was muted by <secondary><arg:1></secondary> for <secondary><arg:3></secondary>.<newline>Reason: <secondary><arg:2>",
"smod.punishment.broadcast.mute.permanent": "<primary><secondary><arg:0></secondary> was muted <secondary>permanently</secondary> by <secondary><arg:1></secondary>.<newline>Reason: <secondary><arg:2>",
"smod.punishment.cancel.ban": "<primary><secondary><arg:0></secondary> was unbanned by <secondary><arg:1></secondary>.", "smod.punishment.cancel.ban": "<primary><secondary><arg:0></secondary> was unbanned by <secondary><arg:1></secondary>.",
"smod.punishment.cancel.mute": "<primary><secondary><arg:0></secondary> was unmuted by <secondary><arg:1></secondary>.", "smod.punishment.cancel.mute": "<primary><secondary><arg:0></secondary> was unmuted by <secondary><arg:1></secondary>.",
"smod.punishment.name.ban": "Ban", "smod.punishment.name.ban": "Ban",
"smod.punishment.name.kick": "Kick", "smod.punishment.name.kick": "Kick",
"smod.punishment.name.mute": "Mute", "smod.punishment.name.mute": "Mute",
"smod.punishment.playerMessage.ban": "<primary>You have been banned from this server by <secondary><arg:0></secondary>.<newline>Reason: <secondary><arg:1></secondary><newline>Your ban expires in <secondary><arg:2></secondary>.", "smod.punishment.playerMessage.ban": "<primary>You have been banned from this server by <secondary><arg:0></secondary>.<newline>Reason: <secondary><arg:1></secondary><newline>Your ban expires in <secondary><arg:2></secondary>.",
"smod.punishment.playerMessage.ban.permanent": "<primary>You have been banned from this server by <secondary><arg:0></secondary>.<newline>Reason: <secondary><arg:1></secondary><newline>Your ban <secondary>does not</secondary> expire.",
"smod.punishment.playerMessage.kick": "<primary>You have been kicked by <secondary><arg:0></secondary>.<newline>Reason: <secondary><arg:1>", "smod.punishment.playerMessage.kick": "<primary>You have been kicked by <secondary><arg:0></secondary>.<newline>Reason: <secondary><arg:1>",
"smod.punishment.playerMessage.mute": "<primary>You have been muted by <secondary><arg:0></secondary>.<newline>Reason: <secondary><arg:1></secondary><newline>Your mute expires in <secondary><arg:2></secondary>.", "smod.punishment.playerMessage.mute": "<primary>You have been muted by <secondary><arg:0></secondary>.<newline>Reason: <secondary><arg:1></secondary><newline>Your mute expires in <secondary><arg:2></secondary>.",
"smod.punishment.playerMessage.mute.permanent": "<primary>You have been muted by <secondary><arg:0></secondary>.<newline>Reason: <secondary><arg:1></secondary><newline>Your mute <secondary>does not</secondary> expire.",
"smod.punishment.playerMessage.mute.chat": "<primary>You can't run this command while you are muted.", "smod.punishment.playerMessage.mute.chat": "<primary>You can't run this command while you are muted.",
"smod.socialspy.command": "<primary>[<secondary>SocialSpy</secondary>] <arg:0>: <secondary><arg:1>", "smod.socialspy.command": "<primary>[<secondary>SocialSpy</secondary>] <arg:0>: <secondary><arg:1>",
"smod.time.days": "<arg:0> days", "smod.time.days": "<arg:0> days",
@@ -106,6 +113,8 @@
"smod.time.month.8": "September", "smod.time.month.8": "September",
"smod.time.month.9": "October", "smod.time.month.9": "October",
"smod.time.months": "<arg:0> months", "smod.time.months": "<arg:0> months",
"smod.time.never": "Never",
"smod.time.permanent": "Permanent",
"smod.time.seconds": "<arg:0> seconds", "smod.time.seconds": "<arg:0> seconds",
"smod.time.timestamp": "<arg:2> <arg:1> <arg:0> <arg:3>:<arg:4>:<arg:5> <arg:6>", "smod.time.timestamp": "<arg:2> <arg:1> <arg:0> <arg:3>:<arg:4>:<arg:5> <arg:6>",
"smod.time.weeks": "<arg:0> weeks", "smod.time.weeks": "<arg:0> weeks",