diff --git a/src/main/java/dev/plex/Plex.java b/src/main/java/dev/plex/Plex.java index 0469381..bb36c2f 100644 --- a/src/main/java/dev/plex/Plex.java +++ b/src/main/java/dev/plex/Plex.java @@ -6,6 +6,7 @@ import dev.plex.cache.DataUtils; import dev.plex.cache.player.MongoPlayerData; import dev.plex.cache.player.PlayerCache; import dev.plex.cache.player.SQLPlayerData; +import dev.plex.cache.sql.SQLNotes; import dev.plex.cache.sql.SQLPunishment; import dev.plex.config.Config; import dev.plex.handlers.CommandHandler; @@ -23,37 +24,46 @@ import dev.plex.util.PlexLog; import dev.plex.util.PlexUtils; import dev.plex.util.UpdateChecker; import dev.plex.world.CustomWorld; -import java.io.File; -import java.io.InputStream; -import java.util.Properties; -import java.util.UUID; import lombok.Getter; import lombok.Setter; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; +import java.io.File; +import java.io.InputStream; +import java.util.Properties; +import java.util.UUID; + @Getter @Setter public class Plex extends JavaPlugin { public static final BuildProperties build = new BuildProperties(); private static Plex plugin; + public Config config; public Config messages; public Config indefBans; + public File modulesFolder; private StorageType storageType = StorageType.SQLITE; + private SQLConnection sqlConnection; private MongoConnection mongoConnection; private RedisConnection redisConnection; + private MongoPlayerData mongoPlayerData; private SQLPlayerData sqlPlayerData; + private SQLPunishment sqlPunishment; + private SQLNotes sqlNotes; + private ModuleManager moduleManager; private RankManager rankManager; private ServiceManager serviceManager; private PunishmentManager punishmentManager; + private AdminList adminList; private UpdateChecker updateChecker; private String system; @@ -103,8 +113,7 @@ public class Plex extends JavaPlugin { PlexUtils.testConnections(); PlexLog.log("Connected to " + storageType.name().toUpperCase()); - } - catch (Exception e) + } catch (Exception e) { PlexLog.error("Failed to connect to " + storageType.name().toUpperCase()); e.printStackTrace(); @@ -121,8 +130,7 @@ public class Plex extends JavaPlugin { redisConnection.getJedis(); PlexLog.log("Connected to Redis!"); - } - else + } else { PlexLog.log("Redis is disabled in the configuration file, not connecting."); } @@ -130,11 +138,11 @@ public class Plex extends JavaPlugin if (storageType == StorageType.MONGODB) { mongoPlayerData = new MongoPlayerData(); - } - else + } else { sqlPlayerData = new SQLPlayerData(); sqlPunishment = new SQLPunishment(); + sqlNotes = new SQLNotes(); } new ListenerHandler(); @@ -175,8 +183,7 @@ public class Plex extends JavaPlugin if (mongoPlayerData != null) //back to mongo checking { mongoPlayerData.update(plexPlayer); //update the player's document - } - else if (sqlPlayerData != null) //sql checking + } else if (sqlPlayerData != null) //sql checking { sqlPlayerData.update(plexPlayer); } @@ -239,8 +246,7 @@ public class Plex extends JavaPlugin author = props.getProperty("buildAuthor", "unknown"); date = props.getProperty("buildDate", "unknown"); head = props.getProperty("buildHead", "unknown"); - } - catch (Exception ex) + } catch (Exception ex) { PlexLog.error("Could not load build properties! Did you compile with NetBeans/Maven?"); } diff --git a/src/main/java/dev/plex/cache/DataUtils.java b/src/main/java/dev/plex/cache/DataUtils.java index fadb12c..b86e73e 100644 --- a/src/main/java/dev/plex/cache/DataUtils.java +++ b/src/main/java/dev/plex/cache/DataUtils.java @@ -55,6 +55,18 @@ public class DataUtils } } + public static PlexPlayer getPlayer(String username) + { + if (Plex.get().getStorageType() == StorageType.MONGODB) + { + return Plex.get().getMongoPlayerData().getByName(username); + } + else + { + return Plex.get().getSqlPlayerData().getByName(username); + } + } + /** * Gets a player from cache or from the database * @@ -80,18 +92,6 @@ public class DataUtils } } - /** - * Gets a player from cache or from the database - * - * @param name Username of the player - * @return a PlexPlayer object - * @see PlexPlayer - */ - public static PlexPlayer getPlayer(String name) - { - return getPlayer(Bukkit.getPlayer(name).getUniqueId()); - } - /** * Updates a player's information in the database * diff --git a/src/main/java/dev/plex/cache/notes/PlayerNotes.java b/src/main/java/dev/plex/cache/notes/PlayerNotes.java new file mode 100644 index 0000000..658d455 --- /dev/null +++ b/src/main/java/dev/plex/cache/notes/PlayerNotes.java @@ -0,0 +1,44 @@ +package dev.plex.cache.notes; + +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import dev.plex.Plex; +import dev.plex.cache.player.PlayerCache; +import dev.plex.player.PlexPlayer; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +public class PlayerNotes +{ + private final String SELECT = "SELECT * FROM `notes` WHERE uuid=?"; + //private final String UPDATE = "UPDATE `notes` SET name=?, written_by=?, note=? WHERE uuid=?"; + private final String INSERT = "INSERT INTO `notes` (`uuid`, `name`, `written_by`, `note`) VALUES (?, ?, ?, ?);"; + + public PlexPlayer getByUUID(UUID uuid) + { + try (Connection con = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = con.prepareStatement(SELECT); + statement.setString(1, uuid.toString()); + ResultSet set = statement.executeQuery(); + PlexPlayer plexPlayer = new PlexPlayer(uuid); + while (set.next()) + { + String name = set.getString("name"); + String writtenBy = set.getString("written_by"); + String note = set.getString("note"); + + } + return plexPlayer; + } + catch (SQLException throwables) + { + throwables.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/dev/plex/cache/player/MongoPlayerData.java b/src/main/java/dev/plex/cache/player/MongoPlayerData.java index c0e816a..f010153 100644 --- a/src/main/java/dev/plex/cache/player/MongoPlayerData.java +++ b/src/main/java/dev/plex/cache/player/MongoPlayerData.java @@ -61,6 +61,18 @@ public class MongoPlayerData return query2.first(); } + public PlexPlayer getByName(String username) + { + PlexPlayer player = PlayerCache.getPlexPlayerMap().values().stream().filter(plexPlayer -> plexPlayer.getName().equalsIgnoreCase(username)).findFirst().orElse(null); + if (player != null) + { + return player; + } + + Query query2 = datastore.find(PlexPlayer.class).filter(Filters.regex("name").caseInsensitive().pattern(username)); + return query2.first(); + } + /** * Gets the player from cache or from mongo's database * diff --git a/src/main/java/dev/plex/cache/player/SQLPlayerData.java b/src/main/java/dev/plex/cache/player/SQLPlayerData.java index f082c72..62f198a 100644 --- a/src/main/java/dev/plex/cache/player/SQLPlayerData.java +++ b/src/main/java/dev/plex/cache/player/SQLPlayerData.java @@ -92,6 +92,49 @@ public class SQLPlayerData return null; } + public PlexPlayer getByName(String username) + { + PlexPlayer player = PlayerCache.getPlexPlayerMap().values().stream().filter(plexPlayer -> plexPlayer.getName().equalsIgnoreCase(username)).findFirst().orElse(null); + if (player != null) + { + return player; + } + try (Connection con = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = con.prepareStatement("SELECT * FROM `players` WHERE name=? LIMIT 1"); + statement.setString(1, username); + ResultSet set = statement.executeQuery(); + while (set.next()) + { + PlexPlayer plexPlayer = new PlexPlayer(UUID.fromString(set.getString("uuid"))); + String loginMSG = set.getString("login_msg"); + String prefix = set.getString("prefix"); + String rankName = set.getString("rank").toUpperCase(); + long coins = set.getLong("coins"); + boolean vanished = set.getBoolean("vanished"); + boolean commandspy = set.getBoolean("commandspy"); + List ips = new Gson().fromJson(set.getString("ips"), new TypeToken>() + { + }.getType()); + plexPlayer.setName(username); + plexPlayer.setLoginMessage(loginMSG); + plexPlayer.setPrefix(prefix); + plexPlayer.setRank(rankName); + plexPlayer.setIps(ips); + plexPlayer.setCoins(coins); + plexPlayer.setVanished(vanished); + plexPlayer.setCommandSpy(commandspy); + return plexPlayer; + } + return null; + } + catch (SQLException throwables) + { + throwables.printStackTrace(); + } + return null; + } + /** * Gets the player from cache or from the SQL database * diff --git a/src/main/java/dev/plex/cache/sql/SQLNotes.java b/src/main/java/dev/plex/cache/sql/SQLNotes.java new file mode 100644 index 0000000..91de294 --- /dev/null +++ b/src/main/java/dev/plex/cache/sql/SQLNotes.java @@ -0,0 +1,97 @@ +package dev.plex.cache.sql; + +import com.google.common.collect.Lists; +import dev.plex.Plex; +import dev.plex.punishment.extra.Note; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public class SQLNotes +{ + private static final String SELECT = "SELECT * FROM `notes` WHERE uuid=?"; + private static final String INSERT = "INSERT INTO `notes` (`id`, `uuid`, `written_by`, `note`, `timestamp`) VALUES(?, ?, ?, ?, ?)"; + private static final String DELETE = "DELETE FROM `notes` WHERE uuid=? AND id=?"; + + public CompletableFuture> getNotes(UUID uuid) + { + return CompletableFuture.supplyAsync(() -> + { + List notes = Lists.newArrayList(); + try (Connection con = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = con.prepareStatement(SELECT); + statement.setString(1, uuid.toString()); + ResultSet set = statement.executeQuery(); + while (set.next()) + { + Note note = new Note( + uuid, + set.getString("note"), + UUID.fromString(set.getString("written_by")), + LocalDateTime.ofInstant(Instant.ofEpochMilli(set.getLong("timestamp")), ZoneId.systemDefault()) + ); + note.setId(set.getInt("id")); + notes.add(note); + } + } + catch (SQLException e) + { + e.printStackTrace(); + } + return notes; + }); + } + + public CompletableFuture deleteNote(int id, UUID uuid) + { + return CompletableFuture.runAsync(() -> + { + try (Connection con = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = con.prepareStatement(DELETE); + statement.setString(1, uuid.toString()); + statement.setInt(2, id); + statement.execute(); + } + catch (SQLException e) + { + e.printStackTrace(); + } + }); + } + + public CompletableFuture addNote(Note note) + { + return CompletableFuture.runAsync(() -> + { + getNotes(note.getUuid()).whenComplete((notes, throwable) -> + { + try (Connection con = Plex.get().getSqlConnection().getCon()) + { + PreparedStatement statement = con.prepareStatement(INSERT); + statement.setInt(1, notes.size()); + statement.setString(2, note.getUuid().toString()); + statement.setString(3, note.getWrittenBy().toString()); + statement.setString(4, note.getNote()); + statement.setLong(5, note.getTimestamp().toInstant(ZoneOffset.UTC).toEpochMilli()); + statement.execute(); + note.setId(notes.size()); + } + catch (SQLException e) + { + e.printStackTrace(); + } + }); + }); + } +} diff --git a/src/main/java/dev/plex/command/impl/EntityWipeCMD.java b/src/main/java/dev/plex/command/impl/EntityWipeCMD.java index c49b687..653bd81 100644 --- a/src/main/java/dev/plex/command/impl/EntityWipeCMD.java +++ b/src/main/java/dev/plex/command/impl/EntityWipeCMD.java @@ -57,9 +57,11 @@ public class EntityWipeCMD extends PlexCommand if (useBlacklist ? entityBlacklist.stream().noneMatch(entityName -> entityName.equalsIgnoreCase(type)) : entityWhitelist.stream().anyMatch(entityName -> entityName.equalsIgnoreCase(type))) { + /* Location loc = entity.getLocation(); loc.setY(-500); entity.teleportAsync(loc); + */ entity.remove(); entityCounts.put(type,entityCounts.getOrDefault(type, 0) + 1); diff --git a/src/main/java/dev/plex/command/impl/MobPurgeCMD.java b/src/main/java/dev/plex/command/impl/MobPurgeCMD.java index c20c629..3f9c362 100644 --- a/src/main/java/dev/plex/command/impl/MobPurgeCMD.java +++ b/src/main/java/dev/plex/command/impl/MobPurgeCMD.java @@ -34,9 +34,11 @@ public class MobPurgeCMD extends PlexCommand { String type = entity.getType().name(); + /* Location loc = entity.getLocation(); loc.setY(-500); entity.teleportAsync(loc); + */ entity.remove(); entityCounts.put(type,entityCounts.getOrDefault(type, 0) + 1); diff --git a/src/main/java/dev/plex/command/impl/NotesCMD.java b/src/main/java/dev/plex/command/impl/NotesCMD.java new file mode 100644 index 0000000..22f233e --- /dev/null +++ b/src/main/java/dev/plex/command/impl/NotesCMD.java @@ -0,0 +1,114 @@ +package dev.plex.command.impl; + +import com.google.common.collect.ImmutableList; +import dev.plex.cache.DataUtils; +import dev.plex.command.PlexCommand; +import dev.plex.command.annotation.CommandParameters; +import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.annotation.System; +import dev.plex.player.PlexPlayer; +import dev.plex.punishment.extra.Note; +import dev.plex.rank.enums.Rank; +import dev.plex.util.PlexLog; +import dev.plex.util.PlexUtils; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@CommandParameters(name = "notes", description = "Manage notes for a player", usage = "/ | remove | clear>") +@CommandPermissions(level = Rank.ADMIN, permission = "plex.notes") +public class NotesCMD extends PlexCommand +{ + private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("MM/dd/yyyy 'at' hh:mm:ss a"); + + @Override + protected Component execute(@NotNull CommandSender sender, @Nullable Player playerSender, String[] args) + { + if (args.length < 2) + { + return usage(); + } + + Player player = getNonNullPlayer(args[0]); + PlexPlayer plexPlayer = getPlexPlayer(player); + + switch (args[1].toLowerCase()) + { + case "list": + { + Component noteList = Component.text("Player notes for: " + plexPlayer.getName()).color(NamedTextColor.GREEN); + /*for (Note note : plugin.getSqlNotes().getNotes(UUID.fromString(plexPlayer.getUuid()))) + { + PlexLog.debug("We got here"); + Component noteLine = Component.text(note.getId() + ". " + note.getWrittenBy() + ": " + note.getNote()).color(NamedTextColor.GOLD); + noteList.append(Component.empty()); + noteList.append(noteLine); + }*/ + send(sender, noteList); + return null; + } + case "add": + { + if (args.length < 3) + { + return usage(); + } + String content = StringUtils.join(ArrayUtils.subarray(args, 2, args.length), " "); + if (playerSender != null) + { + Note note = new Note(UUID.fromString(plexPlayer.getUuid()), content, playerSender.getUniqueId(), LocalDateTime.now()); + plexPlayer.getNotes().add(note); + plugin.getSqlNotes().addNote(note); + return Component.text("Note added.").color(NamedTextColor.GREEN); + } + } + case "remove": + { + return null; + } + case "clear": + { + int count = plexPlayer.getNotes().size(); + final List notes = plexPlayer.getNotes(); + for (Note note : notes) + { + plexPlayer.getNotes().remove(note); + count++; + } + DataUtils.update(plexPlayer); + return Component.text("Cleared " + count + " note(s).").color(NamedTextColor.GREEN); + } + default: + { + return usage(); + } + } + } + + @Override + public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException + { + if (args.length == 1) + { + return PlexUtils.getPlayerNameList(); + } + if (args.length == 2) + { + return Arrays.asList("list", "add", "remove", "clear"); + } + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/src/main/java/dev/plex/command/impl/PlexCMD.java b/src/main/java/dev/plex/command/impl/PlexCMD.java index 7c333d2..4031956 100644 --- a/src/main/java/dev/plex/command/impl/PlexCMD.java +++ b/src/main/java/dev/plex/command/impl/PlexCMD.java @@ -13,6 +13,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; + +import dev.plex.util.PlexLog; import net.kyori.adventure.text.Component; import org.apache.commons.lang.StringUtils; import org.bukkit.command.CommandSender; @@ -52,6 +54,9 @@ public class PlexCMD extends PlexCommand send(sender, "Imported ranks"); send(sender, "Plex successfully reloaded."); plugin.setSystem(plugin.config.getString("system")); + plugin.getServiceManager().endServices(); + plugin.getServiceManager().startServices(); + PlexLog.debug("Restarted services"); return null; } else if (args[0].equalsIgnoreCase("redis")) diff --git a/src/main/java/dev/plex/command/impl/ToggleDropsCMD.java b/src/main/java/dev/plex/command/impl/ToggleDropsCMD.java new file mode 100644 index 0000000..ca396ea --- /dev/null +++ b/src/main/java/dev/plex/command/impl/ToggleDropsCMD.java @@ -0,0 +1,38 @@ +package dev.plex.command.impl; + +import dev.plex.command.PlexCommand; +import dev.plex.command.annotation.CommandParameters; +import dev.plex.command.annotation.CommandPermissions; +import dev.plex.command.source.RequiredCommandSource; +import dev.plex.rank.enums.Rank; +import dev.plex.services.ServiceManager; +import dev.plex.services.impl.AutoWipeService; +import dev.plex.util.PlexUtils; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +@CommandPermissions(level = Rank.ADMIN, permission = "plex.toggledrops", source = RequiredCommandSource.ANY) +@CommandParameters(name = "toggledrops", description = "Toggle immediately removing drops.", usage = "/", aliases = "td") +public class ToggleDropsCMD extends PlexCommand +{ + @Override + protected Component execute(@NotNull CommandSender sender, @Nullable Player playerSender, @NotNull String[] args) + { + plugin.config.set("allowdrops", !plugin.config.getBoolean("allowdrops")); + plugin.config.save(); + send(sender, plugin.config.getBoolean("allowdrops") ? messageComponent("allowDropsEnabled") : messageComponent("allowDropsDisabled")); + return null; + } +} \ No newline at end of file diff --git a/src/main/java/dev/plex/listener/impl/DropListener.java b/src/main/java/dev/plex/listener/impl/DropListener.java new file mode 100644 index 0000000..1aa2dfb --- /dev/null +++ b/src/main/java/dev/plex/listener/impl/DropListener.java @@ -0,0 +1,14 @@ +package dev.plex.listener.impl; + +import dev.plex.listener.PlexListener; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerDropItemEvent; + +public class DropListener extends PlexListener +{ + @EventHandler + public void onPlayerDropItem(PlayerDropItemEvent event) + { + if (!plugin.config.getBoolean("allowdrops")) event.setCancelled(true); + } +} diff --git a/src/main/java/dev/plex/listener/impl/PlayerListener.java b/src/main/java/dev/plex/listener/impl/PlayerListener.java index 16ab66b..7bab735 100644 --- a/src/main/java/dev/plex/listener/impl/PlayerListener.java +++ b/src/main/java/dev/plex/listener/impl/PlayerListener.java @@ -78,6 +78,10 @@ public class PlayerListener extends PlexListener { PlexUtils.broadcast(MiniMessage.miniMessage().deserialize("" + player.getName() + " is " + loginMessage)); } + + plexPlayer.loadNotes().whenComplete((notes, throwable) -> { + //TODO: Send note messages to admins + }); } // saving the player's data diff --git a/src/main/java/dev/plex/player/PlexPlayer.java b/src/main/java/dev/plex/player/PlexPlayer.java index 5cc18ed..64b1ba1 100644 --- a/src/main/java/dev/plex/player/PlexPlayer.java +++ b/src/main/java/dev/plex/player/PlexPlayer.java @@ -1,17 +1,24 @@ package dev.plex.player; import com.google.common.collect.Lists; +import com.google.gson.GsonBuilder; import dev.morphia.annotations.Entity; import dev.morphia.annotations.Id; import dev.morphia.annotations.IndexOptions; import dev.morphia.annotations.Indexed; import dev.plex.Plex; import dev.plex.punishment.Punishment; +import dev.plex.punishment.extra.Note; import dev.plex.rank.enums.Rank; import dev.plex.storage.StorageType; + +import java.time.LocalDateTime; import java.util.List; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; + +import dev.plex.util.adapter.LocalDateTimeSerializer; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -43,9 +50,10 @@ public class PlexPlayer private boolean vanished; private boolean commandSpy; - private boolean frozen; - private boolean muted; - private boolean lockedUp; + // These fields are transient so MongoDB doesn't automatically drop them in. + private transient boolean frozen; + private transient boolean muted; + private transient boolean lockedUp; private long coins; @@ -53,6 +61,7 @@ public class PlexPlayer private List ips = Lists.newArrayList(); private List punishments = Lists.newArrayList(); + private List notes = Lists.newArrayList(); public PlexPlayer() { @@ -111,4 +120,18 @@ public class PlexPlayer this.setPunishments(Plex.get().getSqlPunishment().getPunishments(UUID.fromString(this.getUuid())).stream().filter(punishment -> punishment.getPunished().equals(UUID.fromString(this.getUuid()))).collect(Collectors.toList())); } } + + public CompletableFuture> loadNotes() + { + if (Plex.get().getStorageType() != StorageType.MONGODB) + { + return Plex.get().getSqlNotes().getNotes(UUID.fromString(this.getUuid())); + } + return null; + } + + public String toJSON() + { + return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()).create().toJson(this); + } } diff --git a/src/main/java/dev/plex/punishment/extra/Note.java b/src/main/java/dev/plex/punishment/extra/Note.java new file mode 100644 index 0000000..411a316 --- /dev/null +++ b/src/main/java/dev/plex/punishment/extra/Note.java @@ -0,0 +1,24 @@ +package dev.plex.punishment.extra; + +import com.google.gson.GsonBuilder; +import dev.plex.util.adapter.LocalDateTimeSerializer; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Data +public class Note +{ + private final UUID uuid; + private final String note; + private final UUID writtenBy; + private final LocalDateTime timestamp; + + private int id; // This will be automatically set from addNote + + public String toJSON() + { + return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()).create().toJson(this); + } +} diff --git a/src/main/java/dev/plex/services/AbstractService.java b/src/main/java/dev/plex/services/AbstractService.java index 5ea2edf..45b4af2 100644 --- a/src/main/java/dev/plex/services/AbstractService.java +++ b/src/main/java/dev/plex/services/AbstractService.java @@ -1,25 +1,31 @@ package dev.plex.services; import dev.plex.PlexBase; +import lombok.Getter; +import lombok.Setter; +@Getter public abstract class AbstractService extends PlexBase implements IService { private boolean asynchronous; private boolean repeating; + @Setter + private int taskId; + public AbstractService(boolean repeating, boolean async) { this.repeating = repeating; this.asynchronous = async; } - public boolean isRepeating() + public void onStart() { - return repeating; + } - public boolean isAsynchronous() + public void onEnd() { - return asynchronous; + } } diff --git a/src/main/java/dev/plex/services/ServiceManager.java b/src/main/java/dev/plex/services/ServiceManager.java index afb9906..e3362ab 100644 --- a/src/main/java/dev/plex/services/ServiceManager.java +++ b/src/main/java/dev/plex/services/ServiceManager.java @@ -2,12 +2,15 @@ package dev.plex.services; import com.google.common.collect.Lists; import dev.plex.Plex; +import dev.plex.services.impl.AutoWipeService; import dev.plex.services.impl.BanService; import dev.plex.services.impl.GameRuleService; import dev.plex.services.impl.SpawnEggService; import dev.plex.services.impl.UpdateCheckerService; -import java.util.List; import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitTask; + +import java.util.List; public class ServiceManager { @@ -19,27 +22,64 @@ public class ServiceManager registerService(new GameRuleService()); registerService(new UpdateCheckerService()); registerService(new SpawnEggService()); + registerService(new AutoWipeService()); } public void startServices() { for (AbstractService service : services) { - if (!service.isRepeating()) - { - Bukkit.getScheduler().runTask(Plex.get(), service::run); - } - else if (service.isRepeating() && service.isAsynchronous()) - { - Bukkit.getScheduler().runTaskTimerAsynchronously(Plex.get(), service::run, 0, 20L * service.repeatInSeconds()); - } - else if (service.isRepeating() && !service.isAsynchronous()) - { - Bukkit.getScheduler().runTaskTimer(Plex.get(), service::run, 0, 20L * service.repeatInSeconds()); - } + startService(service); } } + public void endServices() + { + services.forEach(this::endService); + } + + public AbstractService getService(Class clazz) + { + return services.stream().filter(service -> service.getClass().isAssignableFrom(clazz)).findFirst().orElse(null); + } + + public void startService(AbstractService service) + { + if (!service.isRepeating()) + { + BukkitTask task = Bukkit.getScheduler().runTask(Plex.get(), service::run); + service.setTaskId(task.getTaskId()); + } else if (service.isRepeating() && service.isAsynchronous()) + { + BukkitTask task = Bukkit.getScheduler().runTaskTimerAsynchronously(Plex.get(), service::run, 0, 20L * service.repeatInSeconds()); + service.setTaskId(task.getTaskId()); + } else if (service.isRepeating() && !service.isAsynchronous()) + { + BukkitTask task = Bukkit.getScheduler().runTaskTimer(Plex.get(), service::run, 0, 20L * service.repeatInSeconds()); + service.setTaskId(task.getTaskId()); + } + if (!services.contains(service)) + { + services.add(service); + } + service.onStart(); + } + + public void endService(AbstractService service, boolean remove) + { + Bukkit.getScheduler().cancelTask(service.getTaskId()); + service.onEnd(); + if (remove) + { + services.remove(service); + } + } + + public void endService(AbstractService service) + { + endService(service, false); + } + private void registerService(AbstractService service) { services.add(service); diff --git a/src/main/java/dev/plex/services/impl/AutoWipeService.java b/src/main/java/dev/plex/services/impl/AutoWipeService.java new file mode 100644 index 0000000..aff79b5 --- /dev/null +++ b/src/main/java/dev/plex/services/impl/AutoWipeService.java @@ -0,0 +1,44 @@ +package dev.plex.services.impl; + +import dev.plex.Plex; +import dev.plex.services.AbstractService; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; + +import java.util.List; + +public class AutoWipeService extends AbstractService +{ + public AutoWipeService() + { + super(true, false); + } + + @Override + public void run() + { + if (Plex.get().config.getBoolean("autowipe.enabled")) + { + List entities = plugin.config.getStringList("autowipe.entities"); + + for (World world : Bukkit.getWorlds()) + { + for (Entity entity : world.getEntities()) + { + if (entities.stream().anyMatch(entityName -> entityName.equalsIgnoreCase(entity.getType().name()))) + { + entity.remove(); + } + } + } + } + } + + @Override + public int repeatInSeconds() + { + return Math.max(1, plugin.config.getInt("autowipe.interval")); + } +} \ No newline at end of file diff --git a/src/main/java/dev/plex/storage/SQLConnection.java b/src/main/java/dev/plex/storage/SQLConnection.java index 79e0d26..faeb8e0 100644 --- a/src/main/java/dev/plex/storage/SQLConnection.java +++ b/src/main/java/dev/plex/storage/SQLConnection.java @@ -76,6 +76,13 @@ public class SQLConnection extends PlexBase "`active` BOOLEAN, " + "`endDate` BIGINT" + ");").execute(); + con.prepareStatement("CREATE TABLE IF NOT EXISTS `notes` (" + + "`id` INT NOT NULL, " + + "`uuid` VARCHAR(46) NOT NULL, " + + "`written_by` VARCHAR(46), " + + "`note` VARCHAR(2000), " + + "`timestamp` BIGINT" + + ");").execute(); } catch (SQLException throwables) { diff --git a/src/main/java/dev/plex/util/item/ItemBuilder.java b/src/main/java/dev/plex/util/item/ItemBuilder.java new file mode 100644 index 0000000..09ccf4b --- /dev/null +++ b/src/main/java/dev/plex/util/item/ItemBuilder.java @@ -0,0 +1,62 @@ +package dev.plex.util.item; + +import net.kyori.adventure.text.Component; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.Arrays; + +public class ItemBuilder +{ + + private final ItemStack itemStack; + private final ItemMeta meta; + + public ItemBuilder(Material material) + { + this.itemStack = new ItemStack(material); + this.meta = itemStack.getItemMeta(); + } + + public ItemBuilder lore(Component... lore) + { + this.meta.lore(Arrays.asList(lore)); + return this; + } + + public ItemBuilder displayName(Component displayName) + { + this.meta.displayName(displayName); + return this; + } + + public ItemBuilder addEnchantment(Enchantment enchantment, int level) + { + this.meta.addEnchant(enchantment, level, true); + return this; + } + + public ItemBuilder addItemFlag(ItemFlag... flags) + { + this.meta.addItemFlags(flags); + return this; + } + + public ItemBuilder addAttributeModifier(Attribute attribute, AttributeModifier modifier) + { + this.meta.addAttributeModifier(attribute, modifier); + return this; + } + + public ItemStack build() + { + this.itemStack.setItemMeta(this.meta); + return this.itemStack; + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 2e4117a..8a0b567 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -141,6 +141,19 @@ entitywipe_list: - "ZOMBIFIED_PIGLIN" - "PUFFERFISH" +# Automatically wipe the specified entities +autowipe: + # Should we automatically wipe entities? + enabled: true + # How often, in seconds, to automatically wipe entities. Default is 5 minutes. + interval: 300 + # Entities to automatically wipe + entities: + - "DROPPED_ITEM" + +# Should we allow drops from players? +allowdrops: true + worlds: flatlands: name: "Flatlands" diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index a6f6b5d..7cbd1ef 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -159,4 +159,7 @@ invalidEntityType: "Notice: Entity type {0} is invalid!" noRemovedEntities: "No entities were removed." # 0 - The command sender # 1 - Number of mobs removed -removedMobs: "{0} - Removed {1} mobs" \ No newline at end of file +removedMobs: "{0} - Removed {1} mobs" +autoWipeDisabled: "Item wiping is currently disabled in the config!" +allowDropsDisabled: "No longer allowing drops from players." +allowDropsEnabled: "Now allowing drops from players." \ No newline at end of file