diff --git a/build.gradle b/build.gradle index 3a6e295..dd8a7fc 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,9 @@ dependencies { implementation 'org.projectlombok:lombok:1.18.20' implementation 'org.postgresql:postgresql:42.2.20' implementation 'org.apache.commons:commons-lang3:3.12.0' + implementation 'com.github.MilkBowl:VaultAPI:1.7' + implementation 'com.google.code.gson:gson:2.8.7' + implementation 'org.jetbrains:annotations:22.0.0' shadow 'io.projectreactor:reactor-core:3.4.10' compileOnly 'io.papermc.paper:paper-api:1.19.3-R0.1-SNAPSHOT' } diff --git a/src/main/java/mc/unraveled/reforged/api/IService.java b/src/main/java/mc/unraveled/reforged/api/IService.java index 3261836..bfd0b07 100644 --- a/src/main/java/mc/unraveled/reforged/api/IService.java +++ b/src/main/java/mc/unraveled/reforged/api/IService.java @@ -1,7 +1,9 @@ package mc.unraveled.reforged.api; import mc.unraveled.reforged.service.base.ServicePool; +import org.apache.commons.lang3.ArrayUtils; import reactor.core.publisher.Mono; +import reactor.core.publisher.MonoSink; public interface IService extends Runnable { Mono getParentPool(); diff --git a/src/main/java/mc/unraveled/reforged/banning/AbstractBan.java b/src/main/java/mc/unraveled/reforged/banning/AbstractBan.java index 7e0c4c4..9002332 100644 --- a/src/main/java/mc/unraveled/reforged/banning/AbstractBan.java +++ b/src/main/java/mc/unraveled/reforged/banning/AbstractBan.java @@ -13,17 +13,17 @@ public abstract class AbstractBan implements Serializable { private final String ip; private final String source; private final String reason; - private final long propogated; + private final long propagated; private final long expiry; private final List> contentPairs; private boolean active; - public AbstractBan(String uuid, String ip, String source, String reason, long propogated, long expiry, boolean active) { + public AbstractBan(String uuid, String ip, String source, String reason, long propagated, long expiry, boolean active) { this.uuid = uuid; this.ip = ip; this.source = source; this.reason = reason; - this.propogated = propogated; + this.propagated = propagated; this.expiry = expiry; this.active = active; @@ -32,7 +32,7 @@ public abstract class AbstractBan implements Serializable { new Pair<>("ip", ip), new Pair<>("source", source), new Pair<>("reason", reason), - new Pair<>("propogated", String.valueOf(propogated)), + new Pair<>("propagated", String.valueOf(propagated)), new Pair<>("expiry", String.valueOf(expiry)), new Pair<>("active", String.valueOf(active)) ); @@ -55,7 +55,7 @@ public abstract class AbstractBan implements Serializable { char ip = 'i'; char reason = 'r'; char source = 's'; - char propogated = 'p'; + char propagated = 'p'; char expiry = 'e'; char active = 'a'; @@ -63,7 +63,7 @@ public abstract class AbstractBan implements Serializable { String ipString = formatted.substring(formatted.indexOf(ip) + 1, formatted.indexOf(end)); String reasonString = formatted.substring(formatted.indexOf(reason) + 1, formatted.indexOf(end)); String sourceString = formatted.substring(formatted.indexOf(source) + 1, formatted.indexOf(end)); - String propogatedString = formatted.substring(formatted.indexOf(propogated) + 1, formatted.indexOf(end)); + String propagatedString = formatted.substring(formatted.indexOf(propagated) + 1, formatted.indexOf(end)); String expiryString = formatted.substring(formatted.indexOf(expiry) + 1, formatted.indexOf(end)); String activeString = formatted.substring(formatted.indexOf(active) + 1, formatted.indexOf(end)); @@ -71,7 +71,7 @@ public abstract class AbstractBan implements Serializable { ipString, reasonString, sourceString, - Long.parseLong(propogatedString), + Long.parseLong(propagatedString), Long.parseLong(expiryString), Boolean.parseBoolean(activeString)); } diff --git a/src/main/java/mc/unraveled/reforged/banning/BanManager.java b/src/main/java/mc/unraveled/reforged/banning/BanManager.java index 6405776..a88b0b6 100644 --- a/src/main/java/mc/unraveled/reforged/banning/BanManager.java +++ b/src/main/java/mc/unraveled/reforged/banning/BanManager.java @@ -6,6 +6,8 @@ import mc.unraveled.reforged.api.Baker; import mc.unraveled.reforged.api.Locker; import mc.unraveled.reforged.plugin.Traverse; import mc.unraveled.reforged.storage.DBBan; +import mc.unraveled.reforged.storage.DBUser; +import org.bukkit.OfflinePlayer; import java.util.HashSet; import java.util.Set; @@ -40,13 +42,32 @@ public final class BanManager implements Locker, Baker { lock().notify(); storedBans.add(ban); + DBBan db = new DBBan(plugin.getSQLManager().establish()); + db.insert(ban); + db.close(); } public void eject(AbstractBan ban) { if (baked) throw new IllegalStateException("Cannot eject from a baked list."); lock().notify(); - storedBans.remove(ban); + + DBBan db = new DBBan(plugin.getSQLManager().establish()); + db.delete(ban); + db.close(); + } + + public AbstractBan getBan(OfflinePlayer player) { + DBBan db = new DBBan(plugin.getSQLManager().establish()); + AbstractBan ban = db.getBan(player.getUniqueId()); + db.close(); + return ban; + } + + public boolean isBanned(OfflinePlayer player) { + return storedBans.stream() + .anyMatch(ban -> ban.getUuid().equalsIgnoreCase( + player.getUniqueId().toString())); } public void save() { @@ -56,7 +77,6 @@ public final class BanManager implements Locker, Baker { DBBan banHandler = new DBBan(plugin.getSQLManager().establish()); storedBans.forEach(banHandler::insert); banHandler.close(); - } @Override diff --git a/src/main/java/mc/unraveled/reforged/command/BanCMD.java b/src/main/java/mc/unraveled/reforged/command/BanCMD.java index 995905f..59b74a2 100644 --- a/src/main/java/mc/unraveled/reforged/command/BanCMD.java +++ b/src/main/java/mc/unraveled/reforged/command/BanCMD.java @@ -18,8 +18,9 @@ import org.jetbrains.annotations.NotNull; import java.util.Date; @CommandInfo(name = "ban", - description = "Ban a player", - usage = "/ban [duration]") + description = "Ban a player. Use -n as the second parameter for the default ban reason.", + usage = "/ban ", + aliases = {"b", "tempban", "tb"}) public class BanCMD extends AbstractCommandBase { public BanCMD(@NotNull Traverse plugin) { super(plugin, "ban"); @@ -28,13 +29,19 @@ public class BanCMD extends AbstractCommandBase { @Override public Component cmd(CommandSender sender, String[] args) { if (args.length < 2) { - return Component.text("Usage: /ban "); + return Component.text("Usage: /ban "); } BanManager manager = getPlugin().getBanManager(); OfflinePlayer target = (getPlugin().getServer().getPlayer(args[0]) != null) ? getPlugin().getServer().getPlayer(args[0]) : getPlugin().getServer().getOfflinePlayer(args[0]); String duration = args[1]; - String reason = StringUtils.join(ArrayUtils.subarray(args, 2, args.length - 1), " "); + String reason; + + if (args[2].equalsIgnoreCase("-n")) { + reason = MessageDefaults.BANNED.toString(); + } else { + reason = StringUtils.join(ArrayUtils.subarray(args, 2, args.length - 1), " "); + } Date expiry = Utilities.parseDate(duration); String expiryString = Utilities.parseDateToString(expiry); diff --git a/src/main/java/mc/unraveled/reforged/command/EntityPurgeCMD.java b/src/main/java/mc/unraveled/reforged/command/EntityPurgeCMD.java new file mode 100644 index 0000000..a46ef27 --- /dev/null +++ b/src/main/java/mc/unraveled/reforged/command/EntityPurgeCMD.java @@ -0,0 +1,37 @@ +package mc.unraveled.reforged.command; + +import mc.unraveled.reforged.api.annotations.CommandInfo; +import mc.unraveled.reforged.command.base.AbstractCommandBase; +import mc.unraveled.reforged.plugin.Traverse; +import net.kyori.adventure.text.Component; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.*; + +@CommandInfo(name = "entitypurge", + usage = "/entitypurge", + description = "Purge entities", + aliases = {"ep", "ew", "mp", "mw", "mobpurge", "entitywipe", "mobwipe"}) +public class EntityPurgeCMD extends AbstractCommandBase { + public EntityPurgeCMD(Traverse plugin) { + super(plugin, "entitypurge", false); + } + + @Override + public Component cmd(CommandSender sender, String[] args) { + Player player = (Player) sender; + World world = player.getWorld(); + int count = 0; + for (Entity entity : world.getEntities()) { + if ((entity instanceof Player) || + (entity instanceof Tameable) || + (entity instanceof Hanging) || + (entity instanceof Sittable) || + (entity instanceof Steerable)) continue; + + entity.remove(); + count++; + } + return Component.text("Removed " + count + " entities"); + } +} diff --git a/src/main/java/mc/unraveled/reforged/command/GroupCMD.java b/src/main/java/mc/unraveled/reforged/command/GroupCMD.java index dccf77e..38f35f7 100644 --- a/src/main/java/mc/unraveled/reforged/command/GroupCMD.java +++ b/src/main/java/mc/unraveled/reforged/command/GroupCMD.java @@ -17,7 +17,8 @@ import java.util.concurrent.atomic.AtomicBoolean; @CommandInfo(name = "group", description = "Manages groups for all players.", - usage = "/group ") + usage = "/group ", + aliases = {"g"}) public class GroupCMD extends AbstractCommandBase { private final Rank[] ranks = Rank.values(); diff --git a/src/main/java/mc/unraveled/reforged/command/MuteCMD.java b/src/main/java/mc/unraveled/reforged/command/MuteCMD.java index 1635f12..4435927 100644 --- a/src/main/java/mc/unraveled/reforged/command/MuteCMD.java +++ b/src/main/java/mc/unraveled/reforged/command/MuteCMD.java @@ -5,13 +5,18 @@ import mc.unraveled.reforged.command.base.AbstractCommandBase; import mc.unraveled.reforged.data.InfractionData; import mc.unraveled.reforged.data.PlayerData; import mc.unraveled.reforged.plugin.Traverse; +import mc.unraveled.reforged.service.MuteService; +import mc.unraveled.reforged.util.TimeUtil; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -@CommandInfo(name = "mute", description = "Mute a player.", usage = "/mute ") +@CommandInfo(name = "mute", + description = "Mute a player.", + usage = "/mute ", + aliases = {"m", "silence"}) public class MuteCMD extends AbstractCommandBase { public MuteCMD(@NotNull Traverse plugin) { super(plugin, "mute"); @@ -19,14 +24,10 @@ public class MuteCMD extends AbstractCommandBase { @Override public Component cmd(CommandSender sender, String[] args) { - if (args.length != 2) { - return Component.text("Usage: /mute "); - } + if (args.length != 2) return Component.text("Usage: /mute "); Player target = Bukkit.getPlayer(args[0]); - if (target == null) { - return MessageDefaults.MSG_NOT_FOUND; - } + if (target == null) return MessageDefaults.MSG_NOT_FOUND; PlayerData pData = getPlugin().getDataManager().getPlayerData(target.getUniqueId()); if (pData == null) throw new IllegalStateException("PlayerData is null!"); @@ -34,11 +35,15 @@ public class MuteCMD extends AbstractCommandBase { InfractionData infData = pData.getInfractionData(); if (infData == null) throw new IllegalStateException("InfractionData is null!"); + long duration = TimeUtil.parse(args[1]); + if (duration == 0) return Component.text("Invalid duration."); + + MuteService service = new MuteService(getPlugin().getPIPELINE(), "MuteService", duration); + if (!infData.isMuted()) { infData.setMuted(true); + getPlugin().getScheduler().queue(service).subscribe(); return Component.text("You have muted " + target.getName() + " for " + args[1] + " seconds."); - } else { - return Component.text("Target is already muted."); - } + } else return Component.text("Target is already muted."); } } diff --git a/src/main/java/mc/unraveled/reforged/command/PardonCMD.java b/src/main/java/mc/unraveled/reforged/command/PardonCMD.java new file mode 100644 index 0000000..0593e5d --- /dev/null +++ b/src/main/java/mc/unraveled/reforged/command/PardonCMD.java @@ -0,0 +1,46 @@ +package mc.unraveled.reforged.command; + +import mc.unraveled.reforged.api.annotations.CommandInfo; +import mc.unraveled.reforged.banning.AbstractBan; +import mc.unraveled.reforged.command.base.AbstractCommandBase; +import mc.unraveled.reforged.plugin.Traverse; +import mc.unraveled.reforged.storage.DBBan; +import mc.unraveled.reforged.util.Utilities; +import net.kyori.adventure.text.Component; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +@CommandInfo(name = "pardon", description = "Unban a player", usage = "/pardon ", aliases = {"unban", "ub"}) +public class PardonCMD extends AbstractCommandBase { + + public PardonCMD(@NotNull Traverse plugin) { + super(plugin, "pardon"); + } + + @Override + public Component cmd(CommandSender sender, String[] args) { + if (args.length != 1) return Component.text("Usage: /pardon "); + + String name = args[0]; + OfflinePlayer player = Utilities.getOfflinePlayer(name).block(); + + if (player == null) return MessageDefaults.MSG_NOT_FOUND; + + if (getPlugin().getBanManager().isBanned(player)) { + getPlugin().getBanManager().unbake(); + + DBBan ban = new DBBan(getPlugin().getSQLManager().establish()); + AbstractBan inst = ban.getBan(player.getUniqueId()); + + if (inst == null) return Component.text("Failed to find ban for " + name); + + ban.delete(inst); + getPlugin().getBanManager().eject(inst); + getPlugin().getBanManager().bake(); + ban.close(); + + return Component.text("Unbanned " + name); + } else return Component.text(name + " is not banned"); + } +} diff --git a/src/main/java/mc/unraveled/reforged/command/UnmuteCMD.java b/src/main/java/mc/unraveled/reforged/command/UnmuteCMD.java new file mode 100644 index 0000000..5142077 --- /dev/null +++ b/src/main/java/mc/unraveled/reforged/command/UnmuteCMD.java @@ -0,0 +1,41 @@ +package mc.unraveled.reforged.command; + +import mc.unraveled.reforged.api.annotations.CommandInfo; +import mc.unraveled.reforged.command.base.AbstractCommandBase; +import mc.unraveled.reforged.data.InfractionData; +import mc.unraveled.reforged.data.PlayerData; +import mc.unraveled.reforged.plugin.Traverse; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +@CommandInfo(name = "unmute", description = "Unmute a player", usage = "/unmute ", aliases = {"um"}) +public class UnmuteCMD extends AbstractCommandBase { + public UnmuteCMD(@NotNull Traverse plugin) { + super(plugin, "unmute"); + } + + @Override + public Component cmd(CommandSender sender, String[] args) { + if (args.length != 1) return Component.text("Usage: /unmute "); + + String name = args[0]; + + Player player = Bukkit.getPlayer(args[0]); + if (player == null) return MessageDefaults.MSG_NOT_FOUND; + + PlayerData data = getPlugin().getDataManager().getPlayerData(player.getUniqueId()); + if (data == null) return Component.text("Failed to find data for " + name); + + InfractionData inf = data.getInfractionData(); + if (inf == null) return Component.text("Failed to find infraction data for " + name); + + if (inf.isMuted()) { + inf.setMuted(false); + return Component.text("Unmuted " + name); + } + else return Component.text(name + " is not muted"); + } +} diff --git a/src/main/java/mc/unraveled/reforged/command/base/AbstractCommandBase.java b/src/main/java/mc/unraveled/reforged/command/base/AbstractCommandBase.java index c305f9e..023f830 100644 --- a/src/main/java/mc/unraveled/reforged/command/base/AbstractCommandBase.java +++ b/src/main/java/mc/unraveled/reforged/command/base/AbstractCommandBase.java @@ -146,5 +146,7 @@ public abstract class AbstractCommandBase extends TPermission implements IComman public static Component MSG_NOT_FOUND = Component.text("Player not found.").color(NamedTextColor.RED); public static Component MSG_NOT_CONSOLE = Component.text("This command can only be run by a player.").color(NamedTextColor.RED); public static Component MSG_NOT_ENOUGH_ARGS = Component.text("Not enough arguments.").color(NamedTextColor.RED); + public static Component MUTED = Component.text("You are muted!").color(NamedTextColor.RED); + public static Component BANNED = Component.text("You are banned!").color(NamedTextColor.RED); } } diff --git a/src/main/java/mc/unraveled/reforged/data/DataManager.java b/src/main/java/mc/unraveled/reforged/data/DataManager.java index 80c8d60..da73472 100644 --- a/src/main/java/mc/unraveled/reforged/data/DataManager.java +++ b/src/main/java/mc/unraveled/reforged/data/DataManager.java @@ -72,6 +72,12 @@ public final class DataManager implements Baker, Locker { user.close(); } + public void saveCacheToDB() { + DBUser user = new DBUser(plugin.getSQLManager().establish()); + playerDataCache.forEach(user::insert); + user.close(); + } + @SneakyThrows @Override public void bake() { diff --git a/src/main/java/mc/unraveled/reforged/economy/Coin.java b/src/main/java/mc/unraveled/reforged/economy/Coin.java new file mode 100644 index 0000000..0fad0ac --- /dev/null +++ b/src/main/java/mc/unraveled/reforged/economy/Coin.java @@ -0,0 +1,25 @@ +package mc.unraveled.reforged.economy; + +public class Coin { + private final String name; + private final String symbol; + private final double value; + + public Coin(String name, String symbol, double value) { + this.name = name; + this.symbol = symbol; + this.value = value; + } + + public String getName() { + return name; + } + + public String getSymbol() { + return symbol; + } + + public double getValue() { + return value; + } +} diff --git a/src/main/java/mc/unraveled/reforged/economy/EconomyManager.java b/src/main/java/mc/unraveled/reforged/economy/EconomyManager.java new file mode 100644 index 0000000..281d24a --- /dev/null +++ b/src/main/java/mc/unraveled/reforged/economy/EconomyManager.java @@ -0,0 +1,5 @@ +package mc.unraveled.reforged.economy; + +public class EconomyManager { + // TODO: Implement economy +} diff --git a/src/main/java/mc/unraveled/reforged/listening/AbstractListener.java b/src/main/java/mc/unraveled/reforged/listening/AbstractListener.java new file mode 100644 index 0000000..52fab69 --- /dev/null +++ b/src/main/java/mc/unraveled/reforged/listening/AbstractListener.java @@ -0,0 +1,12 @@ +package mc.unraveled.reforged.listening; + +import lombok.AllArgsConstructor; +import lombok.Data; +import mc.unraveled.reforged.plugin.Traverse; +import org.bukkit.event.Listener; + +@AllArgsConstructor +@Data +public class AbstractListener implements Listener { + private final Traverse plugin; +} diff --git a/src/main/java/mc/unraveled/reforged/listening/InfractionListener.java b/src/main/java/mc/unraveled/reforged/listening/InfractionListener.java new file mode 100644 index 0000000..437a466 --- /dev/null +++ b/src/main/java/mc/unraveled/reforged/listening/InfractionListener.java @@ -0,0 +1,40 @@ +package mc.unraveled.reforged.listening; + +import io.papermc.paper.event.player.AsyncChatEvent; +import mc.unraveled.reforged.banning.BanManager; +import mc.unraveled.reforged.data.PlayerData; +import mc.unraveled.reforged.plugin.Traverse; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerLoginEvent; + +public class InfractionListener extends AbstractListener { + + public InfractionListener(Traverse plugin) { + super(plugin); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void banCheck(PlayerLoginEvent event) { + Player player = event.getPlayer(); + BanManager manager = getPlugin().getBanManager(); + if (manager.isBanned(player)) { + Component reason = Component.text(manager.getBan(player).getReason()); + event.disallow(PlayerLoginEvent.Result.KICK_BANNED, reason); + } + } + + @EventHandler + public void muteCheck(AsyncChatEvent event) { + Player player = event.getPlayer(); + PlayerData data = getPlugin().getDataManager().getPlayerData(player.getUniqueId()); + if (data == null) return; + if (data.getInfractionData().isMuted()) { + event.setCancelled(true); + player.sendMessage(Component.text("You are muted!")); + } + } + +} diff --git a/src/main/java/mc/unraveled/reforged/plugin/Traverse.java b/src/main/java/mc/unraveled/reforged/plugin/Traverse.java index 85c25d8..d0545c8 100644 --- a/src/main/java/mc/unraveled/reforged/plugin/Traverse.java +++ b/src/main/java/mc/unraveled/reforged/plugin/Traverse.java @@ -10,6 +10,8 @@ import mc.unraveled.reforged.command.TraverseCMD; import mc.unraveled.reforged.command.base.CommandLoader; import mc.unraveled.reforged.data.DataManager; import mc.unraveled.reforged.permission.RankManager; +import mc.unraveled.reforged.service.base.Scheduling; +import mc.unraveled.reforged.service.base.ServicePool; import mc.unraveled.reforged.storage.DBConnectionHandler; import mc.unraveled.reforged.storage.DBProperties; import org.bukkit.plugin.java.JavaPlugin; @@ -27,6 +29,10 @@ public final class Traverse extends JavaPlugin implements Locker { private BanManager banManager; @Getter private RankManager rankManager; + @Getter + private Scheduling scheduler; + @Getter + private ServicePool PIPELINE; @Override @SneakyThrows @@ -36,10 +42,16 @@ public final class Traverse extends JavaPlugin implements Locker { this.commandLoader = new CommandLoader(this, "TRAVERSE"); this.banManager = new BanManager(this); this.rankManager = new RankManager(this); + this.scheduler = new Scheduling(this); + this.PIPELINE = new ServicePool("PIPELINE", this); } @Override public void onDisable() { + this.banManager.save(); + this.dataManager.saveCacheToDB(); + this.PIPELINE.recycle(); + this.rankManager.save(); // Plugin shutdown logic } diff --git a/src/main/java/mc/unraveled/reforged/service/MuteService.java b/src/main/java/mc/unraveled/reforged/service/MuteService.java new file mode 100644 index 0000000..1cf5a3c --- /dev/null +++ b/src/main/java/mc/unraveled/reforged/service/MuteService.java @@ -0,0 +1,41 @@ +package mc.unraveled.reforged.service; + +import lombok.Getter; +import lombok.Setter; +import mc.unraveled.reforged.data.InfractionData; +import mc.unraveled.reforged.service.base.AbstractService; +import mc.unraveled.reforged.service.base.ServicePool; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import reactor.core.publisher.Mono; + +public class MuteService extends AbstractService { + @Setter + private InfractionData infractionData = null; + + public MuteService(@Nullable ServicePool parentPool, @NotNull String service_name, long delay) { + super(parentPool, service_name, delay); + } + + @Override + public int getServiceId() { + return 0; + } + + @Override + public Mono start() { + if (infractionData == null) return Mono.empty(); + + if (infractionData.isMuted()) return Mono.empty(); + + return Mono.create(sink -> { + infractionData.setMuted(false); + sink.success(); + }); + } + + @Override + public Mono stop() { + return Mono.empty(); + } +} diff --git a/src/main/java/mc/unraveled/reforged/service/SimpleService.java b/src/main/java/mc/unraveled/reforged/service/SimpleService.java deleted file mode 100644 index fd153cc..0000000 --- a/src/main/java/mc/unraveled/reforged/service/SimpleService.java +++ /dev/null @@ -1,28 +0,0 @@ -package mc.unraveled.reforged.service; - -import mc.unraveled.reforged.service.base.AbstractService; -import mc.unraveled.reforged.service.base.ServicePool; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import reactor.core.publisher.Mono; - -public class SimpleService extends AbstractService { - public SimpleService(@Nullable ServicePool parentPool, @NotNull String service_name) { - super(parentPool, service_name); - } - - @Override - public int getServiceId() { - return 0; - } - - @Override - public Mono start() { - return null; - } - - @Override - public Mono stop() { - return null; - } -} diff --git a/src/main/java/mc/unraveled/reforged/service/base/ReactorBukkitScheduler.java b/src/main/java/mc/unraveled/reforged/service/base/ReactorBukkitScheduler.java index 8c572ff..03e62d8 100644 --- a/src/main/java/mc/unraveled/reforged/service/base/ReactorBukkitScheduler.java +++ b/src/main/java/mc/unraveled/reforged/service/base/ReactorBukkitScheduler.java @@ -20,7 +20,7 @@ public final class ReactorBukkitScheduler */ private final BukkitScheduler scheduler; - public ReactorBukkitScheduler(JavaPlugin plugin) { + public ReactorBukkitScheduler(@NotNull JavaPlugin plugin) { this.plugin = plugin; this.scheduler = plugin.getServer().getScheduler(); } diff --git a/src/main/java/mc/unraveled/reforged/storage/DBBan.java b/src/main/java/mc/unraveled/reforged/storage/DBBan.java index c269847..8219a8b 100644 --- a/src/main/java/mc/unraveled/reforged/storage/DBBan.java +++ b/src/main/java/mc/unraveled/reforged/storage/DBBan.java @@ -40,13 +40,13 @@ public class DBBan { statement.setString(3, ban.getIp()); statement.setString(4, ban.getReason()); statement.setString(5, ban.getSource()); - statement.setLong(6, ban.getPropogated()); + statement.setLong(6, ban.getPropagated()); statement.setLong(7, ban.getExpiry()); statement.setBoolean(8, ban.isActive()); statement.setString(9, ban.getIp()); statement.setString(10, ban.getReason()); statement.setString(11, ban.getSource()); - statement.setLong(12, ban.getPropogated()); + statement.setLong(12, ban.getPropagated()); statement.setLong(13, ban.getExpiry()); statement.setBoolean(14, ban.isActive()); statement.setString(15, ban.getUuid()); diff --git a/src/main/java/mc/unraveled/reforged/util/TimeUtil.java b/src/main/java/mc/unraveled/reforged/util/TimeUtil.java new file mode 100644 index 0000000..113328c --- /dev/null +++ b/src/main/java/mc/unraveled/reforged/util/TimeUtil.java @@ -0,0 +1,37 @@ +package mc.unraveled.reforged.util; + +public class TimeUtil { + public static final long SECOND = 1000L; + public static final long MINUTE = SECOND * 60L; + public static final long HOUR = MINUTE * 60L; + public static final long DAY = HOUR * 24L; + public static final long WEEK = DAY * 7L; + public static final long MONTH = DAY * 30L; + public static final long YEAR = DAY * 365L; + public static final long TICK = SECOND / 20L; + + public static long parse(String input) { + long duration = 0L; + StringBuilder number = new StringBuilder(); + for (char c : input.toCharArray()) { + if (Character.isDigit(c)) { + number.append(c); + } else { + String str = number.toString(); + if (str.isEmpty()) continue; + long parsed = Long.parseLong(str); + number = new StringBuilder(); + switch (c) { + case 's' -> duration += parsed * SECOND; + case 'm' -> duration += parsed * MINUTE; + case 'h' -> duration += parsed * HOUR; + case 'd' -> duration += parsed * DAY; + case 'w' -> duration += parsed * WEEK; + case 'M' -> duration += parsed * MONTH; + case 'y' -> duration += parsed * YEAR; + } + } + } + return duration; + } +} diff --git a/src/main/java/mc/unraveled/reforged/util/Utilities.java b/src/main/java/mc/unraveled/reforged/util/Utilities.java index 11edd1e..d529fb2 100644 --- a/src/main/java/mc/unraveled/reforged/util/Utilities.java +++ b/src/main/java/mc/unraveled/reforged/util/Utilities.java @@ -1,15 +1,36 @@ package mc.unraveled.reforged.util; -import org.jetbrains.annotations.Contract; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; import org.jetbrains.annotations.NotNull; +import reactor.core.publisher.Mono; -import java.lang.reflect.Array; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; +import java.util.UUID; import java.util.concurrent.TimeUnit; public final class Utilities { + + /** + * A simple method to serialize a list of pairs into a string. + * The second object in the pair can be of any type. However, + * the second object MUST be serializable. The first object is a denotation device, + * which will only use the first letter of your string. This is to save space in the final output. + * For Example: + *

+ * If you were to have a Pair of "name" and "Bob", a pair of "age" and 20, and a pair of "isAlive" and true, + * the output would be + *

+ * n:Bob;a:20;i:true;

+ * The separator between each string and object is a colon, and the separator between each pair is a semicolon. + *

+ * + * @param objectPairs The list of pairs to serialize. + * @param The type of the second object in the pair. + * @return The serialized string. + */ public static @NotNull String serialize(@NotNull List> objectPairs) { char delimiter = ':'; char end = ';'; @@ -23,6 +44,15 @@ public final class Utilities { return builder.toString(); } + /** + * Convenient method to parse a date from a String which contains a numerical value. + * It's important to note that the contents of the string is converted to a LONG, and thus it is + * subject to the same limitations as a long, i.e. {@link Long#MAX_VALUE} and {@link Long#MIN_VALUE}. + *

+ * + * @param duration The duration to parse. + * @return The parsed date. + */ public static Date parseDate(String duration) { TimeUnit unit; long amount; @@ -39,8 +69,50 @@ public final class Utilities { return new Date(System.currentTimeMillis() + unit.toMillis(amount)); } + /** + * Converts the date into a readable string, with the format dd/MM/yyyy HH:mm:ss. + *

+ * + * @param date The date to convert. + * @return The converted date. + */ public static String parseDateToString(Date date) { SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); return format.format(date); } + + /** + * Converts seconds into ticks. One second = 20 ticks. + * 1 tick = 1/20th of a second. + *

+ * + * @param seconds The amount in seconds to convert. + * @return The amount in ticks. + */ + public static long parseSecondsToTicks(long seconds) { + return seconds * 20; + } + + /** + * Converts ticks into seconds. One second = 20 ticks. + * 1 tick = 1/20th of a second. + * + * @param ticks The amount in ticks to convert. + * @return The amount in seconds. + */ + public static long parseTicksToSeconds(long ticks) { + return ticks / 20; + } + + /** + * This method is necessary because Bukkit's {@link Bukkit#getOfflinePlayer(String)} method + * returns an {@link OfflinePlayer} object, but may execute a blocking web request to retrieve + * the UUID in question. To avoid this, we are wrapping this call in a {@link Mono} object. + * + * @param name The name of the player to retrieve. + * @return A {@link Mono} object containing the {@link OfflinePlayer} object. + */ + public static Mono getOfflinePlayer(String name) { + return Mono.create(sink -> sink.success(Bukkit.getOfflinePlayer(name))); + } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 931deea..6e5f838 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -3,6 +3,8 @@ version: '${version}' main: mc.unraveled.reforged.plugin.Traverse api-version: 1.19 authors: [ SimplexDevelopment ] -description: - A plugin designed for the Unraveled: Reforged server. -website: https://github.com/SimplexDevelopment +description: "A plugin designed for the Unraveled: Reforged server." +website: https://github.com/SimplexDevelopment/Traverse +depend: [ Vault ] +softdepend: [ EssentialsX, EssentialsXSpawn ] +