diff --git a/build.gradle b/build.gradle index dff5a7c3..af2a02a2 100644 --- a/build.gradle +++ b/build.gradle @@ -50,6 +50,7 @@ dependencies { compileOnly fileTree(dir:'libs',includes:['*.jar']) compileOnly('io.papermc.paper:paper-api:1.17.1-R0.1-SNAPSHOT') compileOnly('com.github.angeschossen:LandsAPI:6.5.1') + compileOnly('com.zaxxer:HikariCP:5.0.1') compileOnly('com.github.Archy-X:AureliumSkills:Beta1.3.6') compileOnly('com.github.TechFortress:GriefPrevention:16.18') compileOnly('com.palmergames.bukkit.towny:towny:0.98.2.0') diff --git a/src/main/java/net/momirealms/customfishing/CustomFishing.java b/src/main/java/net/momirealms/customfishing/CustomFishing.java index eb8098fa..8b6ba02d 100644 --- a/src/main/java/net/momirealms/customfishing/CustomFishing.java +++ b/src/main/java/net/momirealms/customfishing/CustomFishing.java @@ -70,6 +70,7 @@ public final class CustomFishing extends JavaPlugin { LibraryLoader.load("redis.clients","jedis","4.2.3","https://repo.maven.apache.org/maven2/"); LibraryLoader.load("org.apache.commons","commons-pool2","2.11.1","https://repo.maven.apache.org/maven2/"); LibraryLoader.load("dev.dejvokep","boosted-yaml","1.3","https://repo.maven.apache.org/maven2/"); + LibraryLoader.load("com.zaxxer","HikariCP","5.0.1","https://repo.maven.apache.org/maven2/"); } @Override diff --git a/src/main/java/net/momirealms/customfishing/api/event/TotemActivationEvent.java b/src/main/java/net/momirealms/customfishing/api/event/TotemActivationEvent.java index 2d350828..590ca4d8 100644 --- a/src/main/java/net/momirealms/customfishing/api/event/TotemActivationEvent.java +++ b/src/main/java/net/momirealms/customfishing/api/event/TotemActivationEvent.java @@ -1,4 +1,48 @@ package net.momirealms.customfishing.api.event; -public class TotemActivationEvent { +import net.momirealms.customfishing.object.totem.Totem; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.NotNull; + +public class TotemActivationEvent extends PlayerEvent implements Cancellable { + + private boolean cancelled; + private final Totem totem; + private final Location location; + private static final HandlerList handlerList = new HandlerList(); + + + public TotemActivationEvent(@NotNull Player who, Location location, Totem totem) { + super(who); + this.cancelled = false; + this.totem = totem; + this.location = location; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + cancelled = cancel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return handlerList; + } + + public Totem getTotem() { + return totem; + } + + public Location getLocation() { + return location; + } } diff --git a/src/main/java/net/momirealms/customfishing/data/SqlConnection.java b/src/main/java/net/momirealms/customfishing/data/SqlConnection.java new file mode 100644 index 00000000..c5d45830 --- /dev/null +++ b/src/main/java/net/momirealms/customfishing/data/SqlConnection.java @@ -0,0 +1,201 @@ +///* +// * Copyright (C) <2022> +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see . +// */ +// +//package net.momirealms.customfishing.data; +// +//import com.zaxxer.hikari.HikariDataSource; +//import net.momirealms.customfishing.CustomFishing; +//import net.momirealms.customnameplates.ConfigManager; +//import net.momirealms.customnameplates.CustomNameplates; +// +//import java.io.File; +//import java.sql.Connection; +//import java.sql.DriverManager; +//import java.sql.SQLException; +// +//public class SqlConnection { +// +// private String driver = "com.mysql.jdbc.Driver"; +// +// private final File dataFolder = CustomFishing.plugin.getDataFolder(); +// +// private boolean secon = false; +// private boolean isfirstry = true; +// +// public int waitTimeOut = 10; +// +// public File userdata = new File(dataFolder, "data.db"); +// private Connection connection = null; +// private HikariDataSource hikari = null; +// +// /* +// 新建Hikari配置 +// */ +// private void createNewHikariConfiguration() { +// hikari = new HikariDataSource(); +// hikari.setPoolName("[Nameplates]"); +// hikari.setJdbcUrl(ConfigManager.Database.url); +// hikari.setUsername(ConfigManager.Database.user); +// hikari.setPassword(ConfigManager.Database.password); +// hikari.setMaximumPoolSize(ConfigManager.Database.maximum_pool_size); +// hikari.setMinimumIdle(ConfigManager.Database.minimum_idle); +// hikari.setMaxLifetime(ConfigManager.Database.maximum_lifetime); +// hikari.addDataSourceProperty("cachePrepStmts", "true"); +// hikari.addDataSourceProperty("prepStmtCacheSize", "250"); +// hikari.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); +// hikari.addDataSourceProperty("userServerPrepStmts", "true"); +// if (hikari.getMinimumIdle() < hikari.getMaximumPoolSize()) { +// hikari.setIdleTimeout(ConfigManager.Database.idle_timeout); +// } else { +// hikari.setIdleTimeout(0); +// } +// } +// +// /* +// 设置驱动,区分Mysql5与8 +// */ +// private void setDriver() { +// if(ConfigManager.Database.use_mysql){ +// try { +// Class.forName("com.mysql.cj.jdbc.Driver"); +// } catch (ClassNotFoundException e) { +// driver = ("com.mysql.jdbc.Driver"); +// return; +// } +// driver = ("com.mysql.cj.jdbc.Driver"); +// }else { +// driver = ("org.sqlite.JDBC"); +// } +// } +// +// public boolean setGlobalConnection() { +// setDriver(); +// try { +// if (ConfigManager.Database.enable_pool) { +// createNewHikariConfiguration(); +// Connection connection = getConnection(); +// closeHikariConnection(connection); +// } else { +// Class.forName(driver); +// if(ConfigManager.Database.use_mysql){ +// connection = DriverManager.getConnection(ConfigManager.Database.url, ConfigManager.Database.user, ConfigManager.Database.password); +// }else { +// connection = DriverManager.getConnection("jdbc:sqlite:" + userdata.toString()); +// } +// } +// if (secon) { +// AdventureUtil.consoleMessage("[CustomNameplates] Successfully reconnect to SQL!"); +// } else { +// secon = true; +// } +// return true; +// } catch (SQLException e) { +// AdventureUtil.consoleMessage("[CustomNameplates] Error! Failed to connect to SQL!"); +// e.printStackTrace(); +// close(); +// return false; +// } catch (ClassNotFoundException e) { +// AdventureUtil.consoleMessage("[CustomNameplates] Error! Failed to load JDBC driver"); +// } +// return false; +// } +// +// public Connection getConnectionAndCheck() { +// if (!canConnect()) { +// return null; +// } +// try { +// return getConnection(); +// } catch (SQLException e) { +// if (isfirstry) { +// isfirstry = false; +// close(); +// return getConnectionAndCheck(); +// } else { +// isfirstry = true; +// AdventureUtil.consoleMessage("[CustomNameplates] Error! Failed to connect to SQL!"); +// close(); +// e.printStackTrace(); +// return null; +// } +// } +// } +// +// public Connection getConnection() throws SQLException { +// if (ConfigManager.Database.enable_pool) { +// return hikari.getConnection(); +// } else { +// return connection; +// } +// } +// +// @SuppressWarnings("BooleanMethodIsAlwaysInverted") +// public boolean canConnect() { +// try { +// if (ConfigManager.Database.enable_pool) { +// if (hikari == null) { +// return setGlobalConnection(); +// } +// if (hikari.isClosed()) { +// return setGlobalConnection(); +// } +// } else { +// if (connection == null) { +// return setGlobalConnection(); +// } +// if (connection.isClosed()) { +// return setGlobalConnection(); +// } +// if (ConfigManager.Database.use_mysql) { +// if (!connection.isValid(waitTimeOut)) { +// secon = false; +// return setGlobalConnection(); +// } +// } +// } +// } catch (SQLException e) { +// e.printStackTrace(); +// return false; +// } +// return true; +// } +// +// public void closeHikariConnection(Connection connection) { +// if (!ConfigManager.Database.enable_pool) { +// return; +// } +// try { +// connection.close(); +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// } +// +// public void close() { +// try { +// if (connection != null) { +// connection.close(); +// } +// if (hikari != null) { +// hikari.close(); +// } +// } catch (SQLException e) { +// AdventureUtil.consoleMessage("[CustomNameplates] Error! Failed to close SQL!"); +// e.printStackTrace(); +// } +// } +//} \ No newline at end of file diff --git a/src/main/java/net/momirealms/customfishing/integration/antigrief/LandsHook.java b/src/main/java/net/momirealms/customfishing/integration/antigrief/LandsHook.java index c62bc9e1..ddf79a32 100644 --- a/src/main/java/net/momirealms/customfishing/integration/antigrief/LandsHook.java +++ b/src/main/java/net/momirealms/customfishing/integration/antigrief/LandsHook.java @@ -19,7 +19,7 @@ package net.momirealms.customfishing.integration.antigrief; import me.angeschossen.lands.api.flags.Flags; import me.angeschossen.lands.api.land.Area; -import net.momirealms.customcrops.CustomCrops; +import net.momirealms.customfishing.CustomFishing; import net.momirealms.customfishing.integration.AntiGriefInterface; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -28,14 +28,14 @@ public class LandsHook implements AntiGriefInterface { @Override public boolean canBreak(Location location, Player player) { - Area area = new me.angeschossen.lands.api.integration.LandsIntegration(CustomCrops.plugin).getAreaByLoc(location); + Area area = new me.angeschossen.lands.api.integration.LandsIntegration(CustomFishing.plugin).getAreaByLoc(location); if (area != null) return area.hasFlag(player, Flags.BLOCK_BREAK, false); else return true; } @Override public boolean canPlace(Location location, Player player) { - Area area = new me.angeschossen.lands.api.integration.LandsIntegration(CustomCrops.plugin).getAreaByLoc(location); + Area area = new me.angeschossen.lands.api.integration.LandsIntegration(CustomFishing.plugin).getAreaByLoc(location); if (area != null) return area.hasFlag(player, Flags.BLOCK_PLACE, false); else return true; } diff --git a/src/main/java/net/momirealms/customfishing/manager/BonusManager.java b/src/main/java/net/momirealms/customfishing/manager/BonusManager.java index 22d93f40..b57ab063 100644 --- a/src/main/java/net/momirealms/customfishing/manager/BonusManager.java +++ b/src/main/java/net/momirealms/customfishing/manager/BonusManager.java @@ -103,7 +103,7 @@ public class BonusManager extends Function { ENCHANTS.put(key + ":" + level, bonus); }); } - AdventureUtil.consoleMessage("[CustomFishing] Loaded " + ENCHANTS.size() + " enchantments"); + AdventureUtil.consoleMessage("[CustomFishing] Loaded " + keys.size() + " enchantments"); } private void loadBait() { diff --git a/src/main/java/net/momirealms/customfishing/manager/DataManager.java b/src/main/java/net/momirealms/customfishing/manager/DataManager.java index 028f9abb..1506deb7 100644 --- a/src/main/java/net/momirealms/customfishing/manager/DataManager.java +++ b/src/main/java/net/momirealms/customfishing/manager/DataManager.java @@ -1,9 +1,22 @@ package net.momirealms.customfishing.manager; import net.momirealms.customfishing.object.Function; +import net.momirealms.customfishing.util.ConfigUtil; +import org.bukkit.configuration.file.YamlConfiguration; public class DataManager extends Function { + public static String user; + public static String password; + public static String url; + public static String ENCODING; + public static String tableName; + public static boolean enable_pool; + public static int maximum_pool_size; + public static int minimum_idle; + public static int maximum_lifetime; + public static int idle_timeout; + @Override public void load() { super.load(); @@ -13,4 +26,9 @@ public class DataManager extends Function { public void unload() { super.unload(); } + + public void loadConfig() { + YamlConfiguration config = ConfigUtil.getConfig("database.yml"); + + } } diff --git a/src/main/java/net/momirealms/customfishing/manager/FishingManager.java b/src/main/java/net/momirealms/customfishing/manager/FishingManager.java index ed517d66..42dc7529 100644 --- a/src/main/java/net/momirealms/customfishing/manager/FishingManager.java +++ b/src/main/java/net/momirealms/customfishing/manager/FishingManager.java @@ -8,11 +8,9 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.momirealms.customfishing.CustomFishing; -import net.momirealms.customfishing.api.event.FishFinderEvent; -import net.momirealms.customfishing.api.event.FishHookEvent; -import net.momirealms.customfishing.api.event.FishResultEvent; -import net.momirealms.customfishing.api.event.RodCastEvent; +import net.momirealms.customfishing.api.event.*; import net.momirealms.customfishing.competition.Competition; +import net.momirealms.customfishing.integration.AntiGriefInterface; import net.momirealms.customfishing.integration.MobInterface; import net.momirealms.customfishing.integration.item.McMMOTreasure; import net.momirealms.customfishing.listener.*; @@ -23,6 +21,8 @@ import net.momirealms.customfishing.object.loot.DroppedItem; import net.momirealms.customfishing.object.loot.Loot; import net.momirealms.customfishing.object.loot.Mob; import net.momirealms.customfishing.object.requirements.RequirementInterface; +import net.momirealms.customfishing.object.totem.ActivatedTotem; +import net.momirealms.customfishing.object.totem.Totem; import net.momirealms.customfishing.util.AdventureUtil; import net.momirealms.customfishing.util.ItemStackUtil; import org.apache.commons.lang.StringUtils; @@ -64,6 +64,7 @@ public class FishingManager extends Function { private final HashMap nextBonus; private final HashMap vanillaLoot; private final ConcurrentHashMap fishingPlayerCache; + private final ConcurrentHashMap totemCache; public FishingManager() { this.playerFishListener = new PlayerFishListener(this); @@ -74,6 +75,7 @@ public class FishingManager extends Function { this.nextBonus = new HashMap<>(); this.vanillaLoot = new HashMap<>(); this.fishingPlayerCache = new ConcurrentHashMap<>(); + this.totemCache = new ConcurrentHashMap<>(); load(); } @@ -183,6 +185,13 @@ public class FishingManager extends Function { } } + for (ActivatedTotem activatedTotem : totemCache.values()) { + if (activatedTotem.getNearbyPlayerSet().contains(player)) { + initialBonus.addBonus(activatedTotem.getTotem().getBonus()); + break; + } + } + if (ConfigManager.enableFishingBag && noBait) { //育儿袋 } @@ -655,19 +664,59 @@ public class FishingManager extends Function { @Override public void onInteract(PlayerInteractEvent event) { ItemStack itemStack = event.getItem(); + final Player player = event.getPlayer(); if (itemStack == null || itemStack.getType() == Material.AIR) return; + NBTItem nbtItem = new NBTItem(itemStack); NBTCompound cfCompound = nbtItem.getCompound("CustomFishing"); if (cfCompound != null && cfCompound.getString("type").equals("util") && cfCompound.getString("id").equals("fishfinder")) { + if (isCoolDown(player, 2000)) return; useFinder(event.getPlayer()); return; } + Block block = event.getClickedBlock(); if (block == null) return; - String totemID = nbtItem.getString("totem"); + String totemID = nbtItem.getString("Totem"); if (totemID.equals("")) return; - if (!TotemManager.TOTEMS.containsKey(totemID)) return; + Totem totem = TotemManager.TOTEMS.get(totemID); + if (totem == null) return; + if (isCoolDown(player, 1000)) return; + String blockID = CustomFishing.plugin.getIntegrationManager().getBlockInterface().getID(block); + if (blockID == null) return; + List totemList = TotemManager.CORES.get(blockID); + if (totemList == null || !totemList.contains(totem)) return; + Location coreLoc = block.getLocation(); + int type = CustomFishing.plugin.getTotemManager().checkLocationModel(totem.getOriginalModel(), coreLoc); + if (type == 0) return; + if (!AntiGriefInterface.testBreak(player, coreLoc)) return; + TotemActivationEvent totemActivationEvent = new TotemActivationEvent(player, coreLoc, totem); + Bukkit.getPluginManager().callEvent(totemActivationEvent); + if (totemActivationEvent.isCancelled()) { + return; + } + + if (totemCache.get(coreLoc) != null) { + totemCache.get(coreLoc).stop(); + } + + CustomFishing.plugin.getTotemManager().removeModel(totem.getFinalModel(), coreLoc, type); + if (player.getGameMode() != GameMode.CREATIVE) itemStack.setAmount(itemStack.getAmount() - 1); + + for (ActionInterface action : totem.getActivatorActions()) { + action.doOn(player, null); + } + for (ActionInterface action : totem.getNearbyActions()) { + for (Player nearby : coreLoc.getNearbyPlayers(totem.getRadius())) { + action.doOn(nearby, player); + } + } + + Location bottomLoc = coreLoc.clone().subtract(0, totem.getOriginalModel().getCorePos().getY(), 0); + ActivatedTotem activatedTotem = new ActivatedTotem(bottomLoc, totem, this); + activatedTotem.runTaskTimer(CustomFishing.plugin, 10, 20); + totemCache.put(coreLoc, activatedTotem); } private void useFinder(Player player) { @@ -780,4 +829,8 @@ public class FishingManager extends Function { if (itemStack.getType().isBlock()) return GsonComponentSerializer.gson().deserialize("{\"translate\":\"block.minecraft." + type + "\"}"); else return GsonComponentSerializer.gson().deserialize("{\"translate\":\"item.minecraft." + type + "\"}"); } + + public void removeTotem(ActivatedTotem activatedTotem) { + totemCache.remove(activatedTotem); + } } diff --git a/src/main/java/net/momirealms/customfishing/manager/SellManager.java b/src/main/java/net/momirealms/customfishing/manager/SellManager.java new file mode 100644 index 00000000..8f742cae --- /dev/null +++ b/src/main/java/net/momirealms/customfishing/manager/SellManager.java @@ -0,0 +1,4 @@ +package net.momirealms.customfishing.manager; + +public class SellManager { +} diff --git a/src/main/java/net/momirealms/customfishing/manager/TotemManager.java b/src/main/java/net/momirealms/customfishing/manager/TotemManager.java index d6e2c52d..658ff8f8 100644 --- a/src/main/java/net/momirealms/customfishing/manager/TotemManager.java +++ b/src/main/java/net/momirealms/customfishing/manager/TotemManager.java @@ -16,6 +16,8 @@ import org.apache.commons.lang.StringUtils; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; import java.util.ArrayList; import java.util.HashMap; @@ -44,12 +46,21 @@ public class TotemManager extends Function { @Override public void load(){ - TOTEMS = new HashMap<>(); CORES = new HashMap<>(); BLOCKS = new HashMap<>(); INVERTED = new HashMap<>(); + loadBlocks(); + loadTotems(); + } + private void loadBlocks() { + YamlConfiguration config = ConfigUtil.getConfig("totem-blocks.yml"); + config.getKeys(false).forEach(key -> BLOCKS.put(key, config.getString(key))); + config.getKeys(false).forEach(key -> INVERTED.put(config.getString(key), key)); + } + + private void loadTotems() { YamlConfiguration config = ConfigUtil.getConfig("totems.yml"); for (String key : config.getKeys(false)) { List cores = config.getStringList(key + ".core"); @@ -110,11 +121,9 @@ public class TotemManager extends Function { Totem totem = new Totem( originalModel, finalModel, - config.getBoolean(key + ".require-item", false), - config.getBoolean(key + ".consume-item", false), config.getInt(key + ".radius", 16), config.getInt(key + ".duration", 300), - Particle.valueOf(config.getString(key + ".particle", "SPELL").toUpperCase()), + Particle.valueOf(config.getString(key + ".particle", "SPELL_MOB").toUpperCase()), BonusManager.getBonus(config, key) ); @@ -151,6 +160,28 @@ public class TotemManager extends Function { totem.setRequirements(requirements.toArray(new RequirementInterface[0])); } + if (config.getBoolean(key + ".hologram.enable", false)) { + totem.setHoloText(config.getStringList(key + ".hologram.text").toArray(new String[0])); + totem.setHoloOffset(config.getDouble(key + ".hologram.y-offset")); + } + + if (config.contains(key + ".potion-effects")) { + List potionEffectList = new ArrayList<>(); + for (String potion : config.getConfigurationSection(key + ".potion-effects").getKeys(false)) { + + PotionEffectType potionType = PotionEffectType.getByName(potion.toUpperCase()); + if (potionType == null) continue; + int time = 40; + if (potionType.equals(PotionEffectType.NIGHT_VISION)) time = 400; + PotionEffect potionEffect = new PotionEffect( + potionType, + time, + config.getInt(key + ".potion-effects." + potion, 1) - 1); + potionEffectList.add(potionEffect); + } + totem.setPotionEffects(potionEffectList.toArray(new PotionEffect[0])); + } + TOTEMS.put(key, totem); for (String core : cores) { diff --git a/src/main/java/net/momirealms/customfishing/object/Function.java b/src/main/java/net/momirealms/customfishing/object/Function.java index 08333e98..e09b228e 100644 --- a/src/main/java/net/momirealms/customfishing/object/Function.java +++ b/src/main/java/net/momirealms/customfishing/object/Function.java @@ -14,14 +14,14 @@ public class Function { } public void onQuit(Player player) { - + //empty } public void onJoin(Player player) { - + //empty } public void onInteract(PlayerInteractEvent event) { - + //empty } } diff --git a/src/main/java/net/momirealms/customfishing/object/totem/ActivatedTotem.java b/src/main/java/net/momirealms/customfishing/object/totem/ActivatedTotem.java new file mode 100644 index 00000000..4ed9af00 --- /dev/null +++ b/src/main/java/net/momirealms/customfishing/object/totem/ActivatedTotem.java @@ -0,0 +1,142 @@ +package net.momirealms.customfishing.object.totem; + +import net.momirealms.customfishing.CustomFishing; +import net.momirealms.customfishing.manager.FishingManager; +import net.momirealms.customfishing.util.ArmorStandUtil; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.scheduler.BukkitRunnable; + +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class ActivatedTotem extends BukkitRunnable { + + public static int id = 127616121; + private int timer; + private final Totem totem; + private final Location location; + private final Set nearbyPlayerSet; + private final int[] entityID; + private final boolean hasHolo; + private final BukkitRunnable particleTimerTask; + private final FishingManager fishingManager; + + public ActivatedTotem(Location location, Totem totem, FishingManager fishingManager) { + this.fishingManager = fishingManager; + this.totem = totem; + this.location = location; + this.entityID = new int[totem.getHoloText().length]; + for (int i = 0; i < totem.getHoloText().length; i++) { + this.entityID[i] = id++; + } + this.hasHolo = totem.getHoloText() != null; + this.nearbyPlayerSet = Collections.synchronizedSet(new HashSet<>()); + this.particleTimerTask = new TotemParticle(location, totem.getRadius(), totem.getParticle()); + this.particleTimerTask.runTaskTimerAsynchronously(CustomFishing.plugin, 0, 4); + } + + @Override + public void run() { + + timer++; + if (timer > totem.getDuration()) { + stop(); + return; + } + + HashSet temp = new HashSet<>(nearbyPlayerSet); + Collection nearbyPlayers = location.getNearbyPlayers(totem.getRadius()); + + for (Player player : temp) { + if (nearbyPlayers.remove(player)) { + if (hasHolo) { + try { + for (int i = 0; i < entityID.length; i++) { + CustomFishing.protocolManager.sendServerPacket(player, ArmorStandUtil.getMetaPacket(entityID[i], + totem.getHoloText()[entityID.length - 1 - i].replace("{time}", String.valueOf(totem.getDuration() - timer)) + .replace("{max_time}", String.valueOf(totem.getDuration())) + )); + } + addPotionEffect(player); + } + catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + } + else { + if (hasHolo) { + try { + for (int j : entityID) { + CustomFishing.protocolManager.sendServerPacket(player, ArmorStandUtil.getDestroyPacket(j)); + } + } + catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + nearbyPlayerSet.remove(player); + } + } + + for (Player newComer : nearbyPlayers) { + if (hasHolo) { + try { + for (int i = 0; i < entityID.length; i++) { + CustomFishing.protocolManager.sendServerPacket(newComer, ArmorStandUtil.getSpawnPacket(entityID[i], location.clone().add(0.5, totem.getHoloOffset() + i * 0.4, 0.5))); + CustomFishing.protocolManager.sendServerPacket(newComer, ArmorStandUtil.getMetaPacket(entityID[i], + totem.getHoloText()[entityID.length - 1 - i].replace("{time}", String.valueOf(totem.getDuration() - timer)) + .replace("{max_time}", String.valueOf(totem.getDuration())) + )); + } + addPotionEffect(newComer); + } + catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + nearbyPlayerSet.add(newComer); + } + } + + public Set getNearbyPlayerSet() { + return nearbyPlayerSet; + } + + public Totem getTotem() { + return totem; + } + + public void stop() { + this.particleTimerTask.cancel(); + cancel(); + fishingManager.removeTotem(this); + + if (hasHolo) { + for (Player player : nearbyPlayerSet) { + try { + for (int j : entityID) { + CustomFishing.protocolManager.sendServerPacket(player, ArmorStandUtil.getDestroyPacket(j)); + } + } + catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + } + nearbyPlayerSet.clear(); + } + + private void addPotionEffect(Player player) { + if (totem.getPotionEffects() != null) { + for (PotionEffect potionEffect : totem.getPotionEffects()) { + player.addPotionEffect(potionEffect); + } + } + } +} diff --git a/src/main/java/net/momirealms/customfishing/object/totem/Totem.java b/src/main/java/net/momirealms/customfishing/object/totem/Totem.java index 99f21954..494e548b 100644 --- a/src/main/java/net/momirealms/customfishing/object/totem/Totem.java +++ b/src/main/java/net/momirealms/customfishing/object/totem/Totem.java @@ -21,13 +21,12 @@ import net.momirealms.customfishing.object.action.ActionInterface; import net.momirealms.customfishing.object.fishing.Bonus; import net.momirealms.customfishing.object.requirements.RequirementInterface; import org.bukkit.Particle; +import org.bukkit.potion.PotionEffect; public class Totem { private final OriginalModel originalModel; private FinalModel finalModel; - private final boolean cItem; - private final boolean rItem; private RequirementInterface[] requirements; private final int radius; private final Particle particle; @@ -35,17 +34,17 @@ public class Totem { private final Bonus bonus; private ActionInterface[] activatorActions; private ActionInterface[] nearbyActions; + private double holoOffset; + private String[] holoText; + private PotionEffect[] potionEffects; - public Totem(OriginalModel originalModel, FinalModel finalModel, boolean rItem, boolean cItem, int radius, int duration, Particle particle, Bonus bonus) { + public Totem(OriginalModel originalModel, FinalModel finalModel, int radius, int duration, Particle particle, Bonus bonus) { this.originalModel = originalModel; this.finalModel = finalModel; this.radius = radius; this.duration = duration; this.particle = particle; this.bonus = bonus; - this.rItem = rItem; - if (rItem) this.cItem = cItem; - else this.cItem = false; } public RequirementInterface[] getRequirements() { @@ -69,14 +68,6 @@ public class Totem { this.finalModel = finalModel; } - public boolean isrItem() { - return rItem; - } - - public boolean iscItem() { - return cItem; - } - public int getRadius() { return radius; } @@ -108,4 +99,28 @@ public class Totem { public void setNearbyActions(ActionInterface[] nearbyActions) { this.nearbyActions = nearbyActions; } + + public double getHoloOffset() { + return holoOffset; + } + + public void setHoloOffset(double holoOffset) { + this.holoOffset = holoOffset; + } + + public String[] getHoloText() { + return holoText; + } + + public void setHoloText(String[] holoText) { + this.holoText = holoText; + } + + public PotionEffect[] getPotionEffects() { + return potionEffects; + } + + public void setPotionEffects(PotionEffect[] potionEffects) { + this.potionEffects = potionEffects; + } } diff --git a/src/main/java/net/momirealms/customfishing/object/totem/TotemParticle.java b/src/main/java/net/momirealms/customfishing/object/totem/TotemParticle.java new file mode 100644 index 00000000..e1d09c17 --- /dev/null +++ b/src/main/java/net/momirealms/customfishing/object/totem/TotemParticle.java @@ -0,0 +1,39 @@ +package net.momirealms.customfishing.object.totem; + +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.World; +import org.bukkit.scheduler.BukkitRunnable; + +public class TotemParticle extends BukkitRunnable { + + private final Location bottomLoc; + private final int radius; + private final double angle_1; + private final double angle_2; + private int timer; + private final Particle particle; + private final World world; + + public TotemParticle(Location bottomLoc, int radius, Particle particle) { + this.bottomLoc = bottomLoc.clone().add(0.5,0,0.5); + this.radius = radius; + this.particle = particle; + this.angle_1 = 360 / (double) radius; + this.angle_2 = 72 / (double) radius; + this.world = bottomLoc.getWorld(); + } + + @Override + public void run() { + timer++; + if (timer > 4) { + timer = 0; + } + for (int i = 0; i < radius; i++) { + double temp_angle = angle_1 * i + angle_2 * timer; + double angle = temp_angle * Math.PI / 180; + world.spawnParticle(particle, bottomLoc.clone().add(Math.cos(angle) * radius, 0.5, Math.sin(angle) * radius), 1 ,0, 0,0, 0); + } + } +} diff --git a/src/main/java/net/momirealms/customfishing/util/ArmorStandUtil.java b/src/main/java/net/momirealms/customfishing/util/ArmorStandUtil.java index 3efb5218..ed6b9545 100644 --- a/src/main/java/net/momirealms/customfishing/util/ArmorStandUtil.java +++ b/src/main/java/net/momirealms/customfishing/util/ArmorStandUtil.java @@ -1,16 +1,71 @@ package net.momirealms.customfishing.util; -import org.bukkit.entity.Player; +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.WrappedChatComponent; +import com.comphenix.protocol.wrappers.WrappedDataWatcher; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import org.bukkit.Location; +import org.bukkit.entity.EntityType; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; public class ArmorStandUtil { - public static int entityID = 654321234; - - public static void showNotice(Player player) { - entityID++; - - + public static PacketContainer getDestroyPacket(int id) { + PacketContainer destroyPacket = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY); + destroyPacket.getIntLists().write(0, List.of(id)); + return destroyPacket; } + public static PacketContainer getSpawnPacket(int id, Location location) { + PacketContainer entityPacket = new PacketContainer(PacketType.Play.Server.SPAWN_ENTITY); + entityPacket.getModifier().write(0, id); + entityPacket.getModifier().write(1, UUID.randomUUID()); + entityPacket.getEntityTypeModifier().write(0, EntityType.ARMOR_STAND); + entityPacket.getDoubles().write(0, location.getX()); + entityPacket.getDoubles().write(1, location.getY()); + entityPacket.getDoubles().write(2, location.getZ()); + return entityPacket; + } + public static PacketContainer getMetaPacket(int id) { + PacketContainer metaPacket = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA); + metaPacket.getIntegers().write(0, id); + metaPacket.getWatchableCollectionModifier().write(0, createDataWatcher().getWatchableObjects()); + return metaPacket; + } + + public static PacketContainer getMetaPacket(int id, String text) { + PacketContainer metaPacket = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA); + metaPacket.getIntegers().write(0, id); + metaPacket.getWatchableCollectionModifier().write(0, createDataWatcher(text).getWatchableObjects()); + return metaPacket; + } + + public static WrappedDataWatcher createDataWatcher() { + WrappedDataWatcher wrappedDataWatcher = new WrappedDataWatcher(); + WrappedDataWatcher.Serializer serializer1 = WrappedDataWatcher.Registry.get(Boolean.class); + WrappedDataWatcher.Serializer serializer2 = WrappedDataWatcher.Registry.get(Byte.class); + wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(3, serializer1), false); + byte flag = 0x20; + wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, serializer2), flag); + return wrappedDataWatcher; + } + + public static WrappedDataWatcher createDataWatcher(String text) { + WrappedDataWatcher wrappedDataWatcher = new WrappedDataWatcher(); + WrappedDataWatcher.Serializer serializer1 = WrappedDataWatcher.Registry.get(Boolean.class); + WrappedDataWatcher.Serializer serializer2 = WrappedDataWatcher.Registry.get(Byte.class); + wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(2, WrappedDataWatcher.Registry.getChatComponentSerializer(true)), Optional.of(WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(MiniMessage.miniMessage().deserialize(text))).getHandle())); + wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(3, serializer1), true); + wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(15, serializer2), (byte) 0x01); + byte flag = 0x20; + wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, serializer2), flag); + wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(3, serializer1), true); + return wrappedDataWatcher; + } } diff --git a/src/main/java/net/momirealms/customfishing/util/ConfigUtil.java b/src/main/java/net/momirealms/customfishing/util/ConfigUtil.java index 291fea6d..237d1a17 100644 --- a/src/main/java/net/momirealms/customfishing/util/ConfigUtil.java +++ b/src/main/java/net/momirealms/customfishing/util/ConfigUtil.java @@ -36,6 +36,8 @@ public class ConfigUtil { CustomFishing.plugin.getFishingManager().load(); CustomFishing.plugin.getCompetitionManager().unload(); CustomFishing.plugin.getCompetitionManager().load(); + CustomFishing.plugin.getTotemManager().unload(); + CustomFishing.plugin.getTotemManager().load(); try { Reflection.load(); } diff --git a/src/main/resources/bars.yml b/src/main/resources/bars.yml index 10a2d38e..5bb591a0 100644 --- a/src/main/resources/bars.yml +++ b/src/main/resources/bars.yml @@ -38,7 +38,7 @@ rainbow_2: 7: 0 rainbow_3: range: 16 - title: '<#808000>YELLOW!' + title: '<#FFFF00>YELLOW!' subtitle: start: '' bar: '뀋' diff --git a/src/main/resources/database.yml b/src/main/resources/database.yml index e249c41f..24134efc 100644 --- a/src/main/resources/database.yml +++ b/src/main/resources/database.yml @@ -22,7 +22,7 @@ MySQL: # SQLite settings SQLite: file-name: data - table: npc + table: customfishing_data # MongoDB settings MongoDB: diff --git a/src/main/resources/sell-shop-gui.yml b/src/main/resources/sell-shop-gui.yml new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/totem-blocks.yml b/src/main/resources/totem-blocks.yml new file mode 100644 index 00000000..28009843 --- /dev/null +++ b/src/main/resources/totem-blocks.yml @@ -0,0 +1,8 @@ +# Vanilla blocks should be in capital format +AIR: 'air' + +ANVIL: 'a' +CRYING_OBSIDIAN: 'c' +PURPUR_STAIRS: 'p' +PURPUR_PILLAR: 'pillar' +OBSERVER: 'o' \ No newline at end of file diff --git a/src/main/resources/totem_blocks.yml b/src/main/resources/totem_blocks.yml deleted file mode 100644 index c3fe848a..00000000 --- a/src/main/resources/totem_blocks.yml +++ /dev/null @@ -1,16 +0,0 @@ -# Vanilla blocks should be in capital format -AIR: 'air' - -COBBLESTONE: 'c' -NETHERRACK: 'n' -CRIMSON_HYPHAE: 'h' - -BEACON: 'b' - -EMERALD_BLOCK: 'e' -DIAMOND_BLOCK: 'd' -GOLD_BLOCK: 'g' -IRON_BLOCK: 'i' - -#ItemsAdder Block support -nether:reactor: 'r' \ No newline at end of file diff --git a/src/main/resources/totems.yml b/src/main/resources/totems.yml index 153b6639..cb5a38cc 100644 --- a/src/main/resources/totems.yml +++ b/src/main/resources/totems.yml @@ -1,16 +1,20 @@ primary_fishing_totem: # Totem Core Block ID core: - - b - - r + - o - activator: - - totem_stone - - radius: 10 + radius: 8 # seconds duration: 300 - particle: SPELL + particle: DRIPPING_OBSIDIAN_TEAR + + hologram: + enable: true + text: + - '{time}s / {max_time}s' + - '<#87CEFA>Fishing Totem' + + y-offset: 3.8 # Potion effect type and its amplifier potion-effects: @@ -18,11 +22,9 @@ primary_fishing_totem: # Fishing bonus modifier: - weight-add: - silver: -20 - gold: 20 + double-loot: 1 - # placeholders: {player} {world} {x} {y} {z} + # placeholders: {activator} {player} {world} {x} {y} {z} action: commands-activator: - '' @@ -42,16 +44,11 @@ primary_fishing_totem: # “>“ represents the block would turn into another block after activating # “|“ represents alternative block choice for this place layer: - 1: - - 'g>n (c) g>n' - - '(c) (c) (c)' - - 'g>n (c) g>n' - 2: - - '(c) air (c)' - - 'air r|b>h air' - - '(c) air (c)' + 4: + - '(p) (o) (p)' 3: - - '* (c) *' - - '(c) (c) (c)' - - '* (c) *' - + - 'air (c) air' + 2: + - 'air (pillar) air' + 1: + - 'air (a) air' \ No newline at end of file