Add some quality of life changes

This commit is contained in:
Esophose 2019-01-26 00:34:50 -07:00
parent e5f5760fb1
commit f306062bfa
25 changed files with 442 additions and 88 deletions

View file

@ -1,5 +1,17 @@
== UPDATING WILL DELETE YOUR CONFIG.YML ==
* Create a backup of your config.yml if you wish to import all your old settings!
=== v6.3 (Implemented so far) ===
+ Added the ability to remove particles by id/effect/style using '/pp remove <id>|<effect>|<style>'
+ The "Save New Group" button in the GUI now actually saves a new group and prompts for a name in chat (15 second timeout)
+ Added a click sound to the GUI for button clicks (Can be disabled in the config.yml)
* Reduced the number of particles that spawn for the styles 'blockbreak', 'blockplace', and 'swords'
* Fix GUI borders showing up as glass panes instead of stained glass panes on servers running 1.12.2 or earlier
* Fix a console error that occurs when trying to remove a group that doesn't exist
* Fix "[PlayerParticles] An error occurred retrieving an SQLite database connection: [SQLITE_BUSY] The database file is locked (database is locked)"
=== v6.2 ===
+ Added command '/ppo' which allows executing a /pp command as another player.
* Fix not being able to change the lore of the player skull in the GUI
* Fix the 'saved groups' count on the player skull in the GUI being one higher than it was supposed to be
=== v6.1 ===
* Fix a bug where sometimes the GUI was unable to be opened due to an error
* You can now use \n on the GUI lore lines in the *.lang file to break them into multiple lines

View file

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.esophose.playerparticles</groupId>
<artifactId>PlayerParticles</artifactId>
<version>6.2</version>
<version>6.3</version>
<name>PlayerParticles</name>
<url>https://github.com/Esophose/PlayerParticles</url>
<description>Display particles around your player using customized styles and data!</description>

View file

@ -1,8 +1,14 @@
/*
* TODO: v6.4+
* + Add new style(s) 'wings_<type>', multiple new wing types: fairy, demon
* + Add ability to create/manage fixed effects from the GUI (may get implemented later)
*/
/*
* TODO: v6.3
* + Add new style 'tornado'
* + Add new style 'doubleorbit'
* + Add new style(s) 'wings_<type>', multiple new wing types: fairy, demon
* + Add named colors to the color data
* * Display effects/styles in the GUI formatted to be more readable
* + Possibly add a couple new styles (tornado, doubleorbit)
*/
package com.esophose.playerparticles;
@ -12,6 +18,7 @@ import java.io.File;
import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
@ -21,6 +28,7 @@ import com.esophose.playerparticles.database.DatabaseConnector;
import com.esophose.playerparticles.database.MySqlDatabaseConnector;
import com.esophose.playerparticles.database.SqliteDatabaseConnector;
import com.esophose.playerparticles.gui.GuiHandler;
import com.esophose.playerparticles.gui.hook.PlayerChatHook;
import com.esophose.playerparticles.manager.LangManager;
import com.esophose.playerparticles.manager.ParticleManager;
import com.esophose.playerparticles.manager.SettingManager;
@ -59,10 +67,12 @@ public class PlayerParticles extends JavaPlugin {
this.registerCommands();
Bukkit.getPluginManager().registerEvents(new ParticleManager(), this);
Bukkit.getPluginManager().registerEvents(new PluginUpdateListener(), this);
Bukkit.getPluginManager().registerEvents(new GuiHandler(), this);
Bukkit.getPluginManager().registerEvents(new PPlayerMovementListener(), this);
PluginManager pm = Bukkit.getPluginManager();
pm.registerEvents(new ParticleManager(), this);
pm.registerEvents(new PluginUpdateListener(), this);
pm.registerEvents(new GuiHandler(), this);
pm.registerEvents(new PPlayerMovementListener(), this);
pm.registerEvents(new PlayerChatHook(), this);
saveDefaultConfig();
double configVersion = PSetting.VERSION.getDouble();
@ -153,6 +163,7 @@ public class PlayerParticles extends JavaPlugin {
ParticleGroup.reload();
GuiHandler.setup();
PlayerChatHook.setup();
ParticleManager.refreshData();
startParticleTask();

View file

@ -176,8 +176,8 @@ public class GroupCommandModule implements CommandModule {
group = ParticleGroup.getPresetGroup(groupName);
if (group != null) {
LangManager.sendMessage(pplayer, Lang.GROUP_REMOVE_PRESET);
return;
}
return;
}
// Delete the group and notify player

View file

@ -1,16 +1,21 @@
package com.esophose.playerparticles.command;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.bukkit.util.StringUtil;
import com.esophose.playerparticles.manager.DataManager;
import com.esophose.playerparticles.manager.LangManager;
import com.esophose.playerparticles.manager.LangManager.Lang;
import com.esophose.playerparticles.particles.PPlayer;
import com.esophose.playerparticles.particles.ParticleEffect;
import com.esophose.playerparticles.particles.ParticleGroup;
import com.esophose.playerparticles.particles.ParticlePair;
import com.esophose.playerparticles.styles.api.ParticleStyle;
public class RemoveCommandModule implements CommandModule {
@ -20,48 +25,92 @@ public class RemoveCommandModule implements CommandModule {
return;
}
int id = -1;
try {
id = Integer.parseInt(args[0]);
} catch (Exception ex) {
LangManager.sendMessage(pplayer, Lang.ID_INVALID);
return;
}
if (id <= 0) {
LangManager.sendMessage(pplayer, Lang.ID_INVALID);
return;
}
boolean removed = false;
ParticleGroup activeGroup = pplayer.getActiveParticleGroup();
for (ParticlePair particle : activeGroup.getParticles()) {
if (particle.getId() == id) {
activeGroup.getParticles().remove(particle);
removed = true;
break;
if (StringUtils.isNumeric(args[0])) { // Removing by ID
int id = -1;
try {
id = Integer.parseInt(args[0]);
} catch (Exception ex) {
LangManager.sendMessage(pplayer, Lang.ID_INVALID);
return;
}
if (id <= 0) {
LangManager.sendMessage(pplayer, Lang.ID_INVALID);
return;
}
boolean removed = false;
ParticleGroup activeGroup = pplayer.getActiveParticleGroup();
for (ParticlePair particle : activeGroup.getParticles()) {
if (particle.getId() == id) {
activeGroup.getParticles().remove(particle);
removed = true;
break;
}
}
if (!removed) {
LangManager.sendMessage(pplayer, Lang.ID_UNKNOWN, id);
return;
}
DataManager.saveParticleGroup(pplayer.getUniqueId(), activeGroup);
LangManager.sendMessage(pplayer, Lang.REMOVE_ID_SUCCESS, id);
} else { // Removing by effect/style name
ParticleEffect effect = ParticleEffect.fromName(args[0]);
ParticleStyle style = ParticleStyle.fromName(args[0]);
if (effect != null) {
int removedCount = 0;
ParticleGroup activeGroup = pplayer.getActiveParticleGroup();
for (int i = activeGroup.getParticles().size() - 1; i >= 0; i--) {
if (activeGroup.getParticles().get(i).getEffect() == effect) {
activeGroup.getParticles().remove(i);
removedCount++;
}
}
if (removedCount > 0) {
DataManager.saveParticleGroup(pplayer.getUniqueId(), activeGroup);
LangManager.sendMessage(pplayer, Lang.REMOVE_EFFECT_SUCCESS, removedCount, effect.getName());
} else {
LangManager.sendMessage(pplayer, Lang.REMOVE_EFFECT_NONE, effect.getName());
}
} else if (style != null) {
int removedCount = 0;
ParticleGroup activeGroup = pplayer.getActiveParticleGroup();
for (int i = activeGroup.getParticles().size() - 1; i >= 0; i--) {
if (activeGroup.getParticles().get(i).getStyle() == style) {
activeGroup.getParticles().remove(i);
removedCount++;
}
}
if (removedCount > 0) {
DataManager.saveParticleGroup(pplayer.getUniqueId(), activeGroup);
LangManager.sendMessage(pplayer, Lang.REMOVE_STYLE_SUCCESS, removedCount, style.getName());
} else {
LangManager.sendMessage(pplayer, Lang.REMOVE_STYLE_NONE, style.getName());
}
} else {
LangManager.sendMessage(pplayer, Lang.REMOVE_UNKNOWN, args[0]);
}
}
if (!removed) {
LangManager.sendMessage(pplayer, Lang.ID_UNKNOWN, id);
return;
}
DataManager.saveParticleGroup(pplayer.getUniqueId(), activeGroup);
LangManager.sendMessage(pplayer, Lang.REMOVE_SUCCESS, id);
}
public List<String> onTabComplete(PPlayer pplayer, String[] args) {
List<String> matches = new ArrayList<String>();
List<String> ids = new ArrayList<String>();
for (ParticlePair particles : pplayer.getActiveParticles())
ids.add(String.valueOf(particles.getId()));
if (args.length == 0) return ids;
StringUtil.copyPartialMatches(args[0], ids, matches);
Set<String> removeBy = new HashSet<String>();
for (ParticlePair particle : pplayer.getActiveParticles()) {
removeBy.add(String.valueOf(particle.getId()));
removeBy.add(particle.getEffect().getName());
removeBy.add(particle.getStyle().getName());
}
if (args.length == 0) return new ArrayList<String>(removeBy);
StringUtil.copyPartialMatches(args[0], removeBy, matches);
return matches;
}

View file

@ -10,6 +10,7 @@ import com.esophose.playerparticles.PlayerParticles;
public class SqliteDatabaseConnector implements DatabaseConnector {
private final String connectionString;
private Connection connection;
public SqliteDatabaseConnector(String directory) {
this.connectionString = "jdbc:sqlite:" + directory + File.separator + "playerparticles.db";
@ -20,14 +21,28 @@ public class SqliteDatabaseConnector implements DatabaseConnector {
}
public void closeConnection() {
// Nothing to do
try {
if (this.connection != null) {
this.connection.close();
}
} catch (SQLException ex) {
PlayerParticles.getPlugin().getLogger().severe("An error occurred closing the SQLite database connection: " + ex.getMessage());
}
}
public void connect(ConnectionCallback callback) {
try (Connection connection = DriverManager.getConnection(this.connectionString)) {
callback.execute(connection);
if (this.connection == null) {
try {
this.connection = DriverManager.getConnection(this.connectionString);
} catch (SQLException ex) {
PlayerParticles.getPlugin().getLogger().severe("An error occurred retrieving the SQLite database connection: " + ex.getMessage());
}
}
try {
callback.execute(this.connection);
} catch (SQLException ex) {
PlayerParticles.getPlugin().getLogger().severe("An error occurred retrieving an SQLite database connection: " + ex.getMessage());
PlayerParticles.getPlugin().getLogger().severe("An error occurred retrieving the SQLite database connection: " + ex.getMessage());
}
}

View file

@ -4,12 +4,15 @@ import java.util.ArrayList;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import com.esophose.playerparticles.manager.SettingManager.PSetting;
import com.esophose.playerparticles.particles.PPlayer;
import com.esophose.playerparticles.util.ParticleUtils;
@ -36,7 +39,7 @@ public abstract class GuiInventory {
if (this.material != null) { // Use 1.13 materials
borderIcon = new ItemStack(this.material, 1);
} else { // Use < 1.13 data values
borderIcon = new ItemStack(ParticleUtils.closestMatch("THIN_GLASS"), 1, this.data);
borderIcon = new ItemStack(ParticleUtils.closestMatch("STAINED_GLASS_PANE"), 1, this.data);
}
ItemMeta meta = borderIcon.getItemMeta();
@ -137,6 +140,12 @@ public abstract class GuiInventory {
for (GuiActionButton button : this.actionButtons) {
if (button.getSlot() == slot) {
button.handleClick(button, isShiftClick);
if (PSetting.GUI_BUTTON_SOUND.getBoolean()) {
if (event.getWhoClicked() instanceof Player) {
Player player = (Player) event.getWhoClicked();
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5f, 1);
}
}
break;
}
}

View file

@ -11,6 +11,7 @@ import com.esophose.playerparticles.manager.SettingManager.GuiIcon;
import com.esophose.playerparticles.particles.PPlayer;
import com.esophose.playerparticles.particles.ParticleEffect;
import com.esophose.playerparticles.particles.ParticlePair;
import com.esophose.playerparticles.util.ParticleUtils;
public class GuiInventoryEditEffect extends GuiInventory {
@ -23,8 +24,8 @@ public class GuiInventoryEditEffect extends GuiInventory {
ParticleEffect effect = effectsUserHasPermissionFor.get(i);
GuiActionButton selectButton = new GuiActionButton(i,
GuiIcon.EFFECT.get(effect.getName()),
LangManager.getText(Lang.GUI_COLOR_ICON_NAME) + effect.getName(),
new String[] { LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_SELECT_EFFECT_DESCRIPTION, effect.getName()) },
LangManager.getText(Lang.GUI_COLOR_ICON_NAME) + ParticleUtils.formatName(effect.getName()),
new String[] { LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_SELECT_EFFECT_DESCRIPTION, ParticleUtils.formatName(effect.getName())) },
(button, isShiftClick) -> {
editingParticle.setEffect(effect);
callbackList.get(callbackListPosition + 1).execute();

View file

@ -11,6 +11,7 @@ import com.esophose.playerparticles.manager.SettingManager.GuiIcon;
import com.esophose.playerparticles.particles.PPlayer;
import com.esophose.playerparticles.particles.ParticlePair;
import com.esophose.playerparticles.styles.api.ParticleStyle;
import com.esophose.playerparticles.util.ParticleUtils;
public class GuiInventoryEditStyle extends GuiInventory {
@ -23,8 +24,8 @@ public class GuiInventoryEditStyle extends GuiInventory {
ParticleStyle style = stylesUserHasPermissionFor.get(i);
GuiActionButton selectButton = new GuiActionButton(i,
GuiIcon.STYLE.get(style.getName()),
LangManager.getText(Lang.GUI_COLOR_ICON_NAME) + style.getName(),
new String[] { LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_SELECT_EFFECT_DESCRIPTION, style.getName()) },
LangManager.getText(Lang.GUI_COLOR_ICON_NAME) + ParticleUtils.formatName(style.getName()),
new String[] { LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_SELECT_EFFECT_DESCRIPTION, ParticleUtils.formatName(style.getName())) },
(button, isShiftClick) -> {
editingParticle.setStyle(style);
callbackList.get(callbackListPosition + 1).execute();

View file

@ -14,6 +14,7 @@ import com.esophose.playerparticles.manager.SettingManager.GuiIcon;
import com.esophose.playerparticles.particles.PPlayer;
import com.esophose.playerparticles.particles.ParticleGroup;
import com.esophose.playerparticles.particles.ParticlePair;
import com.esophose.playerparticles.util.ParticleUtils;
public class GuiInventoryLoadPresetGroups extends GuiInventory {
@ -36,7 +37,7 @@ public class GuiInventoryLoadPresetGroups extends GuiInventory {
lore[0] = LangManager.getText(Lang.GUI_COLOR_SUBTEXT) + LangManager.getText(Lang.GUI_CLICK_TO_LOAD, particles.size());
int i = 1;
for (ParticlePair particle : particles) {
lore[i] = LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_PARTICLE_INFO, particle.getId(), particle.getEffect().getName(), particle.getStyle().getName(), particle.getDataString());
lore[i] = LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_PARTICLE_INFO, particle.getId(), ParticleUtils.formatName(particle.getEffect().getName()), ParticleUtils.formatName(particle.getStyle().getName()), particle.getDataString());
i++;
}

View file

@ -1,17 +1,22 @@
package com.esophose.playerparticles.gui;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import org.bukkit.Bukkit;
import com.esophose.playerparticles.gui.hook.PlayerChatHook;
import com.esophose.playerparticles.gui.hook.PlayerChatHookData;
import com.esophose.playerparticles.manager.DataManager;
import com.esophose.playerparticles.manager.LangManager;
import com.esophose.playerparticles.manager.PermissionManager;
import com.esophose.playerparticles.manager.LangManager.Lang;
import com.esophose.playerparticles.manager.SettingManager.GuiIcon;
import com.esophose.playerparticles.particles.PPlayer;
import com.esophose.playerparticles.particles.ParticleGroup;
import com.esophose.playerparticles.particles.ParticlePair;
import com.esophose.playerparticles.util.ParticleUtils;
public class GuiInventoryManageGroups extends GuiInventory {
@ -36,7 +41,7 @@ public class GuiInventoryManageGroups extends GuiInventory {
lore[0] = LangManager.getText(Lang.GUI_COLOR_SUBTEXT) + LangManager.getText(Lang.GUI_CLICK_TO_LOAD, particles.size());
int i = 1;
for (ParticlePair particle : particles) {
lore[i] = LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_PARTICLE_INFO, particle.getId(), particle.getEffect().getName(), particle.getStyle().getName(), particle.getDataString());
lore[i] = LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_PARTICLE_INFO, particle.getId(), ParticleUtils.formatName(particle.getEffect().getName()), ParticleUtils.formatName(particle.getStyle().getName()), particle.getDataString());
i++;
}
lore[i] = LangManager.getText(Lang.GUI_COLOR_UNAVAILABLE) + LangManager.getText(Lang.GUI_SHIFT_CLICK_TO_DELETE);
@ -68,15 +73,67 @@ public class GuiInventoryManageGroups extends GuiInventory {
if (index > maxIndex) break; // Overflowed the available space
}
boolean canSaveGroup = !PermissionManager.hasPlayerReachedMaxGroups(pplayer);
String[] lore;
if (canSaveGroup) {
lore = new String[] { LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_SAVE_GROUP_DESCRIPTION) };
} else {
lore = new String[] {
LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_SAVE_GROUP_DESCRIPTION),
LangManager.getText(Lang.GUI_COLOR_UNAVAILABLE) + LangManager.getText(Lang.GUI_SAVE_GROUP_FULL)
};
}
// Save Group Button
GuiActionButton saveGroupButton = new GuiActionButton(40,
GuiIcon.CREATE.get(),
LangManager.getText(Lang.GUI_COLOR_ICON_NAME) + LangManager.getText(Lang.GUI_SAVE_GROUP),
new String[] {
LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_SAVE_GROUP_DESCRIPTION),
LangManager.getText(Lang.GUI_COLOR_SUBTEXT) + LangManager.getText(Lang.GUI_SAVE_GROUP_DESCRIPTION_2),
},
(button, isShiftClick) -> {}); // Does nothing on click
lore,
(button, isShiftClick) -> {
if (!canSaveGroup) return;
PlayerChatHook.addHook(new PlayerChatHookData(pplayer.getUniqueId(), 15, (textEntered) -> {
if (textEntered == null || textEntered.equalsIgnoreCase("cancel")) {
GuiHandler.transition(new GuiInventoryManageGroups(pplayer));
} else {
String groupName = textEntered.split(" ")[0];
// Check that the groupName isn't the reserved name
if (groupName.equalsIgnoreCase(ParticleGroup.DEFAULT_NAME)) {
LangManager.sendMessage(pplayer, Lang.GROUP_RESERVED);
return;
}
// The database column can only hold up to 100 characters, cut it off there
if (groupName.length() >= 100) {
groupName = groupName.substring(0, 100);
}
// Use the existing group if available, otherwise create a new one
ParticleGroup group = pplayer.getParticleGroupByName(groupName);
boolean groupUpdated = false;
if (group == null) {
List<ParticlePair> particles = new ArrayList<ParticlePair>();
for (ParticlePair particle : pplayer.getActiveParticles())
particles.add(particle.clone()); // Make sure the ParticlePairs aren't the same references in both the active and saved group
group = new ParticleGroup(groupName, particles);
} else {
groupUpdated = true;
}
// Apply changes and notify player
DataManager.saveParticleGroup(pplayer.getUniqueId(), group);
if (groupUpdated) {
LangManager.sendMessage(pplayer, Lang.GROUP_SAVE_SUCCESS_OVERWRITE, groupName);
} else {
LangManager.sendMessage(pplayer, Lang.GROUP_SAVE_SUCCESS, groupName);
}
GuiHandler.transition(new GuiInventoryManageGroups(pplayer));
}
}));
pplayer.getPlayer().closeInventory();
});
this.actionButtons.add(saveGroupButton);
// Back Button

View file

@ -15,6 +15,7 @@ import com.esophose.playerparticles.particles.PPlayer;
import com.esophose.playerparticles.particles.ParticleGroup;
import com.esophose.playerparticles.particles.ParticlePair;
import com.esophose.playerparticles.particles.ParticleEffect.ParticleProperty;
import com.esophose.playerparticles.util.ParticleUtils;
public class GuiInventoryManageParticles extends GuiInventory {
@ -36,7 +37,7 @@ public class GuiInventoryManageParticles extends GuiInventory {
LangManager.getText(Lang.GUI_COLOR_ICON_NAME) + LangManager.getText(Lang.GUI_PARTICLE_NAME, particle.getId()),
new String[] {
LangManager.getText(Lang.GUI_COLOR_SUBTEXT) + LangManager.getText(Lang.GUI_CLICK_TO_EDIT_PARTICLE, particles.size()),
LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_PARTICLE_INFO, particle.getId(), particle.getEffect().getName(), particle.getStyle().getName(), particle.getDataString()),
LangManager.getText(Lang.GUI_COLOR_INFO) + LangManager.getText(Lang.GUI_PARTICLE_INFO, particle.getId(), ParticleUtils.formatName(particle.getEffect().getName()), ParticleUtils.formatName(particle.getStyle().getName()), particle.getDataString()),
LangManager.getText(Lang.GUI_COLOR_UNAVAILABLE) + LangManager.getText(Lang.GUI_SHIFT_CLICK_TO_DELETE)
},
(button, isShiftClick) -> {

View file

@ -0,0 +1,95 @@
package com.esophose.playerparticles.gui.hook;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import com.esophose.playerparticles.PlayerParticles;
import com.esophose.playerparticles.manager.LangManager;
import com.esophose.playerparticles.manager.LangManager.Lang;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
public class PlayerChatHook extends BukkitRunnable implements Listener {
private static Set<PlayerChatHookData> hooks;
private static BukkitTask hookTask = null;
/**
* Initializes all the static values for this class
*/
public static void setup() {
hooks = new HashSet<PlayerChatHookData>();
if (hookTask != null)
hookTask.cancel();
hookTask = new PlayerChatHook().runTaskTimer(PlayerParticles.getPlugin(), 0, 20);
}
/**
* Called when a player sends a message in chat
*
* @param event The AsyncPlayerChatEvent
*/
@EventHandler
public void onPlayerChat(AsyncPlayerChatEvent event) {
for (PlayerChatHookData hook : hooks) {
if (hook.getPlayerUUID().equals(event.getPlayer().getUniqueId())) {
event.setCancelled(true);
hook.triggerCallback(event.getMessage());
hooks.remove(hook);
return;
}
}
}
/**
* Ticked every second to decrease the seconds remaining on each hook
*/
public void run() {
Set<PlayerChatHookData> hooksToRemove = new HashSet<PlayerChatHookData>();
for (PlayerChatHookData hook : hooks) {
hook.decrementHookLength();
if (hook.timedOut()) {
hook.triggerCallback(null);
hooksToRemove.add(hook);
continue;
}
Player player = Bukkit.getPlayer(hook.getPlayerUUID());
if (player == null) {
hooksToRemove.remove(hook);
} else {
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(LangManager.getText(Lang.GUI_SAVE_GROUP_HOTBAR_MESSAGE, hook.getTimeRemaining())));
}
}
for (PlayerChatHookData hookToRemove : hooksToRemove)
hooks.remove(hookToRemove);
}
/**
* Adds a player chat hook
*
* @param newHook The new hook to add
*/
public static void addHook(PlayerChatHookData newHook) {
for (PlayerChatHookData hook : hooks) {
if (hook.getPlayerUUID().equals(hook.getPlayerUUID())) {
hooks.remove(hook);
break;
}
}
hooks.add(newHook);
}
}

View file

@ -0,0 +1,68 @@
package com.esophose.playerparticles.gui.hook;
import java.util.UUID;
public class PlayerChatHookData {
private UUID playerUUID;
private int hookLength;
private PlayerChatHookCallback hookCallback;
public PlayerChatHookData(UUID playerUUID, int hookLength, PlayerChatHookCallback hookCallback) {
this.playerUUID = playerUUID;
this.hookLength = hookLength;
this.hookCallback = hookCallback;
}
/**
* Gets the owning player of this hook
*
* @return The player's UUID
*/
public UUID getPlayerUUID() {
return this.playerUUID;
}
/**
* Decrements the time remaining on this hook by 1 second
*/
public void decrementHookLength() {
this.hookLength--;
}
/**
* Checks if this hook has timed out
*
* @return If this hook has timed out
*/
public boolean timedOut() {
return this.hookLength <= 0;
}
/**
* Gets how much time is remaining on the hook
*
* @return The amount of time remaining on the hook
*/
public int getTimeRemaining() {
return this.hookLength;
}
/**
* Executes the callback function
*
* @param textEntered The text that was entered by the player
*/
public void triggerCallback(String textEntered) {
this.hookCallback.onPlayerChat(textEntered);
}
/**
* Allows simple hooking into the player chat for a specific time interval
*/
@FunctionalInterface
public static interface PlayerChatHookCallback {
public void onPlayerChat(String textEntered);
}
}

View file

@ -112,7 +112,12 @@ public class LangManager {
// Remove Command
REMOVE_NO_ARGS,
REMOVE_SUCCESS,
REMOVE_ID_SUCCESS,
REMOVE_EFFECT_SUCCESS,
REMOVE_EFFECT_NONE,
REMOVE_STYLE_SUCCESS,
REMOVE_STYLE_NONE,
REMOVE_UNKNOWN,
// List Command
LIST_NONE,
@ -213,6 +218,9 @@ public class LangManager {
FIXED_MAX_REACHED,
FIXED_INVALID_COMMAND,
// Update Available
UPDATE_AVAILABLE,
// GUI
GUI_DISABLED,
GUI_COLOR_ICON_NAME,
@ -245,7 +253,8 @@ public class LangManager {
GUI_LOAD_A_PRESET_GROUP_DESCRIPTION,
GUI_SAVE_GROUP,
GUI_SAVE_GROUP_DESCRIPTION,
GUI_SAVE_GROUP_DESCRIPTION_2,
GUI_SAVE_GROUP_FULL,
GUI_SAVE_GROUP_HOTBAR_MESSAGE,
GUI_RESET_PARTICLES,
GUI_RESET_PARTICLES_DESCRIPTION,
GUI_PARTICLE_NAME,
@ -288,12 +297,7 @@ public class LangManager {
GUI_EDIT_DATA_COLOR_BLACK,
GUI_EDIT_DATA_COLOR_GRAY,
GUI_EDIT_DATA_COLOR_LIGHT_GRAY,
GUI_EDIT_DATA_COLOR_WHITE,
// Update Available
UPDATE_AVAILABLE;
// @formatter:on
GUI_EDIT_DATA_COLOR_WHITE; // @formatter:on
private String message;

View file

@ -32,6 +32,7 @@ public class SettingManager {
TICKS_PER_PARTICLE(PSettingType.LONG),
CHECK_UPDATES(PSettingType.BOOLEAN),
GUI_ENABLED(PSettingType.BOOLEAN),
GUI_BUTTON_SOUND(PSettingType.BOOLEAN),
TOGGLE_ON_MOVE(PSettingType.BOOLEAN),
PARTICLE_RENDER_RANGE_PLAYER(PSettingType.INTEGER),

View file

@ -24,7 +24,7 @@ public class ParticleStyleBlockBreak implements ParticleStyle, Listener {
location.add(0.5, 0.5, 0.5); // Center around the block
for (int i = 0; i < 15; i++)
for (int i = 0; i < 10; i++)
particles.add(new PParticle(location, 0.5F, 0.5F, 0.5F, 0.05F));
return particles;

View file

@ -24,7 +24,7 @@ public class ParticleStyleBlockPlace implements ParticleStyle, Listener {
location.add(0.5, 0.5, 0.5); // Center around the block
for (int i = 0; i < 15; i++)
for (int i = 0; i < 10; i++)
particles.add(new PParticle(location, 0.75F, 0.75F, 0.75F, 0.05F));
return particles;

View file

@ -29,9 +29,9 @@ public class ParticleStyleSwords implements ParticleStyle, Listener {
}
public List<PParticle> getParticles(ParticlePair particle, Location location) {
List<PParticle> baseParticles = DefaultStyles.THICK.getParticles(particle, location);
List<PParticle> baseParticles = DefaultStyles.NORMAL.getParticles(particle, location);
int multiplyingFactor = 3; // Uses the same logic as ParticleStyleThick except multiplies the resulting particles by 3x
int multiplyingFactor = 15; // Uses the same logic as ParticleStyleNormal except multiplies the resulting particles by 3x
List<PParticle> particles = new ArrayList<PParticle>();
for (int i = 0; i < baseParticles.size() * multiplyingFactor; i++) {
particles.add(baseParticles.get(i % baseParticles.size()));

View file

@ -53,12 +53,13 @@ public interface ParticleStyle {
/**
* Gets the ParticleStyle with the name given, returns null if not found
*
* @param styleName The string of the style to search for
* @return The ParticleStyle with the name requested
* @param styleName The name of the style to search for
* @return The ParticleStyle with a matching name
*/
public static ParticleStyle fromName(String styleName) {
for (ParticleStyle style : ParticleStyleManager.getStyles())
if (style.getName().equals(styleName)) return style;
if (style.getName().equalsIgnoreCase(styleName))
return style;
return null;
}

View file

@ -21,6 +21,10 @@ public class ParticleUtils {
}
}
}
private ParticleUtils() {
}
/**
* Finds a block/item as a material from a string
@ -76,6 +80,20 @@ public class ParticleUtils {
public static List<String> getAllItemMaterials() {
return itemMaterials;
}
/**
* Formats a string from the format "word_word" to "Word Word"
*
* @param string The input string
* @return The input string but formatted with each word capitalized
*/
public static String formatName(String string) {
String[] words = string.split("_");
String result = "";
for (String word : words)
result += Character.toUpperCase(word.charAt(0)) + word.substring(1).toLowerCase() + " ";
return result;
}
/**
* Gets the smallest positive integer from an array

View file

@ -13,7 +13,7 @@
# This value is the version of the plugin that last modified the config file
# Changing this value manually will likely result in data loss and errors!
# Do not change this manually unless specifically told to by the plugin author
version: 6.2
version: 6.3
# Check for new versions of the plugin
# Default: true
@ -41,6 +41,10 @@ message-prefix: '&7[&3PlayerParticles&7]'
# Default: true
gui-enabled: true
# If clicking a GUI button should make a noise
# Default: true
gui-button-sound: true
# 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

View file

@ -44,4 +44,4 @@ angel:
2:
effect: 'dust'
style: 'halo'
data: '255 255 0'
data: '255 255 0'

View file

@ -99,7 +99,12 @@ reload-no-permission: '&cYou do not have permission to reload the plugin setting
# Remove Command
remove-no-args: '&cYou did not specify an ID to remove! &b/pp remove <ID>'
remove-success: '&aYour particle with the ID &b{0} &ahas been removed!'
remove-id-success: '&aYour particle with the ID &b{0} &ahas been removed!'
remove-effect-success: '&aRemoved &b{0} &aof your particles with the effect of &b{1}&a!'
remove-effect-none: '&cYou do not have any particles applied with the effect &b{0}&c!'
remove-style-success: '&aRemoved &b{0} &aof your particles with the style of &b{1}&a!'
remove-style-none: '&cYou do not have any particles applied with the style &b{0}&c!'
remove-unknown: '&cAn effect or style with the name of &b{0} &cdoes not exist!'
# List Command
list-none: '&eYou do not have any active particles!'
@ -111,10 +116,10 @@ toggle-on: '&eParticles have been toggled &aON&e!'
toggle-off: '&eParticles have been toggled &cOFF&e!'
# Rainbow
rainbow: '&cr&6a&ei&an&bb&9o&dw'
rainbow: '&cR&6a&ei&an&bb&9o&dw'
# Random
random: 'random'
random: 'Random'
# Effects
effect-no-permission: '&cYou do not have permission to use the effect &b{0} &c!'
@ -200,6 +205,9 @@ fixed-no-permission: '&cYou do not have permission to use fixed effects!'
fixed-max-reached: '&cYou have reached the maximum allowed fixed effects!'
fixed-invalid-command: '&cInvalid sub-command for &b/pp fixed&c!'
# Update Available
update-available: '&eAn update (&b{0}&e) is available! You are running &bv{1}&e. https://www.spigotmc.org/resources/playerparticles.40261/'
# GUI
gui-disabled: '&cThe server administrator has disabled the GUI!'
gui-color-icon-name: '&a'
@ -231,8 +239,9 @@ gui-manage-your-groups-description: 'Create, delete, and load your particle grou
gui-load-a-preset-group: 'Load A Preset Group'
gui-load-a-preset-group-description: 'Load a premade particle group'
gui-save-group: 'Save New Group'
gui-save-group-description: 'You can save a new group using the following command:'
gui-save-group-description-2: '/pp group save <groupName>'
gui-save-group-description: 'Click to save a new group. You will be prompted\nto enter the new group name in chat.'
gui-save-group-full: 'You have reached the max number of groups'
gui-save-group-hotbar-message: '&eType &b1 &eword in chat for the new group name. Type "&ccancel&e" to cancel. (&b{0}&es left)'
gui-reset-particles: 'Reset Your Particles'
gui-reset-particles-description: 'Deletes all your active particles'
gui-particle-name: 'Particle #{0}'
@ -276,6 +285,3 @@ gui-edit-data-color-black: '&8black'
gui-edit-data-color-gray: '&8gray'
gui-edit-data-color-light-gray: '&7light gray'
gui-edit-data-color-white: '&fwhite'
# Update Available
update-available: '&eAn update (&b{0}&e) is available! You are running &bv{1}&e. https://www.spigotmc.org/resources/playerparticles.40261/'

View file

@ -1,6 +1,6 @@
name: PlayerParticles
main: com.esophose.playerparticles.PlayerParticles
version: 6.2
version: 6.3
api-version: 1.13
description: Display particles around your player using customized styles and data!
author: Esophose