Advertisement
JackOUT

Untitled

Feb 19th, 2023
526
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 38.03 KB | None | 0 0
  1. package games.coob.laserturrets.util;
  2.  
  3. import org.bukkit.Bukkit;
  4. import org.bukkit.Location;
  5. import org.bukkit.entity.Entity;
  6. import org.bukkit.entity.LivingEntity;
  7. import org.bukkit.entity.Player;
  8. import org.bukkit.plugin.Plugin;
  9. import org.bukkit.scheduler.BukkitRunnable;
  10. import org.bukkit.scheduler.BukkitTask;
  11. import org.bukkit.util.Vector;
  12. import org.mineacademy.fo.Common;
  13.  
  14. import java.lang.reflect.Constructor;
  15. import java.lang.reflect.Field;
  16. import java.lang.reflect.InvocationTargetException;
  17. import java.lang.reflect.Method;
  18. import java.util.*;
  19. import java.util.concurrent.ConcurrentHashMap;
  20. import java.util.concurrent.ThreadLocalRandom;
  21. import java.util.concurrent.atomic.AtomicInteger;
  22. import java.util.function.Supplier;
  23.  
  24. /**
  25.  * A whole class to create Guardian beams using packets and reflection.<br>
  26.  * Inspired by the API <a href="https://www.spigotmc.org/resources/GuardianBeamapi.18329">GuardianBeamAPI</a><br>
  27.  * <b>1.9 -> 1.19</b>
  28.  *
  29.  * @author SkytAsul
  30.  * @version 2.3.1
  31.  * @see <a href="https://github.com/SkytAsul/GuardianBeam">GitHub repository</a>
  32.  */
  33. public abstract class BeamUtil {
  34.  
  35.     protected final int distanceSquared;
  36.     protected final int duration;
  37.     protected boolean durationInTicks = false;
  38.     protected Location start;
  39.     protected Location end;
  40.  
  41.     protected Plugin plugin;
  42.     protected BukkitRunnable main;
  43.  
  44.     protected BukkitTask startMove;
  45.     protected BukkitTask endMove;
  46.  
  47.     protected Set<Player> show = ConcurrentHashMap.newKeySet();
  48.     private Set<Player> seen = new HashSet<>();
  49.  
  50.     private List<Runnable> executeEnd = new ArrayList<>(1);
  51.  
  52.     protected BeamUtil(final Location start, final Location end, final int duration, final int distance) {
  53.         if (!Packets.enabled)
  54.             throw new IllegalStateException("The beam has been disabled. An error has occurred during initialization.");
  55.         if (start.getWorld() != end.getWorld())
  56.             throw new IllegalArgumentException("Locations do not belong to the same worlds.");
  57.         this.start = start;
  58.         this.end = end;
  59.         this.duration = duration;
  60.         distanceSquared = distance < 0 ? -1 : distance * distance;
  61.     }
  62.  
  63.     /**
  64.      * Adds a runnable to execute when the beam reaches its final duration
  65.      *
  66.      * @param runnable action to execute
  67.      * @return this {@link BeamUtil} instance
  68.      */
  69.     public BeamUtil executeEnd(final Runnable runnable) {
  70.         executeEnd.add(runnable);
  71.         return this;
  72.     }
  73.  
  74.     /**
  75.      * Makes the duration provided in the constructor passed as ticks and not seconds
  76.      *
  77.      * @return this {@link BeamUtil} instance
  78.      */
  79.     public BeamUtil durationInTicks() {
  80.         durationInTicks = true;
  81.         return this;
  82.     }
  83.  
  84.     /**
  85.      * Starts this beam.
  86.      * <p>
  87.      * It will make the beam visible for nearby players and start the countdown to the final duration.
  88.      * <p>
  89.      * Once finished, it will destroy the beam and execute all runnables passed with {@link BeamUtil#executeEnd}.
  90.      *
  91.      * @param plugin plugin used to start the task
  92.      */
  93.     public void start(final Plugin plugin) {
  94.         if (main != null) throw new IllegalStateException("Task already started");
  95.         this.plugin = plugin;
  96.         main = new BukkitRunnable() {
  97.             int time = 0;
  98.  
  99.             @Override
  100.             public void run() {
  101.                 try {
  102.                     if (time == duration) {
  103.                         cancel();
  104.                         return;
  105.                     }
  106.                     if (!durationInTicks || time % 20 == 0) {
  107.                         for (final Player player : start.getWorld().getPlayers()) {
  108.                             if (isCloseEnough(player)) {
  109.                                 if (show.add(player)) {
  110.                                     sendStartPackets(player, !seen.add(player));
  111.                                 }
  112.                             } else if (show.remove(player)) {
  113.                                 sendDestroyPackets(player);
  114.                             }
  115.                         }
  116.                     }
  117.                     time++;
  118.                 } catch (final ReflectiveOperationException e) {
  119.                     e.printStackTrace();
  120.                 }
  121.             }
  122.  
  123.             @Override
  124.             public synchronized void cancel() throws IllegalStateException {
  125.                 super.cancel();
  126.                 main = null;
  127.                 try {
  128.                     for (final Player p : show) {
  129.                         sendDestroyPackets(p);
  130.                     }
  131.                     show.clear();
  132.                     executeEnd.forEach(Runnable::run);
  133.                 } catch (final ReflectiveOperationException e) {
  134.                     e.printStackTrace();
  135.                 }
  136.             }
  137.         };
  138.         main.runTaskTimerAsynchronously(plugin, 0L, durationInTicks ? 1L : 20L);
  139.     }
  140.  
  141.     /**
  142.      * Stops this beam.
  143.      * <p>
  144.      * This will destroy the beam for every player and start execute all runnables passed with {@link BeamUtil#executeEnd}
  145.      */
  146.     public void stop() {
  147.         if (main == null) throw new IllegalStateException("Task not started");
  148.         main.cancel();
  149.     }
  150.  
  151.     /**
  152.      * Gets beam status.
  153.      *
  154.      * @return <code>true</code> if the beam is currently running
  155.      * (i.e. {@link #start} has been called and the duration is not over)
  156.      */
  157.     public boolean isStarted() {
  158.         return main != null;
  159.     }
  160.  
  161.     /**
  162.      * Instantly moves the start of the beam to the location provided.
  163.      *
  164.      * @param location New start location
  165.      * @throws ReflectiveOperationException if a reflection exception occurred during beam moving
  166.      */
  167.     public abstract void moveStart(Location location) throws ReflectiveOperationException;
  168.  
  169.     /**
  170.      * Instantly moves the end of the beam to the location provided.
  171.      *
  172.      * @param location New end location
  173.      * @throws ReflectiveOperationException if a reflection exception occurred during beam moving
  174.      */
  175.     public abstract void moveEnd(Location location) throws ReflectiveOperationException;
  176.  
  177.     /**
  178.      * Gets the start location of the beam.
  179.      *
  180.      * @return where exactly is the start position of the beam located
  181.      */
  182.     public Location getStart() {
  183.         return start;
  184.     }
  185.  
  186.     /**
  187.      * Gets the end location of the beam.
  188.      *
  189.      * @return where exactly is the end position of the beam located
  190.      */
  191.     public Location getEnd() {
  192.         return end;
  193.     }
  194.  
  195.     /**
  196.      * Moves the start of the beam smoothly to the new location, within a given time.
  197.      *
  198.      * @param location New start location to go to
  199.      * @param ticks    Duration (in ticks) to make the move
  200.      * @param callback {@link Runnable} to execute at the end of the move (nullable)
  201.      */
  202.     public void moveStart(final Location location, final int ticks, final Runnable callback) {
  203.         startMove = moveInternal(location, ticks, startMove, this::getStart, this::moveStart, callback);
  204.     }
  205.  
  206.     /**
  207.      * Moves the end of the beam smoothly to the new location, within a given time.
  208.      *
  209.      * @param location New end location to go to
  210.      * @param ticks    Duration (in ticks) to make the move
  211.      * @param callback {@link Runnable} to execute at the end of the move (nullable)
  212.      */
  213.     public void moveEnd(final Location location, final int ticks, final Runnable callback) {
  214.         endMove = moveInternal(location, ticks, endMove, this::getEnd, this::moveEnd, callback);
  215.     }
  216.  
  217.     private BukkitTask moveInternal(final Location location, final int ticks, final BukkitTask oldTask, final Supplier<Location> locationSupplier, final ReflectiveConsumer<Location> moveConsumer, final Runnable callback) {
  218.         if (ticks <= 0) throw new IllegalArgumentException("Ticks must be a positive value");
  219.         if (plugin == null) throw new IllegalStateException("The beam must have been started a least once");
  220.         if (oldTask != null && !oldTask.isCancelled()) oldTask.cancel();
  221.         return new BukkitRunnable() {
  222.             double xPerTick = (location.getX() - locationSupplier.get().getX()) / ticks;
  223.             double yPerTick = (location.getY() - locationSupplier.get().getY()) / ticks;
  224.             double zPerTick = (location.getZ() - locationSupplier.get().getZ()) / ticks;
  225.             int elapsed = 0;
  226.  
  227.             @Override
  228.             public void run() {
  229.                 try {
  230.                     moveConsumer.accept(locationSupplier.get().add(xPerTick, yPerTick, zPerTick));
  231.                 } catch (final ReflectiveOperationException e) {
  232.                     e.printStackTrace();
  233.                     cancel();
  234.                     return;
  235.                 }
  236.  
  237.                 if (++elapsed == ticks) {
  238.                     cancel();
  239.                     if (callback != null) callback.run();
  240.                 }
  241.             }
  242.         }.runTaskTimer(plugin, 0L, 1L);
  243.     }
  244.  
  245.     protected void moveFakeEntity(final Location location, final int entityId, final Object fakeEntity) throws ReflectiveOperationException {
  246.         if (fakeEntity != null) Packets.moveFakeEntity(fakeEntity, location);
  247.         if (main == null) return;
  248.  
  249.         final Object packet;
  250.         if (fakeEntity == null) {
  251.             packet = Packets.createPacketMoveEntity(location, entityId);
  252.         } else {
  253.             packet = Packets.createPacketMoveEntity(fakeEntity);
  254.         }
  255.         for (final Player p : show) {
  256.             Packets.sendPackets(p, packet);
  257.         }
  258.     }
  259.  
  260.     protected abstract void sendStartPackets(Player p, boolean hasSeen) throws ReflectiveOperationException;
  261.  
  262.     protected abstract void sendDestroyPackets(Player p) throws ReflectiveOperationException;
  263.  
  264.     protected boolean isCloseEnough(final Player player) {
  265.         if (distanceSquared == -1) return true;
  266.         final Location location = player.getLocation();
  267.         return getStart().distanceSquared(location) <= distanceSquared ||
  268.                 getEnd().distanceSquared(location) <= distanceSquared;
  269.     }
  270.  
  271.     public static class GuardianBeam extends BeamUtil {
  272.         private static AtomicInteger teamID = new AtomicInteger(ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE));
  273.  
  274.         private Object createGuardianPacket;
  275.         private Object createSquidPacket;
  276.         private Object teamCreatePacket;
  277.         private Object[] destroyPackets;
  278.         private Object metadataPacketGuardian;
  279.         private Object metadataPacketSquid;
  280.         private Object fakeGuardianDataWatcher;
  281.  
  282.         private final UUID squidUUID = UUID.randomUUID();
  283.         private final UUID guardianUUID = UUID.randomUUID();
  284.         private final int squidID = Packets.generateEID();
  285.         private final int guardianID = Packets.generateEID();
  286.         private Object squid;
  287.         private Object guardian;
  288.  
  289.         private int targetID;
  290.         private UUID targetUUID;
  291.  
  292.         protected LivingEntity endEntity;
  293.  
  294.         private Location correctStart;
  295.         private Location correctEnd;
  296.  
  297.         /**
  298.          * Creates a new Guardian beam instance
  299.          *
  300.          * @param start    Location where beam will starts
  301.          * @param end      Location where beam will ends
  302.          * @param duration Duration of beam in seconds (<i>-1 if infinite</i>)
  303.          * @param distance Distance where beam will be visible (<i>-1 if infinite</i>)
  304.          * @throws ReflectiveOperationException if a reflection exception occurred during beam creation
  305.          * @see BeamUtil#start(Plugin) to start the beam
  306.          * @see #durationInTicks() to make the duration in ticks
  307.          * @see #executeEnd(Runnable) to add Runnable-s to execute when the beam will stop
  308.          * @see #GuardianBeam(Location, LivingEntity, int, int) to create a beam which follows an entity
  309.          */
  310.         public GuardianBeam(final Location start, final Location end, final int duration, final int distance) throws ReflectiveOperationException {
  311.             super(start, end, duration, distance);
  312.  
  313.             initSquid();
  314.  
  315.             targetID = squidID;
  316.             targetUUID = squidUUID;
  317.  
  318.             initBeam();
  319.         }
  320.  
  321.         /**
  322.          * Creates a new Guardian beam instance
  323.          *
  324.          * @param start     Location where beam will starts
  325.          * @param endEntity Entity who the beam will follow
  326.          * @param duration  Duration of beam in seconds (<i>-1 if infinite</i>)
  327.          * @param distance  Distance where beam will be visible (<i>-1 if infinite</i>)
  328.          * @throws ReflectiveOperationException if a reflection exception occurred during beam creation
  329.          * @see BeamUtil#start(Plugin) to start the beam
  330.          * @see #durationInTicks() to make the duration in ticks
  331.          * @see #executeEnd(Runnable) to add Runnable-s to execute when the beam will stop
  332.          * @see #GuardianBeam(Location, Location, int, int) to create a beam with a specific end location
  333.          */
  334.         public GuardianBeam(final Location start, final LivingEntity endEntity, final int duration, final int distance) throws ReflectiveOperationException {
  335.             super(start, endEntity.getEyeLocation(), duration, distance);
  336.  
  337.             targetID = endEntity.getEntityId();
  338.             targetUUID = endEntity.getUniqueId();
  339.  
  340.             initBeam();
  341.         }
  342.  
  343.         private void initBeam() throws ReflectiveOperationException {
  344.             fakeGuardianDataWatcher = Packets.createFakeDataWatcher();
  345.             Packets.initGuardianWatcher(fakeGuardianDataWatcher, targetID);
  346.             if (Packets.version >= 17) {
  347.                 guardian = Packets.createGuardian(getCorrectStart(), guardianUUID, guardianID);
  348.             }
  349.             metadataPacketGuardian = Packets.createPacketMetadata(guardianID, fakeGuardianDataWatcher);
  350.  
  351.             teamCreatePacket = Packets.createPacketTeamCreate("noclip" + teamID.getAndIncrement(), squidUUID, guardianUUID);
  352.             destroyPackets = Packets.createPacketsRemoveEntities(squidID, guardianID);
  353.         }
  354.  
  355.         private void initSquid() throws ReflectiveOperationException {
  356.             if (Packets.version >= 17) {
  357.                 squid = Packets.createSquid(getCorrectEnd(), squidUUID, squidID);
  358.             }
  359.             metadataPacketSquid = Packets.createPacketMetadata(squidID, Packets.fakeSquidWatcher);
  360.             Packets.setDirtyWatcher(Packets.fakeSquidWatcher);
  361.         }
  362.  
  363.         private Object getGuardianSpawnPacket() throws ReflectiveOperationException {
  364.             if (createGuardianPacket == null) {
  365.                 if (Packets.version < 17) {
  366.                     createGuardianPacket = Packets.createPacketEntitySpawnLiving(getCorrectStart(), Packets.mappings.getGuardianID(), guardianUUID, guardianID);
  367.                 } else {
  368.                     createGuardianPacket = Packets.createPacketEntitySpawnLiving(guardian);
  369.                 }
  370.             }
  371.             return createGuardianPacket;
  372.         }
  373.  
  374.         private Object getSquidSpawnPacket() throws ReflectiveOperationException {
  375.             if (createSquidPacket == null) {
  376.                 if (Packets.version < 17) {
  377.                     createSquidPacket = Packets.createPacketEntitySpawnLiving(getCorrectEnd(), Packets.mappings.getSquidID(), squidUUID, squidID);
  378.                 } else {
  379.                     createSquidPacket = Packets.createPacketEntitySpawnLiving(squid);
  380.                 }
  381.             }
  382.             return createSquidPacket;
  383.         }
  384.  
  385.         /**
  386.          * Makes the beam follow an entity (moving end location).
  387.          * <p>
  388.          * This is done client-side by making the fake guardian follow the existing entity.
  389.          * Hence, there is no consuming of server resources.
  390.          *
  391.          * @param entity living entity the beam will follow
  392.          * @throws ReflectiveOperationException if a reflection operation fails
  393.          */
  394.         public void attachEndEntity(final LivingEntity entity) throws ReflectiveOperationException {
  395.             if (entity.getWorld() != start.getWorld())
  396.                 throw new IllegalArgumentException("Attached entity is not in the same world as the beam.");
  397.             this.endEntity = entity;
  398.             setTargetEntity(entity.getUniqueId(), entity.getEntityId());
  399.         }
  400.  
  401.         public Entity getEndEntity() {
  402.             return endEntity;
  403.         }
  404.  
  405.         private void setTargetEntity(final UUID uuid, final int id) throws ReflectiveOperationException {
  406.             targetUUID = uuid;
  407.             targetID = id;
  408.             fakeGuardianDataWatcher = Packets.createFakeDataWatcher();
  409.             Packets.initGuardianWatcher(fakeGuardianDataWatcher, targetID);
  410.             metadataPacketGuardian = Packets.createPacketMetadata(guardianID, fakeGuardianDataWatcher);
  411.  
  412.             for (final Player p : show) {
  413.                 Packets.sendPackets(p, metadataPacketGuardian);
  414.             }
  415.         }
  416.  
  417.         @Override
  418.         public Location getEnd() {
  419.             return endEntity == null ? end : endEntity.getEyeLocation();
  420.         }
  421.  
  422.         protected Location getCorrectStart() {
  423.             if (correctStart == null) {
  424.                 correctStart = start.clone();
  425.                 correctStart.subtract(0, 0.5, 0);
  426.             }
  427.             return correctStart;
  428.         }
  429.  
  430.         protected Location getCorrectEnd() {
  431.             if (correctEnd == null) {
  432.                 correctEnd = end.clone();
  433.                 correctEnd.subtract(0, 0.5, 0);
  434.  
  435.                 final Vector corrective = correctEnd.toVector().subtract(getCorrectStart().toVector()).normalize();
  436.  
  437.                 if (Double.isNaN(corrective.getX())) corrective.setX(0);
  438.                 if (Double.isNaN(corrective.getY())) corrective.setY(0);
  439.                 if (Double.isNaN(corrective.getZ())) corrective.setZ(0);
  440.                 // coordinates can be NaN when start and end are stricly equals
  441.                 correctEnd.subtract(corrective);
  442.             }
  443.  
  444.             return correctEnd;
  445.         }
  446.  
  447.         @Override
  448.         protected boolean isCloseEnough(final Player player) {
  449.             return player == endEntity || super.isCloseEnough(player);
  450.         }
  451.  
  452.         @Override
  453.         protected void sendStartPackets(final Player p, final boolean hasSeen) throws ReflectiveOperationException {
  454.             if (squid == null) {
  455.                 Packets.sendPackets(p,
  456.                         getGuardianSpawnPacket(),
  457.                         metadataPacketGuardian);
  458.             } else {
  459.                 Packets.sendPackets(p,
  460.                         getGuardianSpawnPacket(),
  461.                         getSquidSpawnPacket(),
  462.                         metadataPacketGuardian,
  463.                         metadataPacketSquid);
  464.             }
  465.  
  466.             if (!hasSeen) Packets.sendPackets(p, teamCreatePacket);
  467.         }
  468.  
  469.         @Override
  470.         protected void sendDestroyPackets(final Player p) throws ReflectiveOperationException {
  471.             Packets.sendPackets(p, destroyPackets);
  472.         }
  473.  
  474.         @Override
  475.         public void moveStart(final Location location) throws ReflectiveOperationException {
  476.             this.start = location;
  477.             correctStart = null;
  478.  
  479.             createGuardianPacket = null; // will force re-generation of spawn packet
  480.             moveFakeEntity(getCorrectStart(), guardianID, guardian);
  481.  
  482.             if (squid != null) {
  483.                 correctEnd = null;
  484.                 createSquidPacket = null;
  485.                 moveFakeEntity(getCorrectEnd(), squidID, squid);
  486.             }
  487.         }
  488.  
  489.         @Override
  490.         public void moveEnd(final Location location) throws ReflectiveOperationException {
  491.             this.end = location;
  492.             createSquidPacket = null; // will force re-generation of spawn packet
  493.             correctEnd = null;
  494.  
  495.             if (squid == null) {
  496.                 initSquid();
  497.                 for (final Player p : show) {
  498.                     Packets.sendPackets(p, getSquidSpawnPacket(), metadataPacketSquid);
  499.                 }
  500.             } else {
  501.                 moveFakeEntity(getCorrectEnd(), squidID, squid);
  502.             }
  503.             if (targetUUID != squidUUID) {
  504.                 endEntity = null;
  505.                 setTargetEntity(squidUUID, squidID);
  506.             }
  507.         }
  508.  
  509.         /**
  510.          * Asks viewers' clients to change the color of this beam
  511.          *
  512.          * @throws ReflectiveOperationException
  513.          */
  514.         public void callColorChange() throws ReflectiveOperationException {
  515.             for (final Player p : show) {
  516.                 Packets.sendPackets(p, metadataPacketGuardian);
  517.             }
  518.         }
  519.  
  520.     }
  521.  
  522.     private static class Packets {
  523.         private static AtomicInteger lastIssuedEID = new AtomicInteger(2000000000);
  524.  
  525.         static int generateEID() {
  526.             return lastIssuedEID.getAndIncrement();
  527.         }
  528.  
  529.         private static int version;
  530.         private static int versionMinor;
  531.         private static String npack = "net.minecraft.server." + Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
  532.         private static String cpack = Bukkit.getServer().getClass().getPackage().getName() + ".";
  533.         private static ProtocolMappings mappings;
  534.  
  535.         private static Object squidType;
  536.         private static Object guardianType;
  537.  
  538.         private static Constructor<?> squidConstructor;
  539.         private static Constructor<?> guardianConstructor;
  540.  
  541.         private static Object watcherObject1; // invisilibity
  542.         private static Object watcherObject2; // spikes
  543.         private static Object watcherObject3; // attack id
  544.  
  545.         private static Constructor<?> watcherConstructor;
  546.         private static Method watcherSet;
  547.         private static Method watcherRegister;
  548.         private static Method watcherDirty;
  549.         private static Method watcherPack;
  550.  
  551.         private static Constructor<?> blockPositionConstructor;
  552.  
  553.         private static Constructor<?> packetSpawnLiving;
  554.         private static Constructor<?> packetSpawnNormal;
  555.         private static Constructor<?> packetRemove;
  556.         private static Constructor<?> packetTeleport;
  557.         private static Constructor<?> packetMetadata;
  558.         private static Class<?> packetTeam;
  559.  
  560.         private static Method createTeamPacket;
  561.         private static Constructor<?> createTeam;
  562.         private static Constructor<?> createScoreboard;
  563.         private static Method setTeamPush;
  564.         private static Object pushNever;
  565.         private static Method getTeamPlayers;
  566.  
  567.         private static Method getHandle;
  568.         private static Field playerConnection;
  569.         private static Method sendPacket;
  570.         private static Method setLocation;
  571.         private static Method setUUID;
  572.         private static Method setID;
  573.  
  574.         private static Object fakeSquid;
  575.         private static Object fakeSquidWatcher;
  576.  
  577.         private static Object nmsWorld;
  578.  
  579.         public static boolean enabled = false;
  580.  
  581.         static {
  582.             try {
  583.                 // e.g. Bukkit.getServer().getClass().getPackage().getName() -> org.bukkit.craftbukkit.v1_17_R1
  584.                 String[] versions = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3].substring(1).split("_");
  585.                 version = Integer.parseInt(versions[1]); // 1.X
  586.                 if (version >= 17) {
  587.                     // e.g. Bukkit.getBukkitVersion() -> 1.17.1-R0.1-SNAPSHOT
  588.                     versions = Bukkit.getBukkitVersion().split("-R")[0].split("\\.");
  589.                     versionMinor = versions.length <= 2 ? 0 : Integer.parseInt(versions[2]);
  590.                 } else versionMinor = Integer.parseInt(versions[2].substring(1)); // 1.X.Y
  591.                 Common.log("Found server version 1." + version + "." + versionMinor);
  592.  
  593.                 mappings = ProtocolMappings.getMappings(version);
  594.                 if (mappings == null) {
  595.                     mappings = ProtocolMappings.values()[ProtocolMappings.values().length - 1];
  596.                     Common.log("Loaded not matching version of the mappings for your server version (1." + version + "." + versionMinor + ")");
  597.                 }
  598.                 Common.log("Loaded mappings " + mappings.name());
  599.  
  600.                 final Class<?> entityTypesClass = getNMSClass("world.entity", "EntityTypes");
  601.                 final Class<?> entityClass = getNMSClass("world.entity", "Entity");
  602.                 final Class<?> squidClass = getNMSClass("world.entity.animal", "EntitySquid");
  603.                 final Class<?> guardianClass = getNMSClass("world.entity.monster", "EntityGuardian");
  604.                 watcherObject1 = getField(entityClass, mappings.getWatcherFlags(), null);
  605.                 watcherObject2 = getField(guardianClass, mappings.getWatcherSpikes(), null);
  606.                 watcherObject3 = getField(guardianClass, mappings.getWatcherTargetEntity(), null);
  607.  
  608.                 if (version >= 13) {
  609.                     squidType = entityTypesClass.getDeclaredField(mappings.getSquidTypeName()).get(null);
  610.                     guardianType = entityTypesClass.getDeclaredField(mappings.getGuardianTypeName()).get(null);
  611.                 }
  612.  
  613.                 final Class<?> dataWatcherClass = getNMSClass("network.syncher", "DataWatcher");
  614.                 watcherConstructor = dataWatcherClass.getDeclaredConstructor(entityClass);
  615.  
  616.                 if (version >= 18) {
  617.                     watcherSet = dataWatcherClass.getDeclaredMethod("b", watcherObject1.getClass(), Object.class);
  618.                     watcherRegister = dataWatcherClass.getDeclaredMethod("a", watcherObject1.getClass(), Object.class);
  619.                 } else {
  620.                     watcherSet = getMethod(dataWatcherClass, "set");
  621.                     watcherRegister = getMethod(dataWatcherClass, "register");
  622.                 }
  623.                 if (version >= 15)
  624.                     watcherDirty = getMethod(dataWatcherClass, "markDirty");
  625.                 if (version > 19 || (version == 19 && versionMinor >= 3))
  626.                     watcherPack = dataWatcherClass.getDeclaredMethod("b");
  627.  
  628.                 packetSpawnNormal = getNMSClass("network.protocol.game", "PacketPlayOutSpawnEntity").getDeclaredConstructor(version < 17 ? new Class<?>[0] : new Class<?>[]{getNMSClass("world.entity", "Entity")});
  629.                 packetSpawnLiving = version >= 19 ? packetSpawnNormal : getNMSClass("network.protocol.game", "PacketPlayOutSpawnEntityLiving").getDeclaredConstructor(version < 17 ? new Class<?>[0] : new Class<?>[]{getNMSClass("world.entity", "EntityLiving")});
  630.                 packetRemove = getNMSClass("network.protocol.game", "PacketPlayOutEntityDestroy").getDeclaredConstructor(version == 17 && versionMinor == 0 ? int.class : int[].class);
  631.                 packetMetadata = getNMSClass("network.protocol.game", "PacketPlayOutEntityMetadata").getDeclaredConstructor(version < 19 || (version == 19 && versionMinor < 3) ? new Class<?>[]{int.class, dataWatcherClass, boolean.class} : new Class<?>[]{int.class, List.class});
  632.                 packetTeleport = getNMSClass("network.protocol.game", "PacketPlayOutEntityTeleport").getDeclaredConstructor(version < 17 ? new Class<?>[0] : new Class<?>[]{entityClass});
  633.                 packetTeam = getNMSClass("network.protocol.game", "PacketPlayOutScoreboardTeam");
  634.  
  635.                 blockPositionConstructor = getNMSClass("core", "BlockPosition").getConstructor(double.class, double.class, double.class);
  636.  
  637.                 nmsWorld = Class.forName(cpack + "CraftWorld").getDeclaredMethod("getHandle").invoke(Bukkit.getWorlds().get(0));
  638.  
  639.                 squidConstructor = squidClass.getDeclaredConstructors()[0];
  640.                 if (version >= 17) {
  641.                     guardianConstructor = guardianClass.getDeclaredConstructors()[0];
  642.                 }
  643.  
  644.                 final Object[] entityConstructorParams = version < 14 ? new Object[]{nmsWorld} : new Object[]{entityTypesClass.getDeclaredField(mappings.getSquidTypeName()).get(null), nmsWorld};
  645.                 fakeSquid = squidConstructor.newInstance(entityConstructorParams);
  646.                 fakeSquidWatcher = createFakeDataWatcher();
  647.                 tryWatcherSet(fakeSquidWatcher, watcherObject1, (byte) 32);
  648.  
  649.                 getHandle = Class.forName(cpack + "entity.CraftPlayer").getDeclaredMethod("getHandle");
  650.                 playerConnection = getNMSClass("server.level", "EntityPlayer").getDeclaredField(version < 17 ? "playerConnection" : "b");
  651.                 sendPacket = getNMSClass("server.network", "PlayerConnection").getMethod(version < 18 ? "sendPacket" : "a", getNMSClass("network.protocol", "Packet"));
  652.  
  653.                 if (version >= 17) {
  654.                     setLocation = entityClass.getDeclaredMethod(version < 18 ? "setLocation" : "a", double.class, double.class, double.class, float.class, float.class);
  655.                     setUUID = entityClass.getDeclaredMethod("a_", UUID.class);
  656.                     setID = entityClass.getDeclaredMethod("e", int.class);
  657.  
  658.                     createTeamPacket = packetTeam.getMethod("a", getNMSClass("world.scores", "ScoreboardTeam"), boolean.class);
  659.  
  660.                     final Class<?> scoreboardClass = getNMSClass("world.scores", "Scoreboard");
  661.                     final Class<?> teamClass = getNMSClass("world.scores", "ScoreboardTeam");
  662.                     final Class<?> pushClass = getNMSClass("world.scores", "ScoreboardTeamBase$EnumTeamPush");
  663.                     createTeam = teamClass.getDeclaredConstructor(scoreboardClass, String.class);
  664.                     createScoreboard = scoreboardClass.getDeclaredConstructor();
  665.                     setTeamPush = teamClass.getDeclaredMethod(mappings.getTeamSetCollision(), pushClass);
  666.                     pushNever = pushClass.getDeclaredField("b").get(null);
  667.                     getTeamPlayers = teamClass.getDeclaredMethod(mappings.getTeamGetPlayers());
  668.                 }
  669.  
  670.                 enabled = true;
  671.             } catch (final Exception e) {
  672.                 e.printStackTrace();
  673.                 final String errorMsg = "Laser beam reflection failed to initialize. The util is disabled. Please ensure your version (" + Bukkit.getServer().getClass().getPackage().getName() + ") is supported.";
  674.                 Common.log(errorMsg);
  675.             }
  676.         }
  677.  
  678.         public static void sendPackets(final Player p, final Object... packets) throws ReflectiveOperationException {
  679.             final Object connection = playerConnection.get(getHandle.invoke(p));
  680.             for (final Object packet : packets) {
  681.                 if (packet == null) continue;
  682.                 sendPacket.invoke(connection, packet);
  683.             }
  684.         }
  685.  
  686.         public static Object createFakeDataWatcher() throws ReflectiveOperationException {
  687.             final Object watcher = watcherConstructor.newInstance(fakeSquid);
  688.             if (version > 13) setField(watcher, "registrationLocked", false);
  689.             return watcher;
  690.         }
  691.  
  692.         public static void setDirtyWatcher(final Object watcher) throws ReflectiveOperationException {
  693.             if (version >= 15) watcherDirty.invoke(watcher, watcherObject1);
  694.         }
  695.  
  696.         public static Object createSquid(final Location location, final UUID uuid, final int id) throws ReflectiveOperationException {
  697.             final Object entity = squidConstructor.newInstance(squidType, nmsWorld);
  698.             setEntityIDs(entity, uuid, id);
  699.             moveFakeEntity(entity, location);
  700.             return entity;
  701.         }
  702.  
  703.         public static Object createGuardian(final Location location, final UUID uuid, final int id) throws ReflectiveOperationException {
  704.             final Object entity = guardianConstructor.newInstance(guardianType, nmsWorld);
  705.             setEntityIDs(entity, uuid, id);
  706.             moveFakeEntity(entity, location);
  707.             return entity;
  708.         }
  709.  
  710.         public static Object createPacketEntitySpawnLiving(final Location location, final int typeID, final UUID uuid, final int id) throws ReflectiveOperationException {
  711.             final Object packet = packetSpawnLiving.newInstance();
  712.             setField(packet, "a", id);
  713.             setField(packet, "b", uuid);
  714.             setField(packet, "c", typeID);
  715.             setField(packet, "d", location.getX());
  716.             setField(packet, "e", location.getY());
  717.             setField(packet, "f", location.getZ());
  718.             setField(packet, "j", (byte) (location.getYaw() * 256.0F / 360.0F));
  719.             setField(packet, "k", (byte) (location.getPitch() * 256.0F / 360.0F));
  720.             if (version <= 14) setField(packet, "m", fakeSquidWatcher);
  721.             return packet;
  722.         }
  723.  
  724.         public static Object createPacketEntitySpawnNormal(final Location location, final int typeID, final Object type, final int id) throws ReflectiveOperationException {
  725.             final Object packet = packetSpawnNormal.newInstance();
  726.             setField(packet, "a", id);
  727.             setField(packet, "b", UUID.randomUUID());
  728.             setField(packet, "c", location.getX());
  729.             setField(packet, "d", location.getY());
  730.             setField(packet, "e", location.getZ());
  731.             setField(packet, "i", (int) (location.getYaw() * 256.0F / 360.0F));
  732.             setField(packet, "j", (int) (location.getPitch() * 256.0F / 360.0F));
  733.             setField(packet, "k", version < 13 ? typeID : type);
  734.             return packet;
  735.         }
  736.  
  737.         public static Object createPacketEntitySpawnLiving(final Object entity) throws ReflectiveOperationException {
  738.             return packetSpawnLiving.newInstance(entity);
  739.         }
  740.  
  741.         public static Object createPacketEntitySpawnNormal(final Object entity) throws ReflectiveOperationException {
  742.             return packetSpawnNormal.newInstance(entity);
  743.         }
  744.  
  745.         public static void initGuardianWatcher(final Object watcher, final int targetId) throws ReflectiveOperationException {
  746.             tryWatcherSet(watcher, watcherObject1, (byte) 32);
  747.             tryWatcherSet(watcher, watcherObject2, Boolean.FALSE);
  748.             tryWatcherSet(watcher, watcherObject3, targetId);
  749.         }
  750.  
  751.         public static Object[] createPacketsRemoveEntities(final int... entitiesId) throws ReflectiveOperationException {
  752.             final Object[] packets;
  753.             if (version == 17 && versionMinor == 0) {
  754.                 packets = new Object[entitiesId.length];
  755.                 for (int i = 0; i < entitiesId.length; i++) {
  756.                     packets[i] = packetRemove.newInstance(entitiesId[i]);
  757.                 }
  758.             } else {
  759.                 packets = new Object[]{packetRemove.newInstance(entitiesId)};
  760.             }
  761.             return packets;
  762.         }
  763.  
  764.         public static Object createPacketMoveEntity(final Location location, final int entityId) throws ReflectiveOperationException {
  765.             final Object packet = packetTeleport.newInstance();
  766.             setField(packet, "a", entityId);
  767.             setField(packet, "b", location.getX());
  768.             setField(packet, "c", location.getY());
  769.             setField(packet, "d", location.getZ());
  770.             setField(packet, "e", (byte) (location.getYaw() * 256.0F / 360.0F));
  771.             setField(packet, "f", (byte) (location.getPitch() * 256.0F / 360.0F));
  772.             setField(packet, "g", true);
  773.             return packet;
  774.         }
  775.  
  776.         public static void setEntityIDs(final Object entity, final UUID uuid, final int id) throws ReflectiveOperationException {
  777.             setUUID.invoke(entity, uuid);
  778.             setID.invoke(entity, id);
  779.         }
  780.  
  781.         public static void moveFakeEntity(final Object entity, final Location location) throws ReflectiveOperationException {
  782.             setLocation.invoke(entity, location.getX(), location.getY(), location.getZ(), location.getPitch(), location.getYaw());
  783.         }
  784.  
  785.         public static Object createPacketMoveEntity(final Object entity) throws ReflectiveOperationException {
  786.             return packetTeleport.newInstance(entity);
  787.         }
  788.  
  789.         public static Object createPacketTeamCreate(final String teamName, final UUID... entities) throws ReflectiveOperationException {
  790.             final Object packet;
  791.             if (version < 17) {
  792.                 packet = packetTeam.newInstance();
  793.                 setField(packet, "a", teamName);
  794.                 setField(packet, "i", 0);
  795.                 setField(packet, "f", "never");
  796.                 final Collection<String> players = (Collection<String>) getField(packetTeam, "h", packet);
  797.                 for (final UUID entity : entities) players.add(entity.toString());
  798.             } else {
  799.                 final Object team = createTeam.newInstance(createScoreboard.newInstance(), teamName);
  800.                 setTeamPush.invoke(team, pushNever);
  801.                 final Collection<String> players = (Collection<String>) getTeamPlayers.invoke(team);
  802.                 for (final UUID entity : entities) players.add(entity.toString());
  803.                 packet = createTeamPacket.invoke(null, team, true);
  804.             }
  805.             return packet;
  806.         }
  807.  
  808.         private static Object createPacketMetadata(final int entityId, final Object watcher) throws ReflectiveOperationException {
  809.             if (version < 19 || (version == 19 && versionMinor < 3)) {
  810.                 return packetMetadata.newInstance(entityId, watcher, false);
  811.             } else {
  812.                 return packetMetadata.newInstance(entityId, watcherPack.invoke(watcher));
  813.             }
  814.         }
  815.  
  816.         private static void tryWatcherSet(final Object watcher, final Object watcherObject, final Object watcherData) throws ReflectiveOperationException {
  817.             try {
  818.                 watcherSet.invoke(watcher, watcherObject, watcherData);
  819.             } catch (final InvocationTargetException ex) {
  820.                 watcherRegister.invoke(watcher, watcherObject, watcherData);
  821.                 if (version >= 15) watcherDirty.invoke(watcher, watcherObject);
  822.             }
  823.         }
  824.  
  825.         /* Reflection utils */
  826.         private static Method getMethod(final Class<?> clazz, final String name) throws NoSuchMethodException {
  827.             for (final Method m : clazz.getDeclaredMethods()) {
  828.                 if (m.getName().equals(name)) return m;
  829.             }
  830.             throw new NoSuchMethodException(name + " in " + clazz.getName());
  831.         }
  832.  
  833.         private static void setField(final Object instance, final String name, final Object value) throws ReflectiveOperationException {
  834.             final Field field = instance.getClass().getDeclaredField(name);
  835.             field.setAccessible(true);
  836.             field.set(instance, value);
  837.         }
  838.  
  839.         private static Object getField(final Class<?> clazz, final String name, final Object instance) throws ReflectiveOperationException {
  840.             final Field field = clazz.getDeclaredField(name);
  841.             field.setAccessible(true);
  842.             return field.get(instance);
  843.         }
  844.  
  845.         private static Class<?> getNMSClass(final String package17, final String className) throws ClassNotFoundException {
  846.             return Class.forName((version < 17 ? npack : "net.minecraft." + package17) + "." + className);
  847.         }
  848.  
  849.         private enum ProtocolMappings {
  850.             V1_9(9, "Z", "bA", "bB", "b", "c", 94, 68),
  851.             V1_10(10, V1_9),
  852.             V1_11(11, V1_10),
  853.             V1_12(12, V1_11),
  854.             V1_13(13, "ac", "bF", "bG", "b", "c", 70, 28),
  855.             V1_14(14, "W", "b", "bD", "c", "d", 73, 30),
  856.             V1_15(15, "T", "b", "bA", "c", "d", 74, 31),
  857.             V1_16(16, null, "b", "d", "c", "d", -1, 31) {
  858.                 @Override
  859.                 public int getSquidID() {
  860.                     return Packets.versionMinor < 2 ? 74 : 81;
  861.                 }
  862.  
  863.                 @Override
  864.                 public String getWatcherFlags() {
  865.                     return Packets.versionMinor < 2 ? "T" : "S";
  866.                 }
  867.             },
  868.             V1_17(17, "Z", "b", "e", "c", "d", 86, 35, "K", "aJ", "u", "setCollisionRule", "getPlayerNameSet"),
  869.             V1_18(18, null, "b", "e", "c", "d", 86, 35, "K", "aJ", "u", "a", "g") {
  870.                 @Override
  871.                 public String getWatcherFlags() {
  872.                     return Packets.versionMinor < 2 ? "aa" : "Z";
  873.                 }
  874.             },
  875.  
  876.             V1_19(19, "Z", "b", "e", "c", "d", 89, 38, null, null, "w", "a", "g") {
  877.                 @Override
  878.                 public int getGuardianID() {
  879.                     return versionMinor < 3 ? 38 : 39;
  880.                 }
  881.  
  882.                 @Override
  883.                 public String getSquidTypeName() {
  884.                     return versionMinor < 3 ? "aM" : "aN";
  885.                 }
  886.  
  887.                 @Override
  888.                 public String getGuardianTypeName() {
  889.                     return versionMinor < 3 ? "N" : "O";
  890.                 }
  891.             },
  892.             ;
  893.  
  894.             private final int major;
  895.             private final String watcherFlags;
  896.             private final String watcherSpikes;
  897.             private final String watcherTargetEntity;
  898.             private final String watcherTargetLocation;
  899.             private final String watcherBasePlate;
  900.             private final int squidID;
  901.             private final int guardianID;
  902.             private final String guardianTypeName;
  903.             private final String squidTypeName;
  904.             private final String crystalTypeName;
  905.             private final String teamSetCollision;
  906.             private final String teamGetPlayers;
  907.  
  908.             private ProtocolMappings(final int major, final ProtocolMappings parent) {
  909.                 this(major, parent.watcherFlags, parent.watcherSpikes, parent.watcherTargetEntity, parent.watcherTargetLocation, parent.watcherBasePlate, parent.squidID, parent.guardianID, parent.guardianTypeName, parent.squidTypeName, parent.crystalTypeName, parent.teamSetCollision, parent.teamGetPlayers);
  910.             }
  911.  
  912.             private ProtocolMappings(final int major,
  913.                                      final String watcherFlags, final String watcherSpikes, final String watcherTargetEntity, final String watcherTargetLocation, final String watcherBasePlate,
  914.                                      final int squidID, final int guardianID) {
  915.                 this(major, watcherFlags, watcherSpikes, watcherTargetEntity, watcherTargetLocation, watcherBasePlate, squidID, guardianID, null, "SQUID", "END_CRYSTAL", null, null);
  916.             }
  917.  
  918.             private ProtocolMappings(final int major,
  919.                                      final String watcherFlags, final String watcherSpikes, final String watcherTargetEntity, final String watcherTargetLocation, final String watcherBasePlate,
  920.                                      final int squidID, final int guardianID,
  921.                                      final String guardianTypeName, final String squidTypeName, final String crystalTypeName, final String teamSetCollision, final String teamGetPlayers) {
  922.                 this.major = major;
  923.                 this.watcherFlags = watcherFlags;
  924.                 this.watcherSpikes = watcherSpikes;
  925.                 this.watcherTargetEntity = watcherTargetEntity;
  926.                 this.watcherTargetLocation = watcherTargetLocation;
  927.                 this.watcherBasePlate = watcherBasePlate;
  928.                 this.squidID = squidID;
  929.                 this.guardianID = guardianID;
  930.                 this.guardianTypeName = guardianTypeName;
  931.                 this.squidTypeName = squidTypeName;
  932.                 this.crystalTypeName = crystalTypeName;
  933.                 this.teamSetCollision = teamSetCollision;
  934.                 this.teamGetPlayers = teamGetPlayers;
  935.             }
  936.  
  937.             public int getMajor() {
  938.                 return major;
  939.             }
  940.  
  941.             public String getWatcherFlags() {
  942.                 return watcherFlags;
  943.             }
  944.  
  945.             public String getWatcherSpikes() {
  946.                 return watcherSpikes;
  947.             }
  948.  
  949.             public String getWatcherTargetEntity() {
  950.                 return watcherTargetEntity;
  951.             }
  952.  
  953.             public String getWatcherTargetLocation() {
  954.                 return watcherTargetLocation;
  955.             }
  956.  
  957.             public String getWatcherBasePlate() {
  958.                 return watcherBasePlate;
  959.             }
  960.  
  961.             public int getSquidID() {
  962.                 return squidID;
  963.             }
  964.  
  965.             public int getGuardianID() {
  966.                 return guardianID;
  967.             }
  968.  
  969.             public String getGuardianTypeName() {
  970.                 return guardianTypeName;
  971.             }
  972.  
  973.             public String getSquidTypeName() {
  974.                 return squidTypeName;
  975.             }
  976.  
  977.             public String getCrystalTypeName() {
  978.                 return crystalTypeName;
  979.             }
  980.  
  981.             public String getTeamSetCollision() {
  982.                 return teamSetCollision;
  983.             }
  984.  
  985.             public String getTeamGetPlayers() {
  986.                 return teamGetPlayers;
  987.             }
  988.  
  989.             public static ProtocolMappings getMappings(final int major) {
  990.                 for (final ProtocolMappings map : values()) {
  991.                     if (major == map.getMajor()) return map;
  992.                 }
  993.                 return null;
  994.             }
  995.         }
  996.     }
  997.  
  998.     @FunctionalInterface
  999.     public static interface ReflectiveConsumer<T> {
  1000.         abstract void accept(T t) throws ReflectiveOperationException;
  1001.     }
  1002. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement