From 922a2bcc7657d66c4314e8e0604e11c9d5593aff Mon Sep 17 00:00:00 2001 From: Paul Reilly Date: Mon, 27 Mar 2023 20:35:16 -0500 Subject: [PATCH] Change trailer from blocks to particles. --- .../totalfreedommod/api/Interpolator.java | 7 ++ .../totalfreedommod/fun/Trailer.java | 63 +++--------- .../totalfreedommod/util/Groups.java | 21 ++-- .../totalfreedommod/util/Interpolation.java | 58 +++++++++++ .../totalfreedommod/util/ParticleDisplay.java | 57 +++++++++++ .../world/WorldRestrictions.java | 97 ++++++------------- 6 files changed, 182 insertions(+), 121 deletions(-) create mode 100644 commons/src/main/java/me/totalfreedom/totalfreedommod/api/Interpolator.java create mode 100644 commons/src/main/java/me/totalfreedom/totalfreedommod/util/Interpolation.java create mode 100644 commons/src/main/java/me/totalfreedom/totalfreedommod/util/ParticleDisplay.java diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/api/Interpolator.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/api/Interpolator.java new file mode 100644 index 00000000..1f1e6fbd --- /dev/null +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/api/Interpolator.java @@ -0,0 +1,7 @@ +package me.totalfreedom.totalfreedommod.api; + +@FunctionalInterface +public interface Interpolator +{ + double[] interpolate(double from, double to, int max); +} diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/fun/Trailer.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/fun/Trailer.java index 65dd8c02..b7499bbc 100644 --- a/commons/src/main/java/me/totalfreedom/totalfreedommod/fun/Trailer.java +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/fun/Trailer.java @@ -1,28 +1,22 @@ package me.totalfreedom.totalfreedommod.fun; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.SplittableRandom; -import java.util.UUID; - import me.totalfreedom.totalfreedommod.FreedomService; import me.totalfreedom.totalfreedommod.api.ShopItem; -import me.totalfreedom.totalfreedommod.util.Groups; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Particle; -import org.bukkit.block.Block; -import org.bukkit.block.data.BlockData; +import me.totalfreedom.totalfreedommod.util.ParticleDisplay; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerMoveEvent; +import java.util.HashMap; +import java.util.Map; +import java.util.SplittableRandom; +import java.util.UUID; + public class Trailer extends FreedomService { private final SplittableRandom random = new SplittableRandom(); - private final Set trailPlayers = new HashSet<>(); // player UUID + private final Map trailPlayers = new HashMap<>(); // player UUID and relative particle instance. @Override public void onStart() @@ -46,42 +40,15 @@ public class Trailer extends FreedomService * - The player doesn't have permission to modify blocks in their current world */ if (trailPlayers.isEmpty() - || !trailPlayers.contains(event.getPlayer().getUniqueId()) - || !plugin.pl.getData(event.getPlayer()).hasItem(ShopItem.RAINBOW_TRAIL) - || plugin.wr.doRestrict(event.getPlayer()) - || !plugin.wgb.canEditCurrentWorld(event.getPlayer())) + || !trailPlayers.containsKey(event.getPlayer().getUniqueId()) + || !plugin.pl.getData(event.getPlayer()).hasItem(ShopItem.RAINBOW_TRAIL)) { return; } - Block fromBlock = event.getFrom().getBlock(); - if (!fromBlock.isEmpty()) - { - return; - } - - Block toBlock = Objects.requireNonNull(event.getTo()).getBlock(); - if (fromBlock.equals(toBlock)) - { - return; - } - - // TODO: Make this particles instead of blocks! - fromBlock.setType(Groups.WOOL_COLORS.get(random.nextInt(Groups.WOOL_COLORS.size()))); - BlockData data = fromBlock.getBlockData(); - Material material = Material.getMaterial(String.valueOf(fromBlock.getType())); - for (int x = -1; x <= 1; x++) - { - for (int z = -1; z <= 1; z++) - { - final Location trail_pos; - trail_pos = new Location(event.getPlayer().getWorld(), fromBlock.getX() + x, fromBlock.getY(), fromBlock.getZ() + z); - if (trailPlayers.contains(event.getPlayer().getUniqueId()) && plugin.cpb.isEnabled()) - { - plugin.cpb.getCoreProtectAPI().logPlacement(event.getPlayer().getName(), trail_pos, material, data); - } - } - } + final Player player = event.getPlayer(); + final ParticleDisplay particleDisplay = trailPlayers.get(player.getUniqueId()); + particleDisplay.spawnNext(player); } public void remove(Player player) @@ -91,11 +58,13 @@ public class Trailer extends FreedomService public void add(Player player) { - trailPlayers.add(player.getUniqueId()); + if (trailPlayers.containsKey(player.getUniqueId())) return; + + trailPlayers.put(player.getUniqueId(), new ParticleDisplay()); } public boolean contains(Player player) { - return trailPlayers.contains(player.getUniqueId()); + return trailPlayers.containsKey(player.getUniqueId()); } } diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/util/Groups.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/util/Groups.java index 5c1b7c9b..41bca78b 100644 --- a/commons/src/main/java/me/totalfreedom/totalfreedommod/util/Groups.java +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/util/Groups.java @@ -1,19 +1,22 @@ package me.totalfreedom.totalfreedommod.util; -import java.util.Arrays; -import java.util.List; import org.bukkit.Material; import org.bukkit.block.Biome; import org.bukkit.entity.EntityType; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + public class Groups { - public static final List WOOL_COLORS = Arrays.stream(Material.values()).filter((m) -> m.name().endsWith("_WOOL")).toList(); - public static final List SHULKER_BOXES = Arrays.stream(Material.values()).filter((m) -> m.name().endsWith("SHULKER_BOX")).toList(); - public static final List MOB_TYPES = Arrays.stream(EntityType.values()).filter(EntityType::isAlive).filter(EntityType::isSpawnable).toList(); - public static final List SPAWN_EGGS = Arrays.stream(Material.values()).filter((mat) -> mat.name().endsWith("_SPAWN_EGG")).toList(); - public static final List BANNERS = Arrays.stream(Material.values()).filter((m) -> m.name().endsWith("_BANNER")).toList(); - public static final List EXPLOSIVE_BED_BIOMES = Arrays.asList( + public static final Set WOOL_COLORS = Arrays.stream(Material.values()).filter((m) -> m.name().endsWith("_WOOL")).collect(Collectors.toSet()); + public static final Set SHULKER_BOXES = Arrays.stream(Material.values()).filter((m) -> m.name().endsWith("SHULKER_BOX")).collect(Collectors.toSet()); + public static final Set MOB_TYPES = Arrays.stream(EntityType.values()).filter(EntityType::isAlive).filter(EntityType::isSpawnable).collect(Collectors.toSet()); + public static final Set SPAWN_EGGS = Arrays.stream(Material.values()).filter((mat) -> mat.name().endsWith("_SPAWN_EGG")).collect(Collectors.toSet()); + public static final Set BANNERS = Arrays.stream(Material.values()).filter((m) -> m.name().endsWith("_BANNER")).collect(Collectors.toSet()); + public static final Set EXPLOSIVE_BED_BIOMES = new HashSet<>(Arrays.asList( Biome.NETHER_WASTES, Biome.CRIMSON_FOREST, Biome.SOUL_SAND_VALLEY, @@ -23,5 +26,5 @@ public class Groups Biome.END_HIGHLANDS, Biome.END_MIDLANDS, Biome.THE_END, - Biome.SMALL_END_ISLANDS); + Biome.SMALL_END_ISLANDS)); } diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/util/Interpolation.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/util/Interpolation.java new file mode 100644 index 00000000..4b3fafbf --- /dev/null +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/util/Interpolation.java @@ -0,0 +1,58 @@ +package me.totalfreedom.totalfreedommod.util; + +import me.totalfreedom.totalfreedommod.api.Interpolator; +import org.bukkit.Color; + +import java.util.LinkedHashSet; + +public class Interpolation +{ + public LinkedHashSet rainbow(int length) + { + LinkedHashSet base = new LinkedHashSet<>(); + LinkedHashSet redToOrange = hsvGradient(length, Color.RED, Color.ORANGE, this::linear); + LinkedHashSet orangeToYellow = hsvGradient(length, Color.ORANGE, Color.YELLOW, this::linear); + LinkedHashSet yellowToGreen = hsvGradient(length, Color.YELLOW, Color.GREEN, this::linear); + LinkedHashSet greenToBlue = hsvGradient(length, Color.GREEN, Color.BLUE, this::linear); + LinkedHashSet blueToPurple = hsvGradient(length, Color.BLUE, Color.PURPLE, this::linear); + LinkedHashSet purpleToRed = hsvGradient(length, Color.PURPLE, Color.RED, this::linear); + base.addAll(redToOrange); + base.addAll(orangeToYellow); + base.addAll(yellowToGreen); + base.addAll(greenToBlue); + base.addAll(blueToPurple); + base.addAll(purpleToRed); + return base; + } + + private double[] linear(double from, double to, int max) + { + final double[] res = new double[max]; + for (int i = 0; i < max; i++) + { + res[i] = from + i * ((to - from) / (max - 1)); + } + return res; + } + + private LinkedHashSet hsvGradient(int length, Color from, Color to, Interpolator interpolator) + { + // returns a float-array where hsv[0] = hue, hsv[1] = saturation, hsv[2] = value/brightness + final float[] hsvFrom = java.awt.Color.RGBtoHSB(from.getRed(), from.getGreen(), from.getBlue(), null); + final float[] hsvTo = java.awt.Color.RGBtoHSB(to.getRed(), to.getGreen(), to.getBlue(), null); + + final double[] h = interpolator.interpolate(hsvFrom[0], hsvTo[0], length); + final double[] s = interpolator.interpolate(hsvFrom[1], hsvTo[1], length); + final double[] v = interpolator.interpolate(hsvFrom[2], hsvTo[2], length); + + final LinkedHashSet gradient = new LinkedHashSet<>(); + + for (int i = 0; i < length; i++) + { + final int rgb = java.awt.Color.HSBtoRGB((float) h[i], (float) s[i], (float) v[i]); + final Color color = Color.fromRGB(rgb); + gradient.add(color); + } + return gradient; + } +} diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/util/ParticleDisplay.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/util/ParticleDisplay.java new file mode 100644 index 00000000..6ad5b926 --- /dev/null +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/util/ParticleDisplay.java @@ -0,0 +1,57 @@ +package me.totalfreedom.totalfreedommod.util; + +import com.destroystokyo.paper.ParticleBuilder; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; + +public class ParticleDisplay +{ + private final Interpolation interpolation; + private Iterator colorIterator; + + public ParticleDisplay() + { + this.interpolation = new Interpolation(); + this.colorIterator = interpolation.rainbow(43).iterator(); + } + + public void spawnNext(Player player) + { + Location location = getBehind(player); + Color color = getIterator().next(); + Particle.DustOptions options = new Particle.DustOptions(color, 3); + ParticleBuilder builder = new ParticleBuilder(Particle.REDSTONE); + builder.data(options) + .receivers(30, 15, true) + .offset(0.5, 0.5, 0.5) + .location(location) + .spawn(); + } + + private Location getBehind(Player player) + { + @NotNull Vector inverse = player.getLocation() + .clone() + .getDirection() + .normalize() + .multiply(-1); + + return player.getLocation().add(inverse); + } + + private Iterator getIterator() + { + if (!this.colorIterator.hasNext()) + { + this.colorIterator = interpolation.rainbow(43).iterator(); + } + + return this.colorIterator; + } +} diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/world/WorldRestrictions.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/world/WorldRestrictions.java index 3dc501b0..3017b8d5 100644 --- a/commons/src/main/java/me/totalfreedom/totalfreedommod/world/WorldRestrictions.java +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/world/WorldRestrictions.java @@ -1,18 +1,8 @@ package me.totalfreedom.totalfreedommod.world; -import com.sk89q.worldguard.protection.flags.Flag; -import com.sk89q.worldguard.protection.flags.Flags; -import com.sk89q.worldguard.protection.flags.StateFlag; -import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import me.totalfreedom.totalfreedommod.FreedomService; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -23,8 +13,10 @@ import org.bukkit.event.player.PlayerArmorStandManipulateEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerInteractEvent; -public class WorldRestrictions extends FreedomService -{ +import java.util.Arrays; +import java.util.List; + +public class WorldRestrictions extends FreedomService { private final List BLOCKED_WORLDEDIT_COMMANDS = Arrays.asList( "green", "fixlava", "fixwater", "br", "brush", "tool", "mat", "range", "cs", "up", "fill", "setblock", "tree", "replacenear", "bigtree"); @@ -33,118 +25,93 @@ public class WorldRestrictions extends FreedomService "bigtree", "ebigtree", "largetree", "elargetree"); @Override - public void onStart() - { + public void onStart() { } @Override - public void onStop() - { + public void onStop() { } - public boolean doRestrict(Player player) - { - if (!plugin.pl.getData(player).isMasterBuilder() && plugin.pl.canManageMasterBuilders(player.getName())) - { - if (player.getWorld().equals(plugin.wm.masterBuilderWorld.getWorld())) - { - return true; - } + public boolean doRestrict(Player player) { + if (!plugin.pl.getData(player).isMasterBuilder() + && plugin.pl.canManageMasterBuilders(player.getName()) + && (player.getWorld().equals(plugin.wm.masterBuilderWorld.getWorld()))) { + return true; } - return !plugin.al.isAdmin(player) && player.getWorld().equals(plugin.wm.adminworld.getWorld()); + return !plugin.al.isAdmin(player) + && player.getWorld().equals(plugin.wm.adminworld.getWorld()); } @EventHandler(priority = EventPriority.NORMAL) - public void onBlockPlace(BlockPlaceEvent event) - { + public void onBlockPlace(BlockPlaceEvent event) { final Player player = event.getPlayer(); - if (doRestrict(player)) - { + if (doRestrict(player)) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBlockBreak(BlockBreakEvent event) - { + public void onBlockBreak(BlockBreakEvent event) { final Player player = event.getPlayer(); - if (doRestrict(player)) - { + if (doRestrict(player)) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.NORMAL) - public void onPlayerInteract(PlayerInteractEvent event) - { + public void onPlayerInteract(PlayerInteractEvent event) { final Player player = event.getPlayer(); - if (doRestrict(player)) - { + if (doRestrict(player)) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.NORMAL) - public void onArmorStandManipulate(PlayerArmorStandManipulateEvent event) - { + public void onArmorStandManipulate(PlayerArmorStandManipulateEvent event) { final Player player = event.getPlayer(); - if (doRestrict(player)) - { + if (doRestrict(player)) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.NORMAL) - public void onEntityDamageByEntity(EntityDamageByEntityEvent event) - { - if (event.getDamager() instanceof Player) - { - Player player = (Player)event.getDamager(); - - if (doRestrict(player)) - { + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (event.getDamager() instanceof Player player && (doRestrict(player))) { event.setCancelled(true); - } } } @EventHandler(priority = EventPriority.NORMAL) - public void onCommandPreprocess(PlayerCommandPreprocessEvent event) - { + public void onCommandPreprocess(PlayerCommandPreprocessEvent event) { final Player player = event.getPlayer(); String command = event.getMessage().split("\\s+")[0].substring(1).toLowerCase(); - if (doRestrict(player)) - { + if (doRestrict(player)) { /* This is a very poor way of blocking WorldEdit commands, all the methods I know of for obtaining a list of a plugin's commands are returning null for world edit. */ String allowed = player.getWorld().equals(plugin.wm.adminworld.getWorld()) ? "Admins" : "Master Builders"; - if (command.startsWith("/") || BLOCKED_WORLDEDIT_COMMANDS.contains(command)) - { + if (command.startsWith("/") || BLOCKED_WORLDEDIT_COMMANDS.contains(command)) { player.sendMessage(ChatColor.RED + "Only " + allowed + " are allowed to use WorldEdit here."); event.setCancelled(true); } - if (command.equalsIgnoreCase("coreprotect") || command.equalsIgnoreCase("core") || command.equalsIgnoreCase("co")) - { + if (command.equalsIgnoreCase("coreprotect") || command.equalsIgnoreCase("core") || command.equalsIgnoreCase("co")) { player.sendMessage(ChatColor.RED + "Only " + allowed + " are allowed to use CoreProtect here."); event.setCancelled(true); } } - if (player.getWorld().equals(Bukkit.getWorld("plotworld"))) - { - if (BLOCKED_ESSENTIALS_COMMANDS.contains(command)) - { - player.sendMessage(ChatColor.RED + "Sorry, this command is restricted in the plotworld"); - event.setCancelled(true); - } + if (player.getWorld().equals(Bukkit.getWorld("plotworld")) + && (BLOCKED_ESSENTIALS_COMMANDS.contains(command))) { + player.sendMessage(ChatColor.RED + "Sorry, this command is restricted in the plotworld"); + event.setCancelled(true); + } } } \ No newline at end of file