Implement /magnet command
This commit is contained in:
parent
ea247c30c7
commit
7665618c22
@ -1,5 +1,6 @@
|
||||
package dev.w1zzrd.invtweaks;
|
||||
|
||||
import dev.w1zzrd.invtweaks.command.MagnetCommandExecutor;
|
||||
import dev.w1zzrd.invtweaks.command.SortCommandExecutor;
|
||||
import dev.w1zzrd.invtweaks.listener.SortListener;
|
||||
import dev.w1zzrd.invtweaks.listener.StackReplaceListener;
|
||||
@ -21,8 +22,16 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
||||
*/
|
||||
public static final String LOG_PLUGIN_NAME = "[InventoryTweaks]";
|
||||
|
||||
// TODO: Magic values: make a config
|
||||
private static final double MAGNET_DISTANCE = 8.0;
|
||||
private static final long MAGNET_INTERVAL = 5;
|
||||
private static final int MAGNET_SUBDIVIDE = 2;
|
||||
|
||||
private final Logger logger = Bukkit.getLogger();
|
||||
|
||||
// Command executor references in case I need them or something idk
|
||||
private SortCommandExecutor sortCommandExecutor;
|
||||
private MagnetCommandExecutor magnetCommandExecutor;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
@ -36,8 +45,8 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
||||
public void onDisable() {
|
||||
logger.fine(LOG_PLUGIN_NAME + " Plugin disabled");
|
||||
|
||||
// Un-register all listeners
|
||||
HandlerList.unregisterAll(this);
|
||||
disableEvents();
|
||||
disableCommands();
|
||||
}
|
||||
|
||||
|
||||
@ -45,7 +54,12 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
||||
* Initialize commands registered by this plugin
|
||||
*/
|
||||
private void initCommands() {
|
||||
Objects.requireNonNull(getCommand("sort")).setExecutor(new SortCommandExecutor());
|
||||
sortCommandExecutor = new SortCommandExecutor();
|
||||
magnetCommandExecutor = new MagnetCommandExecutor(this, MAGNET_DISTANCE, MAGNET_INTERVAL, MAGNET_SUBDIVIDE);
|
||||
|
||||
// TODO: Bind command by annotation
|
||||
Objects.requireNonNull(getCommand("sort")).setExecutor(sortCommandExecutor);
|
||||
Objects.requireNonNull(getCommand("magnet")).setExecutor(magnetCommandExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,7 +68,24 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
||||
private void initEvents() {
|
||||
final PluginManager pluginManager = getServer().getPluginManager();
|
||||
|
||||
// TODO: Register listeners by annotation
|
||||
pluginManager.registerEvents(new StackReplaceListener(), this);
|
||||
pluginManager.registerEvents(new SortListener(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do whatever is necessary to disable commands and their execution
|
||||
*/
|
||||
private void disableCommands() {
|
||||
sortCommandExecutor = null;
|
||||
magnetCommandExecutor = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do whatever is necessary to disable event listeners
|
||||
*/
|
||||
private void disableEvents() {
|
||||
// Un-register all listeners
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
}
|
||||
|
229
src/dev/w1zzrd/invtweaks/command/MagnetCommandExecutor.java
Normal file
229
src/dev/w1zzrd/invtweaks/command/MagnetCommandExecutor.java
Normal file
@ -0,0 +1,229 @@
|
||||
package dev.w1zzrd.invtweaks.command;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MagnetCommandExecutor implements CommandExecutor {
|
||||
|
||||
/**
|
||||
* List of players with magnet mode active
|
||||
*/
|
||||
private final List<UUID> activeMagnets = new ArrayList<>();
|
||||
private final List<UUID> activeMagnetsView = Collections.unmodifiableList(activeMagnets);
|
||||
|
||||
private final Plugin plugin;
|
||||
private final long interval;
|
||||
private final int subdivide;
|
||||
|
||||
private final double sqRadius;
|
||||
|
||||
|
||||
private int divIndex = 0;
|
||||
|
||||
private BukkitTask refreshTask = null;
|
||||
|
||||
/**
|
||||
* Initialize the magnet executor and manger
|
||||
* @param plugin Owner plugin for this executor
|
||||
* @param sqRadius Radius of the cube to search for items in (half side length)
|
||||
* @param interval Interval (in ticks) between magnetism checks for active magnets
|
||||
* @param subdivide What fraction of the list of active magnets should be iterated over during a magnetism check.
|
||||
* Set to 1 to check the whole list each iteration
|
||||
*/
|
||||
public MagnetCommandExecutor(final Plugin plugin, final double sqRadius, final long interval, final int subdivide) {
|
||||
this.plugin = plugin;
|
||||
this.sqRadius = sqRadius;
|
||||
this.interval = interval;
|
||||
this.subdivide = subdivide;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player))
|
||||
return false;
|
||||
|
||||
toggleMagnet((Player) sender);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle magnet state for the given player
|
||||
* @param player Player to toggle state for
|
||||
* @return True if, after this method call, the UUID is part of the list of active magnets, else false.
|
||||
*/
|
||||
public boolean toggleMagnet(final Player player) {
|
||||
return toggleMagnet(player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle magnet state for the given UUID
|
||||
* @param uuid UUID to toggle state for
|
||||
* @return True if, after this method call, the UUID is part of the list of active magnets, else false.
|
||||
*/
|
||||
public boolean toggleMagnet(final UUID uuid) {
|
||||
try {
|
||||
final int index = Collections.binarySearch(activeMagnets, uuid);
|
||||
|
||||
// See JavaDoc: Collections.binarySearch
|
||||
if (index < 0) {
|
||||
activeMagnets.add(-(index + 1), uuid);
|
||||
return true;
|
||||
} else {
|
||||
activeMagnets.remove(index);
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
updateMagnetismTask();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an list of the currently active magnets
|
||||
* @return Unmodifiable list view of the active magnets
|
||||
*/
|
||||
public List<UUID> getActiveMagnets() {
|
||||
return activeMagnetsView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a player from the list of active magnets
|
||||
* @param player Player to remove from active magnets
|
||||
* @return True if a call to this method changed the list of active magnets
|
||||
*/
|
||||
public boolean removeMagnet(final Player player) {
|
||||
return removeMagnet(player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a UUID from the list of active magnets
|
||||
* @param uuid UUID to remove from active magnets
|
||||
* @return True if a call to this method changed the list of active magnets
|
||||
*/
|
||||
public boolean removeMagnet(final UUID uuid) {
|
||||
try {
|
||||
final int index = Collections.binarySearch(activeMagnets, uuid);
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
activeMagnets.remove(index);
|
||||
return true;
|
||||
} finally {
|
||||
updateMagnetismTask();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a player to the list of active magnets
|
||||
* @param player Player to mark as a magnet
|
||||
* @return True if a call to this method changed the list of active magnets
|
||||
*/
|
||||
public boolean addMagnet(final Player player) {
|
||||
return addMagnet(player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a UUID to the list of active magnets
|
||||
* @param uuid UUID to mark as a magnet
|
||||
* @return True if a call to this method changed the list of active magnets
|
||||
*/
|
||||
public boolean addMagnet(final UUID uuid) {
|
||||
try {
|
||||
final int index = Collections.binarySearch(activeMagnets, uuid);
|
||||
|
||||
if (index < 0) {
|
||||
activeMagnets.add(-(index + 1), uuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} finally {
|
||||
updateMagnetismTask();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given player is a magnet
|
||||
* @param player Player to check magnet state for
|
||||
* @return True if the given player is marked as a magnet
|
||||
*/
|
||||
public boolean isMagnet(final Player player) {
|
||||
return isMagnet(player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given UUID is registered as a magnet
|
||||
* @param uuid UUID of a player to check
|
||||
* @return True if the given UUID is marked as a magnet
|
||||
*/
|
||||
public boolean isMagnet(final UUID uuid) {
|
||||
return Collections.binarySearch(activeMagnets, uuid) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a magnet refresh task needs to be registered for magnet players<br><br>
|
||||
*
|
||||
* A refresh is created if there are active magnet players, there it no active refresh task and the plugin is
|
||||
* enabled. The refresh task is cancelled and state reset if there are no active magnet players, or the plugin is
|
||||
* disabled.
|
||||
*/
|
||||
private void updateMagnetismTask() {
|
||||
if (refreshTask == null && activeMagnets.size() > 0 && plugin.isEnabled())
|
||||
refreshTask = Bukkit.getScheduler().runTaskTimer(plugin, this::taskApplyMagnetism, 0, interval);
|
||||
else if (refreshTask != null && (activeMagnets.size() == 0 || !plugin.isEnabled())) {
|
||||
Bukkit.getScheduler().cancelTask(refreshTask.getTaskId());
|
||||
refreshTask = null;
|
||||
activeMagnets.clear();
|
||||
divIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task for teleporting items to magnet players
|
||||
*
|
||||
* @see MagnetCommandExecutor#updateMagnetismTask()
|
||||
*/
|
||||
private void taskApplyMagnetism() {
|
||||
final int size = activeMagnets.size();
|
||||
|
||||
final List<UUID> toRemove = new ArrayList<>();
|
||||
|
||||
// Iterate over a subdivision of the active magnets
|
||||
for (int index = divIndex; index < size; index += subdivide) {
|
||||
final UUID uuid = activeMagnets.get(index);
|
||||
final Player player = Bukkit.getPlayer(uuid);
|
||||
|
||||
// If the given magnet has logged out, remove the player after the loop
|
||||
if (player == null) toRemove.add(uuid);
|
||||
else {
|
||||
final Location playerLocation = player.getLocation();
|
||||
|
||||
// Get all items near the player that can don't have a pickup delay and teleport them to the player
|
||||
player.getWorld()
|
||||
.getNearbyEntities(playerLocation, sqRadius, sqRadius, sqRadius)
|
||||
.stream()
|
||||
.filter(it -> it instanceof Item)
|
||||
.filter(it -> ((Item) it).getPickupDelay() <= 0)
|
||||
.forEach(it -> it.teleport(playerLocation));
|
||||
}
|
||||
}
|
||||
|
||||
// Remove logged-out players
|
||||
toRemove.forEach(this::removeMagnet);
|
||||
|
||||
// Update subdivision to check next iteration
|
||||
divIndex = (divIndex + 1) % subdivide;
|
||||
}
|
||||
}
|
@ -7,4 +7,8 @@ commands:
|
||||
sort:
|
||||
description: Sort chest you are looking at
|
||||
usage: /<command>
|
||||
permission: invtweaks.sort
|
||||
permission: invtweaks.sort
|
||||
magnet:
|
||||
description: Toggle item magnet mode for player
|
||||
usage: /<command>
|
||||
permission: invtweaks.magnet
|
Loading…
x
Reference in New Issue
Block a user