From 79ed948841ae07479b43fe4a4a2df2caea1d344f Mon Sep 17 00:00:00 2001 From: ImproperIssues Date: Sat, 29 Jul 2023 15:28:31 -0700 Subject: [PATCH] added lazer gun item --- .../ogredupealias/plugin/ItemPresets.java | 6 + .../plugin/custom/items/CustomItems.java | 2 + .../items/customitems/LazerGunItem.java | 88 +++++++++++ .../raytracers/BlockDisplayRaytracer.java | 103 +++++++++++++ .../raytracers/CustomDisplayRaytracer.java | 140 ++++++++++++++++++ 5 files changed, 339 insertions(+) create mode 100644 src/main/java/fun/ogre/ogredupealias/plugin/custom/items/customitems/LazerGunItem.java create mode 100644 src/main/java/fun/ogre/ogredupealias/utils/raytracers/BlockDisplayRaytracer.java create mode 100644 src/main/java/fun/ogre/ogredupealias/utils/raytracers/CustomDisplayRaytracer.java diff --git a/src/main/java/fun/ogre/ogredupealias/plugin/ItemPresets.java b/src/main/java/fun/ogre/ogredupealias/plugin/ItemPresets.java index 1a758ea..6ad947c 100644 --- a/src/main/java/fun/ogre/ogredupealias/plugin/ItemPresets.java +++ b/src/main/java/fun/ogre/ogredupealias/plugin/ItemPresets.java @@ -182,6 +182,12 @@ public abstract class ItemPresets { .customModelData(1111) .build(); + public static ItemStack LAZER_GUN = ItemBuilder.create() + .material(Material.IRON_HORSE_ARMOR) + .name(Text.ofAll("&aGreen &7Lazer Blaster")) + .lore(Text.ofAll("&8click to shoot")) + .build(); + public static ItemStack BLANK = ItemBuilder.create() .material(Material.LIGHT_GRAY_STAINED_GLASS_PANE) .name(" ") diff --git a/src/main/java/fun/ogre/ogredupealias/plugin/custom/items/CustomItems.java b/src/main/java/fun/ogre/ogredupealias/plugin/custom/items/CustomItems.java index 2745663..354ef7d 100644 --- a/src/main/java/fun/ogre/ogredupealias/plugin/custom/items/CustomItems.java +++ b/src/main/java/fun/ogre/ogredupealias/plugin/custom/items/CustomItems.java @@ -1,5 +1,6 @@ package fun.ogre.ogredupealias.plugin.custom.items; +import fun.ogre.ogredupealias.plugin.custom.items.customitems.LazerGunItem; import fun.ogre.ogredupealias.plugin.custom.items.customitems.LazerItem; import fun.ogre.ogredupealias.plugin.custom.items.customitems.RailgunItem; import fun.ogre.ogredupealias.plugin.custom.items.customitems.TazerItem; @@ -21,6 +22,7 @@ public final class CustomItems implements Listener { register(new TazerItem()); register(new LazerItem()); register(new RailgunItem()); + register(new LazerGunItem()); } public static ItemStack register(ItemStack item, CustomItemInteractionCallback interactionCallback) { diff --git a/src/main/java/fun/ogre/ogredupealias/plugin/custom/items/customitems/LazerGunItem.java b/src/main/java/fun/ogre/ogredupealias/plugin/custom/items/customitems/LazerGunItem.java new file mode 100644 index 0000000..dcafd88 --- /dev/null +++ b/src/main/java/fun/ogre/ogredupealias/plugin/custom/items/customitems/LazerGunItem.java @@ -0,0 +1,88 @@ +package fun.ogre.ogredupealias.plugin.custom.items.customitems; + +import fun.ogre.ogredupealias.plugin.ItemPresets; +import fun.ogre.ogredupealias.plugin.custom.items.CustomItem; +import fun.ogre.ogredupealias.plugin.custom.items.CustomItemInteractionCallback; +import fun.ogre.ogredupealias.utils.SoundPlayer; +import fun.ogre.ogredupealias.utils.raytracers.BlockDisplayRaytracer; +import fun.ogre.ogredupealias.utils.raytracers.CustomDisplayRaytracer; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.block.Action; +import org.bukkit.util.Vector; + +import java.util.List; + +public class LazerGunItem extends CustomItem { + + public static final Material LAZER_COLOR = Material.LIME_CONCRETE; + + public LazerGunItem() { + super("lazergun", ItemPresets.LAZER_GUN); + } + + @Override + public CustomItemInteractionCallback getCallback() { + return (player, item, event) -> { + Action action = event.getAction(); + + if (action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK) { + SoundPlayer shootSound = new SoundPlayer(player.getLocation(), Sound.BLOCK_BEACON_DEACTIVATE, 10, 10); + shootSound.playWithin(10); + trace(0, 10, player, player.getEyeLocation().add(0, -0.2, 0), player.getLocation().getDirection(), 64, 10); + } + }; + } + + public void trace(int attempts, int maxAttempts, LivingEntity shooter, Location start, Vector direction, double distance, double damage) { + CustomDisplayRaytracer.Point result = CustomDisplayRaytracer.trace(start, direction, distance, 0.05, point -> { + List nearby = point.getNearbyEntities(shooter, 5, true, 0.1, e -> e instanceof LivingEntity le && !le.isDead()); + if (!nearby.isEmpty() && nearby.get(0) instanceof LivingEntity entity) { + entity.damage(damage, shooter); + } + return (!nearby.isEmpty() || CustomDisplayRaytracer.HIT_BLOCK.test(point)) && point.getTraveledDist() > 0.3; + }); + BlockDisplayRaytracer.trace(LAZER_COLOR, start, result.getLoc(), 10); + SoundPlayer shootSound = new SoundPlayer(result.getLoc(), Sound.BLOCK_BEACON_ACTIVATE, 1, 10); + shootSound.playWithin(10); + + if (CustomDisplayRaytracer.HIT_BLOCK.test(result)) { + BlockDisplayRaytracer.outline(LAZER_COLOR, result.getLoc(), 10); + if (attempts < maxAttempts) { + trace(attempts + 1, maxAttempts, shooter, result.getLoc(), reflect(result.getLoc(), direction), distance, damage); + } + } + } + + public Vector reflect(Location pointOfContact, Vector incoming) { + Vector negate = incoming.clone().multiply(-1).normalize(); + Vector contact = getContactingVector(pointOfContact.getBlock(), pointOfContact).multiply(-1); + Vector reflect = contact.subtract(negate).normalize(); + return reflect; + } + + public Vector getContactingVector(Block block, Location pointOfContact) { + Vector center = block.getLocation().add(0.5, 0.5, 0.5).toVector(); + Vector incoming = center.subtract(pointOfContact.toVector()).normalize(); + double x = incoming.dot(new Vector(1, 0, 0)); + double y = incoming.dot(new Vector(0, 1, 0)); + double z = incoming.dot(new Vector(0, 0, 1)); + double ax = Math.abs(x); + double ay = Math.abs(y); + double az = Math.abs(z); + + if (ax > ay && ax > az) { + return new Vector(x, 0, 0).normalize(); + } + else if (ay > ax && ay > az) { + return new Vector(0, y, 0).normalize(); + } + else { + return new Vector(0, 0, z).normalize(); + } + } +} diff --git a/src/main/java/fun/ogre/ogredupealias/utils/raytracers/BlockDisplayRaytracer.java b/src/main/java/fun/ogre/ogredupealias/utils/raytracers/BlockDisplayRaytracer.java new file mode 100644 index 0000000..f098c3d --- /dev/null +++ b/src/main/java/fun/ogre/ogredupealias/utils/raytracers/BlockDisplayRaytracer.java @@ -0,0 +1,103 @@ +package fun.ogre.ogredupealias.utils.raytracers; + +import fun.ogre.ogredupealias.OgreDupeAlias; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.entity.BlockDisplay; +import org.bukkit.entity.Display; +import org.bukkit.util.Consumer; +import org.bukkit.util.Transformation; +import org.bukkit.util.Vector; +import org.joml.AxisAngle4f; +import org.joml.Vector3f; + +public class BlockDisplayRaytracer { + + private static final OgreDupeAlias system = OgreDupeAlias.instance; + + public static void outline(Material display, Location location, long stayTime) { + outline(display, location, 0.05, stayTime); + } + + public static void outline(Material display, Location location, double thickness, long stayTime) { + Location og = location.getBlock().getLocation(); + + Location a1 = og.clone().add(0, 0, 0); + Location a2 = og.clone().add(1, 0, 0); + Location a3 = og.clone().add(1, 0, 1); + Location a4 = og.clone().add(0, 0, 1); + + Location b1 = og.clone().add(0, 1, 0); + Location b2 = og.clone().add(1, 1, 0); + Location b3 = og.clone().add(1, 1, 1); + Location b4 = og.clone().add(0, 1, 1); + + trace(display, a1, a2, thickness, stayTime); + trace(display, a2, a3, thickness, stayTime); + trace(display, a3, a4, thickness, stayTime); + trace(display, a4, a1, thickness, stayTime); + + trace(display, b1, b2, thickness, stayTime); + trace(display, b2, b3, thickness, stayTime); + trace(display, b3, b4, thickness, stayTime); + trace(display, b4, b1, thickness, stayTime); + + trace(display, a1, b1, thickness, stayTime); + trace(display, a2, b2, thickness, stayTime); + trace(display, a3, b3, thickness, stayTime); + trace(display, a4, b4, thickness, stayTime); + } + + public static void trace(Material display, Location start, Location end, long stayTime) { + trace(display, start, end.toVector().subtract(start.toVector()), 0.05, end.distance(start), stayTime); + } + + public static void trace(Material display, Location start, Location end, double thickness, long stayTime) { + trace(display, start, end.toVector().subtract(start.toVector()), thickness, end.distance(start), stayTime); + } + + public static void trace(Material display, Location start, Vector direction, double thickness, double distance, long stayTime) { + World world = start.getWorld(); + + BlockDisplay beam = world.spawn(start, BlockDisplay.class, entity -> { + AxisAngle4f angle = new AxisAngle4f(0, 0, 0, 1); + Vector3f transition = new Vector3f(-(float)(thickness / 2F)); + Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance); + Transformation trans = new Transformation(transition, angle, scale, angle); + Location vector = entity.getLocation(); + + vector.setDirection(direction); + entity.teleport(vector); + entity.setBlock(display.createBlockData()); + entity.setBrightness(new Display.Brightness(15, 15)); + entity.setInterpolationDelay(0); + entity.setTransformation(trans); + + Bukkit.getScheduler().runTaskLater(system, entity::remove, stayTime); + }); + } + + public static void trace(Material display, Location start, Vector direction, double thickness, double distance, long stayTime, Consumer onEntitySpawn) { + World world = start.getWorld(); + + BlockDisplay beam = world.spawn(start, BlockDisplay.class, entity -> { + AxisAngle4f angle = new AxisAngle4f(0, 0, 0, 1); + Vector3f transition = new Vector3f(-(float)(thickness / 2F)); + Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance); + Transformation trans = new Transformation(transition, angle, scale, angle); + Location vector = entity.getLocation(); + + vector.setDirection(direction); + entity.teleport(vector); + entity.setBlock(display.createBlockData()); + entity.setBrightness(new Display.Brightness(15, 15)); + entity.setInterpolationDelay(0); + entity.setTransformation(trans); + + Bukkit.getScheduler().runTaskLater(system, entity::remove, stayTime); + Bukkit.getScheduler().runTaskLater(system, () -> onEntitySpawn.accept(entity), 5); + }); + } +} diff --git a/src/main/java/fun/ogre/ogredupealias/utils/raytracers/CustomDisplayRaytracer.java b/src/main/java/fun/ogre/ogredupealias/utils/raytracers/CustomDisplayRaytracer.java new file mode 100644 index 0000000..6c17d80 --- /dev/null +++ b/src/main/java/fun/ogre/ogredupealias/utils/raytracers/CustomDisplayRaytracer.java @@ -0,0 +1,140 @@ +package fun.ogre.ogredupealias.utils.raytracers; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.util.Vector; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; + +public class CustomDisplayRaytracer { + + public static final Predicate HIT_BLOCK = point -> { + Block b = point.getBlock(); + Vector v = point.getLoc().toVector(); + return !b.isPassable() && b.getCollisionShape().getBoundingBoxes().stream().noneMatch(box -> box.contains(v)); + }; + + public static final Predicate HIT_ENTITY = point -> { + return !point.getNearbyEntities(null, 5, true, 0.1, e -> e instanceof LivingEntity le && !le.isDead()).isEmpty(); + }; + + public static final Predicate HIT_BLOCK_OR_ENTITY = point -> { + return HIT_BLOCK.test(point) || HIT_ENTITY.test(point); + }; + + public static final Predicate HIT_BLOCK_AND_ENTITY = point -> { + return HIT_BLOCK.test(point) && HIT_ENTITY.test(point); + }; + + public static Predicate hitEntityExclude(Entity exclude) { + return point -> !point.getNearbyEntities(exclude, 5, true, 0.1, e -> e instanceof LivingEntity le && !le.isDead()).isEmpty(); + } + + public static Predicate hitAnythingExclude(Entity exclude) { + return point -> HIT_BLOCK.test(point) || !point.getNearbyEntities(exclude, 5, true, 0.1, e -> e instanceof LivingEntity le && !le.isDead()).isEmpty(); + } + + public static Predicate hitEverythingExclude(Entity exclude) { + return point -> HIT_BLOCK.test(point) && !point.getNearbyEntities(exclude, 5, true, 0.1, e -> e instanceof LivingEntity le && !le.isDead()).isEmpty(); + } + + + public static Point trace(Location start, Location end, Predicate hitCondition) { + return trace(start, end, 0.5, hitCondition); + } + + public static Point trace(Location start, Location end, double interval, Predicate hitCondition) { + return trace(start, end.toVector().subtract(end.toVector()), end.distance(start), interval, hitCondition); + } + + public static Point trace(Location start, Vector direction, double distance, Predicate hitCondition) { + return trace(start, direction, distance, 0.5, hitCondition); + } + + public static Point trace(Location start, Vector direction, double distance, double interval, Predicate hitCondition) { + if (interval < 0) throw new IllegalArgumentException("interval cannot be zero!"); + if (distance < 0) throw new IllegalArgumentException("distance cannot be zero!"); + + for (double i = 0.0; i < distance; i += interval) { + Point point = blocksInFrontOf(start, direction, i, false); + if (hitCondition.test(point)) { + return point; + } + } + return blocksInFrontOf(start, direction, distance, true); + } + + public static Point blocksInFrontOf(Location loc, Vector dir, double blocks, boolean missed) { + return new Point(loc.clone().add(dir.getX() * blocks, dir.getY() * blocks, dir.getZ() * blocks), blocks, missed); + } + + public static class Point { + private final Location loc; + private final World world; + private final Block block; + private final boolean missed; + private final double traveledDist; + + private Point(Location loc, double traveledDist, boolean missed) { + this.loc = loc; + this.world = loc.getWorld(); + this.block = loc.getBlock(); + this.missed = missed; + this.traveledDist = traveledDist; + + if (world == null) { + throw new IllegalArgumentException("point world cannot be null!"); + } + } + + public List getNearbyEntities(Entity exclude, int range, boolean requireContact, double expansionX, double expansionY, double expansionZ, Predicate filter) { + return new ArrayList<>(world.getNearbyEntities(loc, range, range, range, e -> { + if (requireContact && !e.getBoundingBox().expand(expansionX, expansionY, expansionZ).contains(loc.toVector())) { + return false; + } + return filter.test(e) && e != exclude; + })); + } + + public List getNearbyEntities(Entity exclude, int range, boolean requireContact, double expansion, Predicate filter) { + return getNearbyEntities(exclude, range, requireContact, expansion, expansion, expansion, filter); + } + + public List getNearbyEntities(Entity exclude, int range, boolean requireContact, Predicate filter) { + return getNearbyEntities(exclude, range, requireContact, 0, filter); + } + + public List getNearbyEntities(Entity exclude, int range, Predicate filter) { + return getNearbyEntities(exclude, range, false, filter); + } + + public double getTraveledDist() { + return traveledDist; + } + + public boolean wasMissed() { + return missed; + } + + public Block getBlock() { + return block; + } + + public Location getLoc() { + return loc; + } + + public World getWorld() { + return world; + } + + public double distance(Location other) { + return other.distance(loc); + } + } +}