Merge branch 'master' into version-compat

This commit is contained in:
Esophose 2020-06-13 13:07:47 -06:00
parent 9567b06e23
commit a82b4d125e
93 changed files with 1496 additions and 698 deletions

View file

@ -1,88 +1,100 @@
package dev.esophose.playerparticles.particles; package dev.esophose.playerparticles.particles;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
public enum ParticleEffect { public enum ParticleEffect {
AMBIENT_ENTITY_EFFECT(ParticleProperty.REQUIRES_COLOR_DATA), AMBIENT_ENTITY_EFFECT(Collections.singletonList("BEACON"), ParticleProperty.REQUIRES_COLOR_DATA),
ANGRY_VILLAGER, ANGRY_VILLAGER(Collections.singletonList("IRON_DOOR")),
ASH, ASH(Collections.singletonList("BLACKSTONE")),
BARRIER, BARRIER(Collections.singletonList("BARRIER")),
BLOCK(ParticleProperty.REQUIRES_BLOCK_DATA), BLOCK(Collections.singletonList("STONE"), ParticleProperty.REQUIRES_BLOCK_DATA),
BUBBLE, BUBBLE(Arrays.asList("BUBBLE_CORAL", "GLASS")),
BUBBLE_COLUMN_UP, BUBBLE_COLUMN_UP(Collections.singletonList("MAGMA_BLOCK")),
BUBBLE_POP, BUBBLE_POP(Collections.singletonList("BUBBLE_CORAL_FAN")),
CAMPFIRE_COSY_SMOKE, CAMPFIRE_COSY_SMOKE(Collections.singletonList("CAMPFIRE")),
CAMPFIRE_SIGNAL_SMOKE, CAMPFIRE_SIGNAL_SMOKE(Collections.singletonList("REDSTONE_TORCH")),
CLOUD, CLOUD(Arrays.asList("WHITE_WOOL", "WOOL")),
COMPOSTER, COMPOSTER(Collections.singletonList("COMPOSTER")),
CRIMSON_SPORE, CRIMSON_SPORE(Collections.singletonList("CRIMSON_SPORE")),
CRIT, CRIT(Collections.singletonList("IRON_SWORD")),
CURRENT_DOWN, CURRENT_DOWN(Collections.singletonList("SOUL_SAND")),
DAMAGE_INDICATOR, DAMAGE_INDICATOR(Collections.singletonList("BOW")),
DOLPHIN, DOLPHIN(Collections.singletonList("DOLPHIN_SPAWN_EGG")),
DRAGON_BREATH, DRAGON_BREATH(Arrays.asList("DRAGON_BREATH", "DRAGONS_BREATH")),
DRIPPING_HONEY, DRIPPING_HONEY(Collections.singletonList("BEE_NEST")),
DRIPPING_LAVA, DRIPPING_LAVA(Collections.singletonList("LAVA_BUCKET")),
DRIPPING_OBSIDIAN_TEAR, DRIPPING_OBSIDIAN_TEAR(Collections.singletonList("CRYING_OBSIDIAN")),
DRIPPING_WATER, DRIPPING_WATER(Collections.singletonList("WATER_BUCKET")),
DUST(ParticleProperty.REQUIRES_COLOR_DATA), DUST(Collections.singletonList("REDSTONE"), ParticleProperty.REQUIRES_COLOR_DATA),
ELDER_GUARDIAN, ELDER_GUARDIAN(Arrays.asList("ELDER_GUARDIAN_SPAWN_EGG", "PRISMARINE_CRYSTALS")),
ENCHANT, ENCHANT(Arrays.asList("ENCHANTING_TABLE", "ENCHANTMENT_TABLE")),
ENCHANTED_HIT, ENCHANTED_HIT(Collections.singletonList("DIAMOND_SWORD")),
END_ROD, END_ROD(Collections.singletonList("END_ROD")),
ENTITY_EFFECT(ParticleProperty.REQUIRES_COLOR_DATA), ENTITY_EFFECT(Collections.singletonList("GLOWSTONE_DUST"), ParticleProperty.REQUIRES_COLOR_DATA),
EXPLOSION, EXPLOSION(Arrays.asList("FIRE_CHARGE", "FIREBALL")),
EXPLOSION_EMITTER, EXPLOSION_EMITTER(Collections.singletonList("TNT")),
FALLING_DUST(ParticleProperty.REQUIRES_BLOCK_DATA), FALLING_DUST(Collections.singletonList("SAND"), ParticleProperty.REQUIRES_BLOCK_DATA),
FALLING_HONEY, FALLING_HONEY(Collections.singletonList("HONEY_BOTTLE")),
FALLING_LAVA, FALLING_LAVA(Collections.singletonList("RED_DYE")),
FALLING_NECTAR, FALLING_NECTAR(Collections.singletonList("HONEYCOMB")),
FALLING_OBSIDIAN_TEAR, FALLING_OBSIDIAN_TEAR(Collections.singletonList("ANCIENT_DEBRIS")),
FALLING_WATER, FALLING_WATER(Collections.singletonList("BLUE_DYE")),
FIREWORK, FIREWORK(Arrays.asList("FIREWORK_ROCKET", "FIREWORK")),
FISHING, FISHING(Collections.singletonList("FISHING_ROD")),
FLAME, FLAME(Collections.singletonList("BLAZE_POWDER")),
FLASH, FLASH(Collections.singletonList("GOLD_INGOT")),
FOOTSTEP, FOOTSTEP(Collections.singletonList("GRASS")),
HAPPY_VILLAGER, HAPPY_VILLAGER(Arrays.asList("DARK_OAK_DOOR_ITEM", "DARK_OAK_DOOR")),
HEART, HEART(Arrays.asList("POPPY", "RED_ROSE")),
INSTANT_EFFECT, INSTANT_EFFECT(Arrays.asList("SPLASH_POTION", "POTION")),
ITEM(ParticleProperty.REQUIRES_ITEM_DATA), ITEM(Collections.singletonList("ITEM_FRAME"), ParticleProperty.REQUIRES_ITEM_DATA),
ITEM_SLIME, ITEM_SLIME(Collections.singletonList("SLIME_BALL")),
ITEM_SNOWBALL, ITEM_SNOWBALL(Arrays.asList("SNOWBALL", "SNOW_BALL")),
LANDING_HONEY, LANDING_HONEY(Collections.singletonList("HONEY_BLOCK")),
LANDING_LAVA, LANDING_LAVA(Collections.singletonList("ORANGE_DYE")),
LANDING_OBSIDIAN_TEAR, LANDING_OBSIDIAN_TEAR(Collections.singletonList("NETHERITE_BLOCK")),
LARGE_SMOKE, LARGE_SMOKE(Arrays.asList("COBWEB", "WEB")),
LAVA, LAVA(Collections.singletonList("MAGMA_CREAM")),
MYCELIUM, MYCELIUM(Arrays.asList("MYCELIUM", "MYCEL")),
NAUTILUS, NAUTILUS(Collections.singletonList("HEART_OF_THE_SEA")),
NOTE(ParticleProperty.REQUIRES_COLOR_DATA), NOTE(Collections.singletonList("NOTE_BLOCK"), ParticleProperty.REQUIRES_COLOR_DATA),
POOF, POOF(Arrays.asList("FIREWORK_STAR", "FIREWORK_CHARGE")),
PORTAL, PORTAL(Collections.singletonList("OBSIDIAN")),
RAIN, RAIN(Arrays.asList("PUFFERFISH_BUCKET", "LAPIS_BLOCK")),
SMOKE, REVERSE_PORTAL(Collections.singletonList("FLINT_AND_STEEL")),
SNEEZE, SMOKE(Collections.singletonList("TORCH")),
SOUL, SNEEZE(Collections.singletonList("BAMBOO")),
SOUL_FIRE_FLAME, SOUL(Collections.singletonList("SOUL_LANTERN")),
SPELL, // The Minecraft internal name for this is actually "effect", but that's the command name, so it's SPELL for the plugin instead SOUL_FIRE_FLAME(Collections.singletonList("SOUL_CAMPFIRE")),
SPIT, SPELL(Arrays.asList("POTION", "GLASS_BOTTLE")), // The Minecraft internal name for this is actually "effect", but that's the command name, so it's SPELL for the plugin instead
SPLASH, SPIT(Arrays.asList("LLAMA_SPAWN_EGG", "PUMPKIN_SEEDS")),
SQUID_INK, SPLASH(Arrays.asList("SALMON", "FISH", "RAW_FISH")),
SWEEP_ATTACK, SQUID_INK(Collections.singletonList("INK_SAC")),
TOTEM_OF_UNDYING, SWEEP_ATTACK(Arrays.asList("GOLDEN_SWORD", "GOLD_SWORD")),
UNDERWATER, TOTEM_OF_UNDYING(Arrays.asList("TOTEM_OF_UNDYING", "TOTEM")),
WARPED_SPORE, UNDERWATER(Arrays.asList("TURTLE_HELMET", "SPONGE")),
WITCH; WARPED_SPORE(Collections.singletonList("WARPED_FUNGUS")),
WHITE_ASH(Collections.singletonList("BASALT")),
WITCH(Collections.singletonList("CAULDRON"));
private List<ParticleProperty> properties; private List<ParticleProperty> properties;
private List<String> defaultIconMaterialNames;
ParticleEffect(ParticleProperty... properties) { ParticleEffect(List<String> defaultIconMaterialNames, ParticleProperty... properties) {
this.defaultIconMaterialNames = defaultIconMaterialNames;
this.properties = Arrays.asList(properties); this.properties = Arrays.asList(properties);
} }
/**
* @return The Material icon that represents this style in the GUI
*/
public List<String> getGuiIconMaterialNames() {
return this.defaultIconMaterialNames;
}
/** /**
* Determine if this particle effect has a specific property * Determine if this particle effect has a specific property
* *

View file

@ -21,11 +21,14 @@ dependencies {
shadow 'me.clip:placeholderapi:2.10.4' shadow 'me.clip:placeholderapi:2.10.4'
shadow 'org.xerial:sqlite-jdbc:3.23.1' shadow 'org.xerial:sqlite-jdbc:3.23.1'
shadow 'com.comphenix.protocol:ProtocolLib:4.5.0' shadow 'com.comphenix.protocol:ProtocolLib:4.5.0'
shadow 'com.googlecode.json-simple:json-simple:1.1.1'
// Dependencies that will be shaded into the jar // Dependencies that will be shaded into the jar
implementation 'org.slf4j:slf4j-api:1.7.25' implementation 'org.slf4j:slf4j-api:1.7.25'
implementation 'org.slf4j:slf4j-nop:1.7.25' implementation 'org.slf4j:slf4j-nop:1.7.25'
implementation 'com.zaxxer:HikariCP:3.2.0' implementation 'com.zaxxer:HikariCP:3.2.0'
implementation 'org.bstats:bstats-bukkit-lite:1.7'
implementation 'org.codemc.worldguardwrapper:worldguardwrapper:1.1.6-SNAPSHOT'
} }
processResources { processResources {

View file

@ -3,14 +3,8 @@
* + Add ability to create/manage fixed effects from the GUI * + Add ability to create/manage fixed effects from the GUI
* * Convert fixed effect ids into names * * Convert fixed effect ids into names
*/ */
package dev.esophose.playerparticles; package dev.esophose.playerparticles;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.wrappers.EnumWrappers.TitleAction;
import dev.esophose.playerparticles.gui.hook.PlayerChatHook; import dev.esophose.playerparticles.gui.hook.PlayerChatHook;
import dev.esophose.playerparticles.hook.ParticlePlaceholderExpansion; import dev.esophose.playerparticles.hook.ParticlePlaceholderExpansion;
import dev.esophose.playerparticles.hook.PlaceholderAPIHook; import dev.esophose.playerparticles.hook.PlaceholderAPIHook;
@ -28,21 +22,15 @@ import dev.esophose.playerparticles.manager.PermissionManager;
import dev.esophose.playerparticles.manager.PluginUpdateManager; import dev.esophose.playerparticles.manager.PluginUpdateManager;
import dev.esophose.playerparticles.particles.listener.PPlayerCombatListener; import dev.esophose.playerparticles.particles.listener.PPlayerCombatListener;
import dev.esophose.playerparticles.particles.listener.PPlayerMovementListener; import dev.esophose.playerparticles.particles.listener.PPlayerMovementListener;
import dev.esophose.playerparticles.util.Metrics; import dev.esophose.playerparticles.util.LegacyMetrics;
import io.netty.buffer.Unpooled; import dev.esophose.playerparticles.util.NMSUtil;
import java.awt.Color;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import net.minecraft.server.v1_15_R1.PacketDataSerializer; import org.bstats.bukkit.MetricsLite;
import net.minecraft.server.v1_15_R1.PacketPlayOutTitle;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
/** /**
* @author Esophose * @author Esophose
@ -69,6 +57,12 @@ public class PlayerParticles extends JavaPlugin {
*/ */
@Override @Override
public void onEnable() { public void onEnable() {
if (!NMSUtil.isSpigot()) {
this.getLogger().severe("This plugin is only compatible with Spigot and other forks. CraftBukkit is not supported. Disabling PlayerParticles.");
Bukkit.getPluginManager().disablePlugin(this);
return;
}
this.reload(); this.reload();
PluginManager pm = Bukkit.getPluginManager(); PluginManager pm = Bukkit.getPluginManager();
@ -76,80 +70,16 @@ public class PlayerParticles extends JavaPlugin {
pm.registerEvents(new PPlayerCombatListener(), this); pm.registerEvents(new PPlayerCombatListener(), this);
pm.registerEvents(new PlayerChatHook(), this); pm.registerEvents(new PlayerChatHook(), this);
if (Setting.SEND_METRICS.getBoolean()) if (Setting.SEND_METRICS.getBoolean()) {
new Metrics(this); if (NMSUtil.getVersionNumber() > 7) {
new MetricsLite(this, 3531);
} else {
new LegacyMetrics(this);
}
}
if (PlaceholderAPIHook.enabled()) if (PlaceholderAPIHook.enabled())
new ParticlePlaceholderExpansion(this).register(); new ParticlePlaceholderExpansion(this).register();
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
new BukkitRunnable() {
private LinkedList<String> queue = new LinkedList<>();
private String message = "Snapshot 20w17a Chat Hex Code Colors!";
@Override
public void run() {
if (queue.size() >= message.length())
queue.poll();
Color color = getRainbowColor();
String hex = String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue());
queue.add(hex);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[");
boolean isFirst = true;
for (int i = 0; i < queue.size(); i++) {
if (!isFirst)
stringBuilder.append(",");
isFirst = false;
stringBuilder.append("{");
stringBuilder.append("\"color\":\"").append(queue.get(i)).append("\",");
stringBuilder.append("\"text\":\"").append(message.charAt(i)).append("\"");
stringBuilder.append("}");
}
stringBuilder.append("]");
PacketContainer timePacket = protocolManager.createPacket(PacketType.fromClass(PacketPlayOutTitle.class));
timePacket.getTitleActions().write(0, TitleAction.TIMES);
timePacket.getIntegers().write(0, 0).write(1, 20).write(2, 0);
PacketDataSerializer dataSerializer = new PacketDataSerializer(Unpooled.buffer());
try {
PacketPlayOutTitle titlePacket = new PacketPlayOutTitle() {
@Override
public void b(PacketDataSerializer var0) {
var0.a(EnumTitleAction.TITLE);
var0.a(stringBuilder.toString());
}
};
titlePacket.b(dataSerializer);
} catch (IOException e) {
e.printStackTrace();
}
byte[] bytes = new byte[dataSerializer.readableBytes()];
dataSerializer.readBytes(bytes);
Bukkit.getOnlinePlayers().forEach(x -> {
try {
protocolManager.sendServerPacket(x, timePacket);
protocolManager.sendWirePacket(x, 0x50, bytes);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
});
}
}.runTaskTimer(this, 0, 1);
PlayerChatHook.setup();
}
private float hue = 0;
private Color getRainbowColor() {
this.hue = (this.hue + 4) % 362;
return Color.getHSBColor(this.hue / 360F, 1.0F, 1.0F);
} }
@Override @Override
@ -181,16 +111,6 @@ public class PlayerParticles extends JavaPlugin {
} }
} }
/**
* Returns the file which contains this plugin
* Exposes the JavaPlugin.getFile() method
*
* @return File containing this plugin
*/
public File getJarFile() {
return this.getFile();
}
/** /**
* Reloads the plugin * Reloads the plugin
*/ */

View file

@ -1,19 +1,18 @@
package dev.esophose.playerparticles.api; package dev.esophose.playerparticles.api;
import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.manager.DataManager; import dev.esophose.playerparticles.manager.DataManager;
import dev.esophose.playerparticles.manager.GuiManager; import dev.esophose.playerparticles.manager.GuiManager;
import dev.esophose.playerparticles.manager.ParticleManager; import dev.esophose.playerparticles.manager.ParticleManager;
import dev.esophose.playerparticles.manager.ParticleStyleManager;
import dev.esophose.playerparticles.particles.ConsolePPlayer; import dev.esophose.playerparticles.particles.ConsolePPlayer;
import dev.esophose.playerparticles.particles.FixedParticleEffect; import dev.esophose.playerparticles.particles.FixedParticleEffect;
import dev.esophose.playerparticles.particles.PPlayer; import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.particles.ParticleEffect; import dev.esophose.playerparticles.particles.ParticleEffect;
import dev.esophose.playerparticles.particles.ParticleGroup; import dev.esophose.playerparticles.particles.ParticleGroup;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.particles.color.NoteColor; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.particles.color.OrdinaryColor; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.styles.ParticleStyle; import dev.esophose.playerparticles.styles.ParticleStyle;
import dev.esophose.playerparticles.PlayerParticles;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
@ -22,7 +21,9 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -51,12 +52,21 @@ public final class PlayerParticlesAPI {
/** /**
* @return the instance of the PlayerParticlesAPI * @return the instance of the PlayerParticlesAPI
*/ */
@NotNull
public static PlayerParticlesAPI getInstance() { public static PlayerParticlesAPI getInstance() {
if (INSTANCE == null) if (INSTANCE == null)
INSTANCE = new PlayerParticlesAPI(); INSTANCE = new PlayerParticlesAPI();
return INSTANCE; return INSTANCE;
} }
/**
* @return the currently installed version of the plugin
*/
@NotNull
public String getVersion() {
return this.playerParticles.getDescription().getVersion();
}
//region Get PPlayer //region Get PPlayer
/** /**
@ -441,6 +451,7 @@ public final class PlayerParticlesAPI {
* @param player The player to remove from * @param player The player to remove from
* @return The number of particles removed or null if failed * @return The number of particles removed or null if failed
*/ */
@Nullable
public Integer resetActivePlayerParticles(@NotNull Player player) { public Integer resetActivePlayerParticles(@NotNull Player player) {
DataManager dataManager = this.playerParticles.getManager(DataManager.class); DataManager dataManager = this.playerParticles.getManager(DataManager.class);
PPlayer pplayer = this.getPPlayer(player); PPlayer pplayer = this.getPPlayer(player);
@ -453,6 +464,28 @@ public final class PlayerParticlesAPI {
return amount; return amount;
} }
/**
* Attempts to reset the active particles for the given player name.
* This works even if the player is offline.
*
* @param playerName The name of the player to reset the active particles for
* @param successConsumer The callback to execute when finished
*/
public void resetActivePlayerParticles(@NotNull String playerName, @Nullable Consumer<Boolean> successConsumer) {
Objects.requireNonNull(playerName);
if (successConsumer == null)
successConsumer = success -> {};
Player player = Bukkit.getPlayer(playerName);
if (player != null) {
this.resetActivePlayerParticles(player);
successConsumer.accept(true);
} else {
this.playerParticles.getManager(DataManager.class).resetActiveParticleGroup(playerName, successConsumer);
}
}
/** /**
* Gets all active particles from a player * Gets all active particles from a player
* *
@ -1033,30 +1066,4 @@ public final class PlayerParticlesAPI {
//endregion //endregion
//region Registering Custom Styles
/**
* Registers a particle style with the plugin
*
* @param particleStyle The particle style to register
*/
public void registerParticleStyle(@NotNull ParticleStyle particleStyle) {
Objects.requireNonNull(particleStyle);
this.playerParticles.getManager(ParticleStyleManager.class).registerStyle(particleStyle);
}
/**
* Registers an event-based particle style with the plugin
*
* @param particleStyle The particle style to register
*/
public void registerEventParticleStyle(@NotNull ParticleStyle particleStyle) {
Objects.requireNonNull(particleStyle);
this.playerParticles.getManager(ParticleStyleManager.class).registerEventStyle(particleStyle);
}
//endregion
} }

View file

@ -11,8 +11,8 @@ import dev.esophose.playerparticles.particles.ParticleGroup;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.api.PlayerParticlesAPI; import dev.esophose.playerparticles.api.PlayerParticlesAPI;
import dev.esophose.playerparticles.particles.color.NoteColor; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.particles.color.OrdinaryColor; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.styles.ParticleStyle; import dev.esophose.playerparticles.styles.ParticleStyle;
import dev.esophose.playerparticles.util.ParticleUtils; import dev.esophose.playerparticles.util.ParticleUtils;
import dev.esophose.playerparticles.util.StringPlaceholders; import dev.esophose.playerparticles.util.StringPlaceholders;

View file

@ -10,8 +10,8 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.api.PlayerParticlesAPI; import dev.esophose.playerparticles.api.PlayerParticlesAPI;
import dev.esophose.playerparticles.particles.ParticleProperty; import dev.esophose.playerparticles.particles.ParticleProperty;
import dev.esophose.playerparticles.particles.color.NoteColor; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.particles.color.OrdinaryColor; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.styles.ParticleStyle; import dev.esophose.playerparticles.styles.ParticleStyle;
import dev.esophose.playerparticles.util.ParticleUtils; import dev.esophose.playerparticles.util.ParticleUtils;
import dev.esophose.playerparticles.util.StringPlaceholders; import dev.esophose.playerparticles.util.StringPlaceholders;

View file

@ -10,8 +10,8 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.api.PlayerParticlesAPI; import dev.esophose.playerparticles.api.PlayerParticlesAPI;
import dev.esophose.playerparticles.particles.ParticleProperty; import dev.esophose.playerparticles.particles.ParticleProperty;
import dev.esophose.playerparticles.particles.color.NoteColor; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.particles.color.OrdinaryColor; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.styles.ParticleStyle; import dev.esophose.playerparticles.styles.ParticleStyle;
import dev.esophose.playerparticles.util.ParticleUtils; import dev.esophose.playerparticles.util.ParticleUtils;
import dev.esophose.playerparticles.util.StringPlaceholders; import dev.esophose.playerparticles.util.StringPlaceholders;

View file

@ -8,6 +8,7 @@ import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bukkit.Bukkit;
public class GUICommandModule implements CommandModule { public class GUICommandModule implements CommandModule {
@ -45,7 +46,7 @@ public class GUICommandModule implements CommandModule {
return; return;
} }
guiManager.openDefault(pplayer); Bukkit.getScheduler().runTask(PlayerParticles.getInstance(), () -> guiManager.openDefault(pplayer));
} }
public List<String> onTabComplete(PPlayer pplayer, String[] args) { public List<String> onTabComplete(PPlayer pplayer, String[] args) {

View file

@ -56,6 +56,8 @@ public class RemoveCommandModule implements CommandModule {
ParticleEffect effect = particleManager.getEffectFromName(args[0]); ParticleEffect effect = particleManager.getEffectFromName(args[0]);
ParticleStyle style = ParticleStyle.fromName(args[0]); ParticleStyle style = ParticleStyle.fromName(args[0]);
boolean removed = false;
if (effect != null) { if (effect != null) {
Set<Integer> toRemove = new HashSet<>(); Set<Integer> toRemove = new HashSet<>();
ParticleGroup activeGroup = pplayer.getActiveParticleGroup(); ParticleGroup activeGroup = pplayer.getActiveParticleGroup();
@ -68,10 +70,14 @@ public class RemoveCommandModule implements CommandModule {
if (toRemove.size() > 0) { if (toRemove.size() > 0) {
PlayerParticlesAPI.getInstance().savePlayerParticleGroup(pplayer.getPlayer(), activeGroup); PlayerParticlesAPI.getInstance().savePlayerParticleGroup(pplayer.getPlayer(), activeGroup);
localeManager.sendMessage(pplayer, "remove-effect-success", StringPlaceholders.builder("amount", toRemove.size()).addPlaceholder("effect", particleManager.getEffectSettings(effect).getName()).build()); localeManager.sendMessage(pplayer, "remove-effect-success", StringPlaceholders.builder("amount", toRemove.size()).addPlaceholder("effect", particleManager.getEffectSettings(effect).getName()).build());
} else { removed = true;
} else if (style == null) {
localeManager.sendMessage(pplayer, "remove-effect-none", StringPlaceholders.single("effect", particleManager.getEffectSettings(effect).getName())); localeManager.sendMessage(pplayer, "remove-effect-none", StringPlaceholders.single("effect", particleManager.getEffectSettings(effect).getName()));
return;
} }
} else if (style != null) { }
if (style != null) {
Set<Integer> toRemove = new HashSet<>(); Set<Integer> toRemove = new HashSet<>();
ParticleGroup activeGroup = pplayer.getActiveParticleGroup(); ParticleGroup activeGroup = pplayer.getActiveParticleGroup();
for (int id : activeGroup.getParticles().keySet()) for (int id : activeGroup.getParticles().keySet())
@ -83,11 +89,19 @@ public class RemoveCommandModule implements CommandModule {
if (toRemove.size() > 0) { if (toRemove.size() > 0) {
PlayerParticlesAPI.getInstance().savePlayerParticleGroup(pplayer.getPlayer(), activeGroup); PlayerParticlesAPI.getInstance().savePlayerParticleGroup(pplayer.getPlayer(), activeGroup);
localeManager.sendMessage(pplayer, "remove-style-success", StringPlaceholders.builder("amount", toRemove.size()).addPlaceholder("style", style.getName()).build()); localeManager.sendMessage(pplayer, "remove-style-success", StringPlaceholders.builder("amount", toRemove.size()).addPlaceholder("style", style.getName()).build());
} else { removed = true;
} else if (effect == null) {
localeManager.sendMessage(pplayer, "remove-style-none", StringPlaceholders.single("style", style.getName())); localeManager.sendMessage(pplayer, "remove-style-none", StringPlaceholders.single("style", style.getName()));
return;
}
}
if (!removed) {
if (effect != null && style != null) {
localeManager.sendMessage(pplayer, "remove-effect-style-none", StringPlaceholders.single("name", style.getName()));
} else {
localeManager.sendMessage(pplayer, "remove-unknown", StringPlaceholders.single("name", args[0]));
} }
} else {
localeManager.sendMessage(pplayer, "remove-unknown", StringPlaceholders.single("name", args[0]));
} }
} }
} }

View file

@ -1,6 +1,7 @@
package dev.esophose.playerparticles.command; package dev.esophose.playerparticles.command;
import dev.esophose.playerparticles.manager.LocaleManager; import dev.esophose.playerparticles.manager.LocaleManager;
import dev.esophose.playerparticles.manager.PermissionManager;
import dev.esophose.playerparticles.particles.PPlayer; import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.particles.ParticleGroup; import dev.esophose.playerparticles.particles.ParticleGroup;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
@ -8,16 +9,43 @@ import dev.esophose.playerparticles.api.PlayerParticlesAPI;
import dev.esophose.playerparticles.util.StringPlaceholders; import dev.esophose.playerparticles.util.StringPlaceholders;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
public class ResetCommandModule implements CommandModule { public class ResetCommandModule implements CommandModule {
public void onCommandExecute(PPlayer pplayer, String[] args) { public void onCommandExecute(PPlayer pplayer, String[] args) {
int particleCount = pplayer.getActiveParticles().size(); LocaleManager localeManager = PlayerParticles.getInstance().getManager(LocaleManager.class);
PlayerParticlesAPI.getInstance().savePlayerParticleGroup(pplayer.getPlayer(), ParticleGroup.getDefaultGroup());
PlayerParticles.getInstance().getManager(LocaleManager.class).sendMessage(pplayer, "reset-success", StringPlaceholders.single("amount", particleCount)); boolean isConsole = pplayer.getPlayer() == null;
} if (isConsole && args.length == 0) {
localeManager.sendCustomMessage(Bukkit.getConsoleSender(), "&cOnly players can use this command. Did you mean to use '/pp reset [other]'?");
return;
}
if (args.length == 0 || !PlayerParticles.getInstance().getManager(PermissionManager.class).canResetOthers(pplayer)) {
Integer particleCount = PlayerParticlesAPI.getInstance().resetActivePlayerParticles(pplayer.getPlayer());
if (particleCount != null)
localeManager.sendMessage(pplayer, "reset-success", StringPlaceholders.single("amount", particleCount));
} else {
PlayerParticlesAPI.getInstance().resetActivePlayerParticles(args[0], success -> {
if (success) {
localeManager.sendMessage(pplayer, "reset-others-success", StringPlaceholders.single("other", args[0]));
} else {
localeManager.sendMessage(pplayer, "reset-others-none", StringPlaceholders.single("other", args[0]));
}
});
}}
public List<String> onTabComplete(PPlayer pplayer, String[] args) { public List<String> onTabComplete(PPlayer pplayer, String[] args) {
if (args.length == 1 && PlayerParticles.getInstance().getManager(PermissionManager.class).canResetOthers(pplayer)) {
List<String> replacements = Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
List<String> suggestions = new ArrayList<>();
StringUtil.copyPartialMatches(args[0], replacements, suggestions);
return suggestions;
}
return new ArrayList<>(); return new ArrayList<>();
} }
@ -30,7 +58,7 @@ public class ResetCommandModule implements CommandModule {
} }
public String getArguments() { public String getArguments() {
return ""; return "[other]";
} }
public boolean requiresEffectsAndStyles() { public boolean requiresEffectsAndStyles() {
@ -38,7 +66,7 @@ public class ResetCommandModule implements CommandModule {
} }
public boolean canConsoleExecute() { public boolean canConsoleExecute() {
return false; return true;
} }
} }

View file

@ -2,6 +2,7 @@ package dev.esophose.playerparticles.database;
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import dev.esophose.playerparticles.manager.ConfigurationManager.Setting;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
@ -19,7 +20,7 @@ public class MySQLConnector implements DatabaseConnector {
config.setJdbcUrl("jdbc:mysql://" + hostname + ":" + port + "/" + database + "?useSSL=" + useSSL); config.setJdbcUrl("jdbc:mysql://" + hostname + ":" + port + "/" + database + "?useSSL=" + useSSL);
config.setUsername(username); config.setUsername(username);
config.setPassword(password); config.setPassword(password);
config.setMaximumPoolSize(2); config.setMaximumPoolSize(Setting.MYSQL_CONNECTION_POOL_SIZE.getInt());
try { try {
this.hikari = new HikariDataSource(config); this.hikari = new HikariDataSource(config);

View file

@ -0,0 +1,91 @@
package dev.esophose.playerparticles.event;
import dev.esophose.playerparticles.styles.ParticleStyle;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* An event that gets called during the PlayerParticles style registration
*/
public class ParticleStyleRegistrationEvent extends Event {
private static final HandlerList HANDLER_LIST = new HandlerList();
private Map<String, ParticleStyle> registeredStyles;
private Map<String, ParticleStyle> registeredEventStyles;
public ParticleStyleRegistrationEvent() {
this.registeredStyles = new HashMap<>();
this.registeredEventStyles = new HashMap<>();
}
/**
* @return An unmodifiable map of registered styles keyed by the style internal name
*/
public Map<String, ParticleStyle> getRegisteredStyles() {
return Collections.unmodifiableMap(this.registeredStyles);
}
/**
* @return An unmodifiable map of registered event styles keyed by the style internal name
*/
public Map<String, ParticleStyle> getRegisteredEventStyles() {
return Collections.unmodifiableMap(this.registeredEventStyles);
}
/**
* Registers a ParticleStyle, overwriting any existing styles with the same name
*
* @param style The ParticleStyle to register
* @return true if registered without replacing an existing style, false if an existing style was replaced
*/
public boolean registerStyle(ParticleStyle style) {
if (this.registeredEventStyles.containsKey(style.getInternalName())) {
this.registeredEventStyles.remove(style.getInternalName());
this.registeredStyles.put(style.getInternalName(), style);
return false;
}
return this.registeredStyles.put(style.getInternalName(), style) == null;
}
/**
* Registers an event-based ParticleStyle, overwriting any existing styles with the same name.
* Styles registered with this method bypass the normal update loop, and must instead be spawned manually.
*
* @param style The ParticleStyle to register
* @return true if registered without replacing an existing style, false if an existing style was replaced
*/
public boolean registerEventStyle(ParticleStyle style) {
if (this.registeredStyles.containsKey(style.getInternalName())) {
this.registeredStyles.remove(style.getInternalName());
this.registeredEventStyles.put(style.getInternalName(), style);
return false;
}
return this.registeredEventStyles.put(style.getInternalName(), style) == null;
}
/**
* Unregisters a ParticleStyle
*
* @param internalName The internal name of the ParticleStyle to unregister
* @return true if a style was unregistered, false otherwise
*/
public boolean unregisterStyle(String internalName) {
return this.registeredStyles.remove(internalName) != null || this.registeredEventStyles.remove(internalName) != null;
}
@Override
public HandlerList getHandlers() {
return HANDLER_LIST;
}
public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View file

@ -3,6 +3,7 @@ package dev.esophose.playerparticles.gui;
import dev.esophose.playerparticles.gui.GuiInventoryEditData.ColorData; import dev.esophose.playerparticles.gui.GuiInventoryEditData.ColorData;
import dev.esophose.playerparticles.hook.PlaceholderAPIHook; import dev.esophose.playerparticles.hook.PlaceholderAPIHook;
import dev.esophose.playerparticles.particles.PPlayer; import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.util.NMSUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -107,7 +108,9 @@ public class GuiActionButton {
if (this.colors[0].getMaterial() != null) { // Use Materials if (this.colors[0].getMaterial() != null) { // Use Materials
itemStack = new ItemStack(this.colors[this.iconIndex].getMaterial()); itemStack = new ItemStack(this.colors[this.iconIndex].getMaterial());
} else { // Use Dyes } else { // Use Dyes
itemStack = new Dye(this.colors[this.iconIndex].getDyeColor()).toItemStack(1); Dye dye = new Dye();
dye.setColor(this.colors[this.iconIndex].getDyeColor());
itemStack = dye.toItemStack(1);
} }
} }
@ -115,7 +118,8 @@ public class GuiActionButton {
if (itemMeta != null) { if (itemMeta != null) {
itemMeta.setDisplayName(PlaceholderAPIHook.applyPlaceholders(pplayer.getPlayer(), this.name)); itemMeta.setDisplayName(PlaceholderAPIHook.applyPlaceholders(pplayer.getPlayer(), this.name));
itemMeta.setLore(parseLore(pplayer, this.lore)); itemMeta.setLore(parseLore(pplayer, this.lore));
itemMeta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_POTION_EFFECTS); if (NMSUtil.getVersionNumber() > 7)
itemMeta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_POTION_EFFECTS);
itemStack.setItemMeta(itemMeta); itemStack.setItemMeta(itemMeta);
} }

View file

@ -2,6 +2,7 @@ package dev.esophose.playerparticles.gui;
import dev.esophose.playerparticles.manager.ConfigurationManager.Setting; import dev.esophose.playerparticles.manager.ConfigurationManager.Setting;
import dev.esophose.playerparticles.particles.PPlayer; import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.util.NMSUtil;
import dev.esophose.playerparticles.util.ParticleUtils; import dev.esophose.playerparticles.util.ParticleUtils;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import java.util.ArrayList; import java.util.ArrayList;
@ -12,12 +13,11 @@ import org.bukkit.Sound;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
public abstract class GuiInventory implements InventoryHolder { public abstract class GuiInventory {
protected enum BorderColor { protected enum BorderColor {
WHITE(0, "WHITE_STAINED_GLASS_PANE"), WHITE(0, "WHITE_STAINED_GLASS_PANE"),
@ -57,7 +57,8 @@ public abstract class GuiInventory implements InventoryHolder {
ItemMeta meta = borderIcon.getItemMeta(); ItemMeta meta = borderIcon.getItemMeta();
if (meta != null) { if (meta != null) {
meta.setDisplayName(" "); meta.setDisplayName(" ");
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_ENCHANTS); if (NMSUtil.getVersionNumber() > 7)
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_ENCHANTS);
borderIcon.setItemMeta(meta); borderIcon.setItemMeta(meta);
} }
@ -156,7 +157,11 @@ public abstract class GuiInventory implements InventoryHolder {
button.handleClick(isShiftClick); button.handleClick(isShiftClick);
if (Setting.GUI_BUTTON_SOUND.getBoolean() && event.getWhoClicked() instanceof Player) { if (Setting.GUI_BUTTON_SOUND.getBoolean() && event.getWhoClicked() instanceof Player) {
Player player = (Player) event.getWhoClicked(); Player player = (Player) event.getWhoClicked();
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5f, 1); if (NMSUtil.getVersionNumber() > 8) {
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5f, 1);
} else {
player.playSound(player.getLocation(), Sound.valueOf("CLICK"), 0.5f, 1);
}
} }
break; break;
} }

View file

@ -8,8 +8,8 @@ import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.particles.ParticleEffect; import dev.esophose.playerparticles.particles.ParticleEffect;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.particles.ParticleProperty; import dev.esophose.playerparticles.particles.ParticleProperty;
import dev.esophose.playerparticles.particles.color.NoteColor; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.particles.color.OrdinaryColor; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.util.NMSUtil; import dev.esophose.playerparticles.util.NMSUtil;
import dev.esophose.playerparticles.util.ParticleUtils; import dev.esophose.playerparticles.util.ParticleUtils;
import dev.esophose.playerparticles.util.StringPlaceholders; import dev.esophose.playerparticles.util.StringPlaceholders;

View file

@ -40,7 +40,7 @@ public class GuiInventoryEditEffect extends GuiInventory {
ParticleEffectSettings effectSettings = particleManager.getEffectSettings(effect); ParticleEffectSettings effectSettings = particleManager.getEffectSettings(effect);
GuiActionButton selectButton = new GuiActionButton( GuiActionButton selectButton = new GuiActionButton(
slot, slot,
GuiIcon.EFFECT.get(effectSettings.getInternalName()), effectSettings.getGuiIconMaterial(),
localeManager.getLocaleMessage("gui-color-icon-name") + ParticleUtils.formatName(effectSettings.getName()), localeManager.getLocaleMessage("gui-color-icon-name") + ParticleUtils.formatName(effectSettings.getName()),
new String[]{localeManager.getLocaleMessage("gui-color-info") + localeManager.getLocaleMessage("gui-select-effect-description", StringPlaceholders.single("effect", ParticleUtils.formatName(effectSettings.getName())))}, new String[]{localeManager.getLocaleMessage("gui-color-info") + localeManager.getLocaleMessage("gui-select-effect-description", StringPlaceholders.single("effect", ParticleUtils.formatName(effectSettings.getName())))},
(button, isShiftClick) -> { (button, isShiftClick) -> {

View file

@ -36,7 +36,7 @@ public class GuiInventoryEditStyle extends GuiInventory {
ParticleStyle style = stylesUserHasPermissionFor.get(i); ParticleStyle style = stylesUserHasPermissionFor.get(i);
GuiActionButton selectButton = new GuiActionButton( GuiActionButton selectButton = new GuiActionButton(
slot, slot,
GuiIcon.STYLE.get(style.getInternalName()), style.getGuiIconMaterial(),
localeManager.getLocaleMessage("gui-color-icon-name") + ParticleUtils.formatName(style.getName()), localeManager.getLocaleMessage("gui-color-icon-name") + ParticleUtils.formatName(style.getName()),
new String[]{localeManager.getLocaleMessage("gui-color-info") + localeManager.getLocaleMessage("gui-select-style-description", StringPlaceholders.single("style", ParticleUtils.formatName(style.getName())))}, new String[]{localeManager.getLocaleMessage("gui-color-info") + localeManager.getLocaleMessage("gui-select-style-description", StringPlaceholders.single("style", ParticleUtils.formatName(style.getName())))},
(button, isShiftClick) -> { (button, isShiftClick) -> {

View file

@ -1,9 +1,11 @@
package dev.esophose.playerparticles.gui.hook; package dev.esophose.playerparticles.gui.hook;
import dev.esophose.playerparticles.manager.ConfigurationManager.Setting;
import dev.esophose.playerparticles.manager.LocaleManager; import dev.esophose.playerparticles.manager.LocaleManager;
import dev.esophose.playerparticles.util.NMSUtil; import dev.esophose.playerparticles.util.NMSUtil;
import dev.esophose.playerparticles.util.StringPlaceholders; import dev.esophose.playerparticles.util.StringPlaceholders;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
@ -25,7 +27,7 @@ public class PlayerChatHook extends BukkitRunnable implements Listener {
* Initializes all the static values for this class * Initializes all the static values for this class
*/ */
public static void setup() { public static void setup() {
hooks = new HashSet<>(); hooks = Collections.synchronizedSet(new HashSet<>());
if (hookTask != null) if (hookTask != null)
hookTask.cancel(); hookTask.cancel();
hookTask = new PlayerChatHook().runTaskTimer(PlayerParticles.getInstance(), 0, 20); hookTask = new PlayerChatHook().runTaskTimer(PlayerParticles.getInstance(), 0, 20);
@ -42,7 +44,7 @@ public class PlayerChatHook extends BukkitRunnable implements Listener {
if (hook.getPlayerUUID().equals(event.getPlayer().getUniqueId())) { if (hook.getPlayerUUID().equals(event.getPlayer().getUniqueId())) {
event.setCancelled(true); event.setCancelled(true);
hooks.remove(hook); hooks.remove(hook);
Bukkit.getScheduler().scheduleSyncDelayedTask(PlayerParticles.getInstance(), () -> hook.triggerCallback(event.getMessage())); hook.triggerCallback(event.getMessage());
return; return;
} }
} }
@ -55,7 +57,6 @@ public class PlayerChatHook extends BukkitRunnable implements Listener {
Set<PlayerChatHookData> hooksToRemove = new HashSet<>(); Set<PlayerChatHookData> hooksToRemove = new HashSet<>();
for (PlayerChatHookData hook : hooks) { for (PlayerChatHookData hook : hooks) {
hook.decrementHookLength();
if (hook.timedOut()) { if (hook.timedOut()) {
hook.triggerCallback(null); hook.triggerCallback(null);
hooksToRemove.add(hook); hooksToRemove.add(hook);
@ -67,13 +68,28 @@ public class PlayerChatHook extends BukkitRunnable implements Listener {
hooksToRemove.remove(hook); hooksToRemove.remove(hook);
} else { } else {
LocaleManager localeManager = PlayerParticles.getInstance().getManager(LocaleManager.class); LocaleManager localeManager = PlayerParticles.getInstance().getManager(LocaleManager.class);
if (NMSUtil.getVersionNumber() == 9) { String message = localeManager.getLocaleMessage("gui-save-group-hotbar-message", StringPlaceholders.single("seconds", hook.getTimeRemaining()));
if (hook.getMaxHookLength() == hook.getTimeRemaining())
player.sendMessage(localeManager.getLocaleMessage("gui-save-group-hotbar-message", StringPlaceholders.single("seconds", hook.getTimeRemaining()))); if (NMSUtil.getVersionNumber() >= 11) {
switch (Setting.GUI_GROUP_CREATION_MESSAGE_DISPLAY_AREA.getString().toUpperCase()) {
case "ACTION_BAR":
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(localeManager.getLocaleMessage("gui-save-group-hotbar-message", StringPlaceholders.single("seconds", hook.getTimeRemaining()))));
break;
case "TITLE":
player.sendTitle("", message, 5, 40, 10);
break;
default:
if (hook.getMaxHookLength() == hook.getTimeRemaining())
player.sendMessage(message);
break;
}
} else { } else {
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(localeManager.getLocaleMessage("gui-save-group-hotbar-message", StringPlaceholders.single("seconds", hook.getTimeRemaining())))); if (hook.getMaxHookLength() == hook.getTimeRemaining())
player.sendMessage(message);
} }
} }
hook.decrementHookLength();
} }
for (PlayerChatHookData hookToRemove : hooksToRemove) for (PlayerChatHookData hookToRemove : hooksToRemove)

View file

@ -37,6 +37,8 @@ public class ParticlePlaceholderExpansion extends PlaceholderExpansion {
return String.valueOf(pplayer.isMoving()); return String.valueOf(pplayer.isMoving());
case "is_in_combat": case "is_in_combat":
return String.valueOf(pplayer.isInCombat()); return String.valueOf(pplayer.isInCombat());
case "is_in_allowed_region":
return String.valueOf(pplayer.isInAllowedRegion());
case "can_see_particles": case "can_see_particles":
return String.valueOf(pplayer.canSeeParticles()); return String.valueOf(pplayer.canSeeParticles());
} }

View file

@ -0,0 +1,54 @@
package dev.esophose.playerparticles.hook;
import dev.esophose.playerparticles.manager.ConfigurationManager.Setting;
import java.util.List;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.codemc.worldguardwrapper.WorldGuardWrapper;
import org.codemc.worldguardwrapper.region.IWrappedRegion;
public class WorldGuardHook {
private static Boolean enabled;
private static WorldGuardWrapper worldGuardWrapper;
/**
* @return true if WorldGuard is enabled, otherwise false
*/
public static boolean enabled() {
if (enabled != null)
return enabled;
enabled = Bukkit.getPluginManager().getPlugin("WorldGuard") != null;
if (enabled)
worldGuardWrapper = WorldGuardWrapper.getInstance();
return enabled;
}
/**
* Checks if a location is in a region that allows particles to spawn
*
* @param location The location to check
* @return true if the location is in an allowed region, otherwise false
*/
public static boolean isInAllowedRegion(Location location) {
if (!enabled())
return true;
Set<IWrappedRegion> regions = worldGuardWrapper.getRegions(location);
List<String> disallowedRegionIds = Setting.WORLDGUARD_DISALLOWED_REGIONS.getStringList();
if (regions.stream().map(IWrappedRegion::getId).anyMatch(disallowedRegionIds::contains))
return false;
if (Setting.WORLDGUARD_USE_ALLOWED_REGIONS.getBoolean()) {
List<String> allowedRegionIds = Setting.WORLDGUARD_ALLOWED_REGIONS.getStringList();
return regions.stream().map(IWrappedRegion::getId).anyMatch(allowedRegionIds::contains);
}
return true;
}
}

View file

@ -118,6 +118,7 @@ public class EnglishLocale implements Locale {
this.put("remove-effect-none", "&cYou do not have any particles applied with the effect &b%effect%&c!"); this.put("remove-effect-none", "&cYou do not have any particles applied with the effect &b%effect%&c!");
this.put("remove-style-success", "&aRemoved &b%amount% &aof your particles with the style of &b%style%&a!"); this.put("remove-style-success", "&aRemoved &b%amount% &aof your particles with the style of &b%style%&a!");
this.put("remove-style-none", "&cYou do not have any particles applied with the style &b%style%&c!"); this.put("remove-style-none", "&cYou do not have any particles applied with the style &b%style%&c!");
this.put("remove-effect-style-none", "&cYou do not have any particles applied with the effect or style &b%name%&c!");
this.put("remove-unknown", "&cAn effect or style with the name of &b%name% &cdoes not exist!"); this.put("remove-unknown", "&cAn effect or style with the name of &b%name% &cdoes not exist!");
this.put("#10", "List Messages"); this.put("#10", "List Messages");
@ -166,6 +167,8 @@ public class EnglishLocale implements Locale {
this.put("#17", "Reset Message"); this.put("#17", "Reset Message");
this.put("reset-success", "&aRemoved &b%amount% &aactive particle(s)!"); this.put("reset-success", "&aRemoved &b%amount% &aactive particle(s)!");
this.put("reset-others-success", "&aRemoved particles for &b%other%&a!");
this.put("reset-others-none", "&eNo particles were removed for &b%other%&e.");
this.put("#18", "Fixed Create Messages"); this.put("#18", "Fixed Create Messages");
this.put("fixed-create-missing-args", "&cUnable to create fixed effect, you are missing &b%amount% &crequired arguments!"); this.put("fixed-create-missing-args", "&cUnable to create fixed effect, you are missing &b%amount% &crequired arguments!");

View file

@ -118,6 +118,7 @@ public class FrenchLocale implements Locale {
this.put("remove-effect-none", "&cVous n'avez pas de particules appliquées avec l'effet &b%effect% &c!"); this.put("remove-effect-none", "&cVous n'avez pas de particules appliquées avec l'effet &b%effect% &c!");
this.put("remove-style-success", "&aSuppression &b%amount% &ade votre particule avec le style &b%style% &a!"); this.put("remove-style-success", "&aSuppression &b%amount% &ade votre particule avec le style &b%style% &a!");
this.put("remove-style-none", "&cVous n'avez pas de particules appliquées avec le style &b%style% &c!"); this.put("remove-style-none", "&cVous n'avez pas de particules appliquées avec le style &b%style% &c!");
this.put("remove-effect-style-none", "&cVous n'avez pas de particules appliquées avec l'effet ou le style &b%name% &c!");
this.put("remove-unknown", "&cL'effect avec le nom ou le style &b%name% &cn'existe pas !"); this.put("remove-unknown", "&cL'effect avec le nom ou le style &b%name% &cn'existe pas !");
this.put("#10", "List Messages"); this.put("#10", "List Messages");
@ -166,6 +167,8 @@ public class FrenchLocale implements Locale {
this.put("#17", "Reset Message"); this.put("#17", "Reset Message");
this.put("reset-success", "&b%amount% &aparticule(s) actives supprimées !"); this.put("reset-success", "&b%amount% &aparticule(s) actives supprimées !");
this.put("reset-others-success", "&aParticules enlevées pour &b%other%&a !");
this.put("reset-others-none", "&eAucune particule n'a été enlevée pour &b%other%&e.");
this.put("#18", "Fixed Create Messages"); this.put("#18", "Fixed Create Messages");
this.put("fixed-create-missing-args", "&cImpossible de créer un effet fixe, vous oubliez des arguments : &b%amount%"); this.put("fixed-create-missing-args", "&cImpossible de créer un effet fixe, vous oubliez des arguments : &b%amount%");

View file

@ -118,6 +118,7 @@ public class GermanLocale implements Locale {
this.put("remove-effect-none", "&cSie haben keine Partikel mit dem Effekt &b%effect%&cangelegt!"); this.put("remove-effect-none", "&cSie haben keine Partikel mit dem Effekt &b%effect%&cangelegt!");
this.put("remove-style-success", "&b%amount% &adeiner Partikel im Stil von &b%style% &aentfernt!"); this.put("remove-style-success", "&b%amount% &adeiner Partikel im Stil von &b%style% &aentfernt!");
this.put("remove-style-none", "&cSie haben keine Partikel mit dem Stil &b%style%&cangelegt!"); this.put("remove-style-none", "&cSie haben keine Partikel mit dem Stil &b%style%&cangelegt!");
this.put("remove-effect-style-none", "&cSie haben keine Partikel mit der Wirkung oder dem Stil &b%name% &cangewendet!");
this.put("remove-unknown", "&cEs existiert kein Effekt oder Stil mit dem Namen &b%name%&c!"); this.put("remove-unknown", "&cEs existiert kein Effekt oder Stil mit dem Namen &b%name%&c!");
this.put("#10", "List Messages"); this.put("#10", "List Messages");
@ -166,6 +167,8 @@ public class GermanLocale implements Locale {
this.put("#17", "Reset Message"); this.put("#17", "Reset Message");
this.put("reset-success", "&b%amount% &aaktive Partikel entfernt!"); this.put("reset-success", "&b%amount% &aaktive Partikel entfernt!");
this.put("reset-others-success", "&aEntfertigte Partikel für &b%other%&a!");
this.put("reset-others-none", "&eFür &b%other%&e wurden keine Partikel entfernt.");
this.put("#18", "Fixed Create Messages"); this.put("#18", "Fixed Create Messages");
this.put("fixed-create-missing-args", "&cFixer Effekt kann nicht erstellt werden, es fehlen &b%amount% &cerforderliche Argumente!"); this.put("fixed-create-missing-args", "&cFixer Effekt kann nicht erstellt werden, es fehlen &b%amount% &cerforderliche Argumente!");
@ -240,6 +243,7 @@ public class GermanLocale implements Locale {
this.put("gui-color-icon-name", "&a"); this.put("gui-color-icon-name", "&a");
this.put("gui-color-info", "&e"); this.put("gui-color-info", "&e");
this.put("gui-color-subtext", "&b"); this.put("gui-color-subtext", "&b");
this.put("gui-color-unavailable", "&c");
this.put("#28", "GUI Info Messages"); this.put("#28", "GUI Info Messages");
this.put("gui-commands-info", "Informationen zu Befehlen finden Sie mit Hilfe von &b/pp help"); this.put("gui-commands-info", "Informationen zu Befehlen finden Sie mit Hilfe von &b/pp help");

View file

@ -118,6 +118,7 @@ public class RussianLocale implements Locale {
this.put("remove-effect-none", "&cУ Вас нет каких-либо частиц с эффектом &b%effect%&c!"); this.put("remove-effect-none", "&cУ Вас нет каких-либо частиц с эффектом &b%effect%&c!");
this.put("remove-style-success", "&aКоличество удалённых частиц - &b%amount% &a, стилей - &b%style%&a!"); this.put("remove-style-success", "&aКоличество удалённых частиц - &b%amount% &a, стилей - &b%style%&a!");
this.put("remove-style-none", "&cУ Вас нет каких-либо частиц со стилем &b%style%&c!"); this.put("remove-style-none", "&cУ Вас нет каких-либо частиц со стилем &b%style%&c!");
this.put("remove-effect-style-none", "&cУ вас нет никаких частиц с эффектом или стилем &b%name%&c!");
this.put("remove-unknown", "&cЭффект или стиль под названием &b%name% &cне существует!"); this.put("remove-unknown", "&cЭффект или стиль под названием &b%name% &cне существует!");
this.put("#10", "List Messages"); this.put("#10", "List Messages");
@ -166,6 +167,8 @@ public class RussianLocale implements Locale {
this.put("#17", "Reset Message"); this.put("#17", "Reset Message");
this.put("reset-success", "&aУдалено &aактивных частиц - &b%amount%!"); this.put("reset-success", "&aУдалено &aактивных частиц - &b%amount%!");
this.put("reset-others-success", "&aУдаленные частицы для &b%other%&a!");
this.put("reset-others-none", "&eНикакие частицы не были удалены для &b%other% &e.");
this.put("#18", "Fixed Create Messages"); this.put("#18", "Fixed Create Messages");
this.put("fixed-create-missing-args", "&cНевозможно создать эффект, не введено запрашиваемых аргументов - &b%amount%!"); this.put("fixed-create-missing-args", "&cНевозможно создать эффект, не введено запрашиваемых аргументов - &b%amount%!");

View file

@ -118,6 +118,7 @@ public class SimplifiedChineseLocale implements Locale {
this.put("remove-effect-none", "&c你没有使用特效&b%effect%&c的粒子!"); this.put("remove-effect-none", "&c你没有使用特效&b%effect%&c的粒子!");
this.put("remove-style-success", "&已成功删除&b%amount%&a个使用了风格&b%style%&a的粒子!"); this.put("remove-style-success", "&已成功删除&b%amount%&a个使用了风格&b%style%&a的粒子!");
this.put("remove-style-none", "&c你没有已使用风格&b%style%&c的粒子!"); this.put("remove-style-none", "&c你没有已使用风格&b%style%&c的粒子!");
this.put("remove-effect-style-none", "&c您没有应用任何颗粒效果或样式&b%name%&c!");
this.put("remove-unknown", "&c名为&b%name%&c的特效或风格不存在!"); this.put("remove-unknown", "&c名为&b%name%&c的特效或风格不存在!");
this.put("#10", "List Messages"); this.put("#10", "List Messages");
@ -166,6 +167,8 @@ public class SimplifiedChineseLocale implements Locale {
this.put("#17", "Reset Message"); this.put("#17", "Reset Message");
this.put("reset-success", "&a已删除&b%amount%个&a激活的粒子特效!"); this.put("reset-success", "&a已删除&b%amount%个&a激活的粒子特效!");
this.put("reset-others-success", "&a已删除&b%other%&a的颗粒!");
this.put("reset-others-none", "&e没有除去&b%other%&e的颗粒.");
this.put("#18", "Fixed Create Messages"); this.put("#18", "Fixed Create Messages");
this.put("fixed-create-missing-args", "&c无法创建定点特效 缺少 &b%amount% &c必要参数!"); this.put("fixed-create-missing-args", "&c无法创建定点特效 缺少 &b%amount% &c必要参数!");
@ -243,7 +246,7 @@ public class SimplifiedChineseLocale implements Locale {
this.put("gui-color-unavailable", "&c"); this.put("gui-color-unavailable", "&c");
this.put("#28", "GUI Info Messages"); this.put("#28", "GUI Info Messages");
this.put("gui-commands-info", "商人 &b/pp help 查看指令帮助"); this.put("gui-commands-info", "输入 &b/pp help 查看指令帮助");
this.put("gui-back-button", "返回"); this.put("gui-back-button", "返回");
this.put("gui-next-page-button", "下一页 (%start%/%end%)"); this.put("gui-next-page-button", "下一页 (%start%/%end%)");
this.put("gui-previous-page-button", "上一页 (%start%/%end%)"); this.put("gui-previous-page-button", "上一页 (%start%/%end%)");

View file

@ -118,6 +118,7 @@ public class VietnameseLocale implements Locale {
this.put("remove-effect-none", "&cBạn không có bất kì Hạt hiệu ứng nào để áp dụng hiệu ứng &b%effect%&c!"); this.put("remove-effect-none", "&cBạn không có bất kì Hạt hiệu ứng nào để áp dụng hiệu ứng &b%effect%&c!");
this.put("remove-style-success", "&aĐã xóa &b%amount% &aHạt hiệu ứng của bạn với style &b%style%&a!"); this.put("remove-style-success", "&aĐã xóa &b%amount% &aHạt hiệu ứng của bạn với style &b%style%&a!");
this.put("remove-style-none", "&cBạn không có bất kì Hạt hiệu ứng nào để áp dụng style &b%style%&c!"); this.put("remove-style-none", "&cBạn không có bất kì Hạt hiệu ứng nào để áp dụng style &b%style%&c!");
this.put("remove-effect-style-none", "&cBạn không có bất kỳ hạt nào được áp dụng với hiệu ứng hoặc kiểu %name%&c!");
this.put("remove-unknown", "&cEffect hoặc Style với tên &b%name% &ckhông tồn tại!"); this.put("remove-unknown", "&cEffect hoặc Style với tên &b%name% &ckhông tồn tại!");
this.put("#10", "List Messages"); this.put("#10", "List Messages");
@ -166,6 +167,8 @@ public class VietnameseLocale implements Locale {
this.put("#17", "Reset Message"); this.put("#17", "Reset Message");
this.put("reset-success", "&aĐã xóa &b%amount% &aHạt hiệu ứng hoạt động!"); this.put("reset-success", "&aĐã xóa &b%amount% &aHạt hiệu ứng hoạt động!");
this.put("reset-others-success", "&aCác hạt bị loại bỏ cho &b%other%&a!");
this.put("reset-others-none", "&eKhông có hạt nào được loại bỏ cho &b%other%&e.");
this.put("#18", "Fixed Create Messages"); this.put("#18", "Fixed Create Messages");
this.put("fixed-create-missing-args", "&cKhông thể tạo Hiệu ứng cố định, bạn đã quên &b%amount% &cđối số yêu cầu!"); this.put("fixed-create-missing-args", "&cKhông thể tạo Hiệu ứng cố định, bạn đã quên &b%amount% &cđối số yêu cầu!");

View file

@ -26,8 +26,8 @@ import dev.esophose.playerparticles.command.WorldsCommandModule;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;

View file

@ -16,11 +16,11 @@ import org.bukkit.Material;
public class ConfigurationManager extends Manager { public class ConfigurationManager extends Manager {
private static final String[] HEADER = new String[] { private static final String[] HEADER = new String[] {
" _________ __ __________ __ __ __ _________", " _________ __ __________ __ __ __",
" \\______ \\ | _____ ___ __ __________\\______ \\_____ ________/ |_|__| ____ | | ____ ______ \\______ \\", " \\______ \\ | _____ ___ __ __________\\______ \\_____ ________/ |_|__| ____ | | ____ ______",
" | ___/ | \\__ \\< | |/ __ \\_ __ \\ ___/\\__ \\\\_ __ \\ __\\ |/ ___\\| | _/ __ \\ / ___/ / /", " | ___/ | \\__ \\< | |/ __ \\_ __ \\ ___/\\__ \\\\_ __ \\ __\\ |/ ___\\| | _/ __ \\ / ___/",
" | | | |__/ __ \\\\___ \\ ___/| | \\/ | / __ \\| | \\/| | | \\ \\___| |_\\ ___/ \\___ \\ / /", " | | | |__/ __ \\\\___ \\ ___/| | \\/ | / __ \\| | \\/| | | \\ \\___| |_\\ ___/ \\___ \\",
" |____| |____(____ / ____|\\___ >__| |____| (____ /__| |__| |__|\\___ >____/\\___ >____ > /____/", " |____| |____(____ / ____|\\___ >__| |____| (____ /__| |__| |__|\\___ >____/\\___ >____ >",
" \\/\\/ \\/ \\/ \\/ \\/ \\/" " \\/\\/ \\/ \\/ \\/ \\/ \\/"
}; };
@ -41,9 +41,9 @@ public class ConfigurationManager extends Manager {
GUI_PRESETS_ONLY("gui-presets-only", false, "If true, only the preset groups will be available in the GUI", "Permissions to open the GUI will change to only open if the user has any preset groups available"), GUI_PRESETS_ONLY("gui-presets-only", false, "If true, only the preset groups will be available in the GUI", "Permissions to open the GUI will change to only open if the user has any preset groups available"),
GUI_CLOSE_AFTER_GROUP_SELECTED("gui-close-after-group-selected", true, "If true, the GUI will close after selecting a group (either saved or preset)"), GUI_CLOSE_AFTER_GROUP_SELECTED("gui-close-after-group-selected", true, "If true, the GUI will close after selecting a group (either saved or preset)"),
GUI_BUTTON_SOUND("gui-button-sound", true, "If clicking a GUI button should make a noise"), GUI_BUTTON_SOUND("gui-button-sound", true, "If clicking a GUI button should make a noise"),
TOGGLE_ON_MOVE("toggle-on-move", false, "If true, styles will not display while the player is moving", "They will instead have the effect displayed at their feet", "Note: Not all styles abide by this rule, but most will"), TOGGLE_ON_MOVE("toggle-on-move", "NONE", "Valid values: DISPLAY_FEET, DISPLAY_NORMAL, DISPLAY_OVERHEAD, HIDE, NONE", "DISPLAY_FEET will display particles using the feet style while moving", "DISPLAY_NORMAL will display particles using the normal style while moving", "DISPLAY_OVERHEAD will display particles using the overhead style while moving", "HIDE will hide particles while moving", "NONE will make this setting do nothing", "Note: You can change what styles follow this setting in their individual setting files"),
TOGGLE_ON_MOVE_DELAY("toggle-on-move-delay", 9, "The time (in ticks) a player has to be standing still before they are considered to be stopped", "This setting has no effect if toggle-on-move is set to false", "The value must be a positive whole number"), TOGGLE_ON_MOVE_DELAY("toggle-on-move-delay", 9, "The time (in ticks) a player has to be standing still before they are considered to be stopped", "This setting has no effect if toggle-on-move is set to false", "The value must be a positive whole number"),
TOGGLE_ON_COMBAT("toggle-on-combat", false, "If true, particles will be completely disabled while the player is in combat"), TOGGLE_ON_COMBAT("toggle-on-combat", false, "If true, particles will be completely disabled while the player is in combat", "Note: You can change what styles follow this setting in their individual setting files"),
TOGGLE_ON_COMBAT_DELAY("toggle-on-combat-delay", 15, "The time (in seconds) a player has to not be damaged/attacked to be considered out of combat", "This setting has no effect if toggle-on-combat is set to false", "The value must be a positive whole number"), TOGGLE_ON_COMBAT_DELAY("toggle-on-combat-delay", 15, "The time (in seconds) a player has to not be damaged/attacked to be considered out of combat", "This setting has no effect if toggle-on-combat is set to false", "The value must be a positive whole number"),
DISABLED_WORLDS("disabled-worlds", Collections.singletonList("disabled_world_name"), "A list of worlds that the plugin is disabled in"), DISABLED_WORLDS("disabled-worlds", Collections.singletonList("disabled_world_name"), "A list of worlds that the plugin is disabled in"),
MAX_PARTICLES("max-particles", 3, "The maximum number of particles a player can apply at once", "The GUI will only display up to 21, don't set this any higher than that"), MAX_PARTICLES("max-particles", 3, "The maximum number of particles a player can apply at once", "The GUI will only display up to 21, don't set this any higher than that"),
@ -55,7 +55,17 @@ public class ConfigurationManager extends Manager {
PARTICLE_RENDER_RANGE_FIXED_EFFECT("particle-render-range-fixed-effect", 192, "From how many blocks away should a player be able to see the particles from a fixed effect?"), PARTICLE_RENDER_RANGE_FIXED_EFFECT("particle-render-range-fixed-effect", 192, "From how many blocks away should a player be able to see the particles from a fixed effect?"),
RAINBOW_CYCLE_SPEED("rainbow-cycle-speed", 2, "How many out of 360 hue ticks to move per game tick", "Higher values make the rainbow cycle faster", "Note: Must be a positive whole number"), RAINBOW_CYCLE_SPEED("rainbow-cycle-speed", 2, "How many out of 360 hue ticks to move per game tick", "Higher values make the rainbow cycle faster", "Note: Must be a positive whole number"),
DUST_SIZE("dust-size", 1.0, "How large should dust particles appear?", "Note: Can include decimals", "Only works in 1.13+"), DUST_SIZE("dust-size", 1.0, "How large should dust particles appear?", "Note: Can include decimals", "Only works in 1.13+"),
GUI_GROUP_CREATION_MESSAGE_DISPLAY_AREA("gui-group-creation-message-display-area", "ACTION_BAR", "Valid values: ACTION_BAR, TITLE, CHAT", "Where should the GUI group creation countdown message be displayed?", "Note: Server versions less than 1.11.2 will always use CHAT"),
OVERRIDE_PARTICLE_VERSION("override-particle-version", -1, "Allows you to override the version of Minecraft that will be assumed for spawning particles", "This should follow this format: 9, 12, 15, etc. 9 means 1.9, 14 means 1.14... and so on"), OVERRIDE_PARTICLE_VERSION("override-particle-version", -1, "Allows you to override the version of Minecraft that will be assumed for spawning particles", "This should follow this format: 9, 12, 15, etc. 9 means 1.9, 14 means 1.14... and so on"),
WORLDGUARD_SETTINGS("worldguard-settings", null, "Settings for WorldGuard", "If WorldGuard is not installed, these settings will do nothing"),
WORLDGUARD_USE_ALLOWED_REGIONS("worldguard-settings.use-allowed-regions", false, "If true, particles will only be able to spawn if they are in an allowed region and not a disallowed region", "If false, particles will be able to spawn as long as they are not in a disallowed region"),
WORLDGUARD_ALLOWED_REGIONS("worldguard-settings.allowed-regions", Arrays.asList("example_region_1", "example_region_2"), "Regions that particles will be allowed to spawn in"),
WORLDGUARD_DISALLOWED_REGIONS("worldguard-settings.disallowed-regions", Arrays.asList("example_region_3", "example_region_4"), "Regions that particles will be blocked from spawning in", "This overrides allowed regions if they overlap"),
WORLDGUARD_CHECK_INTERVAL("worldguard-settings.check-interval", 10, "How often to check if a player is in a region that allows spawning particles", "Measured in ticks"),
WORLDGUARD_ENABLE_BYPASS_PERMISSION("worldguard-settings.enable-bypass-permission", false, "If true, the permission playerparticles.worldguard.bypass will allow", "the player to bypass the region requirements"),
MYSQL_SETTINGS("mysql-settings", null, "Settings for if you want to use MySQL for data management"), MYSQL_SETTINGS("mysql-settings", null, "Settings for if you want to use MySQL for data management"),
MYSQL_ENABLED("mysql-settings.enabled", false, "Enable MySQL", "If false, SQLite will be used instead"), MYSQL_ENABLED("mysql-settings.enabled", false, "Enable MySQL", "If false, SQLite will be used instead"),
MYSQL_HOSTNAME("mysql-settings.hostname", "", "MySQL Database Hostname"), MYSQL_HOSTNAME("mysql-settings.hostname", "", "MySQL Database Hostname"),
@ -63,14 +73,16 @@ public class ConfigurationManager extends Manager {
MYSQL_DATABASE_NAME("mysql-settings.database-name", "", "MySQL Database Name"), MYSQL_DATABASE_NAME("mysql-settings.database-name", "", "MySQL Database Name"),
MYSQL_USER_NAME("mysql-settings.user-name", "", "MySQL Database User Name"), MYSQL_USER_NAME("mysql-settings.user-name", "", "MySQL Database User Name"),
MYSQL_USER_PASSWORD("mysql-settings.user-password", "", "MySQL Database User Password"), MYSQL_USER_PASSWORD("mysql-settings.user-password", "", "MySQL Database User Password"),
MYSQL_TABLE_PREFIX("mysql-settings.table-prefix", PlayerParticles.getInstance().getDescription().getName().toLowerCase() + "_", "The prefix of the tables in the database", "Do not change this after tables have already been created or you will have data loss"),
MYSQL_USE_SSL("mysql-settings.use-ssl", false, "If the database connection should use SSL", "You should enable this if your database supports SSL"), MYSQL_USE_SSL("mysql-settings.use-ssl", false, "If the database connection should use SSL", "You should enable this if your database supports SSL"),
MYSQL_CONNECTION_POOL_SIZE("mysql-settings.connection-pool-size", 5, "The size of the connection pool to the database", "Not recommended to go below 2 or above 5"),
GUI_ICON("gui-icon", null, GUI_ICON("gui-icon", null,
"This configuration option allows you to change any of the GUI", "This configuration option allows you to change the GUI",
"icons to whatever block/item you want.", "icons to whatever block/item you want. If you want to change an effect",
"or style icon, use their respective config files.",
"Notes: If any of the block/item names are invalid the icon in the GUI", "Notes: If any of the block/item names are invalid the icon in the GUI",
"will be the barrier icon to show that it failed to load.", "will be the barrier icon to show that it failed to load.",
"Do NOT change the particle/style name",
"You MUST use the Spigot-given name for it to work. You can see", "You MUST use the Spigot-given name for it to work. You can see",
"all the Spigot-given names at the link below:", "all the Spigot-given names at the link below:",
"https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html", "https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html",
@ -87,105 +99,7 @@ public class ConfigurationManager extends Manager {
GUI_ICON_MISC_EDIT_EFFECT("gui-icon.misc.edit_effect", Arrays.asList("FIREWORK_ROCKET", "FIREWORK")), GUI_ICON_MISC_EDIT_EFFECT("gui-icon.misc.edit_effect", Arrays.asList("FIREWORK_ROCKET", "FIREWORK")),
GUI_ICON_MISC_EDIT_STYLE("gui-icon.misc.edit_style", Collections.singletonList("NETHER_STAR")), GUI_ICON_MISC_EDIT_STYLE("gui-icon.misc.edit_style", Collections.singletonList("NETHER_STAR")),
GUI_ICON_MISC_EDIT_DATA("gui-icon.misc.edit_data", Collections.singletonList("BOOK")), GUI_ICON_MISC_EDIT_DATA("gui-icon.misc.edit_data", Collections.singletonList("BOOK")),
GUI_ICON_MISC_RESET("gui-icon.misc.reset", Collections.singletonList("BARRIER")), GUI_ICON_MISC_RESET("gui-icon.misc.reset", Collections.singletonList("BARRIER"));
GUI_ICON_EFFECT("gui-icon.effect", null),
GUI_ICON_EFFECT_AMBIENT_ENTITY_EFFECT("gui-icon.effect.ambient_entity_effect", Collections.singletonList("BEACON")),
GUI_ICON_EFFECT_ANGRY_VILLAGER("gui-icon.effect.angry_villager", Collections.singletonList("IRON_DOOR")),
GUI_ICON_EFFECT_BARRIER("gui-icon.effect.barrier", Collections.singletonList("BARRIER")),
GUI_ICON_EFFECT_BLOCK("gui-icon.effect.block", Collections.singletonList("STONE")),
GUI_ICON_EFFECT_BUBBLE("gui-icon.effect.bubble", Arrays.asList("BUBBLE_CORAL", "GLASS")),
GUI_ICON_EFFECT_BUBBLE_COLUMN_UP("gui-icon.effect.bubble_column_up", Collections.singletonList("MAGMA_BLOCK")),
GUI_ICON_EFFECT_BUBBLE_POP("gui-icon.effect.bubble_pop", Collections.singletonList("BUBBLE_CORAL_FAN")),
GUI_ICON_EFFECT_CAMPFIRE_COSY_SMOKE("gui-icon.effect.campfire_cosy_smoke", Collections.singletonList("CAMPFIRE")),
GUI_ICON_EFFECT_CAMPFIRE_SIGNAL_SMOKE("gui-icon.effect.campfire_signal_smoke", Collections.singletonList("REDSTONE_TORCH")),
GUI_ICON_EFFECT_CLOUD("gui-icon.effect.cloud", Arrays.asList("WHITE_WOOL", "WOOL")),
GUI_ICON_EFFECT_COMPOSTER("gui-icon.effect.composter", Collections.singletonList("COMPOSTER")),
GUI_ICON_EFFECT_CRIT("gui-icon.effect.crit", Collections.singletonList("IRON_SWORD")),
GUI_ICON_EFFECT_CURRENT_DOWN("gui-icon.effect.current_down", Collections.singletonList("SOUL_SAND")),
GUI_ICON_EFFECT_DAMAGE_INDICATOR("gui-icon.effect.damage_indicator", Collections.singletonList("BOW")),
GUI_ICON_EFFECT_DOLPHIN("gui-icon.effect.dolphin", Collections.singletonList("DOLPHIN_SPAWN_EGG")),
GUI_ICON_EFFECT_DRAGON_BREATH("gui-icon.effect.dragon_breath", Arrays.asList("DRAGON_BREATH", "DRAGONS_BREATH")),
GUI_ICON_EFFECT_DRIPPING_HONEY("gui-icon.effect.dripping_honey", Collections.singletonList("BEE_NEST")),
GUI_ICON_EFFECT_DRIPPING_LAVA("gui-icon.effect.dripping_lava", Collections.singletonList("LAVA_BUCKET")),
GUI_ICON_EFFECT_DRIPPING_WATER("gui-icon.effect.dripping_water", Collections.singletonList("WATER_BUCKET")),
GUI_ICON_EFFECT_DUST("gui-icon.effect.dust", Collections.singletonList("REDSTONE")),
GUI_ICON_EFFECT_ELDER_GUARDIAN("gui-icon.effect.elder_guardian", Arrays.asList("ELDER_GUARDIAN_SPAWN_EGG", "PRISMARINE_CRYSTALS")),
GUI_ICON_EFFECT_ENCHANT("gui-icon.effect.enchant", Arrays.asList("ENCHANTING_TABLE", "ENCHANTMENT_TABLE")),
GUI_ICON_EFFECT_ENCHANTED_HIT("gui-icon.effect.enchanted_hit", Collections.singletonList("DIAMOND_SWORD")),
GUI_ICON_EFFECT_END_ROD("gui-icon.effect.end_rod", Collections.singletonList("END_ROD")),
GUI_ICON_EFFECT_ENTITY_EFFECT("gui-icon.effect.entity_effect", Collections.singletonList("GLOWSTONE_DUST")),
GUI_ICON_EFFECT_EXPLOSION("gui-icon.effect.explosion", Arrays.asList("FIRE_CHARGE", "FIREBALL")),
GUI_ICON_EFFECT_EXPLOSION_EMITTER("gui-icon.effect.explosion_emitter", Collections.singletonList("TNT")),
GUI_ICON_EFFECT_FALLING_DUST("gui-icon.effect.falling_dust", Collections.singletonList("SAND")),
GUI_ICON_EFFECT_FALLING_HONEY("gui-icon.effect.falling_honey", Collections.singletonList("HONEY_BOTTLE")),
GUI_ICON_EFFECT_FALLING_LAVA("gui-icon.effect.falling_lava", Collections.singletonList("RED_DYE")),
GUI_ICON_EFFECT_FALLING_NECTAR("gui-icon.effect.falling_nectar", Collections.singletonList("HONEYCOMB")),
GUI_ICON_EFFECT_FALLING_WATER("gui-icon.effect.falling_water", Collections.singletonList("BLUE_DYE")),
GUI_ICON_EFFECT_FIREWORK("gui-icon.effect.firework", Arrays.asList("FIREWORK_ROCKET", "FIREWORK")),
GUI_ICON_EFFECT_FISHING("gui-icon.effect.fishing", Collections.singletonList("FISHING_ROD")),
GUI_ICON_EFFECT_FLAME("gui-icon.effect.flame", Collections.singletonList("BLAZE_POWDER")),
GUI_ICON_EFFECT_FLASH("gui-icon.effect.flash", Collections.singletonList("GOLD_INGOT")),
GUI_ICON_EFFECT_FOOTSTEP("gui-icon.effect.footstep", Collections.singletonList("GRASS")),
GUI_ICON_EFFECT_HAPPY_VILLAGER("gui-icon.effect.happy_villager", Arrays.asList("DARK_OAK_DOOR_ITEM", "DARK_OAK_DOOR")),
GUI_ICON_EFFECT_HEART("gui-icon.effect.heart", Arrays.asList("POPPY", "RED_ROSE")),
GUI_ICON_EFFECT_INSTANT_EFFECT("gui-icon.effect.instant_effect", Arrays.asList("SPLASH_POTION", "POTION")),
GUI_ICON_EFFECT_ITEM("gui-icon.effect.item", Collections.singletonList("ITEM_FRAME")),
GUI_ICON_EFFECT_ITEM_SLIME("gui-icon.effect.item_slime", Collections.singletonList("SLIME_BALL")),
GUI_ICON_EFFECT_ITEM_SNOWBALL("gui-icon.effect.item_snowball", Arrays.asList("SNOWBALL", "SNOW_BALL")),
GUI_ICON_EFFECT_LARGE_SMOKE("gui-icon.effect.large_smoke", Arrays.asList("COBWEB", "WEB")),
GUI_ICON_EFFECT_LANDING_HONEY("gui-icon.effect.landing_honey", Collections.singletonList("HONEY_BLOCK")),
GUI_ICON_EFFECT_LANDING_LAVA("gui-icon.effect.landing_lava", Collections.singletonList("ORANGE_DYE")),
GUI_ICON_EFFECT_LAVA("gui-icon.effect.lava", Collections.singletonList("MAGMA_CREAM")),
GUI_ICON_EFFECT_MYCELIUM("gui-icon.effect.mycelium", Arrays.asList("MYCELIUM", "MYCEL")),
GUI_ICON_EFFECT_NAUTILUS("gui-icon.effect.nautilus", Collections.singletonList("HEART_OF_THE_SEA")),
GUI_ICON_EFFECT_NOTE("gui-icon.effect.note", Collections.singletonList("NOTE_BLOCK")),
GUI_ICON_EFFECT_POOF("gui-icon.effect.poof", Arrays.asList("FIREWORK_STAR", "FIREWORK_CHARGE")),
GUI_ICON_EFFECT_PORTAL("gui-icon.effect.portal", Collections.singletonList("OBSIDIAN")),
GUI_ICON_EFFECT_RAIN("gui-icon.effect.rain", Arrays.asList("PUFFERFISH_BUCKET", "LAPIS_BLOCK")),
GUI_ICON_EFFECT_SMOKE("gui-icon.effect.smoke", Collections.singletonList("TORCH")),
GUI_ICON_EFFECT_SNEEZE("gui-icon.effect.sneeze", Collections.singletonList("BAMBOO")),
GUI_ICON_EFFECT_SPELL("gui-icon.effect.spell", Arrays.asList("POTION", "GLASS_BOTTLE")),
GUI_ICON_EFFECT_SPIT("gui-icon.effect.spit", Arrays.asList("LLAMA_SPAWN_EGG", "PUMPKIN_SEEDS")),
GUI_ICON_EFFECT_SPLASH("gui-icon.effect.splash", Arrays.asList("SALMON", "FISH", "RAW_FISH")),
GUI_ICON_EFFECT_SQUID_INK("gui-icon.effect.squid_ink", Collections.singletonList("INK_SAC")),
GUI_ICON_EFFECT_SWEEP_ATTACK("gui-icon.effect.sweep_attack", Arrays.asList("GOLDEN_SWORD", "GOLD_SWORD")),
GUI_ICON_EFFECT_TOTEM_OF_UNDYING("gui-icon.effect.totem_of_undying", Arrays.asList("TOTEM_OF_UNDYING", "TOTEM")),
GUI_ICON_EFFECT_UNDERWATER("gui-icon.effect.underwater", Arrays.asList("TURTLE_HELMET", "SPONGE")),
GUI_ICON_EFFECT_WITCH("gui-icon.effect.witch", Collections.singletonList("CAULDRON")),
GUI_ICON_STYLE("gui-icon.style", null),
GUI_ICON_STYLE_ARROWS("gui-icon.style.arrows", Collections.singletonList("BOW")),
GUI_ICON_STYLE_BATMAN("gui-icon.style.batman", Arrays.asList("BAT_SPAWN_EGG", "COAL")),
GUI_ICON_STYLE_BEAM("gui-icon.style.beam", Collections.singletonList("POWERED_RAIL")),
GUI_ICON_STYLE_BLOCKBREAK("gui-icon.style.blockbreak", Collections.singletonList("IRON_PICKAXE")),
GUI_ICON_STYLE_BLOCKPLACE("gui-icon.style.blockplace", Arrays.asList("OAK_PLANKS", "WOOD")),
GUI_ICON_STYLE_CELEBRATION("gui-icon.style.celebration", Arrays.asList("FIREWORK_ROCKET", "FIREWORK")),
GUI_ICON_STYLE_CHAINS("gui-icon.style.chains", Collections.singletonList("TRIPWIRE_HOOK")),
GUI_ICON_STYLE_COMPANION("gui-icon.style.companion", Collections.singletonList("NAME_TAG")),
GUI_ICON_STYLE_CUBE("gui-icon.style.cube", Collections.singletonList("STONE")),
GUI_ICON_STYLE_FEET("gui-icon.style.feet", Collections.singletonList("GRASS")),
GUI_ICON_STYLE_HALO("gui-icon.style.halo", Arrays.asList("END_PORTAL_FRAME", "ENDER_PORTAL_FRAME")),
GUI_ICON_STYLE_HURT("gui-icon.style.hurt", Collections.singletonList("CACTUS")),
GUI_ICON_STYLE_INVOCATION("gui-icon.style.invocation", Arrays.asList("ENDER_EYE", "EYE_OF_ENDER")),
GUI_ICON_STYLE_MOVE("gui-icon.style.move", Arrays.asList("PISTON", "PISTON_BASE")),
GUI_ICON_STYLE_NORMAL("gui-icon.style.normal", Collections.singletonList("DIRT")),
GUI_ICON_STYLE_ORBIT("gui-icon.style.orbit", Arrays.asList("ENCHANTING_TABLE", "ENCHANTMENT_TABLE")),
GUI_ICON_STYLE_OVERHEAD("gui-icon.style.overhead", Collections.singletonList("GLOWSTONE")),
GUI_ICON_STYLE_POINT("gui-icon.style.point", Collections.singletonList("STONE_BUTTON")),
GUI_ICON_STYLE_POPPER("gui-icon.style.popper", Arrays.asList("POPPED_CHORUS_FRUIT", "CHORUS_FRUIT_POPPED")),
GUI_ICON_STYLE_PULSE("gui-icon.style.pulse", Arrays.asList("REDSTONE_TORCH", "REDSTONE_TORCH_ON")),
GUI_ICON_STYLE_QUADHELIX("gui-icon.style.quadhelix", Arrays.asList("NAUTILUS_SHELL", "ACTIVATOR_RAIL")),
GUI_ICON_STYLE_RINGS("gui-icon.style.rings", Arrays.asList("LEAD", "LEASH")),
GUI_ICON_STYLE_SPHERE("gui-icon.style.sphere", Arrays.asList("HEART_OF_THE_SEA", "SNOWBALL", "SNOW_BALL")),
GUI_ICON_STYLE_SPIN("gui-icon.style.spin", Collections.singletonList("BEACON")),
GUI_ICON_STYLE_SPIRAL("gui-icon.style.spiral", Collections.singletonList("HOPPER")),
GUI_ICON_STYLE_SWORDS("gui-icon.style.swords", Collections.singletonList("IRON_SWORD")),
GUI_ICON_STYLE_THICK("gui-icon.style.thick", Arrays.asList("COBWEB", "WEB")),
GUI_ICON_STYLE_TRAIL("gui-icon.style.trail", Collections.singletonList("GHAST_TEAR")),
GUI_ICON_STYLE_TWINS("gui-icon.style.twins", Arrays.asList("OAK_FENCE", "FENCE")),
GUI_ICON_STYLE_VORTEX("gui-icon.style.vortex", Collections.singletonList("GLOWSTONE_DUST")),
GUI_ICON_STYLE_WHIRL("gui-icon.style.whirl", Collections.singletonList("FEATHER")),
GUI_ICON_STYLE_WHIRLWIND("gui-icon.style.whirlwind", Collections.singletonList("STRING")),
GUI_ICON_STYLE_WINGS("gui-icon.style.wings", Collections.singletonList("ELYTRA"));
private final String key; private final String key;
private final Object defaultValue; private final Object defaultValue;
@ -245,7 +159,7 @@ public class ConfigurationManager extends Manager {
*/ */
public String getString() { public String getString() {
this.loadValue(); this.loadValue();
return (String) this.value; return String.valueOf(this.value);
} }
private double getNumber() { private double getNumber() {
@ -386,10 +300,7 @@ public class ConfigurationManager extends Manager {
EDIT_EFFECT, EDIT_EFFECT,
EDIT_STYLE, EDIT_STYLE,
EDIT_DATA, EDIT_DATA,
RESET, RESET;
EFFECT,
STYLE;
private Map<String, Material> materials; private Map<String, Material> materials;
@ -407,17 +318,6 @@ public class ConfigurationManager extends Manager {
return this.getInternal("gui-icon.misc." + this.name().toLowerCase()); return this.getInternal("gui-icon.misc." + this.name().toLowerCase());
} }
/**
* Gets the Material for a subsection of this icon in the config.yml
* Tries to get from cache first, otherwise loads it
*
* @param subsection The name of the icon in the section
* @return The Material for this Icon
*/
public Material get(String subsection) {
return this.getInternal("gui-icon." + this.name().toLowerCase() + "." + subsection);
}
/** /**
* Gets the Material for this icon * Gets the Material for this icon
* Tries to get from cache first, otherwise loads it * Tries to get from cache first, otherwise loads it
@ -441,7 +341,7 @@ public class ConfigurationManager extends Manager {
} }
if (material == null) if (material == null)
material = Material.BARRIER; material = ParticleUtils.FALLBACK_MATERIAL;
this.materials.put(configPath, material); this.materials.put(configPath, material);

View file

@ -1,23 +1,22 @@
package dev.esophose.playerparticles.manager; package dev.esophose.playerparticles.manager;
import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.database.DatabaseConnector; import dev.esophose.playerparticles.database.DatabaseConnector;
import dev.esophose.playerparticles.database.MySQLConnector; import dev.esophose.playerparticles.database.MySQLConnector;
import dev.esophose.playerparticles.database.SQLiteConnector; import dev.esophose.playerparticles.database.SQLiteConnector;
import dev.esophose.playerparticles.manager.ConfigurationManager.Setting;
import dev.esophose.playerparticles.particles.ConsolePPlayer; import dev.esophose.playerparticles.particles.ConsolePPlayer;
import dev.esophose.playerparticles.particles.FixedParticleEffect; import dev.esophose.playerparticles.particles.FixedParticleEffect;
import dev.esophose.playerparticles.particles.PPlayer; import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.particles.ParticleEffect; import dev.esophose.playerparticles.particles.ParticleEffect;
import dev.esophose.playerparticles.particles.ParticleGroup; import dev.esophose.playerparticles.particles.ParticleGroup;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.manager.ConfigurationManager.Setting; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.particles.color.NoteColor;
import dev.esophose.playerparticles.particles.color.OrdinaryColor;
import dev.esophose.playerparticles.styles.ParticleStyle; import dev.esophose.playerparticles.styles.ParticleStyle;
import dev.esophose.playerparticles.util.ParticleUtils; import dev.esophose.playerparticles.util.ParticleUtils;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -27,6 +26,7 @@ import java.util.function.Consumer;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.World; import org.bukkit.World;
/** /**
@ -81,13 +81,10 @@ public class DataManager extends Manager {
* @return The PPlayer from cache * @return The PPlayer from cache
*/ */
public PPlayer getPPlayer(UUID playerUUID) { public PPlayer getPPlayer(UUID playerUUID) {
Collection<PPlayer> pplayers; for (PPlayer pp : this.playerParticles.getManager(ParticleManager.class).getPPlayers())
synchronized (pplayers = this.playerParticles.getManager(ParticleManager.class).getPPlayers()) { // Under rare circumstances, the PPlayers list can be changed while it's looping if (pp.getUniqueId().equals(playerUUID))
for (PPlayer pp : pplayers) return pp;
if (pp.getUniqueId().equals(playerUUID)) return null;
return pp;
return null;
}
} }
/** /**
@ -253,12 +250,8 @@ public class DataManager extends Manager {
} }
this.sync(() -> { this.sync(() -> {
synchronized (loadedPPlayer) { this.playerParticles.getManager(ParticleManager.class).addPPlayer(loadedPPlayer);
if (this.getPPlayer(playerUUID) == null) { // Make sure the PPlayer still isn't added, since this is async it's possible it got ran twice callback.accept(loadedPPlayer);
this.playerParticles.getManager(ParticleManager.class).addPPlayer(loadedPPlayer); // This will be fine now since loadedPPlayer is synchronized
callback.accept(loadedPPlayer);
}
}
}); });
}); });
}); });
@ -312,6 +305,7 @@ public class DataManager extends Manager {
this.async(() -> this.databaseConnector.connect((connection) -> { this.async(() -> this.databaseConnector.connect((connection) -> {
String groupUUID; String groupUUID;
boolean existingGroup;
String groupUUIDQuery = "SELECT uuid FROM " + this.getTablePrefix() + "group WHERE owner_uuid = ? AND name = ?"; String groupUUIDQuery = "SELECT uuid FROM " + this.getTablePrefix() + "group WHERE owner_uuid = ? AND name = ?";
try (PreparedStatement statement = connection.prepareStatement(groupUUIDQuery)) { try (PreparedStatement statement = connection.prepareStatement(groupUUIDQuery)) {
@ -321,21 +315,25 @@ public class DataManager extends Manager {
ResultSet result = statement.executeQuery(); ResultSet result = statement.executeQuery();
if (result.next()) { // Clear out particles from existing group if (result.next()) { // Clear out particles from existing group
groupUUID = result.getString("uuid"); groupUUID = result.getString("uuid");
existingGroup = true;
String particlesDeleteQuery = "DELETE FROM " + this.getTablePrefix() + "particle WHERE group_uuid = ?";
PreparedStatement particlesDeleteStatement = connection.prepareStatement(particlesDeleteQuery);
particlesDeleteStatement.setString(1, result.getString("uuid"));
particlesDeleteStatement.executeUpdate();
} else { // Create new group } else { // Create new group
groupUUID = UUID.randomUUID().toString(); groupUUID = UUID.randomUUID().toString();
existingGroup = false;
}
}
String groupCreateQuery = "INSERT INTO " + this.getTablePrefix() + "group (uuid, owner_uuid, name) VALUES (?, ?, ?)"; if (existingGroup) {
PreparedStatement groupCreateStatement = connection.prepareStatement(groupCreateQuery); String particlesDeleteQuery = "DELETE FROM " + this.getTablePrefix() + "particle WHERE group_uuid = ?";
try (PreparedStatement particlesDeleteStatement = connection.prepareStatement(particlesDeleteQuery)) {
particlesDeleteStatement.setString(1, groupUUID);
particlesDeleteStatement.executeUpdate();
}
} else {
String groupCreateQuery = "INSERT INTO " + this.getTablePrefix() + "group (uuid, owner_uuid, name) VALUES (?, ?, ?)";
try (PreparedStatement groupCreateStatement = connection.prepareStatement(groupCreateQuery)) {
groupCreateStatement.setString(1, groupUUID); groupCreateStatement.setString(1, groupUUID);
groupCreateStatement.setString(2, playerUUID.toString()); groupCreateStatement.setString(2, playerUUID.toString());
groupCreateStatement.setString(3, group.getName()); groupCreateStatement.setString(3, group.getName());
groupCreateStatement.executeUpdate(); groupCreateStatement.executeUpdate();
} }
} }
@ -403,6 +401,27 @@ public class DataManager extends Manager {
})); }));
} }
/**
* Attempts to reset the active particle group for the given player name.
* This works even if the player is offline.
*
* @param playerName The name of the player to reset the active particle group for
* @param callback The callback to execute when finished, true for successful, otherwise false
*/
public void resetActiveParticleGroup(String playerName, Consumer<Boolean> callback) {
this.async(() -> this.databaseConnector.connect((connection) -> {
@SuppressWarnings("deprecation")
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerName);
String query = "DELETE FROM " + this.getTablePrefix() + "particle WHERE group_uuid IN (SELECT uuid FROM " + this.getTablePrefix() + "group WHERE owner_uuid = ? AND name = ?)";
try (PreparedStatement statement = connection.prepareStatement(query)) {
statement.setString(1, offlinePlayer.getUniqueId().toString());
statement.setString(2, ParticleGroup.DEFAULT_NAME);
callback.accept(statement.executeUpdate() > 0);
}
}));
}
/** /**
* Saves a fixed effect to save data * Saves a fixed effect to save data
* Does not perform a check to see if a fixed effect with this id already exists * Does not perform a check to see if a fixed effect with this id already exists
@ -554,7 +573,11 @@ public class DataManager extends Manager {
* @return the prefix to be used by all table names * @return the prefix to be used by all table names
*/ */
public String getTablePrefix() { public String getTablePrefix() {
return this.playerParticles.getDescription().getName().toLowerCase() + '_'; if (this.databaseConnector instanceof MySQLConnector) {
return Setting.MYSQL_TABLE_PREFIX.getString();
} else {
return this.playerParticles.getDescription().getName().toLowerCase() + '_';
}
} }
} }

View file

@ -7,6 +7,7 @@ import dev.esophose.playerparticles.gui.GuiInventoryDefault;
import dev.esophose.playerparticles.gui.GuiInventoryLoadPresetGroups; import dev.esophose.playerparticles.gui.GuiInventoryLoadPresetGroups;
import dev.esophose.playerparticles.manager.ConfigurationManager.Setting; import dev.esophose.playerparticles.manager.ConfigurationManager.Setting;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -25,7 +26,7 @@ public class GuiManager extends Manager implements Listener, Runnable {
public GuiManager(PlayerParticles playerParticles) { public GuiManager(PlayerParticles playerParticles) {
super(playerParticles); super(playerParticles);
this.guiInventories = new ArrayList<>(); this.guiInventories = Collections.synchronizedList(new ArrayList<>());
this.guiTask = null; this.guiTask = null;
Bukkit.getPluginManager().registerEvents(this, this.playerParticles); Bukkit.getPluginManager().registerEvents(this, this.playerParticles);
@ -108,15 +109,17 @@ public class GuiManager extends Manager implements Listener, Runnable {
* @param pplayer The PPlayer to open the GUI screen for * @param pplayer The PPlayer to open the GUI screen for
*/ */
public void openDefault(PPlayer pplayer) { public void openDefault(PPlayer pplayer) {
GuiInventory inventoryToOpen; Bukkit.getScheduler().runTask(this.playerParticles, () -> {
if (!Setting.GUI_PRESETS_ONLY.getBoolean()) { GuiInventory inventoryToOpen;
inventoryToOpen = new GuiInventoryDefault(pplayer); if (!Setting.GUI_PRESETS_ONLY.getBoolean()) {
} else { inventoryToOpen = new GuiInventoryDefault(pplayer);
inventoryToOpen = new GuiInventoryLoadPresetGroups(pplayer, true); } else {
} inventoryToOpen = new GuiInventoryLoadPresetGroups(pplayer, true);
}
this.guiInventories.add(inventoryToOpen); pplayer.getPlayer().openInventory(inventoryToOpen.getInventory());
Bukkit.getScheduler().runTask(this.playerParticles, () -> pplayer.getPlayer().openInventory(inventoryToOpen.getInventory())); this.guiInventories.add(inventoryToOpen);
});
} }
/** /**
@ -125,8 +128,10 @@ public class GuiManager extends Manager implements Listener, Runnable {
* @param nextInventory The GuiInventory to transition to * @param nextInventory The GuiInventory to transition to
*/ */
public void transition(GuiInventory nextInventory) { public void transition(GuiInventory nextInventory) {
this.guiInventories.add(nextInventory); Bukkit.getScheduler().runTask(this.playerParticles, () -> {
Bukkit.getScheduler().runTask(this.playerParticles, () -> nextInventory.getPPlayer().getPlayer().openInventory(nextInventory.getInventory())); nextInventory.getPPlayer().getPlayer().openInventory(nextInventory.getInventory());
this.guiInventories.add(nextInventory);
});
} }
/** /**
@ -142,13 +147,4 @@ public class GuiManager extends Manager implements Listener, Runnable {
.orElse(null); .orElse(null);
} }
/**
* Removes a GuiInventory from guiInventories by a PPlayer
*
* @param pplayer The PPlayer who owns the GuiInventory
*/
private void removeGuiInventory(PPlayer pplayer) {
this.guiInventories.removeIf(x -> x.getPPlayer().getUniqueId().equals(pplayer.getUniqueId()));
}
} }

View file

@ -124,6 +124,9 @@ public class LocaleManager extends Manager {
* @param stringPlaceholders The placeholders to apply * @param stringPlaceholders The placeholders to apply
*/ */
public void sendMessage(CommandSender sender, String messageKey, StringPlaceholders stringPlaceholders) { public void sendMessage(CommandSender sender, String messageKey, StringPlaceholders stringPlaceholders) {
if (!Setting.MESSAGES_ENABLED.getBoolean())
return;
sender.sendMessage(this.getLocaleMessage("prefix") + this.getLocaleMessage(messageKey, stringPlaceholders)); sender.sendMessage(this.getLocaleMessage("prefix") + this.getLocaleMessage(messageKey, stringPlaceholders));
} }
@ -135,6 +138,9 @@ public class LocaleManager extends Manager {
* @param stringPlaceholders The placeholders to apply * @param stringPlaceholders The placeholders to apply
*/ */
public void sendMessage(PPlayer pplayer, String messageKey, StringPlaceholders stringPlaceholders) { public void sendMessage(PPlayer pplayer, String messageKey, StringPlaceholders stringPlaceholders) {
if (!Setting.MESSAGES_ENABLED.getBoolean())
return;
pplayer.getUnderlyingExecutor().sendMessage(this.parsePlaceholders(pplayer.getPlayer(), this.getLocaleMessage("prefix") + this.getLocaleMessage(messageKey, stringPlaceholders))); pplayer.getUnderlyingExecutor().sendMessage(this.parsePlaceholders(pplayer.getPlayer(), this.getLocaleMessage("prefix") + this.getLocaleMessage(messageKey, stringPlaceholders)));
} }
@ -145,6 +151,9 @@ public class LocaleManager extends Manager {
* @param messageKey The message key of the Locale to send * @param messageKey The message key of the Locale to send
*/ */
public void sendMessage(CommandSender sender, String messageKey) { public void sendMessage(CommandSender sender, String messageKey) {
if (!Setting.MESSAGES_ENABLED.getBoolean())
return;
this.sendMessage(sender, messageKey, StringPlaceholders.empty()); this.sendMessage(sender, messageKey, StringPlaceholders.empty());
} }
@ -155,6 +164,9 @@ public class LocaleManager extends Manager {
* @param messageKey The message key of the Locale to send * @param messageKey The message key of the Locale to send
*/ */
public void sendMessage(PPlayer pplayer, String messageKey) { public void sendMessage(PPlayer pplayer, String messageKey) {
if (!Setting.MESSAGES_ENABLED.getBoolean())
return;
this.sendMessage(pplayer, messageKey, StringPlaceholders.empty()); this.sendMessage(pplayer, messageKey, StringPlaceholders.empty());
} }
@ -166,6 +178,9 @@ public class LocaleManager extends Manager {
* @param stringPlaceholders The placeholders to apply * @param stringPlaceholders The placeholders to apply
*/ */
public void sendSimpleMessage(CommandSender sender, String messageKey, StringPlaceholders stringPlaceholders) { public void sendSimpleMessage(CommandSender sender, String messageKey, StringPlaceholders stringPlaceholders) {
if (!Setting.MESSAGES_ENABLED.getBoolean())
return;
sender.sendMessage(this.getLocaleMessage(messageKey, stringPlaceholders)); sender.sendMessage(this.getLocaleMessage(messageKey, stringPlaceholders));
} }
@ -177,6 +192,9 @@ public class LocaleManager extends Manager {
* @param stringPlaceholders The placeholders to apply * @param stringPlaceholders The placeholders to apply
*/ */
public void sendSimpleMessage(PPlayer pplayer, String messageKey, StringPlaceholders stringPlaceholders) { public void sendSimpleMessage(PPlayer pplayer, String messageKey, StringPlaceholders stringPlaceholders) {
if (!Setting.MESSAGES_ENABLED.getBoolean())
return;
pplayer.getUnderlyingExecutor().sendMessage(this.parsePlaceholders(pplayer.getPlayer(), this.getLocaleMessage(messageKey, stringPlaceholders))); pplayer.getUnderlyingExecutor().sendMessage(this.parsePlaceholders(pplayer.getPlayer(), this.getLocaleMessage(messageKey, stringPlaceholders)));
} }
@ -187,6 +205,9 @@ public class LocaleManager extends Manager {
* @param messageKey The message key of the Locale to send * @param messageKey The message key of the Locale to send
*/ */
public void sendSimpleMessage(CommandSender sender, String messageKey) { public void sendSimpleMessage(CommandSender sender, String messageKey) {
if (!Setting.MESSAGES_ENABLED.getBoolean())
return;
this.sendMessage(sender, messageKey, StringPlaceholders.empty()); this.sendMessage(sender, messageKey, StringPlaceholders.empty());
} }
@ -197,6 +218,9 @@ public class LocaleManager extends Manager {
* @param messageKey The message key of the Locale to send * @param messageKey The message key of the Locale to send
*/ */
public void sendSimpleMessage(PPlayer pplayer, String messageKey) { public void sendSimpleMessage(PPlayer pplayer, String messageKey) {
if (!Setting.MESSAGES_ENABLED.getBoolean())
return;
this.sendMessage(pplayer, messageKey, StringPlaceholders.empty()); this.sendMessage(pplayer, messageKey, StringPlaceholders.empty());
} }
@ -207,6 +231,9 @@ public class LocaleManager extends Manager {
* @param message The message to send * @param message The message to send
*/ */
public void sendCustomMessage(CommandSender sender, String message) { public void sendCustomMessage(CommandSender sender, String message) {
if (!Setting.MESSAGES_ENABLED.getBoolean())
return;
sender.sendMessage(message); sender.sendMessage(message);
} }
@ -217,6 +244,9 @@ public class LocaleManager extends Manager {
* @param message The message to send * @param message The message to send
*/ */
public void sendCustomMessage(PPlayer pplayer, String message) { public void sendCustomMessage(PPlayer pplayer, String message) {
if (!Setting.MESSAGES_ENABLED.getBoolean())
return;
this.sendCustomMessage(pplayer.getUnderlyingExecutor(), this.parsePlaceholders(pplayer.getPlayer(), message)); this.sendCustomMessage(pplayer.getUnderlyingExecutor(), this.parsePlaceholders(pplayer.getPlayer(), message));
} }

View file

@ -7,8 +7,8 @@ import dev.esophose.playerparticles.particles.ParticleGroupPreset;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.particles.ParticleProperty; import dev.esophose.playerparticles.particles.ParticleProperty;
import dev.esophose.playerparticles.particles.color.NoteColor; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.particles.color.OrdinaryColor; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.styles.ParticleStyle; import dev.esophose.playerparticles.styles.ParticleStyle;
import dev.esophose.playerparticles.util.inputparser.InputParser; import dev.esophose.playerparticles.util.inputparser.InputParser;
import java.io.File; import java.io.File;

View file

@ -1,16 +1,17 @@
package dev.esophose.playerparticles.manager; package dev.esophose.playerparticles.manager;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.hook.WorldGuardHook;
import dev.esophose.playerparticles.manager.ConfigurationManager.Setting; import dev.esophose.playerparticles.manager.ConfigurationManager.Setting;
import dev.esophose.playerparticles.nms.wrapper.ParticleHandler; import dev.esophose.playerparticles.nms.wrapper.ParticleHandler;
import dev.esophose.playerparticles.particles.ConsolePPlayer; import dev.esophose.playerparticles.particles.ConsolePPlayer;
import dev.esophose.playerparticles.particles.FixedParticleEffect; import dev.esophose.playerparticles.particles.FixedParticleEffect;
import dev.esophose.playerparticles.particles.ParticleEffectSettings; import dev.esophose.playerparticles.particles.ParticleEffectSettings;
import dev.esophose.playerparticles.particles.color.NoteColor; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.particles.color.OrdinaryColor; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.particles.PParticle; import dev.esophose.playerparticles.particles.PParticle;
import dev.esophose.playerparticles.particles.PPlayer; import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.particles.color.ParticleColor; import dev.esophose.playerparticles.particles.data.ParticleColor;
import dev.esophose.playerparticles.particles.ParticleEffect; import dev.esophose.playerparticles.particles.ParticleEffect;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.particles.ParticleProperty; import dev.esophose.playerparticles.particles.ParticleProperty;
@ -58,6 +59,11 @@ public class ParticleManager extends Manager implements Listener, Runnable {
*/ */
private BukkitTask particleTask; private BukkitTask particleTask;
/**
* The task that checks player worldguard region statuses
*/
private BukkitTask worldGuardTask;
private ParticleHandler particleHandler; private ParticleHandler particleHandler;
private Map<ParticleEffect, ParticleEffectSettings> supportedParticleEffects; private Map<ParticleEffect, ParticleEffectSettings> supportedParticleEffects;
@ -85,6 +91,11 @@ public class ParticleManager extends Manager implements Listener, Runnable {
if (this.particleTask != null) if (this.particleTask != null)
this.particleTask.cancel(); this.particleTask.cancel();
if (this.worldGuardTask != null) {
this.worldGuardTask.cancel();
this.worldGuardTask = null;
}
int overrideVersion = Setting.OVERRIDE_PARTICLE_VERSION.getInt(); int overrideVersion = Setting.OVERRIDE_PARTICLE_VERSION.getInt();
VersionMapping versionMapping = VersionMapping.getVersionMapping(overrideVersion != -1 ? overrideVersion : NMSUtil.getVersionNumber()); VersionMapping versionMapping = VersionMapping.getVersionMapping(overrideVersion != -1 ? overrideVersion : NMSUtil.getVersionNumber());
this.particleHandler = NMSUtil.getHandler(versionMapping); this.particleHandler = NMSUtil.getHandler(versionMapping);
@ -95,8 +106,13 @@ public class ParticleManager extends Manager implements Listener, Runnable {
Bukkit.getScheduler().runTaskLater(this.playerParticles, () -> { Bukkit.getScheduler().runTaskLater(this.playerParticles, () -> {
long ticks = Setting.TICKS_PER_PARTICLE.getLong(); long ticks = Setting.TICKS_PER_PARTICLE.getLong();
this.particleTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this.playerParticles, this, 5, ticks); this.particleTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this.playerParticles, this, 0, ticks);
}, 1);
if (WorldGuardHook.enabled()) {
long worldGuardTicks = Setting.WORLDGUARD_CHECK_INTERVAL.getLong();
this.worldGuardTask = Bukkit.getScheduler().runTaskTimer(this.playerParticles, this::updateWorldGuardStatuses, 0, worldGuardTicks);
}
}, 5);
this.particlePlayers.clear(); this.particlePlayers.clear();
DataManager dataManager = this.playerParticles.getManager(DataManager.class); DataManager dataManager = this.playerParticles.getManager(DataManager.class);
@ -179,7 +195,7 @@ public class ParticleManager extends Manager implements Listener, Runnable {
// Don't show their particles if they are in spectator mode // Don't show their particles if they are in spectator mode
// Don't spawn particles if the world doesn't allow it // Don't spawn particles if the world doesn't allow it
if (player != null && player.getGameMode() != GameMode.SPECTATOR && permissionManager.isWorldEnabled(player.getWorld().getName())) if (player != null && (NMSUtil.getVersionNumber() < 8 || player.getGameMode() != GameMode.SPECTATOR) && permissionManager.isWorldEnabled(player.getWorld().getName()))
for (ParticlePair particles : pplayer.getActiveParticles()) for (ParticlePair particles : pplayer.getActiveParticles())
this.displayParticles(pplayer, particles, player.getLocation().clone().add(0, 1, 0)); this.displayParticles(pplayer, particles, player.getLocation().clone().add(0, 1, 0));
@ -191,6 +207,25 @@ public class ParticleManager extends Manager implements Listener, Runnable {
} }
} }
/**
* Updates the WorldGuard region statuses for players
*/
private void updateWorldGuardStatuses() {
PermissionManager permissionManager = this.playerParticles.getManager(PermissionManager.class);
for (PPlayer pplayer : this.particlePlayers.values()) {
Player player = pplayer.getPlayer();
if (player == null)
continue;
boolean inAllowedRegion = WorldGuardHook.isInAllowedRegion(player.getLocation());
if (!inAllowedRegion && Setting.WORLDGUARD_ENABLE_BYPASS_PERMISSION.getBoolean())
inAllowedRegion = permissionManager.hasWorldGuardBypass(player);
pplayer.setInAllowedRegion(inAllowedRegion);
}
}
/** /**
* Displays particles at the given player location with their settings * Displays particles at the given player location with their settings
* *
@ -200,17 +235,36 @@ public class ParticleManager extends Manager implements Listener, Runnable {
*/ */
private void displayParticles(PPlayer pplayer, ParticlePair particle, Location location) { private void displayParticles(PPlayer pplayer, ParticlePair particle, Location location) {
if (!this.playerParticles.getManager(ParticleStyleManager.class).isEventHandled(particle.getStyle())) { if (!this.playerParticles.getManager(ParticleStyleManager.class).isEventHandled(particle.getStyle())) {
if (Setting.TOGGLE_ON_COMBAT.getBoolean() && pplayer.isInCombat()) if (Setting.TOGGLE_ON_COMBAT.getBoolean() && particle.getStyle().canToggleWithCombat() && pplayer.isInCombat())
return; return;
List<PParticle> particles; if (!pplayer.isInAllowedRegion())
if (Setting.TOGGLE_ON_MOVE.getBoolean() && particle.getStyle().canToggleWithMovement() && pplayer.isMoving()) { return;
particles = DefaultStyles.FEET.getParticles(particle, location);
} else { if (particle.getStyle().canToggleWithMovement() && pplayer.isMoving()) {
particles = particle.getStyle().getParticles(particle, location); switch (Setting.TOGGLE_ON_MOVE.getString().toUpperCase()) {
case "DISPLAY_FEET":
case "TRUE": // Old default value, keep here for legacy config compatibility
for (PParticle pparticle : DefaultStyles.FEET.getParticles(particle, location))
this.displayParticles(particle, pparticle, particle.getStyle().hasLongRangeVisibility(), pplayer.getPlayer());
return;
case "DISPLAY_NORMAL":
for (PParticle pparticle : DefaultStyles.NORMAL.getParticles(particle, location))
this.displayParticles(particle, pparticle, particle.getStyle().hasLongRangeVisibility(), pplayer.getPlayer());
return;
case "DISPLAY_OVERHEAD":
for (PParticle pparticle : DefaultStyles.OVERHEAD.getParticles(particle, location))
this.displayParticles(particle, pparticle, particle.getStyle().hasLongRangeVisibility(), pplayer.getPlayer());
return;
case "NONE":
case "FALSE": // Old default value, keep here for legacy config compatibility
break;
default:
return;
}
} }
for (PParticle pparticle : particles) for (PParticle pparticle : particle.getStyle().getParticles(particle, location))
this.displayParticles(particle, pparticle, particle.getStyle().hasLongRangeVisibility(), pplayer.getPlayer()); this.displayParticles(particle, pparticle, particle.getStyle().hasLongRangeVisibility(), pplayer.getPlayer());
} }
} }
@ -218,19 +272,27 @@ public class ParticleManager extends Manager implements Listener, Runnable {
/** /**
* An alternative method used for event styles * An alternative method used for event styles
* *
* @param source The player the particles are spawning from, nullable for special cases * @param pplayer The PPlayer the particles are spawning from, nullable for special cases
* @param world The world the particles are spawning in * @param world The world the particles are spawning in
* @param particle The ParticlePair to use for getting particle settings * @param particle The ParticlePair to use for getting particle settings
* @param particles The particles to display * @param particles The particles to display
* @param isLongRange If the particle can be viewed from long range * @param isLongRange If the particle can be viewed from long range
*/ */
public void displayParticles(Player source, World world, ParticlePair particle, List<PParticle> particles, boolean isLongRange) { public void displayParticles(PPlayer pplayer, World world, ParticlePair particle, List<PParticle> particles, boolean isLongRange) {
PermissionManager permissionManager = this.playerParticles.getManager(PermissionManager.class); PermissionManager permissionManager = this.playerParticles.getManager(PermissionManager.class);
if ((source != null && source.getGameMode() == GameMode.SPECTATOR) || !permissionManager.isWorldEnabled(world.getName()))
Player player = null;
if (pplayer != null) {
if (!pplayer.isInAllowedRegion())
return;
player = pplayer.getPlayer();
}
if ((player != null && (NMSUtil.getVersionNumber() < 8 || player.getGameMode() == GameMode.SPECTATOR)) || !permissionManager.isWorldEnabled(world.getName()))
return; return;
for (PParticle pparticle : particles) for (PParticle pparticle : particles)
this.displayParticles(particle, pparticle, isLongRange, source); this.displayParticles(particle, pparticle, isLongRange, player);
} }
/** /**

View file

@ -1,11 +1,15 @@
package dev.esophose.playerparticles.manager; package dev.esophose.playerparticles.manager;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.event.ParticleStyleRegistrationEvent;
import dev.esophose.playerparticles.styles.DefaultStyles; import dev.esophose.playerparticles.styles.DefaultStyles;
import dev.esophose.playerparticles.styles.ParticleStyle; import dev.esophose.playerparticles.styles.ParticleStyle;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.bukkit.Bukkit;
public class ParticleStyleManager extends Manager { public class ParticleStyleManager extends Manager {
@ -20,12 +24,49 @@ public class ParticleStyleManager extends Manager {
this.styles = new ArrayList<>(); this.styles = new ArrayList<>();
this.eventStyles = new ArrayList<>(); this.eventStyles = new ArrayList<>();
DefaultStyles.registerStyles(this);
DefaultStyles.initStyles();
} }
@Override @Override
public void reload() { public void reload() {
// Styles List is never reset so you don't need to re-register styles each time the plugin reloads this.styles.clear();
this.eventStyles.clear();
// Call registration event
// We use this event internally, so no other action needs to be done for us to register the default styles
ParticleStyleRegistrationEvent event = new ParticleStyleRegistrationEvent();
Bukkit.getPluginManager().callEvent(event);
Collection<ParticleStyle> eventStyles = event.getRegisteredEventStyles().values();
List<ParticleStyle> styles = new ArrayList<>(event.getRegisteredStyles().values());
styles.addAll(eventStyles);
styles.sort(Comparator.comparing(ParticleStyle::getName));
for (ParticleStyle style : styles) {
try {
if (style == null)
throw new IllegalArgumentException("Tried to register a null style");
if (style.getInternalName() == null || style.getInternalName().trim().isEmpty())
throw new IllegalArgumentException("Tried to register a style with a null or empty name: '" + style.getInternalName() + "'");
for (ParticleStyle testAgainst : this.styles) {
if (testAgainst.equals(style)) {
throw new IllegalArgumentException("Tried to register the same style twice: '" + style.getInternalName() + "'");
} else if (testAgainst.getInternalName().equalsIgnoreCase(style.getInternalName())) {
throw new IllegalArgumentException("Tried to register two styles with the same internal name spelling: '" + style.getInternalName() + "'");
}
}
this.styles.add(style);
if (eventStyles.contains(style))
this.eventStyles.add(style);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
}
} }
@Override @Override
@ -33,41 +74,6 @@ public class ParticleStyleManager extends Manager {
} }
/**
* Registers a style that is put into the plugin's update loop
*
* @param style The style to add
*/
public void registerStyle(ParticleStyle style) {
if (style == null) {
throw new IllegalArgumentException("Tried to register a null style");
}
if (style.getInternalName() == null || style.getInternalName().trim().equals("")) {
throw new IllegalArgumentException("Tried to register a style with a null or empty name: '" + style.getInternalName() + "'");
}
for (ParticleStyle testAgainst : this.styles) {
if (testAgainst.equals(style)) {
throw new IllegalArgumentException("Tried to register the same style twice: '" + style.getInternalName() + "'");
} else if (testAgainst.getInternalName().equalsIgnoreCase(style.getInternalName())) {
throw new IllegalArgumentException("Tried to register two styles with the same internal name spelling: '" + style.getInternalName() + "'");
}
}
this.styles.add(style);
}
/**
* Registers a style that isn't updated on the normal update loop
*
* @param style The style to register
*/
public void registerEventStyle(ParticleStyle style) {
this.registerStyle(style);
this.eventStyles.add(style);
}
/** /**
* Returns if a given style is customly handled * Returns if a given style is customly handled
* *

View file

@ -18,6 +18,7 @@ import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import org.bukkit.permissions.Permission; import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
public class PermissionManager extends Manager { public class PermissionManager extends Manager {
@ -29,17 +30,24 @@ public class PermissionManager extends Manager {
STYLE("style"), STYLE("style"),
FIXED("fixed"), FIXED("fixed"),
FIXED_MAX("fixed.max"),
FIXED_UNLIMITED("fixed.unlimited"), FIXED_UNLIMITED("fixed.unlimited"),
FIXED_CLEAR("fixed.clear"), FIXED_CLEAR("fixed.clear"),
FIXED_TELEPORT("fixed.teleport"), FIXED_TELEPORT("fixed.teleport"),
RELOAD("reload"), RELOAD("reload"),
OVERRIDE("override"), OVERRIDE("override"),
RESET_OTHERS("reset.others"),
GUI("gui"), GUI("gui"),
PARTICLES_MAX("particles.max"),
PARTICLES_UNLIMITED("particles.unlimited"), PARTICLES_UNLIMITED("particles.unlimited"),
GROUPS_UNLIMITED("groups.unlimited");
GROUPS_MAX("groups.max"),
GROUPS_UNLIMITED("groups.unlimited"),
WORLDGUARD_BYPASS("worldguard.bypass");;
private final String permissionString; private final String permissionString;
@ -69,6 +77,11 @@ public class PermissionManager extends Manager {
String permission = PERMISSION_PREFIX + this.permissionString + '.' + subPermission; String permission = PERMISSION_PREFIX + this.permissionString + '.' + subPermission;
return p.hasPermission(permission); return p.hasPermission(permission);
} }
@Override
public String toString() {
return PERMISSION_PREFIX + this.permissionString;
}
} }
public PermissionManager(PlayerParticles playerParticles) { public PermissionManager(PlayerParticles playerParticles) {
@ -87,6 +100,9 @@ public class PermissionManager extends Manager {
// Effects // Effects
Map<String, Boolean> effectPermissions = new HashMap<>(); Map<String, Boolean> effectPermissions = new HashMap<>();
for (ParticleEffect effect : particleManager.getEnabledEffects()) { for (ParticleEffect effect : particleManager.getEnabledEffects()) {
if (particleManager.getEffectSettings(effect) == null)
continue;
Permission permission = new Permission("playerparticles.effect." + particleManager.getEffectSettings(effect).getInternalName()); Permission permission = new Permission("playerparticles.effect." + particleManager.getEffectSettings(effect).getInternalName());
pluginManager.addPermission(permission); pluginManager.addPermission(permission);
effectPermissions.put(permission.getName(), true); effectPermissions.put(permission.getName(), true);
@ -109,6 +125,7 @@ public class PermissionManager extends Manager {
// Fixed // Fixed
pluginManager.addPermission(new Permission("playerparticles.fixed")); pluginManager.addPermission(new Permission("playerparticles.fixed"));
pluginManager.addPermission(new Permission("playerparticles.fixed.max"));
pluginManager.addPermission(new Permission("playerparticles.fixed.unlimited")); pluginManager.addPermission(new Permission("playerparticles.fixed.unlimited"));
pluginManager.addPermission(new Permission("playerparticles.fixed.clear")); pluginManager.addPermission(new Permission("playerparticles.fixed.clear"));
pluginManager.addPermission(new Permission("playerparticles.fixed.teleport")); pluginManager.addPermission(new Permission("playerparticles.fixed.teleport"));
@ -116,10 +133,18 @@ public class PermissionManager extends Manager {
// Misc // Misc
pluginManager.addPermission(new Permission("playerparticles.reload")); pluginManager.addPermission(new Permission("playerparticles.reload"));
pluginManager.addPermission(new Permission("playerparticles.override")); pluginManager.addPermission(new Permission("playerparticles.override"));
pluginManager.addPermission(new Permission("playerparticles.reset.others"));
pluginManager.addPermission(new Permission("playerparticles.gui")); pluginManager.addPermission(new Permission("playerparticles.gui"));
pluginManager.addPermission(new Permission("playerparticles.particles.max"));
pluginManager.addPermission(new Permission("playerparticles.particles.unlimited")); pluginManager.addPermission(new Permission("playerparticles.particles.unlimited"));
pluginManager.addPermission(new Permission("playerparticles.groups.max"));
pluginManager.addPermission(new Permission("playerparticles.groups.unlimited")); pluginManager.addPermission(new Permission("playerparticles.groups.unlimited"));
// WorldGuard
pluginManager.addPermission(new Permission("playerparticles.worldguard.bypass"));
// Register all non-child permissions // Register all non-child permissions
Map<String, Boolean> childPermissions = new HashMap<>(); Map<String, Boolean> childPermissions = new HashMap<>();
for (Permission permission : allPermissions) { for (Permission permission : allPermissions) {
@ -155,7 +180,7 @@ public class PermissionManager extends Manager {
if (executor != pplayer) if (executor != pplayer)
return false; return false;
return pplayer.getActiveParticles().size() >= Setting.MAX_PARTICLES.getInt(); return pplayer.getActiveParticles().size() >= this.getPermissionAmount(pplayer.getUnderlyingExecutor(), PPermission.PARTICLES_MAX, Setting.MAX_PARTICLES.getInt());
} }
/** /**
@ -172,7 +197,7 @@ public class PermissionManager extends Manager {
if (executor != pplayer) if (executor != pplayer)
return false; return false;
return executor.getParticleGroups().size() - 1 >= Setting.MAX_GROUPS.getInt(); return executor.getParticleGroups().size() - 1 >= this.getPermissionAmount(pplayer.getUnderlyingExecutor(), PPermission.GROUPS_MAX, Setting.MAX_GROUPS.getInt());
} }
/** /**
@ -185,7 +210,7 @@ public class PermissionManager extends Manager {
if (PPermission.GROUPS_UNLIMITED.check(pplayer.getUnderlyingExecutor())) if (PPermission.GROUPS_UNLIMITED.check(pplayer.getUnderlyingExecutor()))
return true; return true;
return Setting.MAX_GROUPS.getInt() != 0; return this.getPermissionAmount(pplayer.getUnderlyingExecutor(), PPermission.GROUPS_MAX, Setting.MAX_GROUPS.getInt()) != 0;
} }
/** /**
@ -202,7 +227,7 @@ public class PermissionManager extends Manager {
if (executor != pplayer) if (executor != pplayer)
return false; return false;
return pplayer.getFixedEffectIds().size() >= Setting.MAX_FIXED_EFFECTS.getInt(); return pplayer.getFixedEffectIds().size() >= this.getPermissionAmount(pplayer.getUnderlyingExecutor(), PPermission.FIXED_MAX, Setting.MAX_FIXED_EFFECTS.getInt());
} }
/** /**
@ -228,7 +253,7 @@ public class PermissionManager extends Manager {
if (executor != pplayer) if (executor != pplayer)
return Integer.MAX_VALUE; return Integer.MAX_VALUE;
return Setting.MAX_PARTICLES.getInt(); return this.getPermissionAmount(pplayer.getUnderlyingExecutor(), PPermission.PARTICLES_MAX, Setting.MAX_PARTICLES.getInt());
} }
/** /**
@ -250,6 +275,16 @@ public class PermissionManager extends Manager {
return Setting.DISABLED_WORLDS.getStringList(); return Setting.DISABLED_WORLDS.getStringList();
} }
/**
* Checks if a player can reset another offline player's particles
*
* @param player The player to check the permission for
* @return True if the player has permission, otherwise false
*/
public boolean canResetOthers(PPlayer player) {
return PPermission.RESET_OTHERS.check(player.getUnderlyingExecutor());
}
/** /**
* Checks if a player has permission to use an effect * Checks if a player has permission to use an effect
* *
@ -397,10 +432,10 @@ public class PermissionManager extends Manager {
} }
/** /**
* Checks if a player can use /ppo * Checks if a CommandSender can use /ppo
* *
* @param sender The CommandSender to check * @param sender The CommandSender to check
* @return If the player can use /ppo * @return If the sender can use /ppo
*/ */
public boolean canOverride(CommandSender sender) { public boolean canOverride(CommandSender sender) {
if (this.isConsole(sender)) if (this.isConsole(sender))
@ -409,6 +444,16 @@ public class PermissionManager extends Manager {
return PPermission.OVERRIDE.check(sender); return PPermission.OVERRIDE.check(sender);
} }
/**
* Checks if a player has the WorldGuard bypass permission
*
* @param player The Player to check
* @return If the player has the WorldGuard bypass permission
*/
public boolean hasWorldGuardBypass(Player player) {
return PPermission.WORLDGUARD_BYPASS.check(player);
}
private boolean isConsole(PPlayer pplayer) { private boolean isConsole(PPlayer pplayer) {
return this.isConsole(pplayer.getUnderlyingExecutor()); return this.isConsole(pplayer.getUnderlyingExecutor());
} }
@ -429,4 +474,17 @@ public class PermissionManager extends Manager {
return pplayer; return pplayer;
} }
private int getPermissionAmount(Permissible permissible, PPermission permission, int lowerBound) {
int amount = lowerBound;
for (PermissionAttachmentInfo info : permissible.getEffectivePermissions()) {
String target = info.getPermission().toLowerCase();
if (target.startsWith(permission.toString()) && info.getValue()) {
try {
amount = Math.max(amount, Integer.parseInt(target.substring(target.lastIndexOf('.') + 1)));
} catch (NumberFormatException ignored) { }
}
}
return amount;
}
} }

View file

@ -48,6 +48,11 @@ public class PPlayer {
*/ */
private boolean inCombat; private boolean inCombat;
/**
* If the player is in an allowed region
*/
private boolean inAllowedRegion;
/** /**
* Constructs a new PPlayer * Constructs a new PPlayer
* *
@ -64,6 +69,7 @@ public class PPlayer {
this.particlesHidden = particlesHidden; this.particlesHidden = particlesHidden;
this.isMoving = false; this.isMoving = false;
this.inCombat = false; this.inCombat = false;
this.inAllowedRegion = true;
} }
/** /**
@ -103,7 +109,7 @@ public class PPlayer {
/** /**
* Gets if the Player can see particles spawned by the plugin or not * Gets if the Player can see particles spawned by the plugin or not
* *
* @return True if the player can see particles, otherwise false * @return true if the player can see particles, otherwise false
*/ */
public boolean canSeeParticles() { public boolean canSeeParticles() {
return !this.particlesHidden; return !this.particlesHidden;
@ -112,7 +118,7 @@ public class PPlayer {
/** /**
* Sets if the player can see particles spawned by the plugin or not * Sets if the player can see particles spawned by the plugin or not
* *
* @param hidden True if the player can see particles, otherwise false * @param hidden true if the player can see particles, otherwise false
*/ */
public void setParticlesHidden(boolean hidden) { public void setParticlesHidden(boolean hidden) {
this.particlesHidden = hidden; this.particlesHidden = hidden;
@ -130,7 +136,7 @@ public class PPlayer {
/** /**
* Sets the player's movement state * Sets the player's movement state
* *
* @param isMoving True if the player is moving, otherwise false if they are standing still * @param isMoving true if the player is moving, otherwise false if they are standing still
*/ */
public void setMoving(boolean isMoving) { public void setMoving(boolean isMoving) {
this.isMoving = isMoving; this.isMoving = isMoving;
@ -139,7 +145,7 @@ public class PPlayer {
/** /**
* Gets if a player is moving * Gets if a player is moving
* *
* @return True if the player is moving * @return true if the player is moving
*/ */
public boolean isMoving() { public boolean isMoving() {
return this.isMoving; return this.isMoving;
@ -148,7 +154,7 @@ public class PPlayer {
/** /**
* Sets the player's combat state * Sets the player's combat state
* *
* @param inCombat True if the player is in combat, otherwise false * @param inCombat true if the player is in combat, otherwise false
*/ */
public void setInCombat(boolean inCombat) { public void setInCombat(boolean inCombat) {
this.inCombat = inCombat; this.inCombat = inCombat;
@ -157,12 +163,28 @@ public class PPlayer {
/** /**
* Gets if a player is in combat * Gets if a player is in combat
* *
* @return True if the player is in combat * @return true if the player is in combat
*/ */
public boolean isInCombat() { public boolean isInCombat() {
return this.inCombat; return this.inCombat;
} }
/**
* Sets the player's region state
*
* @param inAllowedRegion true if the player is in an allowed region, otherwise false
*/
public void setInAllowedRegion(boolean inAllowedRegion) {
this.inAllowedRegion = inAllowedRegion;
}
/**
* @return true if the player is in an allowed region, otherwise false
*/
public boolean isInAllowedRegion() {
return this.inAllowedRegion;
}
/** /**
* Gets a ParticleGroup this player has by its name * Gets a ParticleGroup this player has by its name
* *

View file

@ -7,6 +7,7 @@ import dev.esophose.playerparticles.util.ParticleUtils;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Material;
public class ParticleEffectSettings { public class ParticleEffectSettings {
@ -19,6 +20,7 @@ public class ParticleEffectSettings {
private String effectName; private String effectName;
private boolean enabled; private boolean enabled;
private Material guiIconMaterial;
public ParticleEffectSettings(ParticleEffect particleEffect) { public ParticleEffectSettings(ParticleEffect particleEffect) {
this.particleEffect = particleEffect; this.particleEffect = particleEffect;
@ -40,6 +42,7 @@ public class ParticleEffectSettings {
boolean changed = this.setIfNotExists("effect-name", this.getInternalName(), "The name the effect will display as"); boolean changed = this.setIfNotExists("effect-name", this.getInternalName(), "The name the effect will display as");
changed |= this.setIfNotExists("enabled", this.enabledByDefault, "If the effect is enabled or not"); changed |= this.setIfNotExists("enabled", this.enabledByDefault, "If the effect is enabled or not");
changed |= this.setIfNotExists("gui-icon-material", this.particleEffect.getGuiIconMaterialNames());
if (changed) if (changed)
this.config.save(); this.config.save();
@ -56,6 +59,7 @@ public class ParticleEffectSettings {
this.effectName = this.config.getString("effect-name"); this.effectName = this.config.getString("effect-name");
this.enabled = this.config.getBoolean("enabled"); this.enabled = this.config.getBoolean("enabled");
this.guiIconMaterial = ParticleUtils.closestMatchWithFallback(true, this.config.getStringList("gui-icon-material").toArray(new String[0]));
} }
/** /**
@ -95,6 +99,13 @@ public class ParticleEffectSettings {
return this.effectName; return this.effectName;
} }
/**
* @return The Material icon that represents this style in the GUI
*/
public Material getGuiIconMaterial() {
return this.guiIconMaterial;
}
/** /**
* @return true if this effect is enabled, otherwise false * @return true if this effect is enabled, otherwise false
*/ */

View file

@ -3,9 +3,9 @@ package dev.esophose.playerparticles.particles;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.manager.LocaleManager; import dev.esophose.playerparticles.manager.LocaleManager;
import dev.esophose.playerparticles.manager.ParticleManager; import dev.esophose.playerparticles.manager.ParticleManager;
import dev.esophose.playerparticles.particles.color.NoteColor; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.particles.color.OrdinaryColor; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.particles.color.ParticleColor; import dev.esophose.playerparticles.particles.data.ParticleColor;
import dev.esophose.playerparticles.styles.DefaultStyles; import dev.esophose.playerparticles.styles.DefaultStyles;
import dev.esophose.playerparticles.styles.ParticleStyle; import dev.esophose.playerparticles.styles.ParticleStyle;
import dev.esophose.playerparticles.util.ParticleUtils; import dev.esophose.playerparticles.util.ParticleUtils;

View file

@ -1,4 +1,4 @@
package dev.esophose.playerparticles.particles.color; package dev.esophose.playerparticles.particles.data;
import dev.esophose.playerparticles.particles.ParticleEffect; import dev.esophose.playerparticles.particles.ParticleEffect;
import java.util.Objects; import java.util.Objects;

View file

@ -1,4 +1,4 @@
package dev.esophose.playerparticles.particles.color; package dev.esophose.playerparticles.particles.data;
import dev.esophose.playerparticles.particles.ParticleEffect; import dev.esophose.playerparticles.particles.ParticleEffect;
import java.util.Objects; import java.util.Objects;

View file

@ -1,4 +1,4 @@
package dev.esophose.playerparticles.particles.color; package dev.esophose.playerparticles.particles.data;
import dev.esophose.playerparticles.particles.ParticleEffect; import dev.esophose.playerparticles.particles.ParticleEffect;

View file

@ -10,6 +10,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile; import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -55,10 +56,7 @@ public class PPlayerCombatListener implements Listener {
*/ */
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR)
public void onPlayerAttack(EntityDamageByEntityEvent event) { public void onPlayerAttack(EntityDamageByEntityEvent event) {
if (!Setting.TOGGLE_ON_COMBAT.getBoolean()) if (event.getEntity().getType() != EntityType.PLAYER)
return;
if (!(event.getEntity() instanceof Player))
return; return;
Player attacker; Player attacker;

View file

@ -11,22 +11,37 @@ import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.event.EventHandler; import org.bukkit.entity.Player;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.util.Vector;
public class PPlayerMovementListener implements Listener { public class PPlayerMovementListener implements Listener {
private static final int CHECK_INTERVAL = 3; private static final int CHECK_INTERVAL = 3;
private Map<UUID, Integer> timeSinceLastMovement = new HashMap<>(); private Map<UUID, Integer> timeSinceLastMovement;
private Map<UUID, Vector> previousVectors;
public PPlayerMovementListener() { public PPlayerMovementListener() {
DataManager dataManager = PlayerParticles.getInstance().getManager(DataManager.class); DataManager dataManager = PlayerParticles.getInstance().getManager(DataManager.class);
this.timeSinceLastMovement = new HashMap<>();
this.previousVectors = new HashMap<>();
Bukkit.getScheduler().runTaskTimer(PlayerParticles.getInstance(), () -> { Bukkit.getScheduler().runTaskTimer(PlayerParticles.getInstance(), () -> {
if (!Setting.TOGGLE_ON_MOVE.getBoolean()) for (Player player : Bukkit.getOnlinePlayers()) {
return; UUID playerUUID = player.getUniqueId();
Vector previousVector = this.previousVectors.get(playerUUID);
Location currentLocation = player.getLocation();
Vector currentVector = new Vector(currentLocation.getBlockX(), currentLocation.getBlockY(), currentLocation.getBlockZ());
this.previousVectors.put(playerUUID, currentVector);
if (previousVector == null || !previousVector.equals(currentVector)) {
if (!this.timeSinceLastMovement.containsKey(playerUUID)) {
this.timeSinceLastMovement.put(playerUUID, 0);
} else {
this.timeSinceLastMovement.replace(playerUUID, 0);
}
}
}
List<UUID> toRemove = new ArrayList<>(); List<UUID> toRemove = new ArrayList<>();
@ -47,27 +62,4 @@ public class PPlayerMovementListener implements Listener {
}, 0, CHECK_INTERVAL); }, 0, CHECK_INTERVAL);
} }
/**
* Used to detect if the player is moving
*
* @param event The event
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerMove(PlayerMoveEvent event) {
if (!Setting.TOGGLE_ON_MOVE.getBoolean())
return;
Location to = event.getTo();
Location from = event.getFrom();
if (to == null || (to.getBlockX() == from.getBlockX() && to.getBlockY() == from.getBlockY() && to.getBlockZ() == from.getBlockZ()))
return;
UUID playerUUID = event.getPlayer().getUniqueId();
if (!this.timeSinceLastMovement.containsKey(playerUUID)) {
this.timeSinceLastMovement.put(playerUUID, 0);
} else {
this.timeSinceLastMovement.replace(playerUUID, 0);
}
}
} }

View file

@ -5,6 +5,8 @@ import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.ParticleUtils; import dev.esophose.playerparticles.util.ParticleUtils;
import java.io.File; import java.io.File;
import java.util.List;
import org.bukkit.Material;
public abstract class DefaultParticleStyle implements ParticleStyle { public abstract class DefaultParticleStyle implements ParticleStyle {
@ -15,18 +17,22 @@ public abstract class DefaultParticleStyle implements ParticleStyle {
private String internalStyleName; private String internalStyleName;
private boolean canBeFixedByDefault; private boolean canBeFixedByDefault;
private boolean canToggleWithMovementByDefault; private boolean canToggleWithMovementByDefault;
private boolean canToggleWithCombatByDefault;
private double fixedEffectOffsetByDefault; private double fixedEffectOffsetByDefault;
private String styleName; private String styleName;
private boolean enabled; private boolean enabled;
private boolean canBeFixed; private boolean canBeFixed;
private boolean canToggleWithMovement; private boolean canToggleWithMovement;
private boolean canToggleWithCombat;
private double fixedEffectOffset; private double fixedEffectOffset;
private Material guiIconMaterial;
public DefaultParticleStyle(String internalStyleName, boolean canBeFixedByDefault, boolean canToggleWithMovementByDefault, double fixedEffectOffsetByDefault) { public DefaultParticleStyle(String internalStyleName, boolean canBeFixedByDefault, boolean canToggleWithMovementByDefault, double fixedEffectOffsetByDefault) {
this.internalStyleName = internalStyleName; this.internalStyleName = internalStyleName;
this.canBeFixedByDefault = canBeFixedByDefault; this.canBeFixedByDefault = canBeFixedByDefault;
this.canToggleWithMovementByDefault = canToggleWithMovementByDefault; this.canToggleWithMovementByDefault = canToggleWithMovementByDefault;
this.canToggleWithCombatByDefault = true;
this.fixedEffectOffsetByDefault = fixedEffectOffsetByDefault; this.fixedEffectOffsetByDefault = fixedEffectOffsetByDefault;
this.playerParticles = PlayerParticles.getInstance(); this.playerParticles = PlayerParticles.getInstance();
@ -49,7 +55,9 @@ public abstract class DefaultParticleStyle implements ParticleStyle {
this.setIfNotExists("enabled", true, "If the style is enabled or not"); this.setIfNotExists("enabled", true, "If the style is enabled or not");
this.setIfNotExists("can-be-fixed", this.canBeFixedByDefault, "If the style can be used in /pp fixed"); this.setIfNotExists("can-be-fixed", this.canBeFixedByDefault, "If the style can be used in /pp fixed");
this.setIfNotExists("can-toggle-with-movement", this.canToggleWithMovementByDefault, "If the style will only be shown at the player's feet while moving"); this.setIfNotExists("can-toggle-with-movement", this.canToggleWithMovementByDefault, "If the style will only be shown at the player's feet while moving");
this.setIfNotExists("can-toggle-with-combat", this.canToggleWithCombatByDefault, "If particles for this style will be hidden if the player is in combat");
this.setIfNotExists("fixed-effect-offset", this.fixedEffectOffsetByDefault, "How far vertically to offset the style position for fixed effects"); this.setIfNotExists("fixed-effect-offset", this.fixedEffectOffsetByDefault, "How far vertically to offset the style position for fixed effects");
this.setIfNotExists("gui-icon-material", this.getGuiIconMaterialNames(), "The material of the icon to display in the GUI");
this.setDefaultSettings(this.config); this.setDefaultSettings(this.config);
@ -70,7 +78,9 @@ public abstract class DefaultParticleStyle implements ParticleStyle {
this.enabled = this.config.getBoolean("enabled"); this.enabled = this.config.getBoolean("enabled");
this.canBeFixed = this.config.getBoolean("can-be-fixed"); this.canBeFixed = this.config.getBoolean("can-be-fixed");
this.canToggleWithMovement = this.config.getBoolean("can-toggle-with-movement"); this.canToggleWithMovement = this.config.getBoolean("can-toggle-with-movement");
this.canToggleWithCombat = this.config.getBoolean("can-toggle-with-combat");
this.fixedEffectOffset = this.config.getDouble("fixed-effect-offset"); this.fixedEffectOffset = this.config.getDouble("fixed-effect-offset");
this.guiIconMaterial = ParticleUtils.closestMatchWithFallback(true, this.config.getStringList("gui-icon-material").toArray(new String[0]));
this.loadSettings(this.config); this.loadSettings(this.config);
} }
@ -102,14 +112,19 @@ public abstract class DefaultParticleStyle implements ParticleStyle {
return this.enabled; return this.enabled;
} }
@Override
public final String getInternalName() {
return this.internalStyleName;
}
@Override @Override
public final String getName() { public final String getName() {
return this.styleName; return this.styleName;
} }
@Override @Override
public final String getInternalName() { public final Material getGuiIconMaterial() {
return this.internalStyleName; return this.guiIconMaterial;
} }
@Override @Override
@ -122,11 +137,21 @@ public abstract class DefaultParticleStyle implements ParticleStyle {
return this.canToggleWithMovement; return this.canToggleWithMovement;
} }
@Override
public final boolean canToggleWithCombat() {
return this.canToggleWithCombat;
}
@Override @Override
public final double getFixedEffectOffset() { public final double getFixedEffectOffset() {
return this.fixedEffectOffset; return this.fixedEffectOffset;
} }
/**
* @return A list of Strings to try to turn into Materials
*/
protected abstract List<String> getGuiIconMaterialNames();
/** /**
* Sets the default settings for this style * Sets the default settings for this style
* *

View file

@ -1,12 +1,15 @@
package dev.esophose.playerparticles.styles; package dev.esophose.playerparticles.styles;
import dev.esophose.playerparticles.event.ParticleStyleRegistrationEvent;
import dev.esophose.playerparticles.manager.ParticleStyleManager; import dev.esophose.playerparticles.manager.ParticleStyleManager;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
public class DefaultStyles { public class DefaultStyles implements Listener {
/** /**
* All the styles that are available by default from this plugin * All the styles that are available by default from this plugin
@ -21,6 +24,7 @@ public class DefaultStyles {
public static final ParticleStyle COMPANION = new ParticleStyleCompanion(); public static final ParticleStyle COMPANION = new ParticleStyleCompanion();
public static final ParticleStyle CUBE = new ParticleStyleCube(); public static final ParticleStyle CUBE = new ParticleStyleCube();
public static final ParticleStyle FEET = new ParticleStyleFeet(); public static final ParticleStyle FEET = new ParticleStyleFeet();
public static final ParticleStyle FISHING = new ParticleStyleFishing();
public static final ParticleStyle HALO = new ParticleStyleHalo(); public static final ParticleStyle HALO = new ParticleStyleHalo();
public static final ParticleStyle HURT = new ParticleStyleHurt(); public static final ParticleStyle HURT = new ParticleStyleHurt();
public static final ParticleStyle INVOCATION = new ParticleStyleInvocation(); public static final ParticleStyle INVOCATION = new ParticleStyleInvocation();
@ -37,6 +41,7 @@ public class DefaultStyles {
public static final ParticleStyle SPIN = new ParticleStyleSpin(); public static final ParticleStyle SPIN = new ParticleStyleSpin();
public static final ParticleStyle SPIRAL = new ParticleStyleSpiral(); public static final ParticleStyle SPIRAL = new ParticleStyleSpiral();
public static final ParticleStyle SWORDS = new ParticleStyleSwords(); public static final ParticleStyle SWORDS = new ParticleStyleSwords();
public static final ParticleStyle TELEPORT = new ParticleStyleTeleport();
public static final ParticleStyle THICK = new ParticleStyleThick(); public static final ParticleStyle THICK = new ParticleStyleThick();
public static final ParticleStyle TRAIL = new ParticleStyleTrail(); public static final ParticleStyle TRAIL = new ParticleStyleTrail();
public static final ParticleStyle TWINS = new ParticleStyleTwins(); public static final ParticleStyle TWINS = new ParticleStyleTwins();
@ -46,58 +51,65 @@ public class DefaultStyles {
public static final ParticleStyle WINGS = new ParticleStyleWings(); public static final ParticleStyle WINGS = new ParticleStyleWings();
/** /**
* Registers all the default styles to the ParticleStyleManager * Initializes all the default styles
* Registered in alphabetical order
*
* @param particleStyleManager The ParticleStyleManager instance
*/ */
public static void registerStyles(ParticleStyleManager particleStyleManager) { public static void initStyles() {
particleStyleManager.registerStyle(ARROWS); // Register event
particleStyleManager.registerStyle(BATMAN); Bukkit.getPluginManager().registerEvents(new DefaultStyles(), PlayerParticles.getInstance());
particleStyleManager.registerStyle(BEAM);
particleStyleManager.registerEventStyle(BLOCKBREAK);
particleStyleManager.registerEventStyle(BLOCKPLACE);
particleStyleManager.registerStyle(CELEBRATION);
particleStyleManager.registerStyle(CHAINS);
particleStyleManager.registerStyle(COMPANION);
particleStyleManager.registerStyle(CUBE);
particleStyleManager.registerStyle(FEET);
particleStyleManager.registerStyle(HALO);
particleStyleManager.registerEventStyle(HURT);
particleStyleManager.registerStyle(INVOCATION);
particleStyleManager.registerEventStyle(MOVE);
particleStyleManager.registerStyle(NORMAL);
particleStyleManager.registerStyle(ORBIT);
particleStyleManager.registerStyle(OVERHEAD);
particleStyleManager.registerStyle(POINT);
particleStyleManager.registerStyle(POPPER);
particleStyleManager.registerStyle(PULSE);
particleStyleManager.registerStyle(QUADHELIX);
particleStyleManager.registerStyle(RINGS);
particleStyleManager.registerStyle(SPHERE);
particleStyleManager.registerStyle(SPIN);
particleStyleManager.registerStyle(SPIRAL);
particleStyleManager.registerEventStyle(SWORDS);
particleStyleManager.registerStyle(THICK);
particleStyleManager.registerEventStyle(TRAIL);
particleStyleManager.registerStyle(TWINS);
particleStyleManager.registerStyle(VORTEX);
particleStyleManager.registerStyle(WHIRL);
particleStyleManager.registerStyle(WHIRLWIND);
particleStyleManager.registerStyle(WINGS);
// Register their events // Register style events
PluginManager pluginManager = Bukkit.getPluginManager(); PluginManager pluginManager = Bukkit.getPluginManager();
PlayerParticles playerParticles = PlayerParticles.getInstance(); PlayerParticles playerParticles = PlayerParticles.getInstance();
pluginManager.registerEvents((Listener) ARROWS, playerParticles); pluginManager.registerEvents((Listener) ARROWS, playerParticles);
pluginManager.registerEvents((Listener) BLOCKBREAK, playerParticles); pluginManager.registerEvents((Listener) BLOCKBREAK, playerParticles);
pluginManager.registerEvents((Listener) BLOCKPLACE, playerParticles); pluginManager.registerEvents((Listener) BLOCKPLACE, playerParticles);
pluginManager.registerEvents((Listener) FISHING, playerParticles);
pluginManager.registerEvents((Listener) HURT, playerParticles); pluginManager.registerEvents((Listener) HURT, playerParticles);
pluginManager.registerEvents((Listener) MOVE, playerParticles); pluginManager.registerEvents((Listener) MOVE, playerParticles);
pluginManager.registerEvents((Listener) SWORDS, playerParticles); pluginManager.registerEvents((Listener) SWORDS, playerParticles);
pluginManager.registerEvents((Listener) TELEPORT, playerParticles);
pluginManager.registerEvents((Listener) TRAIL, playerParticles); pluginManager.registerEvents((Listener) TRAIL, playerParticles);
} }
@EventHandler(priority = EventPriority.LOWEST)
public void onParticleStyleRegistration(ParticleStyleRegistrationEvent event) {
event.registerStyle(ARROWS);
event.registerStyle(BATMAN);
event.registerStyle(BEAM);
event.registerEventStyle(BLOCKBREAK);
event.registerEventStyle(BLOCKPLACE);
event.registerStyle(CELEBRATION);
event.registerStyle(CHAINS);
event.registerStyle(COMPANION);
event.registerStyle(CUBE);
event.registerStyle(FEET);
event.registerStyle(FISHING);
event.registerStyle(HALO);
event.registerEventStyle(HURT);
event.registerStyle(INVOCATION);
event.registerEventStyle(MOVE);
event.registerStyle(NORMAL);
event.registerStyle(ORBIT);
event.registerStyle(OVERHEAD);
event.registerStyle(POINT);
event.registerStyle(POPPER);
event.registerStyle(PULSE);
event.registerStyle(QUADHELIX);
event.registerStyle(RINGS);
event.registerStyle(SPHERE);
event.registerStyle(SPIN);
event.registerStyle(SPIRAL);
event.registerEventStyle(SWORDS);
event.registerEventStyle(TELEPORT);
event.registerStyle(THICK);
event.registerEventStyle(TRAIL);
event.registerStyle(TWINS);
event.registerStyle(VORTEX);
event.registerStyle(WHIRL);
event.registerStyle(WHIRLWIND);
event.registerStyle(WINGS);
}
/** /**
* Reloads the settings for all default styles * Reloads the settings for all default styles
* *

View file

@ -4,8 +4,10 @@ import dev.esophose.playerparticles.manager.ParticleStyleManager;
import dev.esophose.playerparticles.particles.PParticle; import dev.esophose.playerparticles.particles.PParticle;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.util.ParticleUtils;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
public interface ParticleStyle { public interface ParticleStyle {
@ -42,6 +44,13 @@ public interface ParticleStyle {
return this.getInternalName(); return this.getInternalName();
} }
/**
* @return The Material icon that represents this style in the GUI
*/
default Material getGuiIconMaterial() {
return ParticleUtils.FALLBACK_MATERIAL;
}
/** /**
* Gets if the style can be used in a FixedParticleEffect * Gets if the style can be used in a FixedParticleEffect
* *
@ -50,7 +59,7 @@ public interface ParticleStyle {
boolean canBeFixed(); boolean canBeFixed();
/** /**
* Gets if the style can be replaced with DefaultStyles.FEET when the player is moving * Gets if the style can be displayed differently based on the toggle-on-move setting when the player is moving
* *
* @return True if it can be, otherwise False * @return True if it can be, otherwise False
*/ */
@ -58,6 +67,15 @@ public interface ParticleStyle {
return true; return true;
} }
/**
* Gets if the style can be hidden if the player is in combat with the toggle-on-combat setting
*
* @return True if it can be, otherwise False
*/
default boolean canToggleWithCombat() {
return true;
}
/** /**
* The Y-axis offset to be applied when using '/pp fixed create looking' * The Y-axis offset to be applied when using '/pp fixed create looking'
* *

View file

@ -1,11 +1,14 @@
package dev.esophose.playerparticles.styles; package dev.esophose.playerparticles.styles;
import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.particles.PParticle; import dev.esophose.playerparticles.particles.PParticle;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile; import org.bukkit.entity.Projectile;
@ -15,7 +18,7 @@ import org.bukkit.event.entity.ProjectileLaunchEvent;
public class ParticleStyleArrows extends DefaultParticleStyle implements Listener { public class ParticleStyleArrows extends DefaultParticleStyle implements Listener {
private List<Projectile> projectiles = new ArrayList<>(); private List<Projectile> projectiles;
private int maxArrowsPerPlayer; private int maxArrowsPerPlayer;
private boolean onlySpawnIfFlying; private boolean onlySpawnIfFlying;
@ -24,6 +27,17 @@ public class ParticleStyleArrows extends DefaultParticleStyle implements Listene
public ParticleStyleArrows() { public ParticleStyleArrows() {
super("arrows", false, false, 0); super("arrows", false, false, 0);
this.projectiles = new ArrayList<>();
// Removes all arrows that are considered dead
Bukkit.getScheduler().runTaskTimer(PlayerParticles.getInstance(), () -> {
for (int i = this.projectiles.size() - 1; i >= 0; i--) {
Projectile projectile = this.projectiles.get(i);
if ((this.arrowTrackingTime != -1 && projectile.getTicksLived() >= this.arrowTrackingTime) || !projectile.isValid() || projectile.getShooter() == null)
this.projectiles.remove(i);
}
}, 0L, 5L);
} }
@Override @Override
@ -31,8 +45,9 @@ public class ParticleStyleArrows extends DefaultParticleStyle implements Listene
List<PParticle> particles = new ArrayList<>(); List<PParticle> particles = new ArrayList<>();
int count = 0; int count = 0;
for (int i = this.projectiles.size() - 1; i >= 0; i--) { // Loop backwards so the last-fired projectiles are the ones that have particles if they go over the max List<Projectile> listCopy = new ArrayList<>(this.projectiles); // Copy in case of modification while looping due to async
Projectile projectile = this.projectiles.get(i); for (int i = listCopy.size() - 1; i >= 0; i--) { // Loop backwards so the last-fired projectiles are the ones that have particles if they go over the max
Projectile projectile = listCopy.get(i);
if (this.onlySpawnIfFlying && projectile.isOnGround()) if (this.onlySpawnIfFlying && projectile.isOnGround())
continue; continue;
@ -48,16 +63,9 @@ public class ParticleStyleArrows extends DefaultParticleStyle implements Listene
return particles; return particles;
} }
/**
* Removes all arrows that are considered dead
*/
@Override @Override
public void updateTimers() { public void updateTimers() {
for (int i = this.projectiles.size() - 1; i >= 0; i--) {
Projectile projectile = this.projectiles.get(i);
if ((this.arrowTrackingTime != -1 && projectile.getTicksLived() >= this.arrowTrackingTime) || projectile.isDead() || !projectile.isValid() || projectile.getShooter() == null)
this.projectiles.remove(i);
}
} }
@Override @Override
@ -65,6 +73,11 @@ public class ParticleStyleArrows extends DefaultParticleStyle implements Listene
return true; return true;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("BOW");
}
/** /**
* The event used to get all projectiles fired by players * The event used to get all projectiles fired by players
* Adds all projectiles fired from players to the array * Adds all projectiles fired from players to the array

View file

@ -5,6 +5,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.VectorUtils; import dev.esophose.playerparticles.util.VectorUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@ -120,6 +121,11 @@ public class ParticleStyleBatman extends DefaultParticleStyle {
this.step = (this.step + 1) % this.spawnDelay; // Only spawn once per second this.step = (this.step + 1) % this.spawnDelay; // Only spawn once per second
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("BAT_SPAWN_EGG", "COAL");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("spawn-delay", 20, "The number of ticks to wait between particle spawns"); this.setIfNotExists("spawn-delay", 20, "The number of ticks to wait between particle spawns");

View file

@ -5,6 +5,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -46,6 +47,11 @@ public class ParticleStyleBeam extends DefaultParticleStyle {
} }
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("POWERED_RAIL");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("points", 16, "The number of points in the circle"); this.setIfNotExists("points", 16, "The number of points in the circle");

View file

@ -8,6 +8,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -43,6 +44,11 @@ public class ParticleStyleBlockBreak extends DefaultParticleStyle implements Lis
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("IRON_PICKAXE");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("particle-amount", 10, "The number of particles to spawn"); this.setIfNotExists("particle-amount", 10, "The number of particles to spawn");
@ -63,11 +69,12 @@ public class ParticleStyleBlockBreak extends DefaultParticleStyle implements Lis
Player player = event.getPlayer(); Player player = event.getPlayer();
PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId()); PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId());
if (pplayer != null) { if (pplayer == null)
for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.BLOCKBREAK)) { return;
Location loc = event.getBlock().getLocation().clone();
particleManager.displayParticles(player, player.getWorld(), particle, DefaultStyles.BLOCKBREAK.getParticles(particle, loc), false); for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.BLOCKBREAK)) {
} Location loc = event.getBlock().getLocation().clone();
particleManager.displayParticles(pplayer, player.getWorld(), particle, DefaultStyles.BLOCKBREAK.getParticles(particle, loc), false);
} }
} }

View file

@ -8,6 +8,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -43,6 +44,11 @@ public class ParticleStyleBlockPlace extends DefaultParticleStyle implements Lis
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("OAK_PLANKS", "WOOD");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("particle-amount", 10, "The number of particles to spawn"); this.setIfNotExists("particle-amount", 10, "The number of particles to spawn");
@ -63,11 +69,12 @@ public class ParticleStyleBlockPlace extends DefaultParticleStyle implements Lis
Player player = event.getPlayer(); Player player = event.getPlayer();
PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId()); PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId());
if (pplayer != null) { if (pplayer == null)
for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.BLOCKPLACE)) { return;
Location loc = event.getBlock().getLocation().clone();
particleManager.displayParticles(player, player.getWorld(), particle, DefaultStyles.BLOCKPLACE.getParticles(particle, loc), false); for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.BLOCKPLACE)) {
} Location loc = event.getBlock().getLocation().clone();
particleManager.displayParticles(pplayer, player.getWorld(), particle, DefaultStyles.BLOCKPLACE.getParticles(particle, loc), false);
} }
} }

View file

@ -10,7 +10,9 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import dev.esophose.playerparticles.util.NMSUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
@ -59,7 +61,7 @@ public class ParticleStyleCelebration extends DefaultParticleStyle {
Random random = new Random(); Random random = new Random();
for (PPlayer pplayer : particleManager.getPPlayers()) { for (PPlayer pplayer : particleManager.getPPlayers()) {
Player player = pplayer.getPlayer(); Player player = pplayer.getPlayer();
if (player != null && player.getGameMode() != GameMode.SPECTATOR && permissionManager.isWorldEnabled(player.getWorld().getName())) if (player != null && (NMSUtil.getVersionNumber() < 8 || player.getGameMode() != GameMode.SPECTATOR) && permissionManager.isWorldEnabled(player.getWorld().getName()))
for (ParticlePair particle : pplayer.getActiveParticles()) for (ParticlePair particle : pplayer.getActiveParticles())
if (particle.getStyle() == this) if (particle.getStyle() == this)
this.spawnFirework(player.getLocation(), pplayer, pplayer.getPlayer(), particle, random); this.spawnFirework(player.getLocation(), pplayer, pplayer.getPlayer(), particle, random);
@ -71,6 +73,11 @@ public class ParticleStyleCelebration extends DefaultParticleStyle {
} }
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("FIREWORK_ROCKET", "FIREWORK");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("spawn-frequency", 15, "How many ticks to wait between spawns"); this.setIfNotExists("spawn-frequency", 15, "How many ticks to wait between spawns");
@ -122,7 +129,7 @@ public class ParticleStyleCelebration extends DefaultParticleStyle {
trail.setEffect(ParticleStyleCelebration.this.fuseEffect); trail.setEffect(ParticleStyleCelebration.this.fuseEffect);
trail.setStyle(DefaultStyles.CELEBRATION); trail.setStyle(DefaultStyles.CELEBRATION);
particleManager.displayParticles(player, this.location.getWorld(), trail, Collections.singletonList(new PParticle(this.location)), true); particleManager.displayParticles(pplayer, this.location.getWorld(), trail, Collections.singletonList(new PParticle(this.location)), true);
this.location.add(0, ParticleStyleCelebration.this.fuseSpacing, 0); this.location.add(0, ParticleStyleCelebration.this.fuseSpacing, 0);
} else { } else {
@ -139,7 +146,7 @@ public class ParticleStyleCelebration extends DefaultParticleStyle {
particles.add(new PParticle(this.location.clone().add(dx, dy, dz))); particles.add(new PParticle(this.location.clone().add(dx, dy, dz)));
} }
particleManager.displayParticles(player, this.location.getWorld(), particle, particles, true); particleManager.displayParticles(pplayer, this.location.getWorld(), particle, particles, true);
this.cancel(); this.cancel();
} }

View file

@ -4,6 +4,7 @@ import dev.esophose.playerparticles.particles.PParticle;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -34,6 +35,11 @@ public class ParticleStyleChains extends DefaultParticleStyle {
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("TRIPWIRE_HOOK");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("chain-particle-amount", 8, "The number of particles per chain"); this.setIfNotExists("chain-particle-amount", 8, "The number of particles per chain");

View file

@ -28,6 +28,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@ -71,6 +72,11 @@ public class ParticleStyleCompanion extends DefaultParticleStyle {
this.step++; this.step++;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("NAME_TAG");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("particle-amount", 150, "The number of total particles in the animation cycle"); this.setIfNotExists("particle-amount", 150, "The number of total particles in the animation cycle");

View file

@ -28,6 +28,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.VectorUtils; import dev.esophose.playerparticles.util.VectorUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@ -96,6 +97,11 @@ public class ParticleStyleCube extends DefaultParticleStyle {
this.step++; this.step++;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("STONE");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("edge-length", 2.0, "The length (in blocks) of the edges of the cube"); this.setIfNotExists("edge-length", 2.0, "The length (in blocks) of the edges of the cube");

View file

@ -4,6 +4,7 @@ import dev.esophose.playerparticles.particles.PParticle;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -31,6 +32,11 @@ public class ParticleStyleFeet extends DefaultParticleStyle {
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("GRASS");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("feet-offset", -0.95, "How far to offset the player location vertically"); this.setIfNotExists("feet-offset", -0.95, "How far to offset the player location vertically");

View file

@ -0,0 +1,103 @@
package dev.esophose.playerparticles.styles;
import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.particles.PParticle;
import dev.esophose.playerparticles.particles.ParticlePair;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.projectiles.ProjectileSource;
public class ParticleStyleFishing extends DefaultParticleStyle implements Listener {
// I hate legacy versions. The Spigot API changed the PlayerFishEvent#getHook method from returning a Fish to a FishHook in 1.13
private static Method PlayerFishEvent_getHook;
static {
try {
PlayerFishEvent_getHook = PlayerFishEvent.class.getDeclaredMethod("getHook");
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
}
}
private Set<Projectile> projectiles;
public ParticleStyleFishing() {
super("fishing", false, false, 0);
this.projectiles = new HashSet<>();
// Removes all fish hooks that are considered dead
Bukkit.getScheduler().runTaskTimer(PlayerParticles.getInstance(), () -> this.projectiles.removeIf(x -> !x.isValid()), 0L, 5L);
}
@Override
public List<PParticle> getParticles(ParticlePair particle, Location location) {
List<PParticle> particles = new ArrayList<>();
List<Projectile> listCopy = new ArrayList<>(this.projectiles); // Copy in case of modification while looping due to async
for (Projectile projectile : listCopy) {
ProjectileSource shooter = projectile.getShooter();
if (shooter instanceof Player && ((Player) shooter).getUniqueId().equals(particle.getOwnerUniqueId()))
particles.add(new PParticle(projectile.getLocation(), 0.05F, 0.05F, 0.05F, 0.0F));
}
return particles;
}
@Override
public void updateTimers() {
}
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("FISHING_ROD");
}
@Override
public boolean hasLongRangeVisibility() {
return false;
}
@EventHandler
public void onPlayerFish(PlayerFishEvent event) {
// Done through a string switch for 1.9.4 compatibility
switch (event.getState().toString()) {
case "FISHING":
try {
this.projectiles.add((Projectile) PlayerFishEvent_getHook.invoke(event));
} catch (ReflectiveOperationException ignored) { }
break;
case "CAUGHT_FISH":
case "CAUGHT_ENTITY":
case "REEL_IN":
try {
this.projectiles.remove((Projectile) PlayerFishEvent_getHook.invoke(event));
} catch (ReflectiveOperationException ignored) { }
break;
}
}
@Override
protected void setDefaultSettings(CommentedFileConfiguration config) {
}
@Override
protected void loadSettings(CommentedFileConfiguration config) {
}
}

View file

@ -5,6 +5,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -43,6 +44,11 @@ public class ParticleStyleHalo extends DefaultParticleStyle {
this.skipNextSpawn = !this.skipNextSpawn; this.skipNextSpawn = !this.skipNextSpawn;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("END_PORTAL_FRAME", "ENDER_PORTAL_FRAME");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("particle-amount", 16, "The number of points in the halo"); this.setIfNotExists("particle-amount", 16, "The number of points in the halo");

View file

@ -8,6 +8,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -49,12 +50,17 @@ public class ParticleStyleHurt extends DefaultParticleStyle implements Listener
if (pplayer != null) { if (pplayer != null) {
for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.HURT)) { for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.HURT)) {
Location loc = player.getLocation().clone().add(0, 1, 0); Location loc = player.getLocation().clone().add(0, 1, 0);
particleManager.displayParticles(player, player.getWorld(), particle, DefaultStyles.HURT.getParticles(particle, loc), false); particleManager.displayParticles(pplayer, player.getWorld(), particle, DefaultStyles.HURT.getParticles(particle, loc), false);
} }
} }
} }
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("CACTUS");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("thick-multiplier", 3, "How much to multiply the particles by", "This style uses the same spawning as the 'thick' style"); this.setIfNotExists("thick-multiplier", 3, "How much to multiply the particles by", "This style uses the same spawning as the 'thick' style");

View file

@ -6,6 +6,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -97,6 +98,11 @@ public class ParticleStyleInvocation extends DefaultParticleStyle {
this.circleStep = (this.circleStep + 1) % this.numSteps; this.circleStep = (this.circleStep + 1) % this.numSteps;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("ENDER_EYE", "EYE_OF_ENDER");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("spinning-points", 6, "The number of points that spin around the circle in each direction"); this.setIfNotExists("spinning-points", 6, "The number of points that spin around the circle in each direction");

View file

@ -8,6 +8,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -39,6 +40,11 @@ public class ParticleStyleMove extends DefaultParticleStyle implements Listener
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("PISTON", "PISTON_BASE");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("multiplier", 1, "The multiplier for the number of particles to spawn", "This style uses the same spawning as the 'normal' style"); this.setIfNotExists("multiplier", 1, "The multiplier for the number of particles to spawn", "This style uses the same spawning as the 'normal' style");
@ -55,12 +61,13 @@ public class ParticleStyleMove extends DefaultParticleStyle implements Listener
Player player = event.getPlayer(); Player player = event.getPlayer();
PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId()); PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId());
if (pplayer != null) { if (pplayer == null)
for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.MOVE)) { return;
Location loc = player.getLocation().clone();
loc.setY(loc.getY() + 0.05); for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.MOVE)) {
particleManager.displayParticles(player, player.getWorld(), particle, DefaultStyles.MOVE.getParticles(particle, loc), false); Location loc = player.getLocation().clone();
} loc.setY(loc.getY() + 0.05);
particleManager.displayParticles(pplayer, player.getWorld(), particle, DefaultStyles.MOVE.getParticles(particle, loc), false);
} }
} }

View file

@ -4,6 +4,7 @@ import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.particles.PParticle; import dev.esophose.playerparticles.particles.PParticle;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -59,6 +60,11 @@ public class ParticleStyleNormal extends DefaultParticleStyle {
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("DIRT");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {

View file

@ -5,6 +5,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -36,6 +37,11 @@ public class ParticleStyleOrbit extends DefaultParticleStyle {
this.step = (this.step + 1) % this.numSteps; this.step = (this.step + 1) % this.numSteps;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("ENCHANTING_TABLE", "ENCHANTMENT_TABLE");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("orbs", 3, "The number of orbs that orbit the player"); this.setIfNotExists("orbs", 3, "The number of orbs that orbit the player");

View file

@ -4,6 +4,7 @@ import dev.esophose.playerparticles.particles.PParticle;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -33,6 +34,11 @@ public class ParticleStyleOverhead extends DefaultParticleStyle {
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("GLOWSTONE");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("head-offset", 1.75, "How far to offset the player location vertically"); this.setIfNotExists("head-offset", 1.75, "How far to offset the player location vertically");

View file

@ -25,6 +25,11 @@ public class ParticleStylePoint extends DefaultParticleStyle {
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("STONE_BUTTON");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("player-offset", 1.5, "How far to offset the player location vertically"); this.setIfNotExists("player-offset", 1.5, "How far to offset the player location vertically");

View file

@ -5,6 +5,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@ -51,6 +52,11 @@ public class ParticleStylePopper extends DefaultParticleStyle {
this.step = (this.step + 1) % this.maxStep; this.step = (this.step + 1) % this.maxStep;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("POPPED_CHORUS_FRUIT", "CHORUS_FRUIT_POPPED", "PUMPKIN_SEEDS");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("radius", 1.0, "The radius at the bottom of the vortex"); this.setIfNotExists("radius", 1.0, "The radius at the bottom of the vortex");

View file

@ -6,6 +6,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -77,6 +78,11 @@ public class ParticleStylePulse extends DefaultParticleStyle {
this.step = (this.step + 1) % this.numSteps; this.step = (this.step + 1) % this.numSteps;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("REDSTONE_TORCH", "REDSTONE_TORCH_ON");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("points", 50, "The number of points to spawn in the pulse circle"); this.setIfNotExists("points", 50, "The number of points to spawn in the pulse circle");

View file

@ -5,6 +5,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -51,6 +52,11 @@ public class ParticleStyleQuadhelix extends DefaultParticleStyle {
} }
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("NAUTILUS_SHELL", "ACTIVATOR_RAIL");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("orbs", 4, "The number of orbs to spawn"); this.setIfNotExists("orbs", 4, "The number of orbs to spawn");

View file

@ -5,6 +5,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -38,6 +39,11 @@ public class ParticleStyleRings extends DefaultParticleStyle {
this.step = (this.step + 1) % this.maxStep; this.step = (this.step + 1) % this.maxStep;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("LEAD", "LEASH");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("particles-per-ring", 32, "The number of particles that will spawn for each ring"); this.setIfNotExists("particles-per-ring", 32, "The number of particles that will spawn for each ring");

View file

@ -5,6 +5,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -40,6 +41,11 @@ public class ParticleStyleSphere extends DefaultParticleStyle {
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("HEART_OF_THE_SEA", "SNOWBALL", "SNOW_BALL");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("density", 15, "The number of particles to spawn per tick"); this.setIfNotExists("density", 15, "The number of particles to spawn per tick");

View file

@ -35,6 +35,11 @@ public class ParticleStyleSpin extends DefaultParticleStyle {
this.step = (this.step + 1) % this.maxSteps; this.step = (this.step + 1) % this.maxSteps;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("BEACON");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("particles-per-rotation", 30, "The number of particles to spawn per rotation"); this.setIfNotExists("particles-per-rotation", 30, "The number of particles to spawn per rotation");

View file

@ -5,6 +5,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -37,6 +38,11 @@ public class ParticleStyleSpiral extends DefaultParticleStyle {
this.stepX++; this.stepX++;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("HOPPER");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("particles", 12, "The number of particles to spawn around the player"); this.setIfNotExists("particles", 12, "The number of particles to spawn around the player");

View file

@ -7,8 +7,10 @@ import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.PlayerParticles; import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.NMSUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
@ -17,16 +19,18 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
public class ParticleStyleSwords extends DefaultParticleStyle implements Listener { public class ParticleStyleSwords extends DefaultParticleStyle implements Listener {
private static final List<String> SWORD_NAMES; private static final List<String> DEFAULT_SWORD_NAMES;
private int multiplier; private int multiplier;
private List<String> swordNames;
static { static {
SWORD_NAMES = new ArrayList<>(); DEFAULT_SWORD_NAMES = new ArrayList<>();
SWORD_NAMES.addAll(Arrays.asList("WOOD_SWORD", "STONE_SWORD", "IRON_SWORD", "GOLD_SWORD", "GOLDEN_SWORD", "DIAMOND_SWORD", "TRIDENT")); DEFAULT_SWORD_NAMES.addAll(Arrays.asList("WOOD_SWORD", "WOODEN_SWORD", "STONE_SWORD", "IRON_SWORD", "GOLD_SWORD", "GOLDEN_SWORD", "DIAMOND_SWORD", "TRIDENT"));
} }
public ParticleStyleSwords() { public ParticleStyleSwords() {
@ -48,14 +52,21 @@ public class ParticleStyleSwords extends DefaultParticleStyle implements Listene
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("IRON_SWORD");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("multiplier", 15, "The multiplier for the number of particles to spawn", "This style uses the same spawning as the 'normal' style"); this.setIfNotExists("multiplier", 15, "The multiplier for the number of particles to spawn", "This style uses the same spawning as the 'normal' style");
this.setIfNotExists("sword-materials", DEFAULT_SWORD_NAMES, "The materails that are considered swords", "Set to [] to allow everything to be considered a sword", "Use AIR to allow a bare hand to be considered a sword");
} }
@Override @Override
protected void loadSettings(CommentedFileConfiguration config) { protected void loadSettings(CommentedFileConfiguration config) {
this.multiplier = config.getInt("multiplier"); this.multiplier = config.getInt("multiplier");
this.swordNames = config.getStringList("sword-materials");
} }
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR)
@ -66,13 +77,32 @@ public class ParticleStyleSwords extends DefaultParticleStyle implements Listene
Player player = (Player) event.getDamager(); Player player = (Player) event.getDamager();
LivingEntity entity = (LivingEntity) event.getEntity(); LivingEntity entity = (LivingEntity) event.getEntity();
PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId()); PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId());
if (pplayer != null && SWORD_NAMES.contains(player.getInventory().getItemInMainHand().getType().name())) { if (pplayer == null)
for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.SWORDS)) { return;
Location loc = entity.getLocation().clone().add(0, 1, 0);
particleManager.displayParticles(player, player.getWorld(), particle, DefaultStyles.SWORDS.getParticles(particle, loc), false); if (NMSUtil.getVersionNumber() > 8) {
} if (!this.isSword(player.getInventory().getItemInMainHand()))
return;
} else {
if (!this.isSword(player.getInventory().getItemInHand()))
return;
}
for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.SWORDS)) {
Location loc = entity.getLocation().clone().add(0, 1, 0);
particleManager.displayParticles(pplayer, player.getWorld(), particle, DefaultStyles.SWORDS.getParticles(particle, loc), false);
} }
} }
} }
private boolean isSword(ItemStack itemStack) {
if (this.swordNames.isEmpty())
return true;
if (itemStack == null)
return this.swordNames.contains("AIR");
return this.swordNames.contains(itemStack.getType().name());
}
} }

View file

@ -0,0 +1,103 @@
package dev.esophose.playerparticles.styles;
import dev.esophose.playerparticles.PlayerParticles;
import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.manager.DataManager;
import dev.esophose.playerparticles.manager.ParticleManager;
import dev.esophose.playerparticles.particles.PParticle;
import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.particles.ParticlePair;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
public class ParticleStyleTeleport extends DefaultParticleStyle implements Listener {
private boolean before;
private boolean after;
private float amount;
private float spread;
private float speed;
public ParticleStyleTeleport() {
super("teleport", false, false, 0);
}
@Override
public List<PParticle> getParticles(ParticlePair particle, Location location) {
List<PParticle> particles = new ArrayList<>();
for (int i = 0; i < this.amount; i++)
particles.add(new PParticle(location, this.spread, this.spread, this.spread, this.speed));
return particles;
}
@Override
public void updateTimers() {
}
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("ENDER_PEARL");
}
@Override
protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("before", true, "Spawn the particles at the teleporting position");
this.setIfNotExists("after", true, "Spawn the particles after the teleport in the new position");
this.setIfNotExists("amount", 25, "The number of particles to spawn");
this.setIfNotExists("spread", 0.5, "How much to spread the particles");
this.setIfNotExists("speed", 0.05, "If the particle supports speed, how much speed to apply");
}
@Override
protected void loadSettings(CommentedFileConfiguration config) {
this.before = config.getBoolean("before");
this.after = config.getBoolean("after");
this.amount = config.getFloat("amount");
this.spread = config.getFloat("spread");
this.speed = config.getFloat("speed");
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerTeleport(PlayerTeleportEvent event) {
TeleportCause cause = event.getCause();
if (cause == TeleportCause.UNKNOWN)
return;
ParticleManager particleManager = PlayerParticles.getInstance().getManager(ParticleManager.class);
Player player = event.getPlayer();
PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId());
if (pplayer == null)
return;
for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.TELEPORT)) {
if (this.before) {
Location loc1 = player.getLocation().clone();
loc1.setY(loc1.getY() + 1);
particleManager.displayParticles(pplayer, player.getWorld(), particle, DefaultStyles.TELEPORT.getParticles(particle, loc1), false);
}
if (this.after) {
Bukkit.getScheduler().runTaskLater(PlayerParticles.getInstance(), () -> {
Location loc2 = player.getLocation().clone();
loc2.setY(loc2.getY() + 1);
particleManager.displayParticles(pplayer, player.getWorld(), particle, DefaultStyles.TELEPORT.getParticles(particle, loc2), false);
}, 1);
}
}
}
}

View file

@ -4,6 +4,7 @@ import dev.esophose.playerparticles.particles.PParticle;
import dev.esophose.playerparticles.particles.ParticlePair; import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -30,6 +31,11 @@ public class ParticleStyleThick extends DefaultParticleStyle {
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("COBWEB", "WEB");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("multiplier", 1, "The multiplier for the number of particles to spawn", "This style uses the same spawning as the 'normal' style"); this.setIfNotExists("multiplier", 1, "The multiplier for the number of particles to spawn", "This style uses the same spawning as the 'normal' style");

View file

@ -36,6 +36,11 @@ public class ParticleStyleTrail extends DefaultParticleStyle implements Listener
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("GHAST_TEAR");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("player-offset", 0.0, "How far to offset the player location vertically"); this.setIfNotExists("player-offset", 0.0, "How far to offset the player location vertically");
@ -56,12 +61,13 @@ public class ParticleStyleTrail extends DefaultParticleStyle implements Listener
Player player = event.getPlayer(); Player player = event.getPlayer();
PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId()); PPlayer pplayer = PlayerParticles.getInstance().getManager(DataManager.class).getPPlayer(player.getUniqueId());
if (pplayer != null) { if (pplayer == null)
for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.TRAIL)) { return;
Location loc = player.getLocation().clone();
loc.setY(loc.getY() + 1); for (ParticlePair particle : pplayer.getActiveParticlesForStyle(DefaultStyles.TRAIL)) {
particleManager.displayParticles(player, player.getWorld(), particle, DefaultStyles.TRAIL.getParticles(particle, loc), false); Location loc = player.getLocation().clone();
} loc.setY(loc.getY() + 1);
particleManager.displayParticles(pplayer, player.getWorld(), particle, DefaultStyles.TRAIL.getParticles(particle, loc), false);
} }
} }

View file

@ -5,6 +5,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -56,6 +57,11 @@ public class ParticleStyleTwins extends DefaultParticleStyle {
} }
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("OAK_FENCE", "FENCE");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("orbs", 2, "The number of particle orbs to spawn"); this.setIfNotExists("orbs", 2, "The number of particle orbs to spawn");

View file

@ -28,6 +28,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@ -66,6 +67,11 @@ public class ParticleStyleVortex extends DefaultParticleStyle {
this.step = (this.step + 1) % this.maxStep; this.step = (this.step + 1) % this.maxStep;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("GLOWSTONE_DUST");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("radius", 2.0, "The bottom radius of the vortex"); this.setIfNotExists("radius", 2.0, "The bottom radius of the vortex");

View file

@ -6,6 +6,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -74,6 +75,11 @@ public class ParticleStyleWhirl extends DefaultParticleStyle {
this.step = (this.step + Math.PI * 2 / this.numSteps) % this.numSteps; this.step = (this.step + Math.PI * 2 / this.numSteps) % this.numSteps;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("FEATHER");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("rays", 2, "The number of rays to spawn"); this.setIfNotExists("rays", 2, "The number of rays to spawn");

View file

@ -6,6 +6,7 @@ import dev.esophose.playerparticles.particles.ParticlePair;
import dev.esophose.playerparticles.config.CommentedFileConfiguration; import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
@ -74,6 +75,11 @@ public class ParticleStyleWhirlwind extends DefaultParticleStyle {
this.step = (this.step + Math.PI * 2 / this.numSteps) % this.numSteps; this.step = (this.step + Math.PI * 2 / this.numSteps) % this.numSteps;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Collections.singletonList("STRING");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("rays", 3, "The number of rays to spawn"); this.setIfNotExists("rays", 3, "The number of rays to spawn");

View file

@ -6,6 +6,8 @@ import dev.esophose.playerparticles.config.CommentedFileConfiguration;
import dev.esophose.playerparticles.util.MathL; import dev.esophose.playerparticles.util.MathL;
import dev.esophose.playerparticles.util.VectorUtils; import dev.esophose.playerparticles.util.VectorUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
@ -41,6 +43,11 @@ public class ParticleStyleWings extends DefaultParticleStyle {
this.spawnTimer %= this.spawnDelay; this.spawnTimer %= this.spawnDelay;
} }
@Override
protected List<String> getGuiIconMaterialNames() {
return Arrays.asList("ELYTRA", "RAW_CHICKEN");
}
@Override @Override
protected void setDefaultSettings(CommentedFileConfiguration config) { protected void setDefaultSettings(CommentedFileConfiguration config) {
this.setIfNotExists("spawn-delay", 3, "The number of ticks to wait between particle spawns"); this.setIfNotExists("spawn-delay", 3, "The number of ticks to wait between particle spawns");

View file

@ -1,8 +1,5 @@
package dev.esophose.playerparticles.util; package dev.esophose.playerparticles.util;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
@ -27,6 +24,8 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicePriority; import org.bukkit.plugin.ServicePriority;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
/** /**
* bStats collects some data for plugin authors. * bStats collects some data for plugin authors.
@ -34,7 +33,7 @@ import org.bukkit.plugin.ServicePriority;
* Check out https://bStats.org/ to learn more about bStats! * Check out https://bStats.org/ to learn more about bStats!
*/ */
@SuppressWarnings({"WeakerAccess", "unused"}) @SuppressWarnings({"WeakerAccess", "unused"})
public class Metrics { public class LegacyMetrics {
static { static {
// You can use the property to disable the check in your test environment // You can use the property to disable the check in your test environment
@ -44,7 +43,7 @@ public class Metrics {
new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'});
final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
// We want to make sure nobody just copy & pastes the example and use the wrong package names // We want to make sure nobody just copy & pastes the example and use the wrong package names
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) { if (LegacyMetrics.class.getPackage().getName().equals(defaultPackage) || LegacyMetrics.class.getPackage().getName().equals(examplePackage)) {
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
} }
} }
@ -79,7 +78,7 @@ public class Metrics {
* *
* @param plugin The plugin which stats should be submitted. * @param plugin The plugin which stats should be submitted.
*/ */
public Metrics(Plugin plugin) { public LegacyMetrics(Plugin plugin) {
if (plugin == null) { if (plugin == null) {
throw new IllegalArgumentException("Plugin cannot be null!"); throw new IllegalArgumentException("Plugin cannot be null!");
} }
@ -119,10 +118,8 @@ public class Metrics {
// Load the data // Load the data
serverUUID = config.getString("serverUuid"); serverUUID = config.getString("serverUuid");
logFailedRequests = config.getBoolean("logFailedRequests", false); logFailedRequests = config.getBoolean("logFailedRequests", false);
this.enabled = config.getBoolean("enabled", true); enabled = config.getBoolean("enabled", true);
logSentData = config.getBoolean("logSentData", false); if (enabled) {
logResponseStatusText = config.getBoolean("logResponseStatusText", false);
if (this.enabled) {
boolean found = false; boolean found = false;
// Search for all other bStats Metrics classes to see if we are the first one // Search for all other bStats Metrics classes to see if we are the first one
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) { for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
@ -133,10 +130,10 @@ public class Metrics {
} catch (NoSuchFieldException ignored) { } } catch (NoSuchFieldException ignored) { }
} }
// Register our service // Register our service
Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal); Bukkit.getServicesManager().register(LegacyMetrics.class, this, plugin, ServicePriority.Normal);
if (!found) { if (!found) {
// We are the first! // We are the first!
this.startSubmitting(); startSubmitting();
} }
} }
} }
@ -147,7 +144,7 @@ public class Metrics {
* @return Whether bStats is enabled or not. * @return Whether bStats is enabled or not.
*/ */
public boolean isEnabled() { public boolean isEnabled() {
return this.enabled; return enabled;
} }
/** /**
@ -158,13 +155,13 @@ public class Metrics {
timer.scheduleAtFixedRate(new TimerTask() { timer.scheduleAtFixedRate(new TimerTask() {
@Override @Override
public void run() { public void run() {
if (!Metrics.this.plugin.isEnabled()) { // Plugin was disabled if (!plugin.isEnabled()) { // Plugin was disabled
timer.cancel(); timer.cancel();
return; return;
} }
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
Bukkit.getScheduler().runTask(Metrics.this.plugin, Metrics.this::submitData); Bukkit.getScheduler().runTask(plugin, () -> submitData());
} }
}, 1000 * 60 * 5, 1000 * 60 * 30); }, 1000 * 60 * 5, 1000 * 60 * 30);
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
@ -178,15 +175,16 @@ public class Metrics {
* *
* @return The plugin specific data. * @return The plugin specific data.
*/ */
public JsonObject getPluginData() { public JSONObject getPluginData() {
JsonObject data = new JsonObject(); JSONObject data = new JSONObject();
String pluginName = this.plugin.getDescription().getName(); String pluginName = plugin.getDescription().getName();
String pluginVersion = this.plugin.getDescription().getVersion(); String pluginVersion = plugin.getDescription().getVersion();
data.addProperty("pluginName", pluginName); // Append the name of the plugin data.put("pluginName", pluginName); // Append the name of the plugin
data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin data.put("pluginVersion", pluginVersion); // Append the version of the plugin
data.add("customCharts", new JsonArray()); JSONArray customCharts = new JSONArray();
data.put("customCharts", customCharts);
return data; return data;
} }
@ -196,7 +194,7 @@ public class Metrics {
* *
* @return The server specific data. * @return The server specific data.
*/ */
private JsonObject getServerData() { private JSONObject getServerData() {
// Minecraft specific data // Minecraft specific data
int playerAmount; int playerAmount;
try { try {
@ -211,7 +209,6 @@ public class Metrics {
} }
int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
String bukkitVersion = Bukkit.getVersion(); String bukkitVersion = Bukkit.getVersion();
String bukkitName = Bukkit.getName();
// OS/Java specific data // OS/Java specific data
String javaVersion = System.getProperty("java.version"); String javaVersion = System.getProperty("java.version");
@ -220,20 +217,19 @@ public class Metrics {
String osVersion = System.getProperty("os.version"); String osVersion = System.getProperty("os.version");
int coreCount = Runtime.getRuntime().availableProcessors(); int coreCount = Runtime.getRuntime().availableProcessors();
JsonObject data = new JsonObject(); JSONObject data = new JSONObject();
data.addProperty("serverUUID", serverUUID); data.put("serverUUID", serverUUID);
data.addProperty("playerAmount", playerAmount); data.put("playerAmount", playerAmount);
data.addProperty("onlineMode", onlineMode); data.put("onlineMode", onlineMode);
data.addProperty("bukkitVersion", bukkitVersion); data.put("bukkitVersion", bukkitVersion);
data.addProperty("bukkitName", bukkitName);
data.addProperty("javaVersion", javaVersion); data.put("javaVersion", javaVersion);
data.addProperty("osName", osName); data.put("osName", osName);
data.addProperty("osArch", osArch); data.put("osArch", osArch);
data.addProperty("osVersion", osVersion); data.put("osVersion", osVersion);
data.addProperty("coreCount", coreCount); data.put("coreCount", coreCount);
return data; return data;
} }
@ -242,9 +238,9 @@ public class Metrics {
* Collects the data and sends it afterwards. * Collects the data and sends it afterwards.
*/ */
private void submitData() { private void submitData() {
final JsonObject data = this.getServerData(); final JSONObject data = getServerData();
JsonArray pluginData = new JsonArray(); JSONArray pluginData = new JSONArray();
// Search for all other bStats Metrics classes to get their plugin data // Search for all other bStats Metrics classes to get their plugin data
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) { for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
try { try {
@ -252,43 +248,27 @@ public class Metrics {
for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) { for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
try { try {
Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider()); pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider()));
if (plugin instanceof JsonObject) {
pluginData.add((JsonObject) plugin);
} else { // old bstats version compatibility
try {
Class<?> jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject");
if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) {
Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString");
jsonStringGetter.setAccessible(true);
String jsonString = (String) jsonStringGetter.invoke(plugin);
JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject();
pluginData.add(object);
}
} catch (ClassNotFoundException e) {
// minecraft version 1.14+
if (logFailedRequests) {
this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception ", e);
}
}
}
} catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) {
} }
} }
} catch (NoSuchFieldException ignored) { } } catch (NoSuchFieldException ignored) { }
} }
data.add("plugins", pluginData); data.put("plugins", pluginData);
// Create a new thread for the connection to the bStats server // Create a new thread for the connection to the bStats server
new Thread(() -> { new Thread(new Runnable() {
try { @Override
// Send the data public void run() {
sendData(this.plugin, data); try {
} catch (Exception e) { // Send the data
// Something went wrong! :( sendData(plugin, data);
if (logFailedRequests) { } catch (Exception e) {
this.plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + this.plugin.getName(), e); // Something went wrong! :(
if (logFailedRequests) {
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
}
} }
} }
}).start(); }).start();
@ -301,7 +281,7 @@ public class Metrics {
* @param data The data to send. * @param data The data to send.
* @throws Exception If the request failed. * @throws Exception If the request failed.
*/ */
private static void sendData(Plugin plugin, JsonObject data) throws Exception { private static void sendData(Plugin plugin, JSONObject data) throws Exception {
if (data == null) { if (data == null) {
throw new IllegalArgumentException("Data cannot be null!"); throw new IllegalArgumentException("Data cannot be null!");
} }

View file

@ -40,4 +40,16 @@ public final class NMSUtil {
return cachedVersionNumber; return cachedVersionNumber;
} }
/**
* @return true if the server is running Spigot or a fork, false otherwise
*/
public static boolean isSpigot() {
try {
Class.forName("org.spigotmc.SpigotConfig");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
} }

View file

@ -7,9 +7,16 @@ import org.bukkit.Material;
public final class ParticleUtils { public final class ParticleUtils {
public final static Material FALLBACK_MATERIAL;
private static List<String> blockMaterials, itemMaterials; private static List<String> blockMaterials, itemMaterials;
static { static {
if (NMSUtil.getVersionNumber() > 7) {
FALLBACK_MATERIAL = Material.BARRIER;
} else {
FALLBACK_MATERIAL = Material.BEDROCK;
}
blockMaterials = new ArrayList<>(); blockMaterials = new ArrayList<>();
itemMaterials = new ArrayList<>(); itemMaterials = new ArrayList<>();
@ -43,19 +50,19 @@ public final class ParticleUtils {
* Finds a block/item as a material from a list of possible strings * Finds a block/item as a material from a list of possible strings
* Contains a fallback to the barrier icon just in case * Contains a fallback to the barrier icon just in case
* *
* @param barrierFallback If the material should fall back to barrier * @param fallback If the material should fall back to barrier
* @param input A list of material names * @param input A list of material names
* @return The first matching material * @return The first matching material
*/ */
public static Material closestMatchWithFallback(boolean barrierFallback, String... input) { public static Material closestMatchWithFallback(boolean fallback, String... input) {
for (String name : input) { for (String name : input) {
Material mat = closestMatch(name); Material mat = closestMatch(name);
if (mat != null) if (mat != null)
return mat; return mat;
} }
if (barrierFallback) if (fallback)
return Material.BARRIER; return FALLBACK_MATERIAL;
return null; return null;
} }

View file

@ -2,8 +2,8 @@ package dev.esophose.playerparticles.util.inputparser;
import dev.esophose.playerparticles.particles.PPlayer; import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.particles.ParticleEffect; import dev.esophose.playerparticles.particles.ParticleEffect;
import dev.esophose.playerparticles.particles.color.NoteColor; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.particles.color.OrdinaryColor; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.styles.ParticleStyle; import dev.esophose.playerparticles.styles.ParticleStyle;
import dev.esophose.playerparticles.util.inputparser.parsable.ParsableMaterial; import dev.esophose.playerparticles.util.inputparser.parsable.ParsableMaterial;
import dev.esophose.playerparticles.util.inputparser.parsable.ParsableNoteColor; import dev.esophose.playerparticles.util.inputparser.parsable.ParsableNoteColor;

View file

@ -1,7 +1,10 @@
package dev.esophose.playerparticles.util.inputparser.parsable; package dev.esophose.playerparticles.util.inputparser.parsable;
import dev.esophose.playerparticles.particles.PPlayer; import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.util.NMSUtil;
import dev.esophose.playerparticles.util.inputparser.Parsable; import dev.esophose.playerparticles.util.inputparser.Parsable;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -9,10 +12,22 @@ import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class ParsableLocation extends Parsable<Location> { public class ParsableLocation extends Parsable<Location> {
private static Method LivingEntity_getTargetBlock;
static {
if (NMSUtil.getVersionNumber() < 8) {
try {
LivingEntity_getTargetBlock = LivingEntity.class.getDeclaredMethod("getTargetBlock", HashSet.class, int.class);
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
}
}
public ParsableLocation() { public ParsableLocation() {
super(Location.class); super(Location.class);
} }
@ -23,7 +38,18 @@ public class ParsableLocation extends Parsable<Location> {
Player player = pplayer.getPlayer(); Player player = pplayer.getPlayer();
if (player != null && input.equalsIgnoreCase("looking")) { if (player != null && input.equalsIgnoreCase("looking")) {
Block targetBlock = player.getTargetBlock((Set<Material>) null, 8); // Need the Set<Material> cast for 1.9 support Block targetBlock;
if (NMSUtil.getVersionNumber() > 7) {
targetBlock = player.getTargetBlock((Set<Material>) null, 8); // Need the Set<Material> cast for 1.9 support
} else {
try {
targetBlock = (Block) LivingEntity_getTargetBlock.invoke(player, null, 8);
} catch (ReflectiveOperationException e) {
targetBlock = player.getLocation().getBlock();
e.printStackTrace();
}
}
int maxDistanceSqrd = 6 * 6; int maxDistanceSqrd = 6 * 6;
if (targetBlock.getLocation().distanceSquared(player.getLocation()) > maxDistanceSqrd) if (targetBlock.getLocation().distanceSquared(player.getLocation()) > maxDistanceSqrd)
return null; // Looking at a block too far away return null; // Looking at a block too far away

View file

@ -1,7 +1,7 @@
package dev.esophose.playerparticles.util.inputparser.parsable; package dev.esophose.playerparticles.util.inputparser.parsable;
import dev.esophose.playerparticles.particles.PPlayer; import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.particles.color.NoteColor; import dev.esophose.playerparticles.particles.data.NoteColor;
import dev.esophose.playerparticles.util.inputparser.Parsable; import dev.esophose.playerparticles.util.inputparser.Parsable;
import java.util.List; import java.util.List;

View file

@ -1,7 +1,7 @@
package dev.esophose.playerparticles.util.inputparser.parsable; package dev.esophose.playerparticles.util.inputparser.parsable;
import dev.esophose.playerparticles.particles.PPlayer; import dev.esophose.playerparticles.particles.PPlayer;
import dev.esophose.playerparticles.particles.color.OrdinaryColor; import dev.esophose.playerparticles.particles.data.OrdinaryColor;
import dev.esophose.playerparticles.util.inputparser.Parsable; import dev.esophose.playerparticles.util.inputparser.Parsable;
import java.awt.Color; import java.awt.Color;
import java.util.Collections; import java.util.Collections;

View file

@ -1,11 +1,11 @@
name: PlayerParticles name: PlayerParticles
main: dev.esophose.playerparticles.PlayerParticles main: dev.esophose.playerparticles.PlayerParticles
version: @version@ version: '@version@'
api-version: 1.13 api-version: '1.13'
description: Display particles around your player and blocks using customized styles and data! description: Display particles around your player and blocks using customized styles and data!
author: Esophose author: Esophose
website: https://www.spigotmc.org/resources/playerparticles.40261/ website: https://www.spigotmc.org/resources/playerparticles.40261/
softdepend: [PlaceholderAPI] softdepend: [PlaceholderAPI, WorldGuard, WorldEdit]
commands: commands:
pp: pp:
description: The main PlayerParticles command. By default, opens the GUI. description: The main PlayerParticles command. By default, opens the GUI.

View file

@ -51,7 +51,7 @@ raincloud:
style: 'overhead' style: 'overhead'
data: '' data: ''
2: 2:
effect: 'rain' effect: 'dripping_water'
style: 'overhead' style: 'overhead'
data: '' data: ''
rainbows: rainbows:

View file

@ -10,7 +10,7 @@ For information about how to use the plugin or API within the plugin, please ref
### Server Compatibility ### Server Compatibility
This plugin is compatible with [Spigot](https://www.spigotmc.org/) and any forks, I recommend using [Paper](https://papermc.io/). This plugin is compatible with [Spigot](https://www.spigotmc.org/) and any forks, I recommend using [Paper](https://papermc.io/).
Using CraftBukkit will not work. Using CraftBukkit will not work.
The versions of Minecraft that are currently supported are 1.9.4-1.15.x. Support for 1.8.8 will not be added. The versions of Minecraft that are currently supported are `1.15.2-1.7.10`.
### Compilation ### Compilation

View file

@ -51,6 +51,11 @@ dependencies {
shadowJar { shadowJar {
archiveClassifier.set(null) archiveClassifier.set(null)
relocate('org.bstats', 'dev.esophose.playerparticles.libs.bstats')
relocate('org.slf4j', 'dev.esophose.playerparticles.libs.slf4j')
relocate('com.zaxxer.hikari', 'dev.esophose.playerparticles.libs.hikaricp')
relocate('org.codemc.worldguardwrapper', 'dev.esophose.playerparticles.libs.worldguardwrapper')
} }
jar { jar {

View file

@ -1,4 +1,4 @@
rootProject.name = 'PlayerParticles' rootProject.name = 'playerparticles'
include(':Plugin') include(':Plugin')
project(':Plugin').projectDir = file('Plugin') project(':Plugin').projectDir = file('Plugin')