diff --git a/AtlasParent/Atlas/pom.xml b/AtlasParent/Atlas/pom.xml new file mode 100644 index 00000000..fdb67e14 --- /dev/null +++ b/AtlasParent/Atlas/pom.xml @@ -0,0 +1,242 @@ + + + 4.0.0 + + + cc.funkemunky.utils + 1.8.4 + atlas-parent + + + Atlas + 1.8.4 + + + scm:svn:http://127.0.0.1/dummy + scm:svn:https://127.0.0.1/dummy + HEAD + http://127.0.0.1/dummy + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 8 + 8 + -XDignore.symbol.file + + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + + package + + shade + + + false + + + org.yaml.snakeyaml + cc.funkemunky.api.utils.org.yaml.snakeyaml + + + + + + + + + + src/main/resources + true + + + + + + + funkemunky-releases + https://nexus.funkemunky.cc/content/repositories/releases/ + + + jitpack.io + https://jitpack.io + + + + + + dev.brighten.db + Assembly + 2.0.1 + compile + + + org.apache.commons + commons-math3 + 3.6.1 + compile + + + org.github.paperspigot + 1.8.8 + 1.8.8 + provided + + + com.shevchik.protocolsupport + protocolsupport + 1.8 + provided + + + us.myles.viaversion + ViaVersion + 2.2.3 + provided + + + org.github.spigot + 1.14.1 + 1.14.1 + provided + + + org.github.spigot + 1.15.1 + 1.15.1 + provided + + + org.github.spigot + 1.14.3 + 1.14.3 + provided + + + org.github.spigot + 1.14.2 + 1.14.2 + provided + + + org.github.spigot + 1.15 + 1.15 + provided + + + org.github.spigot + 1.15.2 + 1.15.2 + provided + + + org.github.spigot + 1.13.2 + 1.13.2 + provided + + + org.github.spigot + 1.7.10 + 1.7.10 + provided + + + org.github.spigot + 1.8 + 1.8 + provided + + + org.github.spigot + 1.8.3 + 1.8.3 + provided + + + org.github.spigot + 1.8.8 + 1.8.8 + provided + + + org.github.spigot + 1.16.1 + 1.16.1 + provided + + + org.github.spigot + 1.9 + 1.9 + provided + + + org.github.spigot + 1.9.4 + 1.9.4 + provided + + + org.github.spigot + 1.10.2 + 1.10.2 + provided + + + org.github.spigot + 1.11.1 + 1.11.1 + provided + + + org.github.spigot + 1.11.2 + 1.11.2 + provided + + + org.github.spigot + 1.12.1 + 1.12.1 + provided + + + org.github.spigot + 1.12.2 + 1.12.2 + provided + + + org.github.spigot + 1.13 + 1.13 + provided + + + org.github.spigot + 1.14 + 1.14 + provided + + + org.github.paperspigot + 1.13.2 + 1.13.2 + provided + + + + \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/Atlas.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/Atlas.java new file mode 100644 index 00000000..9f070ef3 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/Atlas.java @@ -0,0 +1,374 @@ +package cc.funkemunky.api; + +import cc.funkemunky.api.bungee.BungeeManager; +import cc.funkemunky.api.commands.FunkeCommandManager; +import cc.funkemunky.api.commands.ancmd.CommandManager; +import cc.funkemunky.api.commands.impl.AtlasCommand; +import cc.funkemunky.api.events.AtlasListener; +import cc.funkemunky.api.events.EventManager; +import cc.funkemunky.api.events.impl.TickEvent; +import cc.funkemunky.api.handlers.PluginLoaderHandler; +import cc.funkemunky.api.metrics.Metrics; +import cc.funkemunky.api.profiling.BaseProfiler; +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.impl.BukkitReflection; +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.tinyprotocol.api.TinyProtocolHandler; +import cc.funkemunky.api.updater.Updater; +import cc.funkemunky.api.utils.*; +import cc.funkemunky.api.utils.blockbox.BlockBoxManager; +import cc.funkemunky.api.utils.objects.RemoteClassLoader; +import dev.brighten.db.Carbon; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.Entity; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; + +import java.io.File; +import java.util.*; +import java.util.concurrent.*; +import java.util.stream.Collectors; + +@Getter +@Setter +@Init +public class Atlas extends JavaPlugin { + @Getter + private static Atlas instance; + private BlockBoxManager blockBoxManager; + private ScheduledExecutorService schedular; + private ConsoleCommandSender consoleSender; + private FunkeCommandManager funkeCommandManager; + private Updater updater; + private BaseProfiler profile; + private Metrics metrics; + private TinyProtocolHandler tinyProtocolHandler; + private int currentThread = 0; + private long profileStart; + private EventManager eventManager; + private int currentTicks; + private PluginLoaderHandler pluginLoaderHandler; + private BungeeManager bungeeManager; + private boolean done; + private ExecutorService service; + private File file; + private final Map entities = new ConcurrentHashMap<>(); + private final Map entityIds = new ConcurrentHashMap<>(); + private Map blocksMap = new ConcurrentHashMap<>(); + private Map pluginCommandManagers = new HashMap<>(); + + @ConfigSetting(path = "updater", name = "autoDownload") + private static boolean autoDownload = false; + + @ConfigSetting(name = "metrics") + private static boolean metricsEnabled = true; + + @ConfigSetting(path = "init", name = "reloadDependingPlugins") + private static boolean enableDependingPlugins = true; + + @ConfigSetting(path = "ticking", name = "runAsync") + private static boolean runAsync = false; + + public void onEnable() { + instance = this; + saveDefaultConfig(); + consoleSender = Bukkit.getConsoleSender(); + + MiscUtils.printToConsole(Color.Red + "Loading Atlas..."); + + MiscUtils.printToConsole(Color.Gray + "Firing up the thread turbines..."); + service = Executors.newFixedThreadPool(2); + schedular = Executors.newSingleThreadScheduledExecutor(); + eventManager = new EventManager(); + Carbon.setup(); + + pluginLoaderHandler = new PluginLoaderHandler(); + tinyProtocolHandler = new TinyProtocolHandler(); + + profileStart = System.currentTimeMillis(); + profile = new BaseProfiler(); + + MiscUtils.printToConsole(Color.Gray + "Loading utilities and managers..."); + blockBoxManager = new BlockBoxManager(); + funkeCommandManager = new FunkeCommandManager(); + + updater = new Updater(); + + runTasks(); + + MiscUtils.printToConsole(Color.Gray + "Starting scanner..."); + + initializeScanner(getClass(), this, + null, + true, + true); + + funkeCommandManager.addCommand(this, new AtlasCommand()); + + MiscUtils.printToConsole(Color.Gray + "Loading other managers and utilities..."); + + if(metricsEnabled) { + MiscUtils.printToConsole(Color.Gray + "Setting up bStats Metrics..."); + metrics = new Metrics(this); + } + + MiscUtils.printToConsole(Color.Gray + "Checking for updates..."); + if(updater.needsToUpdate()) { + MiscUtils.printToConsole(Color.Yellow + + "There is an update available. See more information with /atlas update."); + + if(autoDownload) { + MiscUtils.printToConsole(Color.Gray + "Downloading new version..."); + updater.downloadNewVersion(); + MiscUtils.printToConsole(Color.Green + "Atlas v" + updater.getLatestUpdate() + + " has been downloaded. Please restart/reload your server to import it."); + } + } + + Bukkit.getOnlinePlayers().forEach(player -> TinyProtocolHandler.getInstance().injectPlayer(player)); + bungeeManager = new BungeeManager(); + MiscUtils.printToConsole(Color.Green + "Successfully loaded Atlas and its utilities!"); + done = true; + } + + public void onDisable() { + MiscUtils.printToConsole(Color.Gray + "Unloading all Atlas hooks..."); + HandlerList.unregisterAll(this); + Bukkit.getScheduler().cancelTasks(this); + + eventManager.clearAllRegistered(); + getCommandManager(this).unregisterCommands(); + + MiscUtils.printToConsole(Color.Gray + + "Disabling all plugins that depend on Atlas to prevent any errors..."); + Arrays.stream(Bukkit.getPluginManager().getPlugins()) + .filter(plugin -> plugin.getDescription().getDepend().contains("Atlas") + || plugin.getDescription().getSoftDepend().contains("Atlas")) + .forEach(plugin -> MiscUtils.unloadPlugin(plugin.getName())); + shutdownExecutor(); + + MiscUtils.printToConsole(Color.Red + "Completed shutdown process."); + } + + + private void shutdownExecutor() { + service.shutdown(); + schedular.shutdown(); + } + + public CommandManager getCommandManager(Plugin plugin) { + return pluginCommandManagers.computeIfAbsent(plugin.getName(), key -> new CommandManager(plugin)); + } + + private void runTasks() { + //This allows us to use ticks for intervalTime comparisons to allow for more parallel calculations to actual + //Minecraft and it also has the added benefit of being lighter than using System.currentTimeMillis. + //WARNING: This may be a bit buggy with "legacy" versions of PaperSpigot since they broke the runnable. + //If you are using PaperSpigot, + if(!runAsync) { + new BukkitRunnable() { + public void run() { + runTickEvent(); + } + }.runTaskTimer(this, 1L, 1L); + } else { + getSchedular().scheduleAtFixedRate(this::runTickEvent, 50L, 50L, TimeUnit.MILLISECONDS); + } + + RunUtils.taskTimer(() -> { + synchronized (entities) { + for (World world : Bukkit.getWorlds()) { + for (Entity entity : world.getEntities()) { + entities.put(entity.getUniqueId(), entity); + } + } + entities.keySet().parallelStream().filter(uuid -> entities.get(uuid) == null) + .sequential().forEach(entities::remove); + } + synchronized (entityIds) { + entities.forEach((id, entity) -> entityIds.put(entity.getEntityId(), entity.getUniqueId())); + } + }, 2L, 5L); + + //This allows us to cache the blocks to improve the performance of getting blocks. + schedular.scheduleAtFixedRate(() -> { + profile.start("task::chunkLoader"); + for(World world : Bukkit.getWorlds()) { + Object provider = MinecraftReflection.getChunkProvider(world); + List vChunks = MinecraftReflection.getVanillaChunks(provider) + .parallelStream() + .map(BukkitReflection::getChunkFromVanilla) + .collect(Collectors.toList()); + + List blocksList = Collections.synchronizedList(new ArrayList<>()); + vChunks.parallelStream().forEach(chunk -> { + for(int y = 0 ; y < world.getMaxHeight() ; y++) { + //The << is a reverse of what is needed to get chunk from loc. + int x = chunk.getX() << 4, z = chunk.getZ() << 4; + Block block = chunk.getBlock(x & 15, y, z & 15); + + blocksList.add(block); + } + }); + + for (Block block : blocksList) { + blocksMap.put(block.getLocation(), block); + } + blocksList.clear(); //Clearing to save the java gc from this monster. + } + profile.stop("task::chunkLoader"); + }, 10L, 60L, TimeUnit.SECONDS); + } + private void runTickEvent() { + service.execute(() -> { + TickEvent tickEvent = new TickEvent(currentTicks++); + Atlas.getInstance().getEventManager().callEvent(tickEvent); + }); + } + + public void initializeScanner(Class mainClass, Plugin plugin, ClassLoader loader, + boolean loadListeners, boolean loadCommands) { + initializeScanner(mainClass, plugin, loader, ClassScanner.scanFile(null, mainClass), loadListeners, loadCommands); + } + + public void initializeScanner(Class mainClass, Plugin plugin, ClassLoader loader, Set names, + boolean loadListeners, boolean loadCommands) { + names.stream() + .map(name -> { + if(loader != null) { + try { + if(loader instanceof RemoteClassLoader) { + return new WrappedClass(((RemoteClassLoader)loader).findClass(name)); + } else + return new WrappedClass(Class.forName(name, true, loader)); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return null; + } else { + return Reflections.getClass(name); + } + }) + .filter(Objects::nonNull) + .filter(c -> { + Init init = c.getAnnotation(Init.class); + String[] required = init.requirePlugins(); + + if(required.length > 0) { + if(init.requireType() == Init.RequireType.ALL) { + return Arrays.stream(required) + .allMatch(name -> Bukkit.getPluginManager().isPluginEnabled(name)); + } else { + return Arrays.stream(required) + .anyMatch(name -> Bukkit.getPluginManager().isPluginEnabled(name)); + } + } + return true; + }) + .sorted(Comparator.comparing(c -> + c.getAnnotation(Init.class).priority().getPriority(), Comparator.reverseOrder())) + .forEach(c -> { + Object obj = c.getParent().equals(mainClass) ? plugin : c.getConstructor().newInstance(); + Init annotation = c.getAnnotation(Init.class); + + if(loadListeners) { + if(obj instanceof AtlasListener) { + Atlas.getInstance().getEventManager().registerListeners((AtlasListener)obj, plugin); + MiscUtils.printToConsole("&7Registered Atlas listener &e" + + c.getParent().getSimpleName() + "&7."); + } + if(obj instanceof Listener) { + Bukkit.getPluginManager().registerEvents((Listener)obj, plugin); + MiscUtils.printToConsole("&7Registered Atlas listener &e" + + c.getParent().getSimpleName() + "&7."); + } + } + + if(loadCommands && annotation.commands()) { + MiscUtils.printToConsole("&7Registering commands in class &e" + + c.getParent().getSimpleName() + "&7..."); + Atlas.getInstance().getCommandManager(plugin).registerCommands(obj); + } + + c.getMethods(method -> method.getMethod().isAnnotationPresent(Invoke.class)) + .forEach(method -> { + MiscUtils.printToConsole("&7Invoking method &e" + method.getName() + " &7in &e" + + c.getClass().getSimpleName() + "&7..."); + method.invoke(obj); + }); + + c.getFields(field -> field.isAnnotationPresent(Instance.class)) + .forEach(field -> { + MiscUtils.printToConsole("&7Setting instance of &e" + + c.getClass().getSimpleName() + " &7on field &e" + + field.getField().getName() + "&7..."); + field.set(obj, obj); + }); + + c.getFields(field -> field.isAnnotationPresent(ConfigSetting.class)) + .forEach(field -> { + ConfigSetting setting = field.getAnnotation(ConfigSetting.class); + + String name = setting.name().length() > 0 + ? setting.name() + : field.getField().getName(); + + MiscUtils.printToConsole("&7Found ConfigSetting &e" + field.getField().getName() + + " &7(default=&f" + (setting.hide() ? "HIDDEN" : field.get(obj)) + "&7."); + + if(plugin.getConfig().get(setting.path() + "." + name) == null) { + MiscUtils.printToConsole("&7Value not set in config! Setting value..."); + plugin.getConfig().set(setting.path() + "." + name, field.get(obj)); + plugin.saveConfig(); + } else { + Object configObj = plugin.getConfig().get(setting.path() + "." + name); + MiscUtils.printToConsole("&7Set field to value &e" + + (setting.hide() ? "HIDDEN" : configObj) + "&7."); + field.set(obj, configObj); + } + }); + }); + } + + public void initializeScanner(Class mainClass, Plugin plugin) { + initializeScanner(mainClass, plugin, null, true, true); + } + + public void initializeScanner(Plugin plugin) { + initializeScanner(plugin.getClass(), plugin); + } + + public void initializeScanner(Plugin plugin, boolean loadListeners, boolean loadCommands) { + initializeScanner(plugin.getClass(), plugin, null, loadListeners, loadCommands); + } + + //Always wait to load chunks if you never want this to return as null. It may add delays tho when it is null. + //Max time is 5 seconds to load chunks. + public Block getBlock(Location location, boolean waitToLoadChunks) { + return blocksMap.computeIfAbsent(location, key -> { + if(waitToLoadChunks) { + FutureTask blockTask = new FutureTask<>(key::getBlock); + + try { + return blockTask.get(5000L, TimeUnit.SECONDS); + } catch(InterruptedException | ExecutionException | TimeoutException e) { + e.printStackTrace(); + } + } else { + return BlockUtils.getBlock(location); + } + return null; + }); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/AbstractVersion.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/AbstractVersion.java new file mode 100644 index 00000000..07e357d4 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/AbstractVersion.java @@ -0,0 +1,45 @@ +package cc.funkemunky.api.abstraction; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.utils.world.CollisionBox; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +import java.util.List; + +public interface AbstractVersion { + + AbstractVersion version = getVersion(); + + static AbstractVersion getVersion() { + if(version == null) { + WrappedClass wrapped = Reflections.getClass("cc.funkemunky.api.abstraction.impl.Abstract" + + ProtocolVersion.getGameVersion().name()); + + return wrapped.getConstructor().newInstance(); + } + return version; + } + + //All methods + CollisionBox getBlockBox(Block block); + + List getCollidingBoxes(World world, SimpleCollisionBox box); + + boolean isRiptiding(LivingEntity entity); + + boolean isGliding(Player player); + + boolean isChunkLoaded(Location location); + + float getMovementFactor(LivingEntity entity); + + float getBlockFriction(Block block); + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_7_10.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_7_10.java new file mode 100644 index 00000000..cf77a71a --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_7_10.java @@ -0,0 +1,103 @@ +package cc.funkemunky.api.abstraction.impl; + +import cc.funkemunky.api.abstraction.AbstractVersion; +import cc.funkemunky.api.utils.BlockUtils; +import cc.funkemunky.api.utils.MathHelper; +import cc.funkemunky.api.utils.world.CollisionBox; +import cc.funkemunky.api.utils.world.types.ComplexCollisionBox; +import cc.funkemunky.api.utils.world.types.NoCollisionBox; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import lombok.val; +import net.minecraft.server.v1_7_R4.AxisAlignedBB; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_7_R4.CraftWorld; +import org.bukkit.craftbukkit.v1_7_R4.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_7_R4.util.CraftMagicNumbers; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class AbstractV1_7_10 implements AbstractVersion { + + @Override + public CollisionBox getBlockBox(Block block) { + val nmsBlock = CraftMagicNumbers.getBlock(block); + val nmsWorld = ((CraftWorld)block.getWorld()).getHandle(); + List listAABBS = new ArrayList<>(); + + nmsBlock.a(nmsWorld, block.getX(), block.getY(), block.getZ(), + new SimpleCollisionBox(block.getLocation(), 2, 1).toAxisAlignedBB(), + listAABBS, null); + + if(listAABBS.size() > 1) { + return new ComplexCollisionBox(listAABBS.stream().map(SimpleCollisionBox::new) + .toArray(SimpleCollisionBox[]::new)); + } else if(listAABBS.size() > 0) new SimpleCollisionBox(listAABBS.get(0)); + + return NoCollisionBox.INSTANCE; + } + + @Override + public List getCollidingBoxes(World world, SimpleCollisionBox box) { + int minx = MathHelper.floor_double(box.xMin), miny = MathHelper.floor_double(box.yMin), + minz = MathHelper.floor_double(box.zMin); + int maxx = MathHelper.floor_double(box.xMax), maxy = MathHelper.floor_double(box.yMax), + maxz = MathHelper.floor_double(box.zMax); + + List boxes = new ArrayList<>(); + for(int x = minx ; x < maxx; x++) { + for(int y = miny ; y < maxy ; y++) { + for(int z = minz ; z < maxz ; z++) { + Block block = BlockUtils.getBlock(new Location(world, x, y, z)); + + if(block == null) continue; + + List listAABBS = new ArrayList<>(); + val nmsBlock = CraftMagicNumbers.getBlock(block); + val nmsWorld = ((CraftWorld)block.getWorld()).getHandle(); + nmsBlock.a(nmsWorld, block.getX(), block.getY(), block.getZ(), + new SimpleCollisionBox(block.getLocation(), 2, 1).toAxisAlignedBB(), + listAABBS, null); + + if(listAABBS.size() > 1) { + boxes.add(new ComplexCollisionBox(listAABBS.stream().map(SimpleCollisionBox::new) + .toArray(SimpleCollisionBox[]::new))); + } else if(listAABBS.size() > 0) boxes.add(new SimpleCollisionBox(listAABBS.get(0))); + } + } + } + + return boxes; + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } + + @Override + public boolean isGliding(Player player) { + return false; + } + + @Override + public boolean isChunkLoaded(Location location) { + val world = ((CraftWorld)location.getWorld()).getHandle(); + return !world.isLoaded(location.getBlockX(), location.getBlockY(), location.getBlockZ()) + && world.getChunkAtWorldCoords(location.getBlockX(), location.getBlockZ()).d; + } + + @Override + public float getMovementFactor(LivingEntity entity) { + return ((CraftLivingEntity)entity).getHandle().bl(); + } + + @Override + public float getBlockFriction(Block block) { + return CraftMagicNumbers.getBlock(block).frictionFactor; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_8.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_8.java new file mode 100644 index 00000000..19ce7857 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_8.java @@ -0,0 +1,105 @@ +package cc.funkemunky.api.abstraction.impl; + +import cc.funkemunky.api.abstraction.AbstractVersion; +import cc.funkemunky.api.utils.BlockUtils; +import cc.funkemunky.api.utils.MathHelper; +import cc.funkemunky.api.utils.world.CollisionBox; +import cc.funkemunky.api.utils.world.types.ComplexCollisionBox; +import cc.funkemunky.api.utils.world.types.NoCollisionBox; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import lombok.val; +import net.minecraft.server.v1_8_R1.AxisAlignedBB; +import net.minecraft.server.v1_8_R1.BlockPosition; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_8_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R1.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_8_R1.util.CraftMagicNumbers; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class AbstractV1_8 implements AbstractVersion { + + @Override + public CollisionBox getBlockBox(Block block) { + val nmsBlock = CraftMagicNumbers.getBlock(block); + val nmsWorld = ((CraftWorld)block.getWorld()).getHandle(); + List listAABBS = new ArrayList<>(); + + nmsBlock.a(nmsWorld, new BlockPosition(block.getX(), block.getY(), block.getZ()), nmsBlock.getBlockData(), + new SimpleCollisionBox(block.getLocation(), 2, 1).toAxisAlignedBB(), + listAABBS, null); + + if(listAABBS.size() > 1) { + return new ComplexCollisionBox(listAABBS.stream().map(SimpleCollisionBox::new) + .toArray(SimpleCollisionBox[]::new)); + } else if(listAABBS.size() > 0) new SimpleCollisionBox(listAABBS.get(0)); + + return NoCollisionBox.INSTANCE; + } + + @Override + public List getCollidingBoxes(World world, SimpleCollisionBox box) { + int minx = MathHelper.floor_double(box.xMin), miny = MathHelper.floor_double(box.yMin), + minz = MathHelper.floor_double(box.zMin); + int maxx = MathHelper.floor_double(box.xMax), maxy = MathHelper.floor_double(box.yMax), + maxz = MathHelper.floor_double(box.zMax); + + List boxes = new ArrayList<>(); + for(int x = minx ; x < maxx; x++) { + for(int y = miny ; y < maxy ; y++) { + for(int z = minz ; z < maxz ; z++) { + Block block = BlockUtils.getBlock(new Location(world, x, y, z)); + + if(block == null) continue; + + List listAABBS = new ArrayList<>(); + val nmsBlock = CraftMagicNumbers.getBlock(block); + val nmsWorld = ((CraftWorld)block.getWorld()).getHandle(); + nmsBlock.a(nmsWorld, new BlockPosition(block.getX(), block.getY(), block.getZ()), nmsBlock.getBlockData(), + new SimpleCollisionBox(block.getLocation(), 2, 1).toAxisAlignedBB(), + listAABBS, null); + + if(listAABBS.size() > 1) { + boxes.add(new ComplexCollisionBox(listAABBS.stream().map(SimpleCollisionBox::new) + .toArray(SimpleCollisionBox[]::new))); + } else if(listAABBS.size() > 0) boxes.add(new SimpleCollisionBox(listAABBS.get(0))); + } + } + } + + return boxes; + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } + + @Override + public boolean isGliding(Player player) { + return false; + } + + @Override + public boolean isChunkLoaded(Location location) { + val nmsWorld = ((CraftWorld)location.getWorld()).getHandle(); + BlockPosition pos = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return !nmsWorld.isLoaded(pos) && nmsWorld + .getChunkAtWorldCoords(new BlockPosition(location.getBlockX(), 0, location.getBlockZ())).o(); + } + + @Override + public float getMovementFactor(LivingEntity entity) { + return ((CraftLivingEntity)entity).getHandle().bH(); + } + + @Override + public float getBlockFriction(Block block) { + return CraftMagicNumbers.getBlock(block).frictionFactor; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_8_5.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_8_5.java new file mode 100644 index 00000000..4aeaaf5c --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_8_5.java @@ -0,0 +1,106 @@ +package cc.funkemunky.api.abstraction.impl; + +import cc.funkemunky.api.abstraction.AbstractVersion; +import cc.funkemunky.api.utils.BlockUtils; +import cc.funkemunky.api.utils.MathHelper; +import cc.funkemunky.api.utils.world.CollisionBox; +import cc.funkemunky.api.utils.world.types.ComplexCollisionBox; +import cc.funkemunky.api.utils.world.types.NoCollisionBox; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import lombok.val; +import net.minecraft.server.v1_8_R2.AxisAlignedBB; +import net.minecraft.server.v1_8_R2.BlockPosition; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_8_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R2.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_8_R2.util.CraftMagicNumbers; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class AbstractV1_8_5 implements AbstractVersion { + + @Override + public CollisionBox getBlockBox(Block block) { + val nmsBlock = CraftMagicNumbers.getBlock(block); + val nmsWorld = ((CraftWorld)block.getWorld()).getHandle(); + List listAABBS = new ArrayList<>(); + + nmsBlock.a(nmsWorld, new BlockPosition(block.getX(), block.getY(), block.getZ()), nmsBlock.getBlockData(), + new SimpleCollisionBox(block.getLocation(), 2, 1).toAxisAlignedBB(), + listAABBS, null); + + if(listAABBS.size() > 1) { + return new ComplexCollisionBox(listAABBS.stream().map(SimpleCollisionBox::new) + .toArray(SimpleCollisionBox[]::new)); + } else if(listAABBS.size() > 0) new SimpleCollisionBox(listAABBS.get(0)); + + return NoCollisionBox.INSTANCE; + } + + @Override + public List getCollidingBoxes(World world, SimpleCollisionBox box) { + int minx = MathHelper.floor_double(box.xMin), miny = MathHelper.floor_double(box.yMin), + minz = MathHelper.floor_double(box.zMin); + int maxx = MathHelper.floor_double(box.xMax), maxy = MathHelper.floor_double(box.yMax), + maxz = MathHelper.floor_double(box.zMax); + + List boxes = new ArrayList<>(); + for(int x = minx ; x < maxx; x++) { + for(int y = miny ; y < maxy ; y++) { + for(int z = minz ; z < maxz ; z++) { + Block block = BlockUtils.getBlock(new Location(world, x, y, z)); + + if(block == null) continue; + + List listAABBS = new ArrayList<>(); + val nmsBlock = CraftMagicNumbers.getBlock(block); + val nmsWorld = ((CraftWorld)block.getWorld()).getHandle(); + nmsBlock.a(nmsWorld, new BlockPosition(block.getX(), block.getY(), block.getZ()), nmsBlock.getBlockData(), + new SimpleCollisionBox(block.getLocation(), 2, 1).toAxisAlignedBB(), + listAABBS, null); + + if(listAABBS.size() > 1) { + boxes.add(new ComplexCollisionBox(listAABBS.stream().map(SimpleCollisionBox::new) + .toArray(SimpleCollisionBox[]::new))); + } else if(listAABBS.size() > 0) boxes.add(new SimpleCollisionBox(listAABBS.get(0))); + } + } + } + + return boxes; + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } + + @Override + public boolean isGliding(Player player) { + return false; + } + + @Override + public boolean isChunkLoaded(Location location) { + val nmsWorld = ((CraftWorld)location.getWorld()).getHandle(); + val blockPos = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return !nmsWorld.isLoaded(blockPos) + && nmsWorld.getChunkAtWorldCoords( + new BlockPosition(location.getBlockX(), 0, location.getBlockZ())).o(); + } + + @Override + public float getMovementFactor(LivingEntity entity) { + return ((CraftLivingEntity)entity).getHandle().bI(); + } + + @Override + public float getBlockFriction(Block block) { + return CraftMagicNumbers.getBlock(block).frictionFactor; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_8_9.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_8_9.java new file mode 100644 index 00000000..9d2f4acf --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_8_9.java @@ -0,0 +1,106 @@ +package cc.funkemunky.api.abstraction.impl; + +import cc.funkemunky.api.abstraction.AbstractVersion; +import cc.funkemunky.api.utils.BlockUtils; +import cc.funkemunky.api.utils.MathHelper; +import cc.funkemunky.api.utils.world.CollisionBox; +import cc.funkemunky.api.utils.world.types.ComplexCollisionBox; +import cc.funkemunky.api.utils.world.types.NoCollisionBox; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import lombok.val; +import net.minecraft.server.v1_8_R3.AxisAlignedBB; +import net.minecraft.server.v1_8_R3.BlockPosition; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class AbstractV1_8_9 implements AbstractVersion { + + @Override + public CollisionBox getBlockBox(Block block) { + val nmsBlock = CraftMagicNumbers.getBlock(block); + val nmsWorld = ((CraftWorld)block.getWorld()).getHandle(); + List listAABBS = new ArrayList<>(); + + nmsBlock.a(nmsWorld, new BlockPosition(block.getX(), block.getY(), block.getZ()), nmsBlock.getBlockData(), + new SimpleCollisionBox(block.getLocation(), 2, 1).toAxisAlignedBB(), + listAABBS, null); + + if(listAABBS.size() > 1) { + return new ComplexCollisionBox(listAABBS.stream().map(SimpleCollisionBox::new) + .toArray(SimpleCollisionBox[]::new)); + } else if(listAABBS.size() > 0) new SimpleCollisionBox(listAABBS.get(0)); + + return NoCollisionBox.INSTANCE; + } + + @Override + public List getCollidingBoxes(World world, SimpleCollisionBox box) { + int minx = MathHelper.floor_double(box.xMin), miny = MathHelper.floor_double(box.yMin), + minz = MathHelper.floor_double(box.zMin); + int maxx = MathHelper.floor_double(box.xMax), maxy = MathHelper.floor_double(box.yMax), + maxz = MathHelper.floor_double(box.zMax); + + List boxes = new ArrayList<>(); + for(int x = minx ; x < maxx; x++) { + for(int y = miny ; y < maxy ; y++) { + for(int z = minz ; z < maxz ; z++) { + Block block = BlockUtils.getBlock(new Location(world, x, y, z)); + + if(block == null) continue; + + List listAABBS = new ArrayList<>(); + val nmsBlock = CraftMagicNumbers.getBlock(block); + val nmsWorld = ((CraftWorld)block.getWorld()).getHandle(); + nmsBlock.a(nmsWorld, new BlockPosition(block.getX(), block.getY(), block.getZ()), nmsBlock.getBlockData(), + new SimpleCollisionBox(block.getLocation(), 2, 1).toAxisAlignedBB(), + listAABBS, null); + + if(listAABBS.size() > 1) { + boxes.add(new ComplexCollisionBox(listAABBS.stream().map(SimpleCollisionBox::new) + .toArray(SimpleCollisionBox[]::new))); + } else if(listAABBS.size() > 0) boxes.add(new SimpleCollisionBox(listAABBS.get(0))); + } + } + } + + return boxes; + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } + + @Override + public boolean isGliding(Player player) { + return false; + } + + @Override + public boolean isChunkLoaded(Location location) { + val nmsWorld = ((CraftWorld)location.getWorld()).getHandle(); + val blockPos = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return !nmsWorld.isLoaded(blockPos) + && nmsWorld.getChunkAtWorldCoords( + new BlockPosition(location.getBlockX(), 0, location.getBlockZ())).o(); + } + + @Override + public float getMovementFactor(LivingEntity entity) { + return ((CraftLivingEntity)entity).getHandle().bI(); + } + + @Override + public float getBlockFriction(Block block) { + return CraftMagicNumbers.getBlock(block).frictionFactor; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_9.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_9.java new file mode 100644 index 00000000..87b27a76 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/abstraction/impl/AbstractV1_9.java @@ -0,0 +1,50 @@ +package cc.funkemunky.api.abstraction.impl; + +import cc.funkemunky.api.abstraction.AbstractVersion; +import cc.funkemunky.api.utils.world.CollisionBox; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +import java.util.List; + +public class AbstractV1_9 implements AbstractVersion { + + @Override + public CollisionBox getBlockBox(Block block) { + return null; + } + + @Override + public List getCollidingBoxes(World world, SimpleCollisionBox box) { + return null; + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } + + @Override + public boolean isGliding(Player player) { + return false; + } + + @Override + public boolean isChunkLoaded(Location location) { + return false; + } + + @Override + public float getMovementFactor(LivingEntity entity) { + return 0; + } + + @Override + public float getBlockFriction(Block block) { + return 0; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/BungeeAPI.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/BungeeAPI.java new file mode 100644 index 00000000..23cd8146 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/BungeeAPI.java @@ -0,0 +1,121 @@ +package cc.funkemunky.api.bungee; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.bungee.objects.BungeePlayer; +import cc.funkemunky.api.utils.Color; +import cc.funkemunky.api.utils.ConfigSetting; +import cc.funkemunky.api.utils.Init; +import lombok.val; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.UUID; + + +@Init +public class BungeeAPI { + + @ConfigSetting(name = "bungee") + public static boolean bungee = true; + + public static void broadcastMessage(String message) { + broadcastMessage(message, ""); + } + + public static void broadcastMessage(String message, String permission) { + try { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ObjectOutputStream oStream = new ObjectOutputStream(stream); + + oStream.writeObject("broadcastMsg"); + oStream.writeObject(message); + oStream.writeObject(permission); + + Atlas.getInstance().getBungeeManager().sendData(stream.toByteArray(), "atlas:out"); + } catch(IOException e) { + e.printStackTrace(); + } + } + + public static void movePlayerToServer(String playerName, String server) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataOutputStream oStream = new DataOutputStream(stream); + + try { + oStream.writeUTF("ConnectOther"); + oStream.writeUTF(playerName); + oStream.writeUTF(server); + } catch (IOException e) { + e.printStackTrace(); + } + Atlas.getInstance().getBungeeManager().sendData(stream.toByteArray()); + } + + public static void movePlayerToServer(UUID uuid, String server) { + movePlayerToServer(Bukkit.getOfflinePlayer(uuid).getName(), server); + } + + public static void kickPlayer(String name, String reason) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataOutputStream oStream = new DataOutputStream(stream); + + try { + oStream.writeUTF("KickPlayer"); + oStream.writeUTF(name); + oStream.writeUTF(reason); + } catch (IOException e) { + e.printStackTrace(); + } + + Atlas.getInstance().getBungeeManager().sendData(stream.toByteArray()); + } + + public static void sendMessageToPlayer(String name, String message) { + try { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ObjectOutputStream oStream = new ObjectOutputStream(stream); + oStream.writeUTF("Message"); + oStream.writeUTF(name); + oStream.writeUTF(Color.translate(message)); + Atlas.getInstance().getBungeeManager().sendData(stream.toByteArray()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void sendMessageToPlayer(BungeePlayer player, String message) { + sendMessageToPlayer(player.name, message); + } + + public static int getPlayerVersion(Player player) { + if(player == null) return -1; + + if(Atlas.getInstance().getBungeeManager().getVersionsMap().containsKey(player.getUniqueId())) { + return Atlas.getInstance().getBungeeManager().getVersionsMap().get(player.getUniqueId()).two; + } + + return -1; + } + + public static void sendCommand(String command) { + try { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ObjectOutputStream oStream = new ObjectOutputStream(stream); + oStream.writeObject("commandBungee"); + oStream.writeObject(command); + val array = stream.toByteArray(); + + Atlas.getInstance().getBungeeManager().sendData(array, "atlas:out"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void kickPlayer(UUID uuid, String reason) { + kickPlayer(Bukkit.getOfflinePlayer(uuid).getName(), reason); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/BungeeManager.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/BungeeManager.java new file mode 100644 index 00000000..c149c7e1 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/BungeeManager.java @@ -0,0 +1,241 @@ +package cc.funkemunky.api.bungee; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.bungee.events.BungeeReceiveEvent; +import cc.funkemunky.api.bungee.objects.BungeePlayer; +import cc.funkemunky.api.events.AtlasListener; +import cc.funkemunky.api.events.Listen; +import cc.funkemunky.api.events.impl.PacketReceiveEvent; +import cc.funkemunky.api.handlers.ForgeHandler; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.tinyprotocol.api.Packet; +import cc.funkemunky.api.tinyprotocol.packet.in.WrappedInCustomPayload; +import cc.funkemunky.api.utils.MiscUtils; +import cc.funkemunky.api.utils.Tuple; +import lombok.Getter; +import lombok.val; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.messaging.PluginMessageListener; +import org.bukkit.scheduler.BukkitTask; + +import java.io.*; +import java.util.*; + +@Getter +public class BungeeManager implements AtlasListener, PluginMessageListener { + private String channelOut = "BungeeCord", channelIn = "BungeeCord"; + private String atlasIn = "atlas:in", atlasOut = "atlas:out"; + private Map bungeePlayers = new HashMap<>(); + private Map> versionsMap = new HashMap<>(); + private boolean isBungee; + private List bungeeServers = Collections.synchronizedList(new ArrayList<>()); + private BukkitTask serverCheckTask; + + public BungeeManager() { + Bukkit.getMessenger().registerOutgoingPluginChannel(Atlas.getInstance(), channelOut); + Bukkit.getMessenger().registerOutgoingPluginChannel(Atlas.getInstance(), atlasOut); + Bukkit.getMessenger().registerIncomingPluginChannel(Atlas.getInstance(), channelIn, this); + Bukkit.getMessenger().registerIncomingPluginChannel(Atlas.getInstance(), atlasIn, this); + + + Atlas.getInstance().getEventManager().registerListeners(this, Atlas.getInstance()); + + try { + val wrappedClass = new WrappedClass(Class.forName("org.spigotmc.SpigotConfig")); + + isBungee = wrappedClass.getFieldByName("bungee").get(null); + } catch(ClassNotFoundException e) { + //empty + isBungee = false; + } + if(BungeeAPI.bungee) + isBungee = BungeeAPI.bungee; + + if(isBungee) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + + oos.writeUTF("heartbeat"); + oos.writeUTF("reloadChannels"); + + sendData(baos.toByteArray(), atlasOut); + } catch(IOException e) { + e.printStackTrace(); + } + } + } + + public void sendData(byte[] data, String out) { + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + onlinePlayer.sendPluginMessage(Atlas.getInstance(), out, data); + break; + } + } + + public void sendData(byte[] data) { + sendData(data, channelOut); + } + + public void sendObjects(String server, Object... objects) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + ObjectOutputStream stream = new ObjectOutputStream(output); + + boolean override = server.toLowerCase().contains("override"); + if(override) { + stream.writeObject("sendObjects"); + stream.writeObject(server); + } else { + stream.writeObject("Forward"); + stream.writeObject(server); + stream.writeObject("Forward"); + } + + ByteArrayOutputStream objectOutput = new ByteArrayOutputStream(); + ObjectOutputStream objectStream = new ObjectOutputStream(objectOutput); + + objectStream.writeShort(objects.length); + + for (Object object : objects) objectStream.writeObject(object); + + byte[] array = objectOutput.toByteArray(); + + stream.writeShort(array.length); + stream.write(array); + + sendData(output.toByteArray(), override ? atlasOut : channelOut); //This is where we finally send the data + } + + @Listen + public void onPluginMessageReceived(PacketReceiveEvent event) { + if(event.getType().equals(Packet.Client.CUSTOM_PAYLOAD)) { + WrappedInCustomPayload wrapped = new WrappedInCustomPayload(event.getPacket(), event.getPlayer()); + byte[] bytes = wrapped.getData(); + if(bytes == null || bytes.length <= 0) return; + + String channel = wrapped.getTag(); + ByteArrayInputStream stream = new ByteArrayInputStream(bytes); + if (channel.equals("Bungee")) { + try { + DataInputStream input = new DataInputStream(stream); + + String type = input.readUTF(); + + switch (type) { + case "Forward": { + byte[] array = new byte[input.readShort()]; + input.readFully(array); + + ObjectInputStream objectInput = new ObjectInputStream(new ByteArrayInputStream(array)); + + Object[] objects = new Object[objectInput.readShort()]; + + for (int i = 0; i < objects.length; i++) { + objects[i] = objectInput.readObject(); + } + + Atlas.getInstance().getEventManager().callEvent(new BungeeReceiveEvent(objects, type)); + break; + } + case "GetServers": { + MiscUtils.printToConsole("&7Grabbed servers."); + bungeeServers.clear(); + bungeeServers.addAll(Arrays.asList(input.readUTF().split(", "))); + break; + } + } + + + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } else if (channel.equals(atlasIn)) { + try { + ObjectInputStream input = new ObjectInputStream(stream); + + String dataType = input.readUTF(); + switch (dataType) { + case "mods": { + UUID uuid = (UUID) input.readObject(); + Object modsObject = input.readObject(); + + if (!(modsObject instanceof String)) { + Map mods = (Map) modsObject; + Player pl = Bukkit.getPlayer(uuid); + if (pl != null) { + System.out.println("Received mods for " + pl.getName()); + ForgeHandler.runBungeeModChecker(pl, mods); + } + } + break; + } + case "sendObjects": + String type = input.readUTF(); + + byte[] array = new byte[input.readShort()]; + input.readFully(array); + + ObjectInputStream objectInput = new ObjectInputStream(new ByteArrayInputStream(array)); + + Object[] objects = new Object[objectInput.readShort()]; + + for (int i = 0; i < objects.length; i++) { + objects[i] = objectInput.readObject(); + } + + Atlas.getInstance().getEventManager().callEvent(new BungeeReceiveEvent(objects, type)); + break; + case "version": { + boolean success = input.readBoolean(); + int version = input.readInt(); + UUID uuid = (UUID) input.readObject(); + + versionsMap.put(uuid, new Tuple<>(success, version)); + break; + } + /*case "ping": { + String name = input.readUTF(); + long start = input.readLong(); + long halfPing = input.readLong(); + + bungeePing = System.currentTimeMillis() - start; + bungeeToPing = halfPing; + bungeeFromPing = MathUtils.getDelta(bungeePing, bungeeToPing); + break; + }*/ + } + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } + } + } + + @Override + public void onPluginMessageReceived(String s, Player player, byte[] bytes) { + + } + + /*private void runServerCheckTask() { + if(serverCheckTask != null) serverCheckTask.cancel(); + serverCheckTask = RunUtils.taskTimerAsync(() -> { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream output = new ObjectOutputStream(baos); + output.writeUTF("GetServers"); + sendData(baos.toByteArray()); + + baos = new ByteArrayOutputStream(); + output = new ObjectOutputStream(baos); + + output.writeUTF("ping"); + output.writeLong(System.currentTimeMillis()); + sendData(baos.toByteArray(), atlasOut); + } catch (IOException e) { + MiscUtils.printToConsole("&cFailed to check if the server is connected to Bungee!"); + e.printStackTrace(); + } + }, 20*30, 20*60); + }*/ +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/events/BungeeReceiveEvent.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/events/BungeeReceiveEvent.java new file mode 100644 index 00000000..20317740 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/events/BungeeReceiveEvent.java @@ -0,0 +1,11 @@ +package cc.funkemunky.api.bungee.events; + +import cc.funkemunky.api.events.AtlasEvent; +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public class BungeeReceiveEvent extends AtlasEvent { + public Object[] objects; + public String channel; + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/objects/BungeePlayer.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/objects/BungeePlayer.java new file mode 100644 index 00000000..4e27b9ee --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/bungee/objects/BungeePlayer.java @@ -0,0 +1,43 @@ +package cc.funkemunky.api.bungee.objects; + +import cc.funkemunky.api.tinyprotocol.reflection.Reflection; +import dev.brighten.db.utils.json.JSONException; +import dev.brighten.db.utils.json.JSONObject; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import org.bukkit.Bukkit; + +import java.util.*; + +@NoArgsConstructor +@AllArgsConstructor +public class BungeePlayer { + public String name, server; + public UUID uuid; + public List permissions; + public Map values = new HashMap<>(); + public Map forgeMods = new HashMap<>(); + public boolean usingForge; + + public static BungeePlayer fromJson(String json) { + try { + JSONObject object = new JSONObject(json); + + BungeePlayer player = new BungeePlayer(); + + Iterator iterator = object.keys(); + + while(iterator.hasNext()) { + String key = (String) iterator.next(); + + Reflection.getField(BungeePlayer.class, key, 0).set(player, object.get(key)); + } + + player.uuid = Bukkit.getPlayer(player.name).getUniqueId(); + return player; + } catch (JSONException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/CommandMessages.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/CommandMessages.java new file mode 100644 index 00000000..8e3dd5f0 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/CommandMessages.java @@ -0,0 +1,12 @@ +package cc.funkemunky.api.commands; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +public class CommandMessages { + private String noPermission, invalidArguments, playerOnly, consoleOnly, primaryColor, secondaryColor, titleColor, errorColor, valueColor, successColor; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/FunkeArgument.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/FunkeArgument.java new file mode 100644 index 00000000..ab810f36 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/FunkeArgument.java @@ -0,0 +1,56 @@ +package cc.funkemunky.api.commands; + +import lombok.Getter; +import lombok.Setter; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +import java.util.*; + +@Getter +@Setter +public abstract class FunkeArgument { + private FunkeCommand parent; + private String name, display, description; + private boolean playerOnly; + private List aliases = new ArrayList<>(); + private Map> tabComplete = new HashMap<>(); + private String[] permission; + + public FunkeArgument(FunkeCommand parent, String name, String display, String description) { + this.parent = parent; + this.name = name; + this.display = display; + this.description = description; + + playerOnly = false; + } + + public FunkeArgument(FunkeCommand parent, String name, String display, String description, String... permission) { + this.parent = parent; + this.name = name; + this.display = display; + this.description = description; + this.permission = permission; + playerOnly = false; + } + + public void addAlias(String alias) { + aliases.add(alias); + } + + public void addTabComplete(int arg, String... name) { + List completion = tabComplete.getOrDefault(arg, new ArrayList<>()); + + completion.addAll(Arrays.asList(name)); + + tabComplete.put(arg, completion); + } + + public abstract void onArgument(CommandSender sender, Command cmd, String[] args); + + public FunkeCommand getParent() { + return this.parent; + } +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/FunkeCommand.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/FunkeCommand.java new file mode 100644 index 00000000..dcc287c4 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/FunkeCommand.java @@ -0,0 +1,207 @@ +package cc.funkemunky.api.commands; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.utils.Color; +import cc.funkemunky.api.utils.JsonMessage; +import cc.funkemunky.api.utils.MathUtils; +import cc.funkemunky.api.utils.MiscUtils; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Getter +@Setter +public abstract class FunkeCommand + implements CommandExecutor, TabCompleter { + private static FunkeCommand instance; + private String name, display, permission, description, adminPerm = "api.admin"; + private boolean helpPage, playerOnly; + private final List arguments; + private CommandMessages commandMessages; + + public FunkeCommand(JavaPlugin plugin, String name, String display, String description, String permission) { + this.name = name; + this.display = display; + this.permission = permission; + this.description = description; + + commandMessages = new CommandMessages("No permission.", "Invalid arguments. Please check the help page for more information.", "You must be a player to use this feature", "Only console can use this feature.", Color.Gray, Color.Yellow, Color.Gold, Color.Red, Color.White, Color.Green); + + this.arguments = new ArrayList<>(); + instance = this; + helpPage = true; + plugin.getCommand(name).setExecutor(this); + plugin.getCommand(name).setTabCompleter(this); + + this.addArguments(); + } + + public FunkeCommand(JavaPlugin plugin, String name, String display, String description, String permission, boolean registerLater) { + this.name = name; + this.display = display; + this.permission = permission; + this.description = description; + + commandMessages = new CommandMessages("No permission.", "Invalid arguments. Please check the help page for more information.", "You must be a player to use this feature", "Only console can use this feature.", Color.Gray, Color.Yellow, Color.Gold, Color.Red, Color.White, Color.Green); + + this.arguments = new ArrayList<>(); + instance = this; + helpPage = true; + + if(!registerLater) { + plugin.getCommand(name).setExecutor(this); + plugin.getCommand(name).setTabCompleter(this); + } + + this.addArguments(); + } + + public FunkeCommand(JavaPlugin plugin, String name, String display, String permission, String description, boolean helpPage, boolean registerLater) { + this.name = name; + this.display = display; + this.permission = permission; + this.description = description; + this.helpPage = helpPage; + + commandMessages = new CommandMessages("No permission.", "Invalid arguments. Please check the help page for more information.", "You must be a player to use this feature", "Only console can use this feature.", Color.Gray, Color.Yellow, Color.Gold, Color.Red, Color.White, Color.Green); + commandMessages = new CommandMessages("No permission.", "Invalid arguments. Please check the help page for more information.", "You must be a player to use this feature", "Only console can use this feature.", Color.Gray, Color.Yellow, Color.Gold, Color.Red, Color.White, Color.Green); + + this.arguments = new ArrayList<>(); + instance = this; + if(!registerLater) { + plugin.getCommand(name).setExecutor(this); + plugin.getCommand(name).setTabCompleter(this); + } + + this.addArguments(); + } + + public List onTabComplete(CommandSender commandSender, Command command, String label, String[] args) { + Atlas.getInstance().getProfile().start("command:" + getName() + "#tabComplete"); + List toReturn = new ArrayList<>(); + + if (label.equalsIgnoreCase(name)) { + final FunkeArgument[] funkeArgument = new FunkeArgument[1]; + arguments.forEach(argument -> { + if (args.length == 1 && argument.getName().toLowerCase().startsWith(args[0].toLowerCase()) && !args[0].contains(argument.getName())) { + toReturn.add(argument.getName()); + } + + if (argument.getName().equalsIgnoreCase(args[0])) { + funkeArgument[0] = argument; + } else if (getArgumentByAlias(args[0]) != null) { + funkeArgument[0] = getArgumentByAlias(args[0]); + } + }); + + if (funkeArgument[0] != null) { + funkeArgument[0].getTabComplete().getOrDefault(args.length, new ArrayList<>()).forEach(string -> { + String[] split = string.split(",").length == 0 ? new String[]{string} : string.split(","), conditional = split.length > 1 ? new String[]{split[1], split[2]} : new String[0]; + + String arg = split[0]; + + if (conditional.length > 0) { + if (args[Integer.parseInt(conditional[1]) - 1].equalsIgnoreCase(conditional[0].replaceAll("!", "")) == !conditional[0].startsWith("!") && arg.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) { + toReturn.add(arg); + } + } else if (arg.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) { + toReturn.add(arg); + } + }); + } + + } + Atlas.getInstance().getProfile().stop("command:" + getName() + "#tabComplete"); + return toReturn.size() == 0 ? null : toReturn; + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { + Atlas.getInstance().getProfile().start("command:" + getName() + "#onCommand"); + if (this.permission != null && !sender.hasPermission(this.permission)) { + sender.sendMessage(commandMessages.getErrorColor() + commandMessages.getNoPermission()); + return true; + } + if(playerOnly && !(sender instanceof Player)) { + sender.sendMessage(commandMessages.getErrorColor() + commandMessages.getPlayerOnly()); + return true; + } + + if(helpPage) { + try { + int page = args.length > 0 ? Integer.parseInt(args[0]) : 1; + sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); + sender.sendMessage(commandMessages.getTitleColor() + Color.Bold + this.display + commandMessages.getSecondaryColor() + " Command Help " + commandMessages.getValueColor() + "Page (" + page + " / " + (int) MathUtils.round(arguments.size() / 6D) + ")"); + sender.sendMessage(""); + sender.sendMessage(Color.translate(commandMessages.getSecondaryColor() + "<> " + commandMessages.getPrimaryColor() + "= required. " + commandMessages.getSecondaryColor() + " [] " + commandMessages.getPrimaryColor() + "= optional.")); + sender.sendMessage(""); + if (sender instanceof Player) { + for (int i = (page - 1) * 6; i < Math.min(page * 6, arguments.size()); i++) { + FunkeArgument argument = arguments.get(i); + JsonMessage message = new JsonMessage(); + + StringBuilder aliasesFormatted = new StringBuilder(); + List aliases = argument.getAliases(); + if (aliases.size() > 0) { + for (String aliase : aliases) { + aliasesFormatted.append(Color.White).append(aliase).append(Color.Gray).append(", "); + } + int length = aliasesFormatted.length(); + aliasesFormatted = new StringBuilder(aliasesFormatted.substring(0, length - 2)); + } else { + aliasesFormatted = new StringBuilder(commandMessages.getErrorColor() + "None"); + } + + + String hoverText = Color.translate((argument.getPermission() != null && argument.getPermission().length > 0 ? commandMessages.getTitleColor() + "Permissions: " + commandMessages.getValueColor() + " " + Arrays.toString(argument.getPermission()) : commandMessages.getTitleColor() + "Permission: " + commandMessages.getValueColor() + "none") + + "\n" + commandMessages.getTitleColor() + "Aliases: " + commandMessages.getValueColor() + aliasesFormatted); + message.addText(commandMessages.getPrimaryColor()+ "/" + label.toLowerCase() + commandMessages.getValueColor() + " " + argument.getDisplay() + commandMessages.getPrimaryColor() + " to " + argument.getDescription()).addHoverText(hoverText); + message.sendToPlayer((Player) sender); + } + } else { + for (int i = (page - 1) * 6; i < Math.min(arguments.size(), page * 6); i++) { + FunkeArgument argument = arguments.get(i); + sender.sendMessage(commandMessages.getPrimaryColor() + "/" + label.toLowerCase() + commandMessages.getValueColor() + " " + argument.getDisplay() + commandMessages.getPrimaryColor() + " to " + argument.getDescription()); + } + } + sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); + } catch (NumberFormatException e) { + for (FunkeArgument argument : this.arguments) { + + if (!args[0].equalsIgnoreCase(argument.getName()) && !argument.getAliases().contains(args[0].toLowerCase())) + continue; + + if ((argument.getPermission() == null || sender.hasPermission(adminPerm) + || Arrays.stream(argument.getPermission()).anyMatch(sender::hasPermission))) { + if(!argument.isPlayerOnly() || sender instanceof Player) { + argument.onArgument(sender, cmd, args); + } else { + sender.sendMessage(commandMessages.getErrorColor() + commandMessages.getPlayerOnly()); + } + break; + } + sender.sendMessage(commandMessages.getErrorColor() + commandMessages.getNoPermission()); + break; + } + } + } + Atlas.getInstance().getProfile().stop("command:" + getName() + "#onCommand"); + return true; + } + + private FunkeArgument getArgumentByAlias(String alias) { + return arguments.stream().filter(arg -> arg.getAliases().stream().anyMatch(alias2 -> alias2.equalsIgnoreCase(alias))).findFirst().orElse(null); + } + + protected abstract void addArguments(); +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/FunkeCommandManager.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/FunkeCommandManager.java new file mode 100644 index 00000000..9a9787af --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/FunkeCommandManager.java @@ -0,0 +1,54 @@ +package cc.funkemunky.api.commands; + +import lombok.Getter; +import lombok.val; +import org.bukkit.plugin.Plugin; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Getter +public class FunkeCommandManager { + private final Map> commands; + + public FunkeCommandManager() { + commands = new ConcurrentHashMap<>(); + } + + public void addCommand(Plugin plugin, FunkeCommand command) { + val list = commands.getOrDefault(plugin, new ArrayList<>()); + + list.add(command); + + commands.put(plugin, list); + } + + public void removeAllCommands() { + commands.clear(); + } + + public void removeCommand(String name) { + commands.keySet().forEach(key -> { + val list = commands.get(key); + + list.stream().filter(cmd -> cmd.getName().equalsIgnoreCase(name)).forEach(list::remove); + }); + } + + public void removeAll(Plugin plugin) { + commands.remove(plugin); + } + + public void removeCommand(FunkeCommand command) { + commands.keySet().stream().filter(key -> commands.get(key).contains(command)).forEach(key -> { + val list = commands.get(key); + + list.remove(command); + + commands.put(key, list); + }); + } +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/ColorScheme.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/ColorScheme.java new file mode 100644 index 00000000..a4a2fe3e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/ColorScheme.java @@ -0,0 +1,12 @@ +package cc.funkemunky.api.commands.ancmd; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@AllArgsConstructor +@Getter +@Setter +public class ColorScheme { + private String title, body, key, value, colon, error, body2nd; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/Command.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/Command.java new file mode 100644 index 00000000..9d13c80c --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/Command.java @@ -0,0 +1,23 @@ +package cc.funkemunky.api.commands.ancmd; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface Command { + String name() default ""; + String display() default ""; + boolean playerOnly() default false; + boolean consoleOnly() default false; + boolean opOnly() default false; + boolean async() default false; + String[] permission() default {}; + String[] tabCompletions() default {}; //Format label::result + String description() default ""; + String usage() default ""; + String noPermissionMessage() default "&cNo permission."; + String[] aliases() default {}; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/CommandAdapter.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/CommandAdapter.java new file mode 100644 index 00000000..b26063c3 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/CommandAdapter.java @@ -0,0 +1,20 @@ +package cc.funkemunky.api.commands.ancmd; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +@Getter +@Setter +@AllArgsConstructor +public class CommandAdapter { + private CommandSender sender; + private Command command; + private Player player; + private String label; + private cc.funkemunky.api.commands.ancmd.Command annotation; + private String[] args; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/CommandManager.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/CommandManager.java new file mode 100644 index 00000000..264abce2 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/CommandManager.java @@ -0,0 +1,415 @@ +package cc.funkemunky.api.commands.ancmd; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.commands.tab.TabHandler; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.v1_13.DontImportIfNotLatestThanks; +import cc.funkemunky.api.utils.Color; +import cc.funkemunky.api.utils.JsonMessage; +import cc.funkemunky.api.utils.MathUtils; +import cc.funkemunky.api.utils.MiscUtils; +import lombok.Getter; +import lombok.val; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.SimplePluginManager; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +@Getter +public class CommandManager implements CommandExecutor { + private Map commands = new ConcurrentHashMap<>(); + private Plugin plugin; + @Getter + public SimpleCommandMap map; + public List registered = new ArrayList<>(); + private static DontImportIfNotLatestThanks stuff; + + public CommandManager(Plugin plugin) { + this.plugin = plugin; + + createCommandMap(plugin); + } + + public void createCommandMap(Plugin plugin) { + if (plugin.getServer().getPluginManager() instanceof SimplePluginManager) { + SimplePluginManager manager = (SimplePluginManager) plugin.getServer().getPluginManager(); + try { + Field field = SimplePluginManager.class.getDeclaredField("commandMap"); + field.setAccessible(true); + map = (SimpleCommandMap) field.get(manager); + } catch (IllegalArgumentException | SecurityException | NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + @Deprecated + public void registerCommands(Plugin plugin, Object clazz) { + registerCommands(clazz); + } + + public void registerCommands(Object clazz) { + try { + new WrappedClass(clazz.getClass()).getMethods().stream() + .filter(method -> method.getMethod().isAnnotationPresent(Command.class) + && method.getMethod().getParameterCount() > 0 + && method.getParameters().get(0) == CommandAdapter.class) + .forEach(method -> { + Command annotation = method.getMethod().getAnnotation(Command.class); + + registerCommand(annotation, annotation.name(), method, clazz); + if(annotation.aliases().length > 0) { + Arrays.stream(annotation.aliases()) + .forEach(alias -> registerCommand(annotation, alias, method, clazz)); + } + }); + } catch(Exception e) { + e.printStackTrace(); + } + } + + @Deprecated + public void unregisterCommands(Plugin plugin) { + commands.keySet().stream().filter(key -> commands.get(key).getPlugin().getName().equals(plugin.getName())).forEach(key -> { + + val split = key.split("."); + + val name = split[0]; + + val cmd = map.getCommand(name); + + if(cmd != null) { + cmd.unregister(map); + } + + commands.remove(key); + }); + } + + public void unregisterCommands() { + registered.forEach(cmd -> { + MiscUtils.printToConsole(Color.Yellow + "Unregistered " + cmd.getLabel()); + unregisterBukkitCommand(cmd); + }); + commands.clear(); + } + + public void unregisterCommand(String name) { + registered.stream() + .filter(cmd -> cmd.getName().equalsIgnoreCase(name) || cmd.getLabel().equalsIgnoreCase(name)) + .forEach(cmd -> { + MiscUtils.printToConsole(Color.Yellow + "Unregistered " + cmd.getLabel()); + unregisterBukkitCommand(cmd); + }); + } + + private Object getPrivateField(Object object, String field)throws SecurityException, + NoSuchFieldException, IllegalArgumentException, IllegalAccessException { + Class clazz = object.getClass(); + Field objectField = clazz.getDeclaredField(field); + objectField.setAccessible(true); + Object result = objectField.get(object); + objectField.setAccessible(false); + return result; + } + + public void unregisterBukkitCommand(org.bukkit.command.Command cmd) { + try { + Object map = getPrivateField(getMap(), "knownCommands"); + @SuppressWarnings("unchecked") + HashMap knownCommands = (HashMap) map; + knownCommands.remove(cmd.getName()); + for (String alias : cmd.getAliases()){ + if(knownCommands.containsKey(alias) && knownCommands.get(alias).toString().contains(Atlas.getInstance().getName())){ + knownCommands.remove(alias); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args) { + for(int arg = args.length; arg >= 0 ; arg--) { + StringBuffer buffer = new StringBuffer(); + buffer.append(label.toLowerCase()); + for (int x = 0; x < arg; x++) { + buffer.append("." + args[x].toLowerCase()); + } + String bufferString = buffer.toString(); + if(commands.containsKey(buffer.toString())) { + CommandRegister entry = commands.get(buffer.toString()); + + Command command = entry.getMethod().getMethod().getAnnotation(Command.class); + Atlas.getInstance().getProfile().start("anCommand:" + cmd.getLabel()); + Runnable runnable = () -> { + if(command.opOnly() && !sender.isOp()) { + sender.sendMessage(Color.translate(command.noPermissionMessage())); + } else if(command.playerOnly() && !(sender instanceof Player)) { + sender.sendMessage(Color.Red + "This command is for players only!"); + } else if(command.consoleOnly() && !(sender instanceof ConsoleCommandSender)) { + sender.sendMessage(Color.Red + "This command can only be run via terminal."); + } else { + int subCommand = bufferString.split("\\.").length - 1; + String[] modArgs = IntStream.range(0, args.length - subCommand).mapToObj(i -> args[i + subCommand]).toArray(String[]::new); + + String labelFinal = IntStream.range(0, subCommand).mapToObj(x -> " " + args[x]).collect(Collectors.joining("", label, "")); + if(command.permission().length == 0 || Arrays.stream(command.permission()).anyMatch(sender::hasPermission)) { + CommandAdapter adapter = new CommandAdapter(sender, cmd, sender instanceof Player ? (Player) sender : null, labelFinal, command, modArgs); + try { + entry.getMethod().invoke(entry.getObject(), adapter); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + sender.sendMessage(Color.translate(command.noPermissionMessage())); + } + } + }; + + if(command.async()) Atlas.getInstance().getService().execute(runnable); + else runnable.run(); + + Atlas.getInstance().getProfile().stop("anCommand:" + cmd.getLabel()); + break; + } + } + return true; + } + + public ColorScheme getDefaultScheme() { + return new ColorScheme(Color.Gold + Color.Bold, Color.Gray, Color.Yellow, Color.White, Color.Dark_Gray, Color.Red, Color.White); + } + + public void runHelpMessage(CommandAdapter command, CommandSender sender, ColorScheme scheme) { + try { + int page = command.getArgs().length > 0 ? Integer.parseInt(command.getArgs()[0]) : 1; + Set argumentSet = new HashSet<>(); + + commands.keySet().stream().filter(key -> key.contains(".") && key.startsWith(command.getLabel().toLowerCase())).forEach(key -> { + CommandRegister reg = commands.get(key); + + Command cmd = reg.getMethod().getMethod().getAnnotation(Command.class); + + argumentSet.add(cmd); + }); + + List arguments = new ArrayList<>(argumentSet); + + sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); + sender.sendMessage(scheme.getTitle() + command.getAnnotation().display() + scheme.getBody() + " Help " + scheme.getValue() + "Page (" + page + " / " + (int) MathUtils.round(arguments.size() / 6D) + ")"); + sender.sendMessage(""); + sender.sendMessage(Color.translate(scheme.getBody2nd()) + "<> " + scheme.getBody() + "= required. " + scheme.getBody2nd() + " [] " + scheme.getBody() + "= optional."); + sender.sendMessage(""); + if (sender instanceof Player) { + StringBuilder cmdaliasesFormatted = new StringBuilder(); + List cmdaliases = Arrays.asList(command.getAnnotation().aliases()); + if (cmdaliases.size() > 0) { + for (String aliase : cmdaliases) { + cmdaliasesFormatted.append(scheme.getValue()).append(aliase).append(scheme.getBody()).append(", "); + } + int length = cmdaliasesFormatted.length(); + cmdaliasesFormatted = new StringBuilder(cmdaliasesFormatted.substring(0, length - 2)); + } else { + cmdaliasesFormatted = new StringBuilder(scheme.getError() + "None"); + } + JsonMessage cmdMessage = new JsonMessage(); + String commandText = Color.translate((command.getAnnotation().permission().length > 0 ? scheme.getTitle() + "Permissions: " + scheme.getValue() + " " + Arrays.toString(command.getAnnotation().permission()) : scheme.getTitle() + "Permission: " + scheme.getValue() + "none") + + "\n" + scheme.getTitle() + "Aliases: " + scheme.getValue() + cmdaliasesFormatted); + cmdMessage.addText(scheme.getBody()+ "/" + scheme.getValue() + command.getLabel().toLowerCase() + scheme.getBody() + " to " + command.getAnnotation().description()).addHoverText(commandText); + cmdMessage.sendToPlayer((Player) sender); + for (int i = (page - 1) * 6; i < Math.min(page * 6, arguments.size()); i++) { + JsonMessage message = new JsonMessage(); + + Command argument = arguments.get(i); + StringBuilder aliasesFormatted = new StringBuilder(); + List aliases = Arrays.asList(argument.aliases()); + if (aliases.size() > 0) { + for (String aliase : aliases) { + aliasesFormatted.append(scheme.getValue()).append(aliase).append(scheme.getBody()).append(", "); + } + int length = aliasesFormatted.length(); + aliasesFormatted = new StringBuilder(aliasesFormatted.substring(0, length - 2)); + } else { + aliasesFormatted = new StringBuilder(scheme.getError() + "None"); + } + + + String hoverText = Color.translate((argument.permission().length > 0 ? scheme.getTitle() + "Permissions: " + scheme.getValue() + " " + Arrays.toString(argument.permission()) : scheme.getTitle() + "Permission: " + scheme.getValue() + "none") + + "\n" + scheme.getTitle() + "Aliases: " + scheme.getValue() + aliasesFormatted.toString()); + message.addText(scheme.getBody()+ "/" + command.getLabel().toLowerCase() + scheme.getValue() + " " + (argument.display().length() > 0 ? argument.display() : argument.name()) + scheme.getBody() + " to " + argument.description()).addHoverText(hoverText); + message.sendToPlayer((Player) sender); + } + } else { + sender.sendMessage(scheme.getBody()+ "/" + scheme.getValue() + command.getLabel().toLowerCase() + scheme.getBody() + " to " + command.getAnnotation().description()); + for (int i = (page - 1) * 6; i < Math.min(arguments.size(), page * 6); i++) { + Command argument = arguments.get(i); + sender.sendMessage(scheme.getBody()+ "/" + command.getLabel().toLowerCase() + scheme.getValue() + " " + (argument.display().length() > 0 ? argument.display() : argument.name()) + scheme.getBody() + " to " + argument.description()); + } + } + sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); + } catch(NumberFormatException e) { + sender.sendMessage(scheme.getError() + "The page input must be a number only!"); + } + /*try { + int page = args.length > 0 ? Integer.parseInt(args[0]) : 1; + sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); + sender.sendMessage(commandMessages.getTitleColor() + Color.Bold + this.display + commandMessages.getSecondaryColor() + " Command Help " + commandMessages.getValueColor() + "Page (" + page + " / " + (int) MathUtils.round(arguments.size() / 6D) + ")"); + sender.sendMessage(""); + sender.sendMessage(Color.translate(commandMessages.getSecondaryColor() + "<> " + commandMessages.getPrimaryColor() + "= required. " + commandMessages.getSecondaryColor() + " [] " + commandMessages.getPrimaryColor() + "= optional.")); + sender.sendMessage(""); + if (sender instanceof Player) { + for (int i = (page - 1) * 6; i < Math.min(page * 6, arguments.size()); i++) { + FunkeArgument argument = arguments.get(i); + JsonMessage message = new JsonMessage(); + + StringBuilder aliasesFormatted = new StringBuilder(); + List aliases = argument.getAliases(); + if (aliases.size() > 0) { + for (String aliase : aliases) { + aliasesFormatted.append(Color.White).append(aliase).append(Color.Gray).append(", "); + } + int length = aliasesFormatted.length(); + aliasesFormatted = new StringBuilder(aliasesFormatted.substring(0, length - 2)); + } else { + aliasesFormatted = new StringBuilder(commandMessages.getErrorColor() + "None"); + } + + + String hoverText = Color.translate((argument.getPermission() != null && argument.getPermission().length > 0 ? commandMessages.getTitleColor() + "Permissions: " + commandMessages.getValueColor() + " " + Arrays.toString(argument.getPermission()) : commandMessages.getTitleColor() + "Permission: " + commandMessages.getValueColor() + "none") + + "\n" + commandMessages.getTitleColor() + "Aliases: " + commandMessages.getValueColor() + aliasesFormatted); + message.addText(commandMessages.getPrimaryColor()+ "/" + label.toLowerCase() + commandMessages.getValueColor() + " " + argument.getDisplay() + commandMessages.getPrimaryColor() + " to " + argument.getDescription()).addHoverText(hoverText); + message.sendToPlayer((Player) sender); + } + } else { + for (int i = (page - 1) * 6; i < Math.min(arguments.size(), page * 6); i++) { + FunkeArgument argument = arguments.get(i); + sender.sendMessage(commandMessages.getPrimaryColor() + "/" + label.toLowerCase() + commandMessages.getValueColor() + " " + argument.getDisplay() + commandMessages.getPrimaryColor() + " to " + argument.getDescription()); + } + } + sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); + } catch (NumberFormatException e) { + for (FunkeArgument argument : this.arguments) { + + if (!args[0].equalsIgnoreCase(argument.getName()) && !argument.getAliases().contains(args[0].toLowerCase())) + continue; + + if ((argument.getPermission() == null || sender.hasPermission(adminPerm) + || sender.hasPermission(permission))) { + if(!argument.isPlayerOnly() || sender instanceof Player) { + argument.onArgument(sender, cmd, args); + } else { + sender.sendMessage(commandMessages.getErrorColor() + commandMessages.getPlayerOnly()); + } + break; + } + sender.sendMessage(commandMessages.getErrorColor() + commandMessages.getNoPermission()); + break; + } + }*/ + } + + public void registerCommand(Command command, String label, WrappedMethod method, Object clazz) { + Command annotation = method.getMethod().getAnnotation(Command.class); + + CommandRegister cmdReg = new CommandRegister(plugin, method, clazz); + + commands.put(annotation.name().toLowerCase(), cmdReg); + + val split = ("/" + annotation.name().toLowerCase()).split("\\."); + if(split.length > 0) { + String[] requirements; + if(split.length > 1) { + requirements = new String[split.length - 1]; + + System.arraycopy(split, 0, requirements, 0, requirements.length); + } else requirements = new String[]{"/"}; + + TabHandler.INSTANCE.addTabComplete(requirements, split[split.length - 1].replace("/", "")); + } + Arrays.stream(annotation.aliases()).forEach(alias -> commands.put(alias.toLowerCase(), cmdReg)); + MiscUtils.printToConsole(Color.Yellow + "Registered ancmd: " + annotation.name()); + + String cmdLabel = label.split("\\.")[0].toLowerCase(); + + if (map.getCommand(cmdLabel) == null) { + SpigotCommand cmd = new SpigotCommand(cmdLabel, this, plugin); + Arrays.stream(annotation.tabCompletions()).forEach(string -> { + val split1 = ("/" + annotation.name().toLowerCase()).split("."); + String[] requirements1; + if(split1.length > 1) { + requirements1 = new String[split1.length - 1]; + + System.arraycopy(split1, 0, requirements1, 0, requirements1.length); + } else requirements1 = new String[]{"/"}; + + TabHandler.INSTANCE.addTabComplete(requirements1, split1[split1.length - 1] + .replace("/", "")); + }); + + map.register(plugin.getName(), cmd); + + registered.add(cmd); + + if(label.contains(".")) { + String[] args = label.split("."); + + if(args.length > 1) { + StringBuilder completeLabel = new StringBuilder(); + for(int i = 0 ; i < args.length - 1 ; i++) { + completeLabel.append(args[i]).append("."); + } + + completeLabel.deleteCharAt(completeLabel.length() - 1); + + cmd.completer.addCompleter(completeLabel.toString(), args[label.length() - 1]); + } + } + } + if (!command.description().equalsIgnoreCase("") && Objects.equals(cmdLabel, label)) { + map.getCommand(cmdLabel).setDescription(command.description()); + } + if (!command.usage().equalsIgnoreCase("") && Objects.equals(cmdLabel, label)) { + map.getCommand(cmdLabel).setUsage(command.usage()); + } + } + + @Deprecated + public void registerCommand(Plugin plugin, Command command, String label, Method method, Object clazz) { + registerCommand(command, label, new WrappedMethod(new WrappedClass(clazz.getClass()), method), clazz); + } + + public void addCompletionsForCommand(String command, String...completions) { + if(commands.containsKey(command)) { + CommandRegister reg = commands.get(command); + + String[] split = command.split("."); + String label = split[0]; + + SpigotCommand cmd = (SpigotCommand) map.getCommand(label); + + for (String completion : completions) { + cmd.completer.addCompleter(command, completion); + } + } + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) { + stuff = new DontImportIfNotLatestThanks(); + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/CommandRegister.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/CommandRegister.java new file mode 100644 index 00000000..4bbb62bb --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/CommandRegister.java @@ -0,0 +1,16 @@ +package cc.funkemunky.api.commands.ancmd; + +import cc.funkemunky.api.reflections.types.WrappedMethod; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.plugin.Plugin; + +@AllArgsConstructor +@Getter +@Setter +public class CommandRegister { + private Plugin plugin; + private WrappedMethod method; + private Object object; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/SpigotCommand.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/SpigotCommand.java new file mode 100644 index 00000000..91f0e597 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/SpigotCommand.java @@ -0,0 +1,96 @@ +package cc.funkemunky.api.commands.ancmd; + +import org.apache.commons.lang.Validate; +import org.bukkit.command.CommandException; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.plugin.Plugin; + +import java.util.List; + +public class SpigotCommand extends org.bukkit.command.Command { + + private Plugin owningPlugin; + protected SpigotCompleter completer; + private CommandExecutor executor; + private boolean notAno = false; + + + public SpigotCommand(String label, CommandExecutor executor, Plugin owner) { + super(label); + this.executor = executor; + this.owningPlugin = owner; + this.usageMessage = ""; + } + + public SpigotCommand(String label, CommandExecutor executor, Plugin owner, boolean notAno) { + super(label); + this.executor = executor; + this.owningPlugin = owner; + this.usageMessage = ""; + this.notAno = notAno; + } + + @Override + public boolean execute(CommandSender sender, String commandLabel, String[] args) { + if (!owningPlugin.isEnabled()) { + return false; + } + if(notAno) { + return executor.onCommand(sender, this, commandLabel, args); + } else { + boolean success = false; + + if (!testPermission(sender)) { + return true; + } + + try { + success = executor.onCommand(sender, this, commandLabel, args); + } catch (Throwable ex) { + throw new CommandException("Unhandled exception executing ancmd '" + commandLabel + "' in plugin " + owningPlugin.getDescription().getFullName(), ex); + } + + if (!success && usageMessage.length() > 0) { + for (String line : usageMessage.replace("", commandLabel).split("\n")) { + sender.sendMessage(line); + } + } + + return success; + } + } + + @Override + public java.util.List tabComplete(CommandSender sender, String alias, String[] args) throws CommandException, IllegalArgumentException { + Validate.notNull(sender, "Sender cannot be null"); + Validate.notNull(args, "Arguments cannot be null"); + Validate.notNull(alias, "Alias cannot be null"); + + List completions = null; + try { + if (completer != null) { + completions = completer.onTabComplete(sender, this, alias, args); + } + if (completions == null && executor instanceof TabCompleter) { + completions = ((TabCompleter) executor).onTabComplete(sender, this, alias, args); + } + } catch (Throwable ex) { + StringBuilder message = new StringBuilder(); + message.append("Unhandled exception during tab completion for ancmd '/").append(alias).append(' '); + for (String arg : args) { + message.append(arg).append(' '); + } + message.deleteCharAt(message.length() - 1).append("' in plugin ") + .append(owningPlugin.getDescription().getFullName()); + throw new CommandException(message.toString(), ex); + } + + if (completions == null) { + return super.tabComplete(sender, alias, args); + } + return completions; + } + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/SpigotCompleter.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/SpigotCompleter.java new file mode 100644 index 00000000..bdc8c6d8 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/ancmd/SpigotCompleter.java @@ -0,0 +1,43 @@ +package cc.funkemunky.api.commands.ancmd; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SpigotCompleter implements TabCompleter { + + private Map> completers = new HashMap<>(); + + public void addCompleter(String label, String completer) { + List completers = this.completers.getOrDefault(label, new ArrayList<>()); + + completers.add(completer); + + this.completers.put(label, completers); + } + + @SuppressWarnings("unchecked") + @Override + public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { + for (int i = args.length; i >= 0; i--) { + StringBuffer buffer = new StringBuffer(); + buffer.append(label.toLowerCase()); + for (int x = 0; x < i; x++) { + if (!args[x].equals("") && !args[x].equals(" ")) { + buffer.append("." + args[x].toLowerCase()); + } + } + String cmdLabel = buffer.toString(); + if (completers.containsKey(cmdLabel)) { + return completers.get(cmdLabel); + } + } + return null; + } + +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/AtlasCommand.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/AtlasCommand.java new file mode 100644 index 00000000..d4ca8453 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/AtlasCommand.java @@ -0,0 +1,24 @@ +package cc.funkemunky.api.commands.impl; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.commands.FunkeCommand; +import cc.funkemunky.api.commands.impl.args.ProfileArgument; +import cc.funkemunky.api.commands.impl.args.ReloadArgument; +import cc.funkemunky.api.commands.impl.args.ToggleArgument; +import cc.funkemunky.api.commands.impl.args.UpdateArgument; + +public class AtlasCommand extends FunkeCommand { + public AtlasCommand() { + super(Atlas.getInstance(), "atlas", "Atlas", "The Atlas main ancmd.", "atlas.admin"); + } + + @Override + protected void addArguments() { + getArguments().add(new UpdateArgument(this)); + getArguments().add(new ReloadArgument(this)); + getArguments().add(new ToggleArgument(this, "toggle", "toggle ", + "toggle parts of Atlas on or off.", "atlas.toggle")); + getArguments().add(new ProfileArgument(this, "profile", "profile [reset]", + "view or reset the lag information gathered.", "atlas.profile")); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/BungeeCommand.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/BungeeCommand.java new file mode 100644 index 00000000..29545e70 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/BungeeCommand.java @@ -0,0 +1,17 @@ +package cc.funkemunky.api.commands.impl.args; + +import cc.funkemunky.api.bungee.BungeeAPI; +import cc.funkemunky.api.commands.ancmd.Command; +import cc.funkemunky.api.commands.ancmd.CommandAdapter; +import cc.funkemunky.api.utils.Init; +import cc.funkemunky.api.utils.Priority; + +@Init(commands = true,priority = Priority.LOW) +public class BungeeCommand { + + @Command(name = "bungeecmd", display = "bungee [args]", description = "send command to bungee", + permission = "atlas.command.bungee") + public void onCommand(CommandAdapter cmd) { + BungeeAPI.sendCommand(String.join(" ", cmd.getArgs())); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/ProfileArgument.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/ProfileArgument.java new file mode 100644 index 00000000..949582ae --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/ProfileArgument.java @@ -0,0 +1,88 @@ +package cc.funkemunky.api.commands.impl.args; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.commands.FunkeArgument; +import cc.funkemunky.api.commands.FunkeCommand; +import cc.funkemunky.api.profiling.ResultsType; +import cc.funkemunky.api.utils.Color; +import cc.funkemunky.api.utils.MiscUtils; +import cc.funkemunky.api.utils.Pastebin; +import cc.funkemunky.api.utils.Tuple; +import lombok.val; +import org.apache.commons.lang.time.DateFormatUtils; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; +import java.util.TimeZone; + +public class ProfileArgument extends FunkeArgument { + public ProfileArgument(FunkeCommand parent, String name, String display, String description, String... permission) { + super(parent, name, display, description, permission); + + addTabComplete(2, "reset"); + } + + @Override + public void onArgument(CommandSender sender, Command cmd, String[] args) { + if(args.length > 1) { + switch(args[1].toLowerCase()) { + case "reset": { + Atlas.getInstance().getProfile().reset(); + break; + } + case "average": + case "avg": { + makePaste(sender, ResultsType.AVERAGE); + break; + } + case "tick": { + makePaste(sender, ResultsType.TICK); + break; + } + case "samples": + case "sample": { + makePaste(sender, ResultsType.SAMPLES); + break; + } + default: { + makePaste(sender, ResultsType.TOTAL); + break; + } + } + } else { + makePaste(sender, ResultsType.TOTAL); + } + } + + private void makePaste(CommandSender sender, ResultsType type) { + List body = new ArrayList<>(); + body.add(MiscUtils.lineNoStrike()); + float totalPCT = 0; + val results = Atlas.getInstance().getProfile().results(type); + + for (String key : results.keySet()) { + //Converting nanoseconds to millis to be more readable. + Tuple result = results.get(key); + double amount = result.two / 1000000D; + + body.add(key + ": " + amount + "ms (" + result.one + " calls)"); + } + StringBuilder builder = new StringBuilder(); + for (String aBody : body) { + builder.append(aBody).append(";"); + } + + builder.deleteCharAt(body.size() - 1); + + String bodyString = builder.toString().replaceAll(";", "\n"); + + try { + sender.sendMessage(Color.Green + "Results: " + Pastebin.makePaste(bodyString, "Atlas Profile: " + DateFormatUtils.format(System.currentTimeMillis(), ", ", TimeZone.getTimeZone("604")), Pastebin.Privacy.UNLISTED)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/ReloadArgument.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/ReloadArgument.java new file mode 100644 index 00000000..baaf3386 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/ReloadArgument.java @@ -0,0 +1,37 @@ +package cc.funkemunky.api.commands.impl.args; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.commands.FunkeArgument; +import cc.funkemunky.api.commands.FunkeCommand; +import cc.funkemunky.api.utils.Color; +import cc.funkemunky.api.utils.MiscUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ReloadArgument extends FunkeArgument { + public ReloadArgument(FunkeCommand command) { + super(command, "reload", "reload", "reload the configuration.", "atlas.reload"); + } + + @Override + public void onArgument(CommandSender sender, Command cmd, String[] args) { + Atlas.getInstance().reloadConfig(); + + List dependingPls = new ArrayList<>(); + Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(pl -> pl.getDescription().getDepend().contains("Atlas")).forEach(pl -> dependingPls.add(pl)); + + dependingPls.forEach(pl -> MiscUtils.unloadPlugin(pl.getName())); + MiscUtils.unloadPlugin("Atlas"); + MiscUtils.loadPlugin("Atlas"); + + dependingPls.forEach(pl -> MiscUtils.loadPlugin(pl.getName())); + + sender.sendMessage(Color.Green + "Successfully reloaded the Atlas configuration file!"); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/ToggleArgument.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/ToggleArgument.java new file mode 100644 index 00000000..6048250e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/ToggleArgument.java @@ -0,0 +1,39 @@ +package cc.funkemunky.api.commands.impl.args; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.commands.FunkeArgument; +import cc.funkemunky.api.commands.FunkeCommand; +import cc.funkemunky.api.utils.Color; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class ToggleArgument extends FunkeArgument { + public ToggleArgument(FunkeCommand parent, String name, String display, String description, String... permission) { + super(parent, name, display, description, permission); + + addTabComplete(2, "event", "events", "packets"); + } + + @Override + public void onArgument(CommandSender sender, Command cmd, String[] args) { + if(args.length > 1) { + switch(args[1].toLowerCase()) { + case "event": + case "events": { + Atlas.getInstance().getEventManager().paused = !Atlas.getInstance().getEventManager().paused; + sender.sendMessage(Color.translate("&7The Atlas AtlasEvent System has been " + (Atlas.getInstance().getEventManager().paused ? "&cpaused" : "&aunpaused") + "&7.")); + break; + } + case "packets": { + Atlas.getInstance().getTinyProtocolHandler().paused = !Atlas.getInstance().getTinyProtocolHandler().paused; + sender.sendMessage(Color.translate("&7The Atlas Packet System has been " + (Atlas.getInstance().getTinyProtocolHandler().paused ? "&cpaused" : "&aunpaused") + "&7.")); + break; + } + default: { + sender.sendMessage(getParent().getCommandMessages().getErrorColor() + getParent().getCommandMessages().getInvalidArguments()); + break; + } + } + } else sender.sendMessage(getParent().getCommandMessages().getErrorColor() + getParent().getCommandMessages().getInvalidArguments()); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/UpdateArgument.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/UpdateArgument.java new file mode 100644 index 00000000..a7660b71 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/impl/args/UpdateArgument.java @@ -0,0 +1,137 @@ +package cc.funkemunky.api.commands.impl.args; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.commands.FunkeArgument; +import cc.funkemunky.api.commands.FunkeCommand; +import cc.funkemunky.api.handlers.chat.ChatHandler; +import cc.funkemunky.api.handlers.chat.OnChat; +import cc.funkemunky.api.utils.Color; +import cc.funkemunky.api.utils.MiscUtils; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +import java.util.List; +import java.util.stream.Collectors; + +public class UpdateArgument extends FunkeArgument { + public UpdateArgument(FunkeCommand command) { + super(command, "update", "update [args]", "manage updates for Atlas.", "atlas.update"); + + addTabComplete(2, "check", "download", "update"); + } + + @Override + public void onArgument(CommandSender sender, Command cmd, String[] args) { + if(args.length > 1) { + switch (args[1].toLowerCase()) { + case "check": { + sender.sendMessage(Color.Gray + "Running update check..."); + // Refreshes the update information from GitHub. + Atlas.getInstance().getUpdater().runUpdateCheck(); + sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); + sender.sendMessage(Color.translate("&eLatest Version: &f" + + Atlas.getInstance().getUpdater().getLatestUpdate())); + sender.sendMessage(Color.translate("&eLatest Release Date:")); + sender.sendMessage(Color.White + Atlas.getInstance().getUpdater().getReleaseDate()); + sender.sendMessage(Color.Yellow + "View update:"); + sender.sendMessage(Color.White + Atlas.getInstance().getUpdater().getViewLink()); + sender.sendMessage(Color.translate("&eCurrent Version: &f" + + Atlas.getInstance().getUpdater().getCurrentUpdate())); + sender.sendMessage(""); + + if(Atlas.getInstance().getUpdater().needsToUpdate()) { + sender.sendMessage(Color.Green + Color.Bold + "There is an update available!"); + } else { + sender.sendMessage(Color.Green + "You are on the latest version, no need to worry."); + } + sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); + break; + } + case "download": + case "update": { + if(sender instanceof Player) { + Player player = (Player) sender; + player.sendMessage(Color.Gray + "You need to confirm this decision by typing " + + Color.Yellow + "'download' " + Color.Gray + "in chat or " + Color.Yellow + + "'cancel' " + Color.Gray + "to cancel!"); + ChatHandler.onChat(player, false, (chat, message) -> { + switch(message.toLowerCase()) { + case "cancel": { + ChatHandler.remove(player, chat); + sender.sendMessage(Color.Red + "Canceled download."); + break; + } + case "download": { + Atlas.getInstance().getSchedular().execute(() -> { + sender.sendMessage(Color.Red + "Downloading the latest version..."); + //Downloads the latest version from git. + Atlas.getInstance().getUpdater().downloadNewVersion(); + // The server needs restarting or reloading to prevent any errors from hiccups when reloading. + sender.sendMessage(Color.translate("&7Downloaded! Would you like to " + + "reload Atlas? Type &e'yes' &7to reload or anything else to cancel")); + }); + ChatHandler.remove(player, chat); + ChatHandler.onChat(player, true, (chat2, message2) -> { + Atlas.getInstance().getSchedular().execute(() -> { + if(message2.toLowerCase().contains("yes")) { + player.sendMessage(Color.Red + "Reloading..."); + player.sendMessage(Color.Gray + "Grabbing plugins using Atlas..."); + List atlasPlugins = Atlas.getInstance().getPluginLoaderHandler() + .getLoadedPlugins().stream() + .map(Plugin::getName).collect(Collectors.toList()); + + player.sendMessage(Color.Gray + "Unloading dependant plugins..."); + for (int i = atlasPlugins.size() - 1; i > 0; --i) { + String pl = atlasPlugins.get(i); + player.sendMessage(Color.Gray + "Unloading " + pl + "..."); + MiscUtils.unloadPlugin(pl); + } + + player.sendMessage(Color.Gray + "Unloading Atlas..."); + MiscUtils.unloadPlugin("Atlas"); + + player.sendMessage(Color.Gray + "Loading Atlas..."); + MiscUtils.loadPlugin("Atlas"); + + player.sendMessage(Color.Gray + "Loading dependant plugins..."); + for (String pl : atlasPlugins) { + player.sendMessage(Color.Gray + "Loading " + pl + "..."); + MiscUtils.loadPlugin(pl); + } + + player.sendMessage(Color.Green + "Completed reload! " + + "Now running updated Atlas version."); + } else player.sendMessage(Color.Red + "Restart server to run updated Atlas."); + }); + }); + break; + } + default: { + sender.sendMessage(Color.Red + "Message \"" + message + "\" is not an option."); + break; + } + } + }); + } else { + sender.sendMessage(Color.Red + "Downloading the latest version..."); + Atlas.getInstance().getUpdater().downloadNewVersion(); //Downloads the latest version from git. + // The server needs restarting or reloading to prevent any errors from hiccups when reloading. + sender.sendMessage(Color.Green + + "Downloaded! Would you like to reload Atlas? Type 'yes' to reload and 'no' to cancel"); + } + break; + } + default: { + sender.sendMessage(Color.Red + + "Invalid arguments! Check the help to see where you made a mistake."); + break; + } + } + } else { + sender.sendMessage(Color.Red + + "Invalid arguments! Check the help to see where you made a mistake."); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/tab/TabHandler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/tab/TabHandler.java new file mode 100644 index 00000000..a8489bf1 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/commands/tab/TabHandler.java @@ -0,0 +1,75 @@ +package cc.funkemunky.api.commands.tab; + +import cc.funkemunky.api.events.AtlasListener; +import cc.funkemunky.api.events.Listen; +import cc.funkemunky.api.events.ListenerPriority; +import cc.funkemunky.api.events.impl.PacketReceiveEvent; +import cc.funkemunky.api.tinyprotocol.api.Packet; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.api.TinyProtocolHandler; +import cc.funkemunky.api.tinyprotocol.packet.in.WrappedInTabComplete; +import cc.funkemunky.api.tinyprotocol.packet.out.WrappedOutTabComplete; +import cc.funkemunky.api.tinyprotocol.packet.types.v1_13.DontImportIfNotLatestThanks; +import cc.funkemunky.api.utils.Init; +import cc.funkemunky.api.utils.Priority; + +import java.util.*; + +@Init(priority = Priority.HIGH) +public class TabHandler implements AtlasListener { + + public static TabHandler INSTANCE; + private Map> tabArgs = new HashMap<>(); + private static DontImportIfNotLatestThanks stuff; + + public TabHandler() { + INSTANCE = this; + } + + @Listen(priority = ListenerPriority.HIGH) + public void onTab(PacketReceiveEvent event) { + if(event.getType().equals(Packet.Client.TAB_COMPLETE)) { + WrappedInTabComplete packet = new WrappedInTabComplete(event.getPacket(), event.getPlayer()); + + String[] args = (packet.getMessage().startsWith("/") + ? packet.getMessage().toLowerCase().substring(1) : packet.getMessage().toLowerCase()) + .split(" "); + + if(tabArgs.containsKey(args)) { + Set options = tabArgs.get(args); + + WrappedOutTabComplete complete = new WrappedOutTabComplete(options.stream() + .sorted(Comparator.comparing(s -> s)) + .toArray(String[]::new)); + + TinyProtocolHandler.sendPacket(event.getPlayer(), complete.getObject()); + } + } + } + + public void addTabComplete(String[] requirement, String... args) { + if(stuff != null) { + for (String arg : args) { + String[] array = new String[requirement.length + 1]; + + System.arraycopy(requirement, 0, array, 0, requirement.length); + + array[array.length - 1] = arg; + + stuff.registerTabComplete(array); + } + return; + } + Set complete = tabArgs.getOrDefault(requirement, new HashSet<>()); + + complete.addAll(Arrays.asList(args)); + + tabArgs.put(requirement, complete); + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) { + stuff = new DontImportIfNotLatestThanks(); + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/config/ConfigUtils.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/config/ConfigUtils.java new file mode 100644 index 00000000..2c91cfc1 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/config/ConfigUtils.java @@ -0,0 +1,51 @@ +package cc.funkemunky.api.config; + +import lombok.RequiredArgsConstructor; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; + +@RequiredArgsConstructor +public class ConfigUtils { + private final FileConfiguration config; + private final JavaPlugin plugin; + + public ConfigUtils(JavaPlugin plugin) { + this.plugin = plugin; + this.config = plugin.getConfig(); + } + + public boolean getBooleanOrDefault(String path, boolean def) { + return (boolean) getOrDefault(path, def); + } + + public double getDoubleOrDefault(String path, double def) { + return (double) getOrDefault(path, def); + } + + public String getStringOrDefault(String path, String def) { + return (String) getOrDefault(path, def); + } + + public List getListOrDefault(String path, List def) { + return (List) getOrDefault(path, def); + } + + public long getLongOrDefault(String path, long def) { + return (long) getOrDefault(path, def); + } + + public Object getOrDefault(String path, Object def) { + Object object; + + if((object = config.get(path)) != null) { + return object; + } + + config.set(path, def); + plugin.saveConfig(); + + return def; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/config/MessageConfig.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/config/MessageConfig.java new file mode 100644 index 00000000..6e4cc11e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/config/MessageConfig.java @@ -0,0 +1,76 @@ +package cc.funkemunky.api.config; + +import cc.funkemunky.api.utils.Color; +import cc.funkemunky.api.utils.FunkeFile; +import cc.funkemunky.api.utils.MiscUtils; +import dev.brighten.db.utils.Pair; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +public class MessageConfig { + + public String language; + private FunkeFile file; + private Map messages = new HashMap<>(); + + public MessageConfig(FunkeFile file, String language) { + this.file = file; + this.language = language; + load(); + } + + public void save() { + file.getLines().clear(); + messages.forEach((key, value) -> file.addLine(key + ": " + "" + value + "")); + file.write(); + } + + public void reload() { + file.readFile(); + load(); + } + + private void load() { + messages.clear(); + + for (int i = 0; i < file.getLines().size(); i++) { + String line = file.getLines().get(i); + + int lineNumber = i; //For the sole purpose of using in the consumer below since it needs the int as final. + if(runCheck(line, reason -> MiscUtils.printToConsole("&cError while parsing message " + + "&8(&f" + language + "&8) &con line " + lineNumber))) { + return; + } + } + + file.getLines().stream().map(line -> { + String[] split = line.replace("\"", "").split(": ", 2); + + return new Pair<>(split[0], split[1]); + }).forEach(pair -> messages.put(pair.key, pair.value)); + } + + public String msg(String key, String def) { + boolean contains = messages.containsKey(key); + String string = Color.translate(messages.computeIfAbsent(key, stringKey -> def)); + if(!contains) save(); + return string; + } + + //Returns true if the check failed. + private boolean runCheck(String line, Consumer reason) { + if(line.length() == 0) { + reason.accept("Line is blank. Please remove this line."); + return true; + } else if(!line.contains(":")) { + reason.accept("No ':' was used."); + return true; + } else if(String.valueOf(line.charAt(0)).equals(":")) { + reason.accept("There is no key value (name) before ':' character."); + return true; + } + return false; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/config/MessageHandler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/config/MessageHandler.java new file mode 100644 index 00000000..76f98e29 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/config/MessageHandler.java @@ -0,0 +1,64 @@ +package cc.funkemunky.api.config; + +import cc.funkemunky.api.utils.FunkeFile; +import lombok.Setter; +import org.bukkit.plugin.Plugin; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MessageHandler { + + public List messageConfigs = new ArrayList<>(); + private Plugin plugin; + @Setter + private String currentLang; + + public MessageHandler(Plugin plugin) { + this.plugin = plugin; + + load(); + } + + public MessageConfig getLanguage(String language) { + return messageConfigs.stream().filter(cnf -> cnf.language.equals(language)) + .findFirst().orElseGet(() -> { + FunkeFile fFile = new FunkeFile(plugin, "messages", "messages_" + language); + MessageConfig config = new MessageConfig(fFile, language); + + messageConfigs.add(config); + return config; + }); + } + + public MessageConfig getLanguage() { + return getLanguage(currentLang); + } + + private void load() { + File dir = new File(plugin.getDataFolder().getPath() + File.separator + "messages"); + + dir.mkdirs(); + + File[] files = dir.listFiles(); + + if(files == null) return; + + Arrays.stream(files) + .filter(file -> file.getName().startsWith("messages_")) + .forEach(file -> { + FunkeFile fFile = new FunkeFile(file); + + MessageConfig config = new MessageConfig(fFile, file.getName().split("_")[1]); + + messageConfigs.add(config); + }); + } + + public void reloadAll() { + messageConfigs.clear(); + load(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/AtlasEvent.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/AtlasEvent.java new file mode 100644 index 00000000..637acff6 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/AtlasEvent.java @@ -0,0 +1,8 @@ +package cc.funkemunky.api.events; + +import lombok.NoArgsConstructor; + +@NoArgsConstructor +public abstract class AtlasEvent { +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/AtlasListener.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/AtlasListener.java new file mode 100644 index 00000000..07461c64 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/AtlasListener.java @@ -0,0 +1,5 @@ +package cc.funkemunky.api.events; + +public interface AtlasListener { +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/Cancellable.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/Cancellable.java new file mode 100644 index 00000000..2d0c68d2 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/Cancellable.java @@ -0,0 +1,8 @@ +package cc.funkemunky.api.events; + +public interface Cancellable { + boolean isCancelled(); + + void setCancelled(boolean var1); +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/EventManager.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/EventManager.java new file mode 100644 index 00000000..e689acf1 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/EventManager.java @@ -0,0 +1,95 @@ +package cc.funkemunky.api.events; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.events.exceptions.ListenParamaterException; +import lombok.Getter; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; + +@Getter +public class EventManager { + private final List listenerMethods = new CopyOnWriteArrayList<>(); + public boolean paused = false; + + public void registerListener(Method method, AtlasListener listener, Plugin plugin) throws ListenParamaterException { + if(method.getParameterTypes().length == 1) { + if(method.getParameterTypes()[0].getSuperclass().equals(AtlasEvent.class)) { + Listen listen = method.getAnnotation(Listen.class); + ListenerMethod lm = new ListenerMethod(plugin, method, listener, listen.priority()); + + if(!listen.priority().equals(ListenerPriority.NONE)) { + lm.listenerPriority = listen.priority(); + } + + listenerMethods.add(lm); + listenerMethods.sort(Comparator.comparing(mth -> mth.listenerPriority.getPriority(), Comparator.reverseOrder())); + } else { + throw new ListenParamaterException("Method " + method.getDeclaringClass().getName() + "#" + method.getName() + "'s paramater: " + method.getParameterTypes()[0].getName() + " is not an instanceof " + AtlasEvent.class.getSimpleName() + "!"); + } + } else { + throw new ListenParamaterException("Method " + method.getDeclaringClass().getName() + "#" + method.getName() + " has an invalid amount of paramters (count=" + method.getParameterTypes().length + ")!"); + } + } + + public void clearAllRegistered() { + listenerMethods.clear(); + } + + public void unregisterAll(Plugin plugin) { + listenerMethods.stream() + .filter(lm -> lm.plugin.getName().equals(plugin.getName())) + .forEach(listenerMethods::remove); + } + + public void unregisterListener(AtlasListener listener) { + listenerMethods.stream().filter(lm -> lm.listener.equals(listener)).forEach(listenerMethods::remove); + } + + public void registerListeners(AtlasListener listener, Plugin plugin) { + Arrays.stream(listener.getClass().getMethods()).filter(method -> method.isAnnotationPresent(Listen.class)).forEach(method -> { + try { + registerListener(method, listener, plugin); + } catch(ListenParamaterException e) { + e.printStackTrace(); + } + }); + } + + public void callEvent(AtlasEvent event) { + if(!paused && event != null) { + String name = event.getClass().getSimpleName(); + Atlas.getInstance().getProfile().start("event:" + name); + + List methods = listenerMethods.parallelStream() + .filter(lm -> lm.method.getParameters().get(0).equals(event.getClass())) + .sequential() + .sorted(Comparator.comparing(lm -> lm.listenerPriority.getPriority(), Comparator.reverseOrder())) + .collect(Collectors.toList()); + + + if(event instanceof Cancellable) { + Cancellable cancellable = (Cancellable) event; + for (ListenerMethod lm : methods) { + if(!cancellable.isCancelled() || !lm.ignoreCancelled) { + lm.method.invoke(lm.listener, cancellable); + } + } + } else { + for(ListenerMethod lm : methods) { + lm.method.invoke(lm.listener, event); + } + } + Atlas.getInstance().getProfile().stop("event:" + name); + } + } + + public void callEventAsync(AtlasEvent event) { + Atlas.getInstance().getService().execute(() -> callEvent(event)); + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/Listen.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/Listen.java new file mode 100644 index 00000000..8a96535b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/Listen.java @@ -0,0 +1,13 @@ +package cc.funkemunky.api.events; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(value = RetentionPolicy.RUNTIME) +@Target(value = {ElementType.METHOD}) +public @interface Listen { + ListenerPriority priority() default ListenerPriority.NORMAL; + boolean ignoreCancelled() default false; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/ListenerMethod.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/ListenerMethod.java new file mode 100644 index 00000000..dd1cfbc6 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/ListenerMethod.java @@ -0,0 +1,27 @@ +package cc.funkemunky.api.events; + +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Method; + +class ListenerMethod { + public Plugin plugin; + public WrappedMethod method; + public WrappedClass listenerClass; + public AtlasListener listener; + public ListenerPriority listenerPriority; + public String className; + public boolean ignoreCancelled; + + public ListenerMethod(Plugin plugin, Method method, AtlasListener listener, ListenerPriority listenerPriority) { + this.plugin = plugin; + this.listenerClass = new WrappedClass(listener.getClass()); + this.method = new WrappedMethod(listenerClass, method); + this.listener = listener; + this.listenerPriority = listenerPriority; + this.ignoreCancelled = method.getAnnotation(Listen.class).ignoreCancelled(); + this.className = method.getParameterTypes()[0].getName(); + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/ListenerPriority.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/ListenerPriority.java new file mode 100644 index 00000000..77c36841 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/ListenerPriority.java @@ -0,0 +1,14 @@ +package cc.funkemunky.api.events; + +import lombok.Getter; + +public enum ListenerPriority { + NONE(2), LOWEST(0), LOW(1), NORMAL(2), HIGH(3), HIGHEST(4); + + @Getter + private int priority; + + ListenerPriority(int priority) { + this.priority = priority; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/exceptions/ListenParamaterException.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/exceptions/ListenParamaterException.java new file mode 100644 index 00000000..46ba5a10 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/exceptions/ListenParamaterException.java @@ -0,0 +1,8 @@ +package cc.funkemunky.api.events.exceptions; + +public class ListenParamaterException extends Exception { + + public ListenParamaterException(String message) { + super(message); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/PacketLoginEvent.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/PacketLoginEvent.java new file mode 100644 index 00000000..f2594bd6 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/PacketLoginEvent.java @@ -0,0 +1,21 @@ +package cc.funkemunky.api.events.impl; + +import cc.funkemunky.api.events.AtlasEvent; +import cc.funkemunky.api.events.Cancellable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +import java.net.SocketAddress; + +@RequiredArgsConstructor +@Getter +public class PacketLoginEvent extends AtlasEvent implements Cancellable { + @Setter + private boolean cancelled; + + public final SocketAddress address; + @Setter + private final Object packet; + private final String packetType; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/PacketReceiveEvent.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/PacketReceiveEvent.java new file mode 100644 index 00000000..d1f8615f --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/PacketReceiveEvent.java @@ -0,0 +1,26 @@ +package cc.funkemunky.api.events.impl; + +import cc.funkemunky.api.events.AtlasEvent; +import cc.funkemunky.api.events.Cancellable; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.entity.Player; + +@Getter +public class PacketReceiveEvent extends AtlasEvent implements Cancellable { + private Player player; + @Setter + private Object packet; + @Setter + private boolean cancelled; + private String type; + private long timeStamp; + + public PacketReceiveEvent(Player player, Object packet, String type) { + this.player = player; + this.packet = packet; + this.type = type; + + timeStamp = System.currentTimeMillis(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/PacketSendEvent.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/PacketSendEvent.java new file mode 100644 index 00000000..1bd98802 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/PacketSendEvent.java @@ -0,0 +1,25 @@ +package cc.funkemunky.api.events.impl; + +import cc.funkemunky.api.events.AtlasEvent; +import cc.funkemunky.api.events.Cancellable; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.entity.Player; +@Getter +public class PacketSendEvent extends AtlasEvent implements Cancellable { + private Player player; + @Setter + private Object packet; + @Setter + private boolean cancelled; + private String type; + private long timeStamp; + + public PacketSendEvent(Player player, Object packet, String type) { + this.player = player; + this.packet = packet; + this.type = type; + + timeStamp = System.currentTimeMillis(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/TickEvent.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/TickEvent.java new file mode 100644 index 00000000..72b94236 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/events/impl/TickEvent.java @@ -0,0 +1,11 @@ +package cc.funkemunky.api.events.impl; + +import cc.funkemunky.api.events.AtlasEvent; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class TickEvent extends AtlasEvent { + private int currentTick; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/ForgeHandler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/ForgeHandler.java new file mode 100644 index 00000000..a42ef72b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/ForgeHandler.java @@ -0,0 +1,172 @@ +package cc.funkemunky.api.handlers; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.utils.ConfigSetting; +import cc.funkemunky.api.utils.Init; +import cc.funkemunky.api.utils.RunUtils; +import lombok.val; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.plugin.messaging.PluginMessageListener; +import org.bukkit.scheduler.BukkitRunnable; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +@Init +public class ForgeHandler implements Listener, PluginMessageListener { + + public ForgeHandler() { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + Atlas.getInstance().getServer().getMessenger() + .registerIncomingPluginChannel(Atlas.getInstance(), "FML|HS", this); + Atlas.getInstance().getServer().getMessenger() + .registerOutgoingPluginChannel(Atlas.getInstance(), "FML|HS"); + } + INSTANCE = this; + } + + @ConfigSetting(path = "forge", name = "enabled") + private static boolean enabled = false; + + @ConfigSetting(path = "forge", name = "bungee") + public static boolean fromBungee = false; + + private static Map mods = new HashMap<>(); + + private static ForgeHandler INSTANCE; + + @EventHandler + public void onJoin(PlayerJoinEvent event) + { + if(enabled) { + if(!Atlas.getInstance().getBungeeManager().isBungee()) { + Player player = event.getPlayer(); + + new BukkitRunnable() { + @Override + public void run() { + sendFmlPacket(player, (byte) -2, (byte) 0); + sendFmlPacket(player, (byte) 0, (byte) 2, (byte) 0, (byte) 0, (byte) 0, (byte) 0); + sendFmlPacket(player, (byte) 2, (byte) 0, (byte) 0, (byte) 0, (byte) 0); + } + }.runTaskLater(Atlas.getInstance(), 20L); + } else { + RunUtils.taskLater(() -> { + queryBungeeMods(event.getPlayer()); + }, 80L); + } + } + } + + /** + * Sends a packet through the FML|HS channel + * + * @param player The player to send the packet to + * @param data The data to send with the packet + */ + private static void sendFmlPacket(Player player, byte... data) + { + player.sendPluginMessage(Atlas.getInstance(), "FML|HS", data); + } + + @Override + public void onPluginMessageReceived(String channel, Player player, byte[] data) + { + // ModList has ID 2 + if (data[0] == 2) + { + ModData modData = getModData(data); + if(modData != null && modData.getMods().size() > 0) { + mods.put(player, modData); + } + } + } + + /** + * Fetches a {@link ModData} object from the raw mods data + * + * @param data The input data + * @return A ModData object + */ + private ModData getModData(byte[] data) + { + Map mods = new HashMap<>(); + + boolean store = false; + String tempName = null; + + for (int i = 2; i < data.length; store = !store) + { + int end = i + data[i] + 1; + byte[] range = Arrays.copyOfRange(data, i + 1, end); + + String string = new String(range); + + if (store) + { + mods.put(tempName, string); + } + else + { + tempName = string; + } + + i = end; + } + + return new ModData(mods); + } + + public static ModData getMods(Player player) { + val modData = mods.computeIfAbsent(player, key -> { + if(Atlas.getInstance().getBungeeManager().isBungee()) { + ForgeHandler.INSTANCE.queryBungeeMods(player); + } else { + sendFmlPacket(player, (byte) -2, (byte) 0); + sendFmlPacket(player, (byte) 0, (byte) 2, (byte) 0, (byte) 0, (byte) 0, (byte) 0); + sendFmlPacket(player, (byte) 2, (byte) 0, (byte) 0, (byte) 0, (byte) 0); + } + + return null; + }); + + if(mods.containsKey(player) && modData == null) { + if(Atlas.getInstance().getBungeeManager().isBungee()) { + ForgeHandler.INSTANCE.queryBungeeMods(player); + } else { + sendFmlPacket(player, (byte) -2, (byte) 0); + sendFmlPacket(player, (byte) 0, (byte) 2, (byte) 0, (byte) 0, (byte) 0, (byte) 0); + sendFmlPacket(player, (byte) 2, (byte) 0, (byte) 0, (byte) 0, (byte) 0); + } + } + return modData; + } + + public static void runBungeeModChecker(Player player, Map modStrings) { + mods.put(player, new ModData(modStrings)); + } + + private void queryBungeeMods(Player player) { + if(Atlas.getInstance().getBungeeManager().isBungee()) { + try { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + ObjectOutputStream output = new ObjectOutputStream(bytesOut); + + output.writeObject("mods"); + output.writeObject(player.getUniqueId()); + + player.sendPluginMessage(Atlas.getInstance(), "atlas:out", bytesOut.toByteArray()); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/ModData.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/ModData.java new file mode 100644 index 00000000..b6a2cc34 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/ModData.java @@ -0,0 +1,45 @@ +package cc.funkemunky.api.handlers; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Credit: https://github.com/Mas281/ForgeModBlocker/ + * Data holding a player's mods and their versions + */ +public class ModData +{ + /** + * Map of mod IDs to versions + */ + private final Map mods; + + public ModData(Map mods) + { + this.mods = mods; + } + + /** + * Fetches the list of mod IDs + * + * @see #mods + * @return An immutable set of mod IDs + */ + public Set getMods() + { + return new HashSet<>(mods.keySet()); + } + + /** + * Fetches the mods map + * + * @see #mods + * @return The mods map + */ + public Map getModsMap() + { + return Collections.unmodifiableMap(mods); + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/PluginLoaderHandler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/PluginLoaderHandler.java new file mode 100644 index 00000000..dc68bb6f --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/PluginLoaderHandler.java @@ -0,0 +1,67 @@ +package cc.funkemunky.api.handlers; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.utils.AutoLoad; +import cc.funkemunky.api.utils.Init; +import cc.funkemunky.api.utils.MiscUtils; +import lombok.Getter; +import lombok.val; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.event.server.PluginEnableEvent; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.HashSet; +import java.util.Set; + +@Init +public class PluginLoaderHandler implements Listener { + + @Getter + private Set loadedPlugins = new HashSet<>(); + + @EventHandler(priority = EventPriority.HIGH) + public void onEvent(PluginEnableEvent event) { + val description = event.getPlugin().getDescription(); + if(description.getDepend().contains("Atlas") || description.getSoftDepend().contains("Atlas")) { + MiscUtils.printToConsole("&7Plugin &f" + description.getName() + " &7has been detected!"); + loadedPlugins.add(event.getPlugin()); + + loadPlugin(event.getPlugin()); + } + } + + @EventHandler + public void onEvent(PluginDisableEvent event) { + if(loadedPlugins.contains(event.getPlugin())) { + val description = event.getPlugin().getDescription(); + MiscUtils.printToConsole("&7Plugin &f" + description.getName() + " &7is being unloaded."); + loadedPlugins.remove(event.getPlugin()); + + Atlas.getInstance().getPluginCommandManagers().computeIfPresent(description.getName(), (key, obj) -> { + obj.unregisterCommands(); + return null; + }); + } + } + + public boolean isPluginLoaded(Plugin plugin) { + return loadedPlugins.contains(plugin); + } + + private void loadPlugin(Plugin plugin) { + try { + val plClass = Class.forName(plugin.getDescription().getMain()); + if(plClass.isAnnotationPresent(AutoLoad.class)) { + MiscUtils.printToConsole("&cAutoload is commencing..."); + Atlas.getInstance().initializeScanner((JavaPlugin) plugin, true, true); + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/chat/ChatHandler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/chat/ChatHandler.java new file mode 100644 index 00000000..ce69209b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/chat/ChatHandler.java @@ -0,0 +1,87 @@ +package cc.funkemunky.api.handlers.chat; + +import cc.funkemunky.api.events.AtlasListener; +import cc.funkemunky.api.events.Listen; +import cc.funkemunky.api.events.impl.PacketReceiveEvent; +import cc.funkemunky.api.tinyprotocol.api.Packet; +import cc.funkemunky.api.tinyprotocol.packet.in.WrappedInChatPacket; +import cc.funkemunky.api.utils.Color; +import cc.funkemunky.api.utils.Init; +import lombok.val; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.entity.Player; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +@Init +public class ChatHandler implements AtlasListener { + + private final static Map> chatListeners = Collections.synchronizedMap(new HashMap<>()); + + @Listen + public void onReceive(PacketReceiveEvent event) { + if(event.getType().equals(Packet.Client.CHAT)) { + WrappedInChatPacket packet = new WrappedInChatPacket(event.getPacket(), event.getPlayer()); + + if(chatListeners.size() > 0) { + synchronized (chatListeners) { + chatListeners.computeIfPresent(event.getPlayer().getUniqueId(), (key, chats) -> { + List returnChats = new ArrayList<>(chats); + returnChats.forEach(chat -> { + chat.message.accept(chat, packet.getMessage()); + if (chat.removeOnFirstChat) returnChats.remove(chat); + }); + + event.setCancelled(true); + + //Removing player from map if theres nothing else to listen to. + return returnChats.size() > 0 ? returnChats : null; + }); + } + } + } + } + + public static void removeAll(Player player) { + removeAll(player.getUniqueId()); + } + + public static void removeAll(UUID uuid) { + synchronized (chatListeners) { + chatListeners.remove(uuid); + } + } + + public static void remove(UUID uuid, OnChat chat) { + if(!chatListeners.containsKey(uuid)) return; + synchronized (chatListeners) { + chatListeners.compute(uuid, (key, chats) -> { + if(chats != null) { + chats.remove(chat); + if(chats.size() == 0) chats = null; + } + + return chats; + }); + } + } + + public static void remove(Player player, OnChat chat) { + remove(player.getUniqueId(), chat); + } + + public static void onChat(Player player, boolean removeOnFirstChat, BiConsumer consumer) { + OnChat chat = new OnChat(player, consumer, removeOnFirstChat); + + synchronized (chatListeners) { + chatListeners.compute(player.getUniqueId(), (key, chats) -> { + if(chats == null) chats = new ArrayList<>(); + chats.add(chat); + + return chats; + }); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/chat/OnChat.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/chat/OnChat.java new file mode 100644 index 00000000..6104f630 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/chat/OnChat.java @@ -0,0 +1,19 @@ +package cc.funkemunky.api.handlers.chat; + +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.bukkit.entity.Player; + +import java.util.function.BiConsumer; + +@AllArgsConstructor +@RequiredArgsConstructor +public class OnChat { + final Player player; + final BiConsumer message; + boolean removeOnFirstChat; + + public void remove() { + ChatHandler.removeAll(player); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/Protocol.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/Protocol.java new file mode 100644 index 00000000..ea82b2a8 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/Protocol.java @@ -0,0 +1,7 @@ +package cc.funkemunky.api.handlers.protocolsupport; + +import org.bukkit.entity.Player; + +public interface Protocol { + int getPlayerVersion(Player player); +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/ProtocolAPI.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/ProtocolAPI.java new file mode 100644 index 00000000..d3b06972 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/ProtocolAPI.java @@ -0,0 +1,29 @@ +package cc.funkemunky.api.handlers.protocolsupport; + +import cc.funkemunky.api.handlers.protocolsupport.impl.NoAPI; +import cc.funkemunky.api.handlers.protocolsupport.impl.ProtocolSupport; +import cc.funkemunky.api.handlers.protocolsupport.impl.ViaVersionAPI; +import cc.funkemunky.api.utils.Init; +import cc.funkemunky.api.utils.Instance; +import org.bukkit.Bukkit; + +import java.util.HashMap; +import java.util.Map; + +@Init +public class ProtocolAPI { + + public Map protocolVersionByIP = new HashMap<>(); + + public static Protocol INSTANCE; + @Instance + public static ProtocolAPI classInstance; + + public ProtocolAPI() { + if(Bukkit.getPluginManager().isPluginEnabled("ViaVersion")) { + INSTANCE = new ViaVersionAPI(); + } else if(Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport")) { + INSTANCE = new ProtocolSupport(); + } else INSTANCE = new NoAPI(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/impl/NoAPI.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/impl/NoAPI.java new file mode 100644 index 00000000..a80c5124 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/impl/NoAPI.java @@ -0,0 +1,26 @@ +package cc.funkemunky.api.handlers.protocolsupport.impl; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.bungee.BungeeAPI; +import cc.funkemunky.api.handlers.protocolsupport.Protocol; +import cc.funkemunky.api.handlers.protocolsupport.ProtocolAPI; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.api.TinyProtocolHandler; +import org.bukkit.entity.Player; + +public class NoAPI implements Protocol { + + @Override + public int getPlayerVersion(Player player) { + return ProtocolAPI.classInstance.protocolVersionByIP.computeIfAbsent(player.getAddress().getAddress() + .getHostAddress().substring(1), shit -> { + if(Atlas.getInstance().getBungeeManager().isBungee()) { + int version = TinyProtocolHandler.bungeeVersionCache + .computeIfAbsent(player.getUniqueId(), key -> BungeeAPI.getPlayerVersion(player)); + + if(version != -1) return ProtocolVersion.getVersion(version).getVersion(); + } + return TinyProtocolHandler.getInstance().getProtocolVersion(player); + }); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/impl/ProtocolSupport.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/impl/ProtocolSupport.java new file mode 100644 index 00000000..7af800b0 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/impl/ProtocolSupport.java @@ -0,0 +1,13 @@ +package cc.funkemunky.api.handlers.protocolsupport.impl; + +import cc.funkemunky.api.handlers.protocolsupport.Protocol; +import org.bukkit.entity.Player; +import protocolsupport.api.ProtocolSupportAPI; + +public class ProtocolSupport implements Protocol { + + @Override + public int getPlayerVersion(Player player) { + return ProtocolSupportAPI.getProtocolVersion(player).getId(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/impl/ViaVersionAPI.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/impl/ViaVersionAPI.java new file mode 100644 index 00000000..7c6dd55f --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/protocolsupport/impl/ViaVersionAPI.java @@ -0,0 +1,13 @@ +package cc.funkemunky.api.handlers.protocolsupport.impl; + +import cc.funkemunky.api.handlers.protocolsupport.Protocol; +import org.bukkit.entity.Player; +import us.myles.ViaVersion.api.Via; + +public class ViaVersionAPI implements Protocol { + + @Override + public int getPlayerVersion(Player player) { + return Via.getAPI().getPlayerVersion(player.getUniqueId()); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/tab/TabHandler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/tab/TabHandler.java new file mode 100644 index 00000000..9fd06abd --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/handlers/tab/TabHandler.java @@ -0,0 +1,4 @@ +package cc.funkemunky.api.handlers.tab; + +public class TabHandler { +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/listeners/AtlasConnectionListeners.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/listeners/AtlasConnectionListeners.java new file mode 100644 index 00000000..a1fc97b3 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/listeners/AtlasConnectionListeners.java @@ -0,0 +1,44 @@ +package cc.funkemunky.api.listeners; + +import cc.funkemunky.api.events.AtlasListener; +import cc.funkemunky.api.events.Listen; +import cc.funkemunky.api.events.impl.PacketLoginEvent; +import cc.funkemunky.api.handlers.protocolsupport.ProtocolAPI; +import cc.funkemunky.api.reflections.impl.BukkitReflection; +import cc.funkemunky.api.tinyprotocol.api.Packet; +import cc.funkemunky.api.tinyprotocol.packet.login.WrappedHandshakingInSetProtocol; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumProtocol; +import cc.funkemunky.api.utils.Init; + +@Init +public class AtlasConnectionListeners implements AtlasListener { + + private boolean bungeeMode; + + public AtlasConnectionListeners() { + bungeeMode = BukkitReflection.isBungeeMode(); + } + + @Listen + public void onEvent(PacketLoginEvent event) { + if(event.getPacketType().equals(Packet.Login.HANDSHAKE)) { + WrappedHandshakingInSetProtocol packet = new WrappedHandshakingInSetProtocol(event.getPacket()); + + if(event.getAddress().toString().contains("127.0.0.1") && bungeeMode + && packet.enumProtocol.equals(WrappedEnumProtocol.LOGIN)) { + String[] split = packet.hostname.split("\00"); + + if (split.length >= 3) { + ProtocolAPI.classInstance.protocolVersionByIP.put(split[1], packet.a); + } + } else { + String address = event.getAddress().toString(); + + if(address.contains(":")) address = address.split(":")[0]; + address = address.substring(1); + + ProtocolAPI.classInstance.protocolVersionByIP.put(address, packet.a); + } + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/listeners/ConnectionListeners.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/listeners/ConnectionListeners.java new file mode 100644 index 00000000..077924d5 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/listeners/ConnectionListeners.java @@ -0,0 +1,39 @@ +package cc.funkemunky.api.listeners; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.tinyprotocol.api.TinyProtocolHandler; +import cc.funkemunky.api.utils.Init; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; + +@Init +public class ConnectionListeners implements Listener { + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + TinyProtocolHandler.bungeeVersionCache.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) { + if(Atlas.getInstance().getBungeeManager().isBungee()) { + try { + ByteArrayOutputStream bstream = new ByteArrayOutputStream(); + ObjectOutputStream ostream = new ObjectOutputStream(bstream); + + ostream.writeObject("version"); + ostream.writeObject(event.getPlayer().getUniqueId()); + + event.getPlayer().sendPluginMessage(Atlas.getInstance(), "atlas:out", bstream.toByteArray()); + } catch(IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/listeners/PluginShutdownListeners.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/listeners/PluginShutdownListeners.java new file mode 100644 index 00000000..af616c6b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/listeners/PluginShutdownListeners.java @@ -0,0 +1,23 @@ +package cc.funkemunky.api.listeners; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.utils.MiscUtils; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.server.PluginDisableEvent; + +//@Init +public class PluginShutdownListeners implements Listener { + + @EventHandler(priority = EventPriority.HIGHEST) + public void onEvent(PluginDisableEvent event) { + if(event.getPlugin().getDescription().getDepend().contains("Atlas")) { + MiscUtils.printToConsole("&c" + event.getPlugin().getName() + " &7is being shutdown. Removing its hooks and listeners..."); + Atlas.getInstance().getEventManager().unregisterAll(event.getPlugin()); + Atlas.getInstance().getSchedular().shutdownNow(); + Atlas.getInstance().getFunkeCommandManager().removeAll(event.getPlugin()); + MiscUtils.printToConsole("&aCompleted!"); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/metrics/Metrics.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/metrics/Metrics.java new file mode 100644 index 00000000..dff27c03 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/metrics/Metrics.java @@ -0,0 +1,695 @@ +package cc.funkemunky.api.metrics; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; + +/** + * bStats collects some data for plugin authors. + *

+ * Check out https://bStats.org/ to learn more about bStats! + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +public class Metrics { + + static { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D + final String defaultPackage = new String( + new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); + final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure nobody just copy & pastes the example and use the wrong package names + if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + // The version of this bStats class + public static final int B_STATS_VERSION = 1; + + // The url to which the data is sent + private static final String URL = "https://bStats.org/submitData/bukkit"; + + // Is bStats enabled on this server? + private boolean enabled; + + // Should failed requests be logged? + private static boolean logFailedRequests; + + // Should the sent data be logged? + private static boolean logSentData; + + // Should the response text be logged? + private static boolean logResponseStatusText; + + // The uuid of the server + private static String serverUUID; + + // The plugin + private final Plugin plugin; + + // A list with all custom charts + private final List charts = new ArrayList<>(); + + /** + * Class constructor. + * + * @param plugin The plugin which stats should be submitted. + */ + public Metrics(Plugin plugin) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + + // Get the atlasConfig file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + + // Check if the atlasConfig file exists + if (!config.isSet("serverUuid")) { + + // Add default values + config.addDefault("enabled", true); + // Every server gets it's unique random id. + config.addDefault("serverUuid", UUID.randomUUID().toString()); + // Should failed request be logged? + config.addDefault("logFailedRequests", false); + // Should the sent data be logged? + config.addDefault("logSentData", false); + // Should the response text be logged? + config.addDefault("logResponseStatusText", false); + + // Inform the server owners about bStats + config.options().header( + "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + + "To honor their work, you should not disable it.\n" + + "This has nearly no effect on the server performance!\n" + + "Check out https://bStats.org/ to learn more :)" + ).copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { } + } + + // Load the data + enabled = config.getBoolean("enabled", true); + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + logSentData = config.getBoolean("logSentData", false); + logResponseStatusText = config.getBoolean("logResponseStatusText", false); + + if (enabled) { + boolean found = false; + // Search for all other bStats Metrics classes to see if we are the first one + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + found = true; // We aren't the first + break; + } catch (NoSuchFieldException ignored) { } + } + // Register our service + Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal); + if (!found) { + // We are the first! + startSubmitting(); + } + } + } + + /** + * Checks if bStats is enabled. + * + * @return Whether bStats is enabled or not. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + if (chart == null) { + throw new IllegalArgumentException("Chart cannot be null!"); + } + charts.add(chart); + } + + /** + * Starts the Scheduler which submits our data every 30 minutes. + */ + private void startSubmitting() { + final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + if (!plugin.isEnabled()) { // Plugin was disabled + timer.cancel(); + return; + } + // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler + // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) + Bukkit.getScheduler().runTask(plugin, () -> submitData()); + } + }, 1000 * 60 * 5, 1000 * 60 * 30); + // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start + // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! + // WARNING: Just don't do it! + } + + /** + * Gets the plugin specific data. + * This method is called using Reflection. + * + * @return The plugin specific data. + */ + public JSONObject getPluginData() { + JSONObject data = new JSONObject(); + + String pluginName = plugin.getDescription().getName(); + String pluginVersion = plugin.getDescription().getVersion(); + + data.put("pluginName", pluginName); // Append the name of the plugin + data.put("pluginVersion", pluginVersion); // Append the version of the plugin + JSONArray customCharts = new JSONArray(); + for (CustomChart customChart : charts) { + // Add the data of the custom charts + JSONObject chart = customChart.getRequestJsonObject(); + if (chart == null) { // If the chart is null, we skip it + continue; + } + customCharts.add(chart); + } + data.put("customCharts", customCharts); + + return data; + } + + /** + * Gets the server specific data. + * + * @return The server specific data. + */ + private JSONObject getServerData() { + // Minecraft specific data + int playerAmount; + try { + // Around MC 1.8 the return type was changed to a collection from an array, + // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed + } + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = Bukkit.getVersion(); + + // OS/Java specific data + String javaVersion = System.getProperty("java.version"); + String osName = System.getProperty("os.name"); + String osArch = System.getProperty("os.arch"); + String osVersion = System.getProperty("os.version"); + int coreCount = Runtime.getRuntime().availableProcessors(); + + JSONObject data = new JSONObject(); + + data.put("serverUUID", serverUUID); + + data.put("playerAmount", playerAmount); + data.put("onlineMode", onlineMode); + data.put("bukkitVersion", bukkitVersion); + + data.put("javaVersion", javaVersion); + data.put("osName", osName); + data.put("osArch", osArch); + data.put("osVersion", osVersion); + data.put("coreCount", coreCount); + + return data; + } + + /** + * Collects the data and sends it afterwards. + */ + private void submitData() { + final JSONObject data = getServerData(); + + JSONArray pluginData = new JSONArray(); + // Search for all other bStats Metrics classes to get their plugin data + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + + for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { + try { + pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider())); + } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { } + } + } catch (NoSuchFieldException ignored) { } + } + + data.put("plugins", pluginData); + + // Create a new thread for the connection to the bStats server + new Thread(new Runnable() { + @Override + public void run() { + try { + // Send the data + sendData(plugin, data); + } catch (Exception e) { + // Something went wrong! :( + if (logFailedRequests) { + plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); + } + } + } + }).start(); + } + + /** + * Sends the data to the bStats server. + * + * @param plugin Any plugin. It's just used to get a logger instance. + * @param data The data to send. + * @throws Exception If the request failed. + */ + private static void sendData(Plugin plugin, JSONObject data) throws Exception { + if (data == null) { + throw new IllegalArgumentException("Data cannot be null!"); + } + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException("This method must not be called from the main thread!"); + } + if (logSentData) { + plugin.getLogger().info("Sending data to bStats: " + data.toString()); + } + HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + // Add headers + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format + connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); + + // Send data + connection.setDoOutput(true); + DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); + outputStream.write(compressedData); + outputStream.flush(); + outputStream.close(); + + InputStream inputStream = connection.getInputStream(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + + StringBuilder builder = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + bufferedReader.close(); + if (logResponseStatusText) { + plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString()); + } + } + + /** + * Gzips the given String. + * + * @param str The string to gzip. + * @return The gzipped String. + * @throws IOException If the compression failed. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + GZIPOutputStream gzip = new GZIPOutputStream(outputStream); + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + gzip.close(); + return outputStream.toByteArray(); + } + + /** + * Represents a custom chart. + */ + public static abstract class CustomChart { + + // The id of the chart + final String chartId; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + */ + CustomChart(String chartId) { + if (chartId == null || chartId.isEmpty()) { + throw new IllegalArgumentException("ChartId cannot be null or empty!"); + } + this.chartId = chartId; + } + + private JSONObject getRequestJsonObject() { + JSONObject chart = new JSONObject(); + chart.put("chartId", chartId); + try { + JSONObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + chart.put("data", data); + } catch (Throwable t) { + if (logFailedRequests) { + Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return chart; + } + + protected abstract JSONObject getChartData() throws Exception; + + } + + /** + * Represents a custom simple pie. + */ + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + data.put("value", value); + return data; + } + } + + /** + * Represents a custom advanced pie. + */ + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.put(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + } + + /** + * Represents a custom drilldown pie. + */ + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JSONObject value = new JSONObject(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + value.put(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + values.put(entryValues.getKey(), value); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + } + + /** + * Represents a custom single line chart. + */ + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + data.put("value", value); + return data; + } + + } + + /** + * Represents a custom multi line chart. + */ + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.put(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + + } + + /** + * Represents a custom simple bar chart. + */ + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + JSONArray categoryValues = new JSONArray(); + categoryValues.add(entry.getValue()); + values.put(entry.getKey(), categoryValues); + } + data.put("values", values); + return data; + } + + } + + /** + * Represents a custom advanced bar chart. + */ + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + continue; // Skip this invalid + } + allSkipped = false; + JSONArray categoryValues = new JSONArray(); + for (int categoryValue : entry.getValue()) { + categoryValues.add(categoryValue); + } + values.put(entry.getKey(), categoryValues); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + } + +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/BaseProfiler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/BaseProfiler.java new file mode 100644 index 00000000..af00b1a0 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/BaseProfiler.java @@ -0,0 +1,128 @@ +package cc.funkemunky.api.profiling; + +import cc.funkemunky.api.utils.Tuple; +import lombok.Getter; + +import java.util.HashMap; +import java.util.Map; + +public class BaseProfiler implements Profiler { + @Getter + private Map timingsMap = new HashMap<>(); + public long lastSample = 0, lastReset; + public int totalCalls = 0; + public long start = 0; + + public BaseProfiler() { + } + + @Override + public void start() { + StackTraceElement stack = Thread.currentThread().getStackTrace()[2]; + start(stack.getMethodName()); + + if(start == 0) start = System.currentTimeMillis(); + } + + @Override + public void start(String name) { + Timing timing = getTiming(name); + timing.lastCall = System.nanoTime(); + + if(start == 0) start = System.currentTimeMillis(); + } + + @Override + public void stop() { + if(System.currentTimeMillis() - lastReset < 100L) return; + long extense = System.nanoTime(); + StackTraceElement stack = Thread.currentThread().getStackTrace()[2]; + stop(stack.getMethodName(), extense); + totalCalls++; + } + + @Override + public void reset() { + lastSample = totalCalls = 0; + timingsMap.clear(); + start = lastReset = System.currentTimeMillis(); + } + + //Returns Tuple + @Override + public Map> results(ResultsType type) { + Map> toReturn = new HashMap<>(); + switch(type) { + case TOTAL: { + for (String key : timingsMap.keySet()) { + Timing timing = timingsMap.get(key); + + toReturn.put(key, new Tuple<>(timing.calls, timing.average.getAverage() + * (timing.calls / (double)totalCalls))); + } + break; + } + case AVERAGE: { + for(String key : timingsMap.keySet()) { + Timing timing = timingsMap.get(key); + + toReturn.put(key, new Tuple<>(timing.calls, timing.average.getAverage())); + } + break; + } + case SAMPLES: { + for(String key : timingsMap.keySet()) { + Timing timing = timingsMap.get(key); + + toReturn.put(key, new Tuple<>(timing.calls, (double)timing.call)); + } + break; + } + default: { + for (String key : timingsMap.keySet()) { + Timing timing = timingsMap.get(key); + + toReturn.put(key, new Tuple<>(timing.calls, timing.total / (double)timing.calls)); + } + break; + } + } + return toReturn; + } + + @Override + public void stop(String name) { + long ts = System.currentTimeMillis(); + if(ts - lastReset < 100L) return; + long extense = System.nanoTime(); + Timing timing = getTiming(name); + long time = (System.nanoTime() - timing.lastCall) - (System.nanoTime() - extense); + timing.average.add(time); + timing.stdDev = Math.abs(time - timing.average.getAverage()); + timing.total+= time; + timing.call = time; + timing.calls++; + totalCalls++; + lastSample = ts; + } + + @Override + public void stop(String name, long extense) { + long ts = System.currentTimeMillis(); + if(ts - lastReset < 100L) return; + Timing timing = getTiming(name); + long time = (System.nanoTime() - timing.lastCall) - (System.nanoTime() - extense); + + timing.average.add(time); + timing.stdDev = Math.abs(time - timing.average.getAverage()); + timing.total+= time; + timing.call = time; + timing.calls++; + totalCalls++; + lastSample = ts; + } + + private Timing getTiming(String name) { + return timingsMap.computeIfAbsent(name, Timing::new); + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/Profiler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/Profiler.java new file mode 100644 index 00000000..3ba45424 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/Profiler.java @@ -0,0 +1,21 @@ +package cc.funkemunky.api.profiling; + +import cc.funkemunky.api.utils.Tuple; + +import java.util.Map; + +public interface Profiler { + void start(String name); + + void start(); + + void stop(String name, long extense); + + void stop(String name); + + void stop(); + + void reset(); + + Map> results(ResultsType type); +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/ResultsType.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/ResultsType.java new file mode 100644 index 00000000..ae5b0787 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/ResultsType.java @@ -0,0 +1,5 @@ +package cc.funkemunky.api.profiling; + +public enum ResultsType { + SAMPLES, TOTAL, AVERAGE, TICK, MEDIAN; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/Timing.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/Timing.java new file mode 100644 index 00000000..4075ca29 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/Timing.java @@ -0,0 +1,13 @@ +package cc.funkemunky.api.profiling; + +import cc.funkemunky.api.utils.math.RollingAverageDouble; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class Timing { + public final String name; + public int calls; + public long call, total, lastCall; + public double stdDev; + public RollingAverageDouble average = new RollingAverageDouble(40, 0); +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/ToggleableProfiler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/ToggleableProfiler.java new file mode 100644 index 00000000..d944f22b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/profiling/ToggleableProfiler.java @@ -0,0 +1,40 @@ +package cc.funkemunky.api.profiling; + +public class ToggleableProfiler extends BaseProfiler { + private boolean enabled; + + @Override + public void start() { + if(!enabled) return; + super.start(); + } + + @Override + public void start(String name) { + if(!enabled) return; + super.start(name); + } + + @Override + public void stop() { + if(!enabled) return; + super.stop(); + } + + @Override + public void stop(String name) { + if(!enabled) return; + super.stop(name); + } + + @Override + public void stop(String name, long extense) { + if(!enabled) return; + super.stop(name, extense); + } + + public void setEnabled(boolean enabled) { + if(this.enabled = enabled) start = System.currentTimeMillis(); + else reset(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/Reflections.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/Reflections.java new file mode 100644 index 00000000..b94f783c --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/Reflections.java @@ -0,0 +1,104 @@ +/* + * Created by Justin Heflin on 4/19/18 8:21 PM + * Copyright (c) 2018. + * + * Can be redistributed non commercially as long as credit is given to original copyright owner. + * + * last modified: 4/19/18 7:22 PM + */ +package cc.funkemunky.api.reflections; + +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.utils.objects.QuadFunction; +import cc.funkemunky.api.utils.objects.TriFunction; +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.val; +import org.bukkit.Bukkit; + +import java.lang.invoke.LambdaMetafactory; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Method; +import java.util.function.BiFunction; +import java.util.function.Function; + +@Getter +public class Reflections { + private static final String craftBukkitString; + private static final String netMinecraftServerString; + private static MethodHandles.Lookup lookup = MethodHandles.lookup(); + + static { + String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; + craftBukkitString = "org.bukkit.craftbukkit." + version + "."; + netMinecraftServerString = "net.minecraft.server." + version + "."; + } + + public static boolean classExists(String name) { + try { + Class.forName(name); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + + public static WrappedClass getCBClass(String name) { + return getClass(craftBukkitString + name); + } + + public static WrappedClass getNMSClass(String name) { + return getClass(netMinecraftServerString + name); + } + + public static WrappedClass getClass(String name) { + try { + return new WrappedClass(Class.forName(name)); + } catch (ClassNotFoundException | NoClassDefFoundError e) { + throw new NullPointerException("Class" + name + " could not be found!"); + } + } + + public static WrappedClass getUtilClass(String name) { + return getClass((ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8) + ? "net.minecraft.util." : "") + name); + } + + @SneakyThrows + public static T createMethodLambda(Method method) { + if(!method.isAccessible()) return null; + val handle = lookup.unreflect(method); + Class functionType; + switch(method.getParameterCount()) { + case 0: + functionType = Function.class; + break; + case 1: + functionType = BiFunction.class; + break; + case 2: + functionType = TriFunction.class; + break; + case 3: + functionType = QuadFunction.class; + default: + functionType = null; + break; + } + + if(functionType != null) { + return (T) LambdaMetafactory.metafactory(lookup, "apply", + MethodType.methodType(functionType), + MethodType.methodType(method.getReturnType(), handle.type().parameterArray()), + handle, handle.type()).getTarget().invoke(); + } + + return null; + } + + public static WrappedClass getClass(Class clazz) { + return new WrappedClass(clazz); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/impl/BukkitReflection.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/impl/BukkitReflection.java new file mode 100644 index 00000000..24ec502c --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/impl/BukkitReflection.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.reflections.impl; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import org.bukkit.Chunk; +import org.bukkit.inventory.ItemStack; + +public class BukkitReflection { + public static WrappedField bukkitChunkField = MinecraftReflection.chunk.getFieldByType(Chunk.class, 0); + public static WrappedClass spigotConfig; + private static WrappedMethod asBukkitCopyItemStack = CraftReflection.craftItemStack + .getMethod("asBukkitCopy", MinecraftReflection.itemStack.getParent()); + + public static boolean isBungeeMode() { + if(spigotConfig == null) return false; + + return spigotConfig.getFieldByName("bungee").get(null); + } + + public static Chunk getChunkFromVanilla(Object vanillaChunk) { + return bukkitChunkField.get(vanillaChunk); + } + + public static ItemStack getBukkitStackFromVanilla(Object object) { + return asBukkitCopyItemStack.invoke(null, object); + } + + static { + if(Reflections.classExists("org.spigotmc.SpigotConfig")) { + spigotConfig = Reflections.getClass("org.spigotmc.SpigotConfig"); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/impl/CraftReflection.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/impl/CraftReflection.java new file mode 100644 index 00000000..a91e0061 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/impl/CraftReflection.java @@ -0,0 +1,74 @@ +package cc.funkemunky.api.reflections.impl; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class CraftReflection { + public static WrappedClass craftHumanEntity = Reflections.getCBClass("entity.CraftHumanEntity"); //1.7-1.14 + public static WrappedClass craftEntity = Reflections.getCBClass("entity.CraftEntity"); //1.7-1.14 + public static WrappedClass craftItemStack = Reflections.getCBClass("inventory.CraftItemStack"); //1.7-1.14 + public static WrappedClass craftBlock = Reflections.getCBClass("block.CraftBlock"); //1.7-1.14 + public static WrappedClass craftPlayer = Reflections.getCBClass("entity.CraftPlayer"); + public static WrappedClass craftWorld = Reflections.getCBClass("CraftWorld"); //1.7-1.14 + public static WrappedClass craftInventoryPlayer = Reflections.getCBClass("inventory.CraftInventoryPlayer"); //1.7-1.14 + public static WrappedClass craftServer = Reflections.getCBClass("CraftServer"); //1.7-1.14 + + //Vanilla Instances + private static WrappedMethod itemStackInstance = craftItemStack.getMethod("asNMSCopy", ItemStack.class); //1.7-1.14 + private static WrappedMethod humanEntityInstance = craftHumanEntity.getMethod("getHandle"); //1.7-1.14 + private static WrappedMethod entityInstance = craftEntity.getMethod("getHandle"); //1.7-1.14 + private static WrappedMethod blockInstance = craftBlock.getMethod("getNMSBlock"); //1.7-1.14 + private static WrappedMethod worldInstance = craftWorld.getMethod("getHandle"); //1.7-1.14 + private static WrappedMethod bukkitEntity = MinecraftReflection.entity.getMethod("getBukkitEntity"); //1.7-1.14 + private static WrappedMethod getInventory = craftInventoryPlayer.getMethod("getInventory"); //1.7-1.14 + private static WrappedMethod mcServerInstance = craftServer.getMethod("getServer"); //1.7-1.14 + private static WrappedMethod entityPlayerInstance = craftPlayer.getMethod("getHandle"); + + public static T getVanillaItemStack(ItemStack stack) { + return itemStackInstance.invoke(null, stack); + } + + public static T getEntityHuman(HumanEntity entity) { + return humanEntityInstance.invoke(entity); + } + + public static T getEntity(Entity entity) { + return entityInstance.invoke(entity); + } + + public static T getEntityPlayer(Player player) { + return entityPlayerInstance.invoke(player); + } + + public static T getVanillaBlock(Block block) { + return blockInstance.invoke(block); + } + + public static T getVanillaWorld(World world) { + return worldInstance.invoke(world); + } + + public static Entity getBukkitEntity(Object vanillaEntity) { + return bukkitEntity.invoke(vanillaEntity); + } + + public static T getVanillaInventory(Player player) { + return getInventory.invoke(player.getInventory()); + } + + public static T getMinecraftServer() { + return mcServerInstance.invoke(Bukkit.getServer()); + } + + static { + + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/impl/MinecraftReflection.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/impl/MinecraftReflection.java new file mode 100644 index 00000000..d1cf716c --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/impl/MinecraftReflection.java @@ -0,0 +1,437 @@ +package cc.funkemunky.api.reflections.impl; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedConstructor; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.BaseBlockPosition; +import cc.funkemunky.api.tinyprotocol.packet.types.Vec3D; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumAnimation; +import cc.funkemunky.api.utils.BoundingBox; +import cc.funkemunky.api.utils.Materials; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class MinecraftReflection { + public static WrappedClass entity = Reflections.getNMSClass("Entity"); + public static WrappedClass axisAlignedBB = Reflections.getNMSClass("AxisAlignedBB"); + public static WrappedClass entityHuman = Reflections.getNMSClass("EntityHuman"); + public static WrappedClass entityLiving = Reflections.getNMSClass("EntityLiving"); + public static WrappedClass block = Reflections.getNMSClass("Block"); + public static WrappedClass iBlockData; + public static WrappedClass itemClass = Reflections.getNMSClass("Item"); + public static WrappedClass world = Reflections.getNMSClass("World"); + public static WrappedClass worldServer = Reflections.getNMSClass("WorldServer"); + public static WrappedClass playerInventory = Reflections.getNMSClass("PlayerInventory"); + public static WrappedClass itemStack = Reflections.getNMSClass("ItemStack"); + public static WrappedClass enumAnimation = Reflections.getNMSClass("EnumAnimation"); + public static WrappedClass chunk = Reflections.getNMSClass("Chunk"); + public static WrappedClass minecraftServer = Reflections.getNMSClass("MinecraftServer"); + public static WrappedClass entityPlayer = Reflections.getNMSClass("EntityPlayer"); + public static WrappedClass playerConnection = Reflections.getNMSClass("PlayerConnection"); + public static WrappedClass networkManager = Reflections.getNMSClass("NetworkManager"); + public static WrappedClass serverConnection = Reflections.getNMSClass("ServerConnection"); + public static WrappedClass gameProfile = Reflections.getUtilClass("com.mojang.authlib.GameProfile"); + private static WrappedClass propertyMap = Reflections.getUtilClass("com.mojang.authlib.properties.PropertyMap"); + private static WrappedClass forwardMultiMap = Reflections.getUtilClass("com.google.common.collect.ForwardingMultimap"); + public static WrappedClass iChatBaseComponent = Reflections.getNMSClass("IChatBaseComponent"); + public static WrappedClass vec3D = Reflections.getNMSClass("Vec3D"); + + private static WrappedMethod getProfile = CraftReflection.craftPlayer.getMethod("getProfile"); + private static WrappedMethod getProperties = gameProfile.getMethod("getProperties"); + private static WrappedMethod removeAll = forwardMultiMap.getMethod("removeAll", Object.class); + private static WrappedMethod putAll = propertyMap.getMethod("putAll", Object.class, Iterable.class); + private static WrappedMethod worldGetType; + //BoundingBoxes + private static WrappedMethod getCubes; + private static WrappedField aBB = axisAlignedBB.getFieldByName("a"); + private static WrappedField bBB = axisAlignedBB.getFieldByName("b"); + private static WrappedField cBB = axisAlignedBB.getFieldByName("c"); + private static WrappedField dBB = axisAlignedBB.getFieldByName("d"); + private static WrappedField eBB = axisAlignedBB.getFieldByName("e"); + private static WrappedField fBB = axisAlignedBB.getFieldByName("f"); + private static WrappedConstructor aabbConstructor; + private static WrappedMethod idioticOldStaticConstructorAABB; + private static WrappedField entityBoundingBox = entity.getFirstFieldByType(axisAlignedBB.getParent()); + + //ItemStack methods and fields + private static WrappedMethod enumAnimationStack; + private static WrappedField activeItemField; + private static WrappedMethod getItemMethod = itemStack.getMethod("getItem"); + private static WrappedMethod getAnimationMethod = itemClass.getMethodByType(enumAnimation.getParent(), 0); + private static WrappedMethod canDestroyMethod; + + //1.13+ only + private static WrappedClass voxelShape; + private static WrappedClass worldReader; + private static WrappedMethod getCubesFromVoxelShape; + + private static WrappedField pingField = entityPlayer.getFieldByName("ping"); + + //Blocks + private static WrappedMethod addCBoxes; + public static WrappedClass blockPos; + private static WrappedConstructor blockPosConstructor; + private static WrappedMethod getBlockData, getBlock; + private static WrappedField blockData = block.getFieldByName("blockData"); + private static WrappedField frictionFactor = block.getFieldByName("frictionFactor"); + private static WrappedField strength = block.getFieldByName("strength"); + private static WrappedField chunkProvider = MinecraftReflection.world + .getFieldByType(Reflections.getNMSClass("IChunkProvider").getParent(), 0); + private static WrappedField chunksList = Reflections.getNMSClass("ChunkProviderServer") + .getFieldByName("chunks"); + + //Entity Player fields + private static WrappedField connectionField = entityPlayer.getFieldByName("playerConnection"); + private static WrappedField connectionNetworkField = playerConnection + .getFieldByType(networkManager.getParent(), 0); + private static WrappedField networkChannelField = networkManager.getFieldByName("channel"); + + //General Fields + private static WrappedField primaryThread = minecraftServer.getFirstFieldByType(Thread.class); + + public static WrappedEnumAnimation getArmAnimation(HumanEntity entity) { + if(entity.getItemInHand() != null) { + return getItemAnimation(entity.getItemInHand()); + } + return WrappedEnumAnimation.NONE; + } + + public static WrappedEnumAnimation getItemAnimation(ItemStack stack) { + Object itemStack = CraftReflection.getVanillaItemStack(stack); + + return WrappedEnumAnimation.fromNMS(enumAnimationStack.invoke(itemStack)); + } + + public static List getBlockBox(@Nullable Entity entity, Block block) { + Object vanillaBlock = getBlock(block); + Object world = CraftReflection.getVanillaWorld(block.getWorld()); + + //TODO Use increasedHeight if it doesnt get fence or wall boxes properly. + //boolean increasedHeight = BlockUtils.isFence(block) || BlockUtils.isWall(block); + //We do this so we can get the block inside + BoundingBox box = new BoundingBox( + block.getLocation().toVector(), + block.getLocation().clone() + .add(1,1,1) + .toVector()); + + List aabbs = new ArrayList<>(); + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + addCBoxes.invoke(vanillaBlock, world, + block.getX(), block.getY(), block.getZ(), + box.toAxisAlignedBB(), aabbs, + entity != null ? CraftReflection.getEntity(entity) : null); //Entity is always null for these + } else if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + BaseBlockPosition blockPos = new BaseBlockPosition(block.getX(), block.getY(), block.getZ()); + Object blockData = getBlockData.invoke(vanillaBlock); + + addCBoxes.invoke(vanillaBlock, world, blockPos.getAsBlockPosition(), blockData, + box.toAxisAlignedBB(), aabbs, entity != null ? CraftReflection.getEntity(entity) : null); //Entity is always null for these + } + + return aabbs.stream().map(MinecraftReflection::fromAABB).collect(Collectors.toList()); + } + + public static T getGameProfile(Player player) { + return getProfile.invoke(player); + } + + //1.7 field is boundingBox + //1.8+ method is getBoundingBox. + public static T getEntityBoundingBox(Entity entity) { + Object vanillaEntity = CraftReflection.getEntity(entity); + + return entityBoundingBox.get(vanillaEntity); + } + + public static T getItemInUse(HumanEntity entity) { + Object humanEntity = CraftReflection.getEntityHuman(entity); + return activeItemField.get(humanEntity); + } + + public static T getBlock(Block block) { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + Object blockData = getBlockData(block); + + return getBlock.invoke(blockData); + } else { + return worldGetType.invoke(CraftReflection.getVanillaWorld(block.getWorld()), + block.getX(), block.getY(), block.getZ()); + } + } + + //Can use either a Bukkit or vanilla object + public static T getItemFromStack(Object object) { + Object vanillaStack; + if(object instanceof ItemStack) { + vanillaStack = CraftReflection.getVanillaItemStack((ItemStack)object); + } else vanillaStack = object; + + return getItemMethod.invoke(vanillaStack); + } + + //Can use either a Bukkit or vanilla object + public static T getItemAnimation(Object object) { + Object vanillaStack; + if(object instanceof ItemStack) { + vanillaStack = CraftReflection.getVanillaItemStack((ItemStack)object); + } else vanillaStack = object; + + Object item = getItemFromStack(vanillaStack); + + return getAnimationMethod.invoke(item, vanillaStack); + } + + /* Checks if the player is able to destroy a block. Input can be NMS Block or Bukkit Block */ + public static boolean canDestroyBlock(Player player, Object block) { + Object inventory = CraftReflection.getVanillaInventory(player); + Object vBlock; + if(block instanceof Block) { + vBlock = getBlock((Block)block); + } else vBlock = block; + + return canDestroyMethod.invoke(inventory, + ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8_9) + ? blockData.get(vBlock) : vBlock); + } + + /* Gets the friction of a block. Input can be NMS Block or Bukkit Block. */ + public static float getFriction(Object block) { + Object vBlock; + if(block instanceof Block) { + vBlock = getBlock((Block)block); + } else vBlock = block; + + return frictionFactor.get(vBlock); + } + + public static int getPing(Player player) { + return pingField.get(CraftReflection.getEntityPlayer(player)); + } + + /* Gets the amount of mining required to break a block. Input can be NMS Block or Bukkit Block. */ + public static float getBlockDurability(Object block) { + Object vBlock; + if(block instanceof Block) { + vBlock = getBlock((Block)block); + } else vBlock = block; + + return strength.get(vBlock); + } + + //Argument can either be org.bukkit.block.Block or vanilla Block. + public static T getBlockData(Object object) { + if(object instanceof Block) { + Block block = (Block) object; + Object vworld = CraftReflection.getVanillaWorld(block.getWorld()); + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + return worldGetType.invoke(vworld, block.getX(), block.getY(), block.getZ()); + } else { + Object bpos = new BaseBlockPosition(block.getX(), block.getY(), block.getZ()).getAsBlockPosition(); + + return worldGetType.invoke(vworld, bpos); + } + } else return blockData.get(object); + } + + public static List getCollidingBoxes(@Nullable Entity entity, World world, BoundingBox box) { + Object vWorld = CraftReflection.getVanillaWorld(world); + List boxes = new ArrayList<>(); + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + List aabbs = ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_12) + ? getCubes.invoke(vWorld, box.toAxisAlignedBB()) + : getCubes.invoke(vWorld, entity != null ? CraftReflection.getEntity(entity) : null, box.toAxisAlignedBB()); + + boxes = aabbs + .stream() + .map(MinecraftReflection::fromAABB) + .collect(Collectors.toList()); + } else { + Object voxelShape = getCubes.invoke(vWorld, null, box.toAxisAlignedBB(), 0D, 0D, 0D); + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13_2)) { + List aabbs = getCubesFromVoxelShape.invoke(voxelShape); + + boxes = aabbs.stream().map(MinecraftReflection::fromAABB).collect(Collectors.toList()); + } else { + List aabbs = new ArrayList<>(); + + ((List) voxelShape).stream() + .map(ob -> { + List aabbList = getCubesFromVoxelShape.invoke(ob); + return aabbList; + }).forEach(aabbs::addAll); + + boxes = aabbs.stream().map(MinecraftReflection::fromAABB).collect(Collectors.toList()); + } + } + return boxes; + } + + public static Thread getMainThread(Object minecraftServer) { + return primaryThread.get(minecraftServer); + } + + public static Thread getMainThread() { + return getMainThread(CraftReflection.getMinecraftServer()); + } + + //a, b, c is minX, minY, minZ + //d, e, f is maxX, maxY, maxZ + public static BoundingBox fromAABB(Object aabb) { + double a, b, c, d, e, f; + + a = aBB.get(aabb); + b = bBB.get(aabb); + c = cBB.get(aabb); + d = dBB.get(aabb); + e = eBB.get(aabb); + f = fBB.get(aabb); + + return new BoundingBox((float) a,(float) b,(float) c,(float) d,(float) e,(float) f); + } + + + //Can either use Player or EntityPlayer object. + public static T getPlayerConnection(Object player) { + Object entityPlayer; + if(player instanceof Player) { + entityPlayer = CraftReflection.getEntityPlayer((Player)player); + } else entityPlayer = player; + + return connectionField.get(entityPlayer); + } + + //Can either use Player or EntityPlayer object. + public static T getNetworkManager(Object player) { + return connectionNetworkField.get(getPlayerConnection(player)); + } + + //Can either use Player or EntityPlayer object. + public static T getChannel(Object player) { + Object networkManager = getNetworkManager(player); + + return networkChannelField.get(networkManager); + } + + //Use the netty Channel class. + public static void disconnectChannel(Object channel) { + new WrappedClass(channel.getClass()).getMethod("close").invoke(channel); + } + + private static WrappedMethod fluidMethod, getFlowMethod; + + public static Vec3D getBlockFlow(Block block) { + if(Materials.checkFlag(block.getType(), Materials.LIQUID)) { + Object world = CraftReflection.getVanillaWorld(block.getWorld()); + BaseBlockPosition pos = new BaseBlockPosition(block.getX(), block.getY(), block.getZ()); + if(ProtocolVersion.getGameVersion().isOrBelow(ProtocolVersion.V1_13)) { + Object vanillaBlock = CraftReflection.getVanillaBlock(block); + + return new Vec3D((Object)getFlowMethod.invoke(vanillaBlock, world, pos.getAsBlockPosition())); + } else { + Object fluid = fluidMethod.invoke(world, pos.getAsBlockPosition()); + + return new Vec3D((Object)getFlowMethod.invoke(fluid, world, pos.getAsBlockPosition())); + } + } else return new Vec3D(0,0,0); + } + + + public static T toAABB(BoundingBox box) { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + return idioticOldStaticConstructorAABB + .invoke(null, + (double)box.minX, (double)box.minY, (double)box.minZ, + (double)box.maxX, (double)box.maxY, (double)box.maxZ); + } else return aabbConstructor + .newInstance((double)box.minX, (double)box.minY, (double)box.minZ, + (double)box.maxX, (double)box.maxY, (double)box.maxZ); + } + + //Either bukkit or vanilla world object can be used. + public static T getChunkProvider(Object world) { + Object vanillaWorld; + if(world instanceof World) { + vanillaWorld = CraftReflection.getVanillaWorld((World)world); + } else vanillaWorld = world; + + return chunkProvider.get(vanillaWorld); + } + + public static List getVanillaChunks(Object provider) { + return chunksList.get(provider); + } + + static { + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_7_10)) { + iBlockData = Reflections.getNMSClass("IBlockData"); + blockPos = Reflections.getNMSClass("BlockPosition"); + getBlock = iBlockData.getMethod("getBlock"); + blockPosConstructor = blockPos.getConstructor(int.class, int.class, int.class); + getBlockData = block.getMethod("getBlockData"); + aabbConstructor = axisAlignedBB + .getConstructor(double.class, double.class, double.class, double.class, double.class, double.class); + worldGetType = worldServer.getMethod("getType", blockPos.getParent()); + } else { + idioticOldStaticConstructorAABB = axisAlignedBB.getMethod("a", + double.class, double.class, double.class, double.class, double.class, double.class); + worldGetType = worldServer.getMethod("getType", int.class, int.class, int.class); + } + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_12)) { + getCubes = world.getMethod("a", axisAlignedBB.getParent()); + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + //1.7.10 does not have the BlockPosition object yet. + addCBoxes = block.getMethod("a", world.getParent(), int.class, int.class, int.class, + axisAlignedBB.getParent(), List.class, entity.getParent()); + } else { + addCBoxes = block.getMethod("a", world.getParent(), blockPos.getParent(), iBlockData.getParent(), + axisAlignedBB.getParent(), List.class, entity.getParent()); + } + + getFlowMethod = Reflections.getNMSClass("BlockFluids").getDeclaredMethodByType(vec3D.getParent(), 0); + } else if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + getCubes = world.getMethod("getCubes", entity.getParent(), axisAlignedBB.getParent()); + addCBoxes = block.getMethod("a", world.getParent(), blockPos.getParent(), iBlockData.getParent(), + axisAlignedBB.getParent(), List.class, entity.getParent()); + getFlowMethod = Reflections.getNMSClass("BlockFluids").getDeclaredMethodByType(vec3D.getParent(), 0); + } else { + worldReader = Reflections.getNMSClass("IWorldReader"); + //1.13 and 1.13.1 returns just VoxelShape while 1.13.2+ returns a Stream + getCubes = worldReader.getMethod("a", entity.getParent(), axisAlignedBB.getParent(), + double.class, double.class, double.class); + voxelShape = Reflections.getNMSClass("VoxelShape"); + getCubesFromVoxelShape = voxelShape.getMethodByType(List.class, 0); + fluidMethod = world.getMethod("getFluidIfLoaded"); + getFlowMethod = Reflections.getNMSClass("Fluid").getMethodByType(vec3D.getParent(), 0); + } + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + activeItemField = entityHuman.getFieldByType(itemStack.getParent(), 0); + } else { + activeItemField = entityLiving.getFieldByType(itemStack.getParent(), 0); + } + try { + enumAnimationStack = itemStack.getMethodByType(enumAnimation.getParent(), 0); + } catch(Exception e) { + e.printStackTrace(); + } + canDestroyMethod = playerInventory.getMethod("b", + ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8_9) + ? iBlockData.getParent() : block.getParent()); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedClass.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedClass.java new file mode 100644 index 00000000..a9461dc9 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedClass.java @@ -0,0 +1,204 @@ +/* + * Created by Justin Heflin on 4/19/18 8:21 PM + * Copyright (c) 2018. + * + * Can be redistributed non commercially as long as credit is given to original copyright owner. + * + * last modified: 4/19/18 7:22 PM + */ +package cc.funkemunky.api.reflections.types; + +import lombok.Getter; +import lombok.val; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +@Getter +public class WrappedClass { + private final Class parent; + + public WrappedClass(Class parent) { + this.parent = parent; + } + + public WrappedField getFieldByName(String name) { + Field tempField = null; + for (Field field : this.parent.getDeclaredFields()) { + if (field.getName().equals(name)) { + tempField = field; + break; + } + } + if (tempField != null) { + tempField.setAccessible(true); + return new WrappedField(this, tempField); + } + return null; + } + + public WrappedConstructor getConstructor(Class... types) { + try { + return new WrappedConstructor(this, this.parent.getDeclaredConstructor(types)); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + return null; + } + } + + public List getFields(Predicate... parameters) { + return getFields() + .stream() + .filter(field -> Arrays.stream(parameters).allMatch(param -> param.test(field))) + .collect(Collectors.toList()); + } + + public List getMethods(Predicate... parameters) { + return getMethods() + .stream() + .filter(method -> Arrays.stream(parameters).allMatch(param -> param.test(method))) + .collect(Collectors.toList()); + } + + public List getConstructors() { + return Arrays.stream(this.parent.getConstructors()) + .map(construct -> new WrappedConstructor(this, construct)) + .collect(Collectors.toList()); + } + + public WrappedConstructor getConstructor() { + val optional = Arrays.stream(this.parent.getConstructors()).filter(cons -> cons.getParameterCount() == 0).findFirst(); + return optional.map(constructor -> new WrappedConstructor(this, constructor)).orElse(null); + } + + public WrappedConstructor getConstructorAtIndex(int index) { + return new WrappedConstructor(this, this.parent.getConstructors()[index]); + } + + public boolean isAnnotationPresent(Class annClass) { + return parent.isAnnotationPresent(annClass); + } + + public T getAnnotation(Class annClass) { + return (T) parent.getDeclaredAnnotation(annClass); + } + + public WrappedField getFieldByType(Class type, int index) { + for (Field field : this.parent.getDeclaredFields()) { + if (field.getType().equals(type) && index-- <= 0) { + return new WrappedField(this, field); + } + } + throw new NullPointerException("Could not find field with type " + type.getSimpleName() + " at index " + index); + } + + public WrappedField getFirstFieldByType(Class type) { + return this.getFieldByType(type, 0); + } + + public WrappedMethod getMethod(String name, Class... parameters) { + for (Method method : this.parent.getDeclaredMethods()) { + if (!method.getName().equals(name) || parameters.length != method.getParameterTypes().length) { + continue; + } + boolean same = true; + for (int x = 0; x < method.getParameterTypes().length; x++) { + if (method.getParameterTypes()[x] != parameters[x]) { + same = false; + break; + } + } + if (same) { + return new WrappedMethod(this, method); + } + } + for (Method method : this.parent.getMethods()) { + if (!method.getName().equals(name) || parameters.length != method.getParameterTypes().length) { + continue; + } + boolean same = true; + for (int x = 0; x < method.getParameterTypes().length; x++) { + if (method.getParameterTypes()[x] != parameters[x]) { + same = false; + break; + } + } + if (same) { + return new WrappedMethod(this, method); + } + } + throw new NullPointerException("Could not find method in " + getParent().getSimpleName() + " with name " + name); + } + + public WrappedMethod getDeclaredMethodByType(Class type, int index) { + for (Method method : this.parent.getDeclaredMethods()) { + if(method.getReturnType().equals(type) && index-- <= 0) { + return new WrappedMethod(this, method); + } + } + throw new NullPointerException("Could not find method with return type " + type.getSimpleName() + " at index " + index); + } + + public WrappedMethod getMethodByType(Class type, int index) throws NullPointerException { + for (Method method : this.parent.getMethods()) { + if(method.getReturnType().equals(type) && index-- <= 0) { + return new WrappedMethod(this, method); + } + } + throw new NullPointerException("Could not find method with return type " + type.getName() + + " at index " + index); + } + + //We have a separate method instead of just calling WrappedClass#getMethods(boolean, boolean) + //for performance reasons. + public List getMethods() { + return Arrays.stream(parent.getMethods()) + .map(method -> new WrappedMethod(this, method)) + .collect(Collectors.toList()); + } + + public List getMethods(boolean noStatic, boolean noFinal) { + return Arrays.stream(parent.getMethods()) + .filter(method -> + (!noFinal || !Modifier.isFinal(method.getModifiers()) + && (!noStatic || !Modifier.isStatic(method.getModifiers())))) + .map(method -> new WrappedMethod(this, method)) + .collect(Collectors.toList()); + + } + + public List getMethods(boolean noStatic) { + return getMethods(noStatic, false); + } + + //We have a separate method instead of just calling WrappedClass#getFields(boolean, boolean) + // or performance reasons. + public List getFields() { + return Arrays.stream(parent.getDeclaredFields()) + .map(field -> new WrappedField(this, field)) + .collect(Collectors.toList()); + } + + public List getFields(boolean noStatic, boolean noFinal) { + return Arrays.stream(parent.getFields()) + .filter(field -> + (!noFinal || !Modifier.isFinal(field.getModifiers()) + && (!noStatic || !Modifier.isStatic(field.getModifiers())))) + .map(field -> new WrappedField(this, field)) + .collect(Collectors.toList()); + } + + public List getFields(boolean noStatic) { + return getFields(noStatic, false); + } + + public Enum getEnum(String name) { + return Enum.valueOf(this.parent, name); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedConstructor.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedConstructor.java new file mode 100644 index 00000000..96e9553c --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedConstructor.java @@ -0,0 +1,44 @@ +/* + * Created by Justin Heflin on 4/19/18 8:21 PM + * Copyright (c) 2018. + * + * Can be redistributed non commercially as long as credit is given to original copyright owner. + * + * last modified: 4/19/18 7:22 PM + */ +package cc.funkemunky.api.reflections.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +@RequiredArgsConstructor +@AllArgsConstructor +@Getter +public class WrappedConstructor { + private final WrappedClass parent; + private Constructor constructor; + + public T newInstance(Object... args) { + try { + constructor.setAccessible(true); + return (T) constructor.newInstance(args); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } + + public T newInstance() { + try { + constructor.setAccessible(true); + return (T) constructor.newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedField.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedField.java new file mode 100644 index 00000000..ca9ca684 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedField.java @@ -0,0 +1,62 @@ +/* + * Created by Justin Heflin on 4/19/18 8:21 PM + * Copyright (c) 2018. + * + * Can be redistributed non commercially as long as credit is given to original copyright owner. + * + * last modified: 4/19/18 7:22 PM + */ +package cc.funkemunky.api.reflections.types; + +import lombok.Getter; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +@Getter +public class WrappedField { + private final WrappedClass parent; + private final Field field; + private final Class type; + + public WrappedField(WrappedClass parent, Field field) { + this.parent = parent; + this.field = field; + this.type = field.getType(); + this.field.setAccessible(true); + } + + public T get(Object parent) { + try { + return (T) this.field.get(parent); + } catch (IllegalAccessException e) { + e.printStackTrace(); + return null; + } + } + + public void set(Object parent, Object value) { + try { + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(this.field, this.field.getModifiers() & ~Modifier.FINAL); + this.field.setAccessible(true); + this.field.set(parent, value); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + } + + public boolean isAnnotationPresent(Class annClass) { + return field.isAnnotationPresent(annClass); + } + + public T getAnnotation(Class annClass) { + return (T) field.getAnnotation(annClass); + } + + public int getModifiers() { + return this.field.getModifiers(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedMethod.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedMethod.java new file mode 100644 index 00000000..624a9429 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/reflections/types/WrappedMethod.java @@ -0,0 +1,75 @@ +/* + * Created by Justin Heflin on 4/19/18 8:21 PM + * Copyright (c) 2018. + * + * Can be redistributed non commercially as long as credit is given to original copyright owner. + * + * last modified: 4/19/18 7:22 PM + */ +package cc.funkemunky.api.reflections.types; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.utils.objects.MethodFunction; +import cc.funkemunky.api.utils.objects.QuadFunction; +import cc.funkemunky.api.utils.objects.TriFunction; +import lombok.Getter; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +@Getter +public class WrappedMethod { + private final WrappedClass parent; + private Method method; + private final String name; + private MethodFunction mfunc; + private final List> parameters; + private boolean isVoid; + + public WrappedMethod(WrappedClass parent, Method method) { + this.name = method.getName(); + this.method = method; + this.parent = parent; + this.parameters = Arrays.asList(method.getParameterTypes()); + + try { + int length = method.getParameterCount(); + switch(length) { + case 0: + Function func = Reflections.createMethodLambda(method); + mfunc = new MethodFunction(method, func); + break; + case 1: + BiFunction bifunc = Reflections.createMethodLambda(method); + mfunc = new MethodFunction(method, bifunc); + break; + case 2: + TriFunction trifunc = Reflections.createMethodLambda(method); + mfunc = new MethodFunction(method, trifunc); + break; + case 3: + QuadFunction quadFunc = Reflections.createMethodLambda(method); + mfunc = new MethodFunction(method, quadFunc); + break; + default: + method.setAccessible(true); + mfunc = new MethodFunction(method); + break; + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + isVoid = method.getReturnType().equals(void.class); + } + + public T invoke(Object object, Object... args) { + return mfunc.invokeMethod(object, args); + } + + public int getModifiers() { + return this.method.getModifiers(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/settings/MongoSettings.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/settings/MongoSettings.java new file mode 100644 index 00000000..f0f1deb2 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/settings/MongoSettings.java @@ -0,0 +1,25 @@ +package cc.funkemunky.api.settings; + +import cc.funkemunky.api.utils.ConfigSetting; +import cc.funkemunky.api.utils.Init; + +@Init +public class MongoSettings { + @ConfigSetting(path = "database.mongo", name = "enabled") + public static boolean enabled = false; + + @ConfigSetting(path = "database.mongo", name = "name") + public static String database = "Atlas"; + + @ConfigSetting(path = "database.mongo", name = "ip") + public static String ip = "127.0.0.1"; + + @ConfigSetting(path = "database.mongo", name = "port") + public static int port = 27017; + + @ConfigSetting(path = "database.mongo", name = "username") + public static String username = "username"; + + @ConfigSetting(path = "database.mongo", name = "password") + public static String password = "password"; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/settings/MySQLSettings.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/settings/MySQLSettings.java new file mode 100644 index 00000000..43a77799 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/settings/MySQLSettings.java @@ -0,0 +1,22 @@ +package cc.funkemunky.api.settings; + +import cc.funkemunky.api.utils.ConfigSetting; +import cc.funkemunky.api.utils.Init; + +@Init +public class MySQLSettings { + @ConfigSetting(path = "database.mysql", name = "name") + public static String database = "Atlas"; + + @ConfigSetting(path = "database.mysql", name = "ip") + public static String ip = "127.0.0.1"; + + @ConfigSetting(path = "database.mysql", name = "port") + public static int port = 3306; + + @ConfigSetting(path = "database.mysql", name = "username") + public static String username = "username"; + + @ConfigSetting(path = "database.mysql", name = "password") + public static String password = "password"; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/GeneralObject.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/GeneralObject.java new file mode 100644 index 00000000..48830790 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/GeneralObject.java @@ -0,0 +1,33 @@ +package cc.funkemunky.api.tinyprotocol; + +import cc.funkemunky.api.reflections.types.WrappedClass; +import lombok.*; + +import java.util.Arrays; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class GeneralObject { + + private Object object; + private WrappedClass wrapper; + + public GeneralObject(Object object) { + this.wrapper = new WrappedClass(object.getClass()); + } + + public GeneralObject(WrappedClass wrapper) { + this.wrapper = wrapper; + } + + public T wrap(Object... args) { + val classes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new); + + T instance = wrapper.getConstructor(classes).newInstance(args); + object = instance; + + return instance; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/Parameter.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/Parameter.java new file mode 100644 index 00000000..6fc23106 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/Parameter.java @@ -0,0 +1,15 @@ +package cc.funkemunky.api.tinyprotocol; + +import cc.funkemunky.api.reflections.types.WrappedClass; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class Parameter { + public final WrappedClass wrappedClass; + public final Object object; + + public Parameter(Class c, Object object) { + this.wrappedClass = new WrappedClass(c); + this.object = object; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/GeneralField.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/GeneralField.java new file mode 100644 index 00000000..ee75daf5 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/GeneralField.java @@ -0,0 +1,14 @@ +package cc.funkemunky.api.tinyprotocol.api; + +import cc.funkemunky.api.reflections.types.WrappedField; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class GeneralField { + public final WrappedField field; + private final Object object; + + public T getObject() { + return (T) object; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/GeneralWrapper.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/GeneralWrapper.java new file mode 100644 index 00000000..c5de3113 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/GeneralWrapper.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.tinyprotocol.api; + +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.val; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/* This class can be used for packets that do not have dedicated wrappers or change constantly between versions. */ +@Getter +@RequiredArgsConstructor +public class GeneralWrapper { + private List fields = new ArrayList<>(); + private List methods; + private final WrappedClass objectClass; + + public GeneralWrapper(Object object) { + objectClass = new WrappedClass(object.getClass()); + methods = objectClass.getMethods(); + + objectClass.getFields().forEach(field -> fields.add(new GeneralField(field, field.get(object)))); + } + + public T build(Object... args) { + val classes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new); + + return objectClass.getConstructor(classes).newInstance(args); + } + + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/NMSObject.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/NMSObject.java new file mode 100644 index 00000000..6fcf08db --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/NMSObject.java @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.api; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.events.impl.PacketReceiveEvent; +import cc.funkemunky.api.events.impl.PacketSendEvent; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import cc.funkemunky.api.tinyprotocol.reflection.MethodInvoker; +import cc.funkemunky.api.tinyprotocol.reflection.Reflection; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import static cc.funkemunky.api.tinyprotocol.api.NMSObject.Type.CRAFTITEMSTACK; +import static cc.funkemunky.api.tinyprotocol.api.NMSObject.Type.ITEMSTACK; + +@Getter +@Setter +@NoArgsConstructor +public abstract class NMSObject { + private static final MethodInvoker asCraftMirror = Reflection.getMethod(CRAFTITEMSTACK, "asCraftMirror", Reflection.getClass(ITEMSTACK)); + private static Map> constructors = new HashMap<>(); + @Setter + private Object object; + private boolean cancelled; + private Player player = null; + + public NMSObject(Object object) { + Atlas.getInstance().getProfile().start("processor:" + object.getClass().getName()); + this.object = object; + process(player, ProtocolVersion.getGameVersion()); + Atlas.getInstance().getProfile().stop("processor:" + object.getClass().getName()); + } + + public NMSObject(Object object, Player player) { + this.object = object; + this.player = player; + process(player, ProtocolVersion.getGameVersion()); + } + + public NMSObject(PacketReceiveEvent event) { + this.object = event.getPacket(); + this.player = event.getPlayer(); + } + + public NMSObject(PacketSendEvent event) { + this.object = event.getPacket(); + this.player = event.getPlayer(); + } + + public static Object construct(String packet, Object... args) { + try { + Class c = constructors.get(packet); + if (c == null) { + c = Reflection.getMinecraftClass(packet); + constructors.put(packet, c); + } + Object p = c.newInstance(); + Field[] fields = c.getDeclaredFields(); + int failed = 0; + for (int i = 0; i < args.length; i++) { + Object o = args[i]; + if (o == null) continue; + fields[i - failed].setAccessible(true); + try { + fields[i - failed].set(p, o); + } catch (Exception e) { + //attempt to continue + failed++; + } + } + return p; + } catch (Exception e) { + System.out.println("The plugin cannot work as protocol incompatibilities were detected... Disabling..."); + e.printStackTrace(); + } + return null; + } + + public static Object construct(String packet, Object arg) { + try { + Class c = constructors.get(packet); + if (c == null) { + c = Reflection.getMinecraftClass(packet); + constructors.put(packet, c); + } + Object p = c.newInstance(); + Field[] fields = c.getDeclaredFields(); + + if(arg != null) { + fields[0].setAccessible(true); + fields[0].set(p, arg); + } + return p; + } catch (Exception e) { + System.out.println("The plugin cannot work as protocol incompatibilities were detected... Disabling..."); + e.printStackTrace(); + } + return null; + } + + public static Object construct(Object obj, String packet, Object... args) { + try { + Class c = constructors.get(packet); + if (c == null) { + c = Reflection.getMinecraftClass(packet); + constructors.put(packet, c); + } + + Object p = obj != null ? obj : constructors + .computeIfAbsent(packet, Reflection::getMinecraftClass).newInstance(); + Field[] fields = c.getDeclaredFields(); + int failed = 0; + for (int i = 0; i < args.length; i++) { + Object o = args[i]; + if (o == null) continue; + fields[i - failed].setAccessible(true); + try { + fields[i - failed].set(p, o); + } catch (Exception e) { + //attempt to continue + failed++; + } + } + return p; + } catch (Exception e) { + System.out.println("The plugin cannot work as protocol incompatibilities were detected... Disabling..."); + e.printStackTrace(); + } + return null; + } + + public static ItemStack toBukkitStack(Object nmsStack) { + return (ItemStack) asCraftMirror.invoke(null, nmsStack); + } + + public static FieldAccessor fetchField(String className, Class fieldType, int index) { + return Reflection.getFieldSafe(Reflection.NMS_PREFIX + "." + className, fieldType, index); + } + + public static FieldAccessor fetchFieldByName(String className, String name, Class fieldType) { + return Reflection.getField(Reflection.NMS_PREFIX + "." + className, name, fieldType); + } + + public static FieldAccessor fetchField(String className, String fieldType, int index) { + return Reflection.getFieldSafe(Reflection.NMS_PREFIX + "." + className, (Class) Reflection.getClass(fieldType), index); + } + + public static WrappedField fetchField(WrappedClass wrappedClass, Class type, int index) { + return wrappedClass.getFieldByType(type, index); + } + + public static WrappedField fetchField(WrappedClass wrappedClass, String name) { + return wrappedClass.getFieldByName(name); + } + + /** Updates the vanilla object with the fields set **/ + public abstract void updateObject(); + + public String getPacketName() { + String name = object.getClass().getName(); + return name.substring(name.lastIndexOf(".") + 1); + } + + public void set(WrappedField field, Object value) { + field.set(getObject(), value); + } + + public void set(FieldAccessor accessor, Object value) { + accessor.set(getObject(), value); + } + + public void process(Player player, ProtocolVersion version) { + } + + public void setPacket(String packet, Object... args) { + this.object = construct(packet, args); + } + + public T fetch(FieldAccessor field) { + return field.get(object); + } + + public T fetch(WrappedField field) { + return field.get(object); + } + + public T fetch(WrappedField field, Object obj) { + return field.get(obj); + } + + public T fetch(FieldAccessor field, Object obj) { + return field.get(obj); + } + + public static class Type { + public static final String WATCHABLE_OBJECT = (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8_5)) + ? "WatchableObject" : + (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9) + ? "DataWatcher$WatchableObject" + : "DataWatcher$Item"); + public static final String BASEBLOCKPOSITION = "BaseBlockPosition"; + public static final String BLOCKPOSITION = "BlockPosition"; + public static final String ITEMSTACK = Reflection.NMS_PREFIX + ".ItemStack"; + public static final String ENTITY = Reflection.NMS_PREFIX + ".Entity"; + public static final String DATAWATCHER = Reflection.NMS_PREFIX + ".DataWatcher"; + public static final String DATAWATCHEROBJECT = Reflection.NMS_PREFIX + ".DataWatcherObject"; + public static final String CHATMESSAGE = Reflection.NMS_PREFIX + ".ChatMessage"; + public static final String CRAFTITEMSTACK = Reflection.OBC_PREFIX + ".inventory.CraftItemStack"; + public static final String GAMEPROFILE = (Reflection.VERSION.startsWith("v1_7") ? "net.minecraft.util." : "") + "com.mojang.authlib.GameProfile"; + public static final String PROPERTYMAP = (Reflection.VERSION.startsWith("v1_7") ? "net.minecraft.util." : "") + "com.mojang.authlib.PropertyMap"; + public static final String VEC3D = Reflection.NMS_PREFIX + ".Vec3D"; + public static final String PLAYERINFODATA = Reflection.NMS_PREFIX + Server.PLAYER_INFO + ".PlayerInfoData"; + } + + public static class Client { + private static final String CLIENT = "PacketPlayIn"; + + public static final String KEEP_ALIVE = CLIENT + "KeepAlive"; + public static final String FLYING = CLIENT + "Flying"; + public static final String POSITION = FLYING + "$" + CLIENT + "Position"; + public static final String POSITION_LOOK = FLYING + "$" + CLIENT + "PositionLook"; + public static final String LOOK = FLYING + "$" + CLIENT + "Look"; + public static final String LEGACY_POSITION = CLIENT + "Position"; + public static final String LEGACY_POSITION_LOOK = CLIENT + "PositionLook"; + public static final String LEGACY_LOOK = CLIENT + "Look"; + public static final String TRANSACTION = CLIENT + "Transaction"; + public static final String BLOCK_DIG = CLIENT + "BlockDig"; + public static final String ENTITY_ACTION = CLIENT + "EntityAction"; + public static final String USE_ENTITY = CLIENT + "UseEntity"; + public static final String WINDOW_CLICK = CLIENT + "WindowClick"; + public static final String CUSTOM_PAYLOAD = CLIENT + "CustomPayload"; + public static final String ARM_ANIMATION = CLIENT + "ArmAnimation"; + public static final String BLOCK_PLACE_1_9 = CLIENT + "BlockPlace"; + public static final String BLOCK_PLACE = CLIENT + + (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9) ? "BlockPlace" : "UseItem"); + public static final String STEER_VEHICLE = CLIENT + "SteerVehicle"; + public static final String HELD_ITEM = CLIENT + "HeldItemSlot"; + public static final String CLIENT_COMMAND = CLIENT + "ClientCommand"; + public static final String CLOSE_WINDOW = CLIENT + "CloseWindow"; + public static final String ABILITIES = CLIENT + "Abilities"; + public static final String TAB_COMPLETE = CLIENT + "TabComplete"; + public static final String CHAT = CLIENT + "Chat"; + public static final String CREATIVE_SLOT = CLIENT + "SetCreativeSlot"; + public static final String SETTINGS = CLIENT + "Settings"; + public static final String ADVANCEMENTS = CLIENT + "Advancements"; + } + + public static class Server { + private static final String SERVER = "PacketPlayOut"; + + public static final String KEEP_ALIVE = SERVER + "KeepAlive"; + public static final String CHAT = SERVER + "Chat"; + public static final String POSITION = SERVER + "Position"; + public static final String TRANSACTION = SERVER + "Transaction"; + public static final String NAMED_ENTITY_SPAWN = SERVER + "NamedEntitySpawn"; + public static final String SPAWN_ENTITY_LIVING = SERVER + "SpawnEntityLiving"; + public static final String SPAWN_ENTITY = SERVER + "SpawnEntity"; + public static final String CUSTOM_PAYLOAD = SERVER + "CustomPayload"; + public static final String ENTITY_METADATA = SERVER + "EntityMetadata"; + public static final String ENTITY_VELOCITY = SERVER + "EntityVelocity"; + public static final String ENTITY_DESTROY = SERVER + "EntityDestroy"; + + public static final String ENTITY = SERVER + "Entity"; + public static final String REL_POSITION = ENTITY + "$" + SERVER + "RelEntityMove"; + public static final String REL_POSITION_LOOK = ENTITY + "$" + SERVER + "RelEntityMoveLook"; + public static final String REL_LOOK = ENTITY + "$" + SERVER + "EntityLook"; + public static final String LEGACY_REL_POSITION = SERVER + "RelEntityMove"; + public static final String ENTITY_HEAD_ROTATION = SERVER + "EntityHeadRotation"; + public static final String LEGACY_REL_POSITION_LOOK = SERVER + "RelEntityMoveLook"; + public static final String LEGACY_REL_LOOK = SERVER + "EntityLook"; + public static final String ABILITIES = SERVER + "Abilities"; + public static final String OPEN_WINDOW = SERVER + "OpenWindow"; + public static final String HELD_ITEM = SERVER + "HeldItemSlot"; + public static final String PLAYER_INFO = SERVER + "PlayerInfo"; + public static final String TAB_COMPLETE = SERVER + "TabComplete"; + public static final String RESPAWN = SERVER + "Respawn"; + public static final String COMMANDS = SERVER + "Commands"; + public static final String CLOSE_WINDOW = SERVER + "CloseWindow"; + public static final String ENTITY_EFFECT = SERVER + "EntityEffect"; + } + + public static class Login { + public static final String HANDSHAKE = "PacketHandshakingInSetProtocol"; + public static final String PING = "PacketStatusInPing"; + public static final String START = "PacketStatusInStart"; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/Packet.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/Packet.java new file mode 100644 index 00000000..afeee6a3 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/Packet.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.api; + +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import cc.funkemunky.api.tinyprotocol.reflection.Reflection; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.bukkit.entity.Player; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +@NoArgsConstructor +@Getter +@Setter +public abstract class Packet { + private static Map> constructors = new HashMap<>(); + private Object packet; + private boolean cancelled; + + public Packet(Object packet) { + this.packet = packet; + } + + public static Object construct(String packet, Object... args) { + try { + Class c = constructors.get(packet); + if (c == null) { + c = Reflection.getMinecraftClass(packet); + constructors.put(packet, c); + } + Object p = c.newInstance(); + Field[] fields = c.getDeclaredFields(); + int failed = 0; + for (int i = 0; i < args.length; i++) { + Object o = args[i]; + if (o == null) continue; + fields[i - failed].setAccessible(true); + try { + fields[i - failed].set(p, o); + } catch (Exception e) { + //attempt to continue + failed++; + } + } + return p; + } catch (Exception e) { + System.out.println("The plugin cannot work as protocol incompatibilities were detected... Disabling..."); + e.printStackTrace(); + } + return null; + } + + public static FieldAccessor fetchField(String className, Class fieldType, int index) { + return Reflection.getFieldSafe(Reflection.NMS_PREFIX + "." + className, fieldType, index); + } + + public static boolean isPositionLook(String type) { + switch (type) { + case Client.POSITION_LOOK: + case Client.LEGACY_POSITION_LOOK: + return true; + default: + return false; + } + } + + public static boolean isPosition(String type) { + switch (type) { + case Client.POSITION: + case Client.LEGACY_POSITION: + return true; + default: + return false; + } + } + + public static boolean isLook(String type) { + switch (type) { + case Client.LOOK: + case Client.LEGACY_LOOK: + return true; + default: + return false; + } + } + + public String getPacketName() { + String name = packet.getClass().getName(); + return name.substring(name.lastIndexOf(".") + 1); + } + + public void process(Player player, ProtocolVersion version) { + } + + public void setPacket(String packet, Object... args) { + this.packet = construct(packet, args); + } + + public T fetch(FieldAccessor field) { + return field.get(packet); + } + + public static class Type { + public static final String WATCHABLE_OBJECT = Reflection.NMS_PREFIX + + (ProtocolVersion.getGameVersion().isOrBelow(ProtocolVersion.V1_8) + ? ".WatchableObject" : ".DataWatcher$WatchableObject"); + public static final String BASEBLOCKPOSITION = Reflection.NMS_PREFIX + "BaseBlockPosition"; + public static final String ITEMSTACK = Reflection.NMS_PREFIX + ".ItemStack"; + public static final String ENTITY = Reflection.NMS_PREFIX + ".Entity"; + public static final String DATAWATCHER = Reflection.NMS_PREFIX + ".DataWatcher"; + public static final String DATAWATCHEROBJECT = Reflection.NMS_PREFIX + ".DataWatcherObject"; + public static final String CRAFTITEMSTACK = Reflection.OBC_PREFIX + ".inventory.CraftItemStack"; + public static final String GAMEPROFILE = "com.mojang.authlib.GameProfile"; + public static final String PROPERTYMAP = "com.mojang.authlib.PropertyMap"; + public static final String CHUNKCOORDINTPAIR = Reflection.NMS_PREFIX + ".ChunkCoordInPair"; + } + + public static class Client { + private static final String CLIENT = "PacketPlayIn"; + + public static final String KEEP_ALIVE = CLIENT + "KeepAlive"; + public static final String FLYING = CLIENT + "Flying"; + + public static final String POSITION = CLIENT + "Position"; + public static final String POSITION_LOOK = CLIENT + "PositionLook"; + public static final String LOOK = CLIENT + "Look"; + @Deprecated + public static final String LEGACY_POSITION = FLYING + "$" + CLIENT + "Position"; + @Deprecated + public static final String LEGACY_POSITION_LOOK = FLYING + "$" + CLIENT + "PositionLook"; + @Deprecated + public static final String LEGACY_LOOK = FLYING + "$" + CLIENT + "Look"; + + public static final String TRANSACTION = CLIENT + "Transaction"; + public static final String BLOCK_DIG = CLIENT + "BlockDig"; + public static final String ENTITY_ACTION = CLIENT + "EntityAction"; + public static final String USE_ENTITY = CLIENT + "UseEntity"; + public static final String WINDOW_CLICK = CLIENT + "WindowClick"; + public static final String STEER_VEHICLE = CLIENT + "SteerVehicle"; + public static final String CUSTOM_PAYLOAD = CLIENT + "CustomPayload"; + public static final String ARM_ANIMATION = CLIENT + "ArmAnimation"; + public static final String BLOCK_PLACE_1_9 = CLIENT + "BlockPlace1_9"; + public static final String BLOCK_PLACE = CLIENT + "BlockPlace"; + public static final String ABILITIES = CLIENT + "Abilities"; + public static final String HELD_ITEM_SLOT = CLIENT + "HeldItemSlot"; + public static final String CLOSE_WINDOW = CLIENT + "CloseWindow"; + public static final String TAB_COMPLETE = CLIENT + "TabComplete"; + public static final String CHAT = CLIENT + "Chat"; + public static final String CREATIVE_SLOT = CLIENT + "SetCreativeSlot"; + public static final String CLIENT_COMMAND = CLIENT + "ClientCommand"; + public static final String SETTINGS = CLIENT + "Settings"; + public static final String ADVANCEMENTS = CLIENT + "Advancements"; + } + + public static class Server { + private static final String SERVER = "PacketPlayOut"; + + public static final String KEEP_ALIVE = SERVER + "KeepAlive"; + public static final String CHAT = SERVER + "Chat"; + public static final String POSITION = SERVER + "Position"; + public static final String TRANSACTION = SERVER + "Transaction"; + public static final String NAMED_ENTITY_SPAWN = SERVER + "NamedEntitySpawn"; + public static final String SPAWN_ENTITY_LIVING = SERVER + "SpawnEntityLiving"; + public static final String SPAWN_ENTITY = SERVER + "SpawnEntity"; + public static final String CUSTOM_PAYLOAD = SERVER + "CustomPayload"; + public static final String ABILITIES = SERVER + "Abilities"; + public static final String ENTITY_METADATA = SERVER + "EntityMetadata"; + public static final String ENTITY_VELOCITY = SERVER + "EntityVelocity"; + public static final String ENTITY_DESTROY = SERVER + "EntityDestroy"; + public static final String ENTITY_HEAD_ROTATION = SERVER + "EntityHeadRotation"; + public static final String ENTITY = SERVER + "Entity"; + public static final String REL_POSITION = ENTITY + "$" + SERVER + "RelEntityMove"; + public static final String REL_POSITION_LOOK = ENTITY + "$" + SERVER + "RelEntityMoveLook"; + public static final String REL_LOOK = ENTITY + "$" + SERVER + "EntityLook"; + public static final String LEGACY_REL_POSITION = SERVER + "RelEntityMove"; + public static final String LEGACY_REL_POSITION_LOOK = SERVER + "RelEntityMoveLook"; + public static final String LEGACY_REL_LOOK = SERVER + "EntityLook"; + public static final String BLOCK_CHANGE = SERVER + "BlockChange"; + public static final String CLOSE_WINDOW = SERVER + "CloseWindow"; + public static final String HELD_ITEM = SERVER + "HeldItemSlot"; + public static final String TAB_COMPLETE = SERVER + "TabComplete"; + public static final String RESPAWN = SERVER + "Respawn"; + public static final String WORLD_PARTICLE = SERVER + "WorldParticles"; + public static final String COMMANDS = SERVER + "Commands"; + public static final String OPEN_WINDOW = SERVER + "OpenWindow"; + public static final String ENTITY_EFFECT = SERVER + "EntityEffect"; + public static final String MULTI_BLOCK_CHANGE = SERVER + "MultiBlockChange"; + } + + public static class Login { + public static final String HANDSHAKE = "PacketHandshakingInSetProtocol"; + public static final String PING = "PacketStatusInPing"; + public static final String START = "PacketStatusInStart"; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/ProtocolVersion.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/ProtocolVersion.java new file mode 100644 index 00000000..47cd67cc --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/ProtocolVersion.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.api; + +import cc.funkemunky.api.tinyprotocol.reflection.Reflection; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ProtocolVersion { + V1_7(4, "v1_7_R3"), + V1_7_10(5, "v1_7_R4"), + V1_8(45, "v1_8_R1"), + V1_8_5(46, "v1_8_R2"), + V1_8_9(47, "v1_8_R3"), + V1_9(107, "v1_9_R1"), + V1_9_1(108, null), + V1_9_2(109, "v1_9_R2"), + V1_9_4(110, "v1_9_R2"), + V1_10(210, "v1_10_R1"), + V1_10_2(210, "v1_10_R1"), + V1_11(316, "v1_11_R1"), + V1_12(335, "v1_12_R1"), + V1_12_1(338, null), + V1_12_2(340, "v1_12_R1"), + V1_13(350, "v1_13_R1"), + V1_13_1(351, "v1_13_R2"), + V1_13_2(352, "v1_13_R2"), + V1_14(477, "v1_14_R1"), + V1_14_1(480, "v1_14_R1"), + v1_14_2(485, "v1_14_R1"), + v1_14_3(490, "v1_14_R1"), + v1_14_4(498, "v1_14_R1"), + v1_15(573, "v1_15_R1"), + v1_15_1(575, "v1_15_R1"), + v1_15_2(578, "v1_15_R1"), + UNKNOWN(-1, "UNKNOWN"); + + @Getter + private static ProtocolVersion gameVersion = fetchGameVersion(); + private int version; + @Getter + private static boolean paper; + private String serverVersion; + + private static ProtocolVersion fetchGameVersion() { + for (ProtocolVersion version : values()) { + if (version.getServerVersion() != null && version.getServerVersion().equals(Reflection.VERSION)) + return version; + } + return UNKNOWN; + } + + public static ProtocolVersion getVersion(int versionId) { + for (ProtocolVersion version : values()) { + if (version.getVersion() == versionId) return version; + } + return UNKNOWN; + } + + public boolean isBelow(ProtocolVersion version) { + return this.getVersion() < version.getVersion(); + } + + public boolean isOrBelow(ProtocolVersion version) { + return this.getVersion() <= version.getVersion(); + } + + public boolean isAbove(ProtocolVersion version) { + return this.getVersion() > version.getVersion(); + } + + public boolean isOrAbove(ProtocolVersion version) { + return this.getVersion() >= version.getVersion(); + } + + static { + try { + Class.forName("org.github.paperspigot.PaperSpigotConfig"); + paper = true; + } catch(Exception e) { + paper = false; + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/TinyProtocolHandler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/TinyProtocolHandler.java new file mode 100644 index 00000000..d912677b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/TinyProtocolHandler.java @@ -0,0 +1,135 @@ +package cc.funkemunky.api.tinyprotocol.api; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.events.impl.PacketLoginEvent; +import cc.funkemunky.api.events.impl.PacketReceiveEvent; +import cc.funkemunky.api.events.impl.PacketSendEvent; +import cc.funkemunky.api.handlers.protocolsupport.ProtocolAPI; +import cc.funkemunky.api.tinyprotocol.api.packets.AbstractTinyProtocol; +import cc.funkemunky.api.tinyprotocol.api.packets.channelhandler.TinyProtocol1_7; +import cc.funkemunky.api.tinyprotocol.api.packets.channelhandler.TinyProtocol1_8; +import lombok.Getter; +import org.bukkit.entity.Player; + +import java.net.SocketAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class TinyProtocolHandler { + @Getter + private static AbstractTinyProtocol instance; + + public boolean paused = false; + + public static Map bungeeVersionCache = new HashMap<>(); + + public TinyProtocolHandler() { + // 1.8+ and 1.7 NMS have different class paths for their libraries used. This is why we have to separate the two. + // These feed the packets asynchronously, before Minecraft processes it, into our own methods to process and be used as an API. + + TinyProtocolHandler self = this; + // 1.8+ and 1.7 NMS have different class paths for their libraries used. This is why we have to separate the two. + // These feed the packets asynchronously, before Minecraft processes it, into our own methods to process and be used as an API. + instance = ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8) ? + new TinyProtocol1_7(Atlas.getInstance()) { + @Override + public Object onHandshake(SocketAddress address, Object packet) { + return self.onHandshake(address, packet); + } + + @Override + public Object onPacketOutAsync(Player receiver, Object packet) { + return self.onPacketOutAsync(receiver, packet); + } + + @Override + public Object onPacketInAsync(Player sender, Object packet) { + return self.onPacketInAsync(sender, packet); + } + } : new TinyProtocol1_8(Atlas.getInstance()) { + @Override + public Object onHandshake(SocketAddress address, Object packet) { + return self.onHandshake(address, packet); + } + + @Override + public Object onPacketOutAsync(Player receiver, Object packet) { + return self.onPacketOutAsync(receiver, packet); + } + + @Override + public Object onPacketInAsync(Player sender, Object packet) { + return self.onPacketInAsync(sender, packet); + } + }; + } + + // Purely for making the code cleaner + public static void sendPacket(Player player, Object obj) { + Object packet; + + if(obj instanceof NMSObject) packet = ((NMSObject) obj).getObject(); + else packet = obj; + + instance.sendPacket(player, packet); + } + + public static ProtocolVersion getProtocolVersion(Player player) { + return ProtocolVersion.getVersion(ProtocolAPI.INSTANCE.getPlayerVersion(player)); + } + + public Object onPacketOutAsync(Player sender, Object packet) { + if(!paused && sender != null && packet != null) { + String name = packet.getClass().getName(); + int index = name.lastIndexOf("."); + String packetName = name.substring(index + 1); + + PacketSendEvent event = new PacketSendEvent(sender, packet, packetName); + + //EventManager.callEvent(new cc.funkemunky.api.event.custom.PacketSendEvent(sender, packet, packetName)); + + Atlas.getInstance().getEventManager().callEvent(event); + return !event.isCancelled() ? event.getPacket() : null; + } else return packet; + } + + public Object onPacketInAsync(Player sender, Object packet) { + if(!paused && sender != null && packet != null) { + String name = packet.getClass().getName(); + int index = name.lastIndexOf("."); + + String packetName = name.substring(index + 1) + .replace(Packet.Client.LEGACY_LOOK, Packet.Client.LOOK) + .replace(Packet.Client.LEGACY_POSITION, Packet.Client.POSITION) + .replace(Packet.Client.LEGACY_POSITION_LOOK, Packet.Client.POSITION_LOOK); + + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + packetName = packetName.replace("PacketPlayInBlockPlace", + "PacketPlayInBlockPlace1_9") + .replace("PacketPlayInUseItem", "PacketPlayInBlockPlace"); + } + + //Bukkit.broadcastMessage(packetName); + + PacketReceiveEvent event = new PacketReceiveEvent(sender, packet, packetName); + + Atlas.getInstance().getEventManager().callEvent(event); + + return !event.isCancelled() ? event.getPacket() : null; + } return packet; + } + + public Object onHandshake(SocketAddress address, Object packet) { + String name = packet.getClass().getName(); + int index = name.lastIndexOf("."); + String packetName = name.substring(index + 1); + + PacketLoginEvent event = new PacketLoginEvent(address, packet, packetName); + + Atlas.getInstance().getEventManager().callEvent(event); + + return !event.isCancelled() ? event.getPacket() : null; + } +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/AbstractTinyProtocol.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/AbstractTinyProtocol.java new file mode 100644 index 00000000..1279f8ad --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/AbstractTinyProtocol.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.api.packets; + +import org.bukkit.entity.Player; + +public interface AbstractTinyProtocol { + void sendPacket(Player player, Object packet); + + void receivePacket(Player player, Object packet); + + void injectPlayer(Player player); + + int getProtocolVersion(Player player); + + void uninjectPlayer(Player player); + + boolean hasInjected(Player player); + + void close(); +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/channelhandler/NoProtocol.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/channelhandler/NoProtocol.java new file mode 100644 index 00000000..3b73472b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/channelhandler/NoProtocol.java @@ -0,0 +1,41 @@ +package cc.funkemunky.api.tinyprotocol.api.packets.channelhandler; + +import cc.funkemunky.api.tinyprotocol.api.packets.AbstractTinyProtocol; +import org.bukkit.entity.Player; + +public class NoProtocol implements AbstractTinyProtocol { + @Override + public void sendPacket(Player player, Object packet) { + + } + + @Override + public void receivePacket(Player player, Object packet) { + + } + + @Override + public void injectPlayer(Player player) { + + } + + @Override + public int getProtocolVersion(Player player) { + return 0; + } + + @Override + public void uninjectPlayer(Player player) { + + } + + @Override + public boolean hasInjected(Player player) { + return false; + } + + @Override + public void close() { + + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/channelhandler/TinyProtocol1_7.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/channelhandler/TinyProtocol1_7.java new file mode 100644 index 00000000..3e1e3a23 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/channelhandler/TinyProtocol1_7.java @@ -0,0 +1,552 @@ +package cc.funkemunky.api.tinyprotocol.api.packets.channelhandler; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.tinyprotocol.api.packets.AbstractTinyProtocol; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import cc.funkemunky.api.tinyprotocol.reflection.MethodInvoker; +import cc.funkemunky.api.tinyprotocol.reflection.Reflection; +import com.google.common.collect.MapMaker; +import lombok.val; +import net.minecraft.util.com.mojang.authlib.GameProfile; +import net.minecraft.util.io.netty.channel.*; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; + +import java.lang.reflect.Method; +import java.net.SocketAddress; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; + +/** + * Represents a very tiny alternative to ProtocolLib. + *

+ * It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)! + * + * @author Kristian + */ + +public abstract class TinyProtocol1_7 implements AbstractTinyProtocol { + private static final AtomicInteger ID = new AtomicInteger(0); + + // Used in order to lookup a channel + private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle"); + private static final FieldAccessor getConnection = Reflection.getField("{nms}.EntityPlayer", "playerConnection", Object.class); + private static final FieldAccessor getManager = Reflection.getField("{nms}.PlayerConnection", "networkManager", Object.class); + private static final FieldAccessor getChannel = Reflection.getField("{nms}.NetworkManager", Channel.class, 0); + + // Looking up ServerConnection + private static final Class minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer"); + private static final Class serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection"); + private static final FieldAccessor getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0); + private static final FieldAccessor getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0); + private static final MethodInvoker getNetworkMarkers = Reflection.getTypedMethod(serverConnectionClass, 0, List.class, serverConnectionClass); + + // Packets we have to intercept + private static final Class PACKET_SET_PROTOCOL = Reflection.getMinecraftClass("PacketHandshakingInSetProtocol"); + private static final Class PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart"); + private static final FieldAccessor getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0); + private static final FieldAccessor protocolId = Reflection.getField(PACKET_SET_PROTOCOL, int.class, 0); + private static final FieldAccessor protocolType = Reflection.getField(PACKET_SET_PROTOCOL, Enum.class, 0); + + + // Speedup channel lookup + private Map channelLookup = new MapMaker().weakValues().makeMap(); + private Map protocolLookup = new MapMaker().weakKeys().makeMap(); + private Listener listener; + + // Channels that have already been removed + private Set uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap()); + + // List of network markers + private List networkManagers; + + // Injected channel handlers + private List serverChannels = new ArrayList<>(); + private ChannelInboundHandlerAdapter serverChannelHandler; + private ChannelInitializer beginInitProtocol; + private ChannelInitializer endInitProtocol; + + // Current handler name + private String handlerName; + + protected volatile boolean closed; + protected Plugin plugin; + + /** + * Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients. + *

+ * You can construct multiple instances per plugin. + * + * @param plugin - the plugin. + */ + public TinyProtocol1_7(final Plugin plugin) { + this.plugin = plugin; + + // Compute handler name + this.handlerName = getHandlerName(); + + // Prepare existing players + registerBukkitEvents(); + + try { + System.out.println("Attempting to inject into netty"); + registerChannelHandler(); + registerPlayers(plugin); + } catch (IllegalArgumentException ex) { + // Damn you, late bind + plugin.getLogger().info("Attempting to delay injection."); + + new BukkitRunnable() { + @Override + public void run() { + registerChannelHandler(); + registerPlayers(plugin); + plugin.getLogger().info("Injection complete."); + } + }.runTask(plugin); + } + } + + private void createServerChannelHandler() { + // Handle connected channels + endInitProtocol = new ChannelInitializer() { + + @Override + protected void initChannel(Channel channel) throws Exception { + try { + // This can take a while, so we need to stop the main thread from interfering + synchronized (networkManagers) { + // Stop injecting channels + if (!closed) { + channel.eventLoop().submit(() -> injectChannelInternal(channel)); + } + } + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e); + } + } + + }; + + // This is executed before Minecraft's channel handler + beginInitProtocol = new ChannelInitializer() { + + @Override + protected void initChannel(Channel channel) throws Exception { + channel.pipeline().addLast(endInitProtocol); + } + + }; + + serverChannelHandler = new ChannelInboundHandlerAdapter() { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + Channel channel = (Channel) msg; + + channel.pipeline().addFirst(beginInitProtocol); + ctx.fireChannelRead(msg); + } + + }; + } + + /** + * Register bukkit events. + */ + private void registerBukkitEvents() { + listener = new Listener() { + + @EventHandler(priority = EventPriority.LOWEST) + public final void onPlayerLogin(PlayerJoinEvent e) { + if (closed) + return; + + Channel channel = getChannel(e.getPlayer()); + + // Don't inject players that have been explicitly uninjected + if (!uninjectedChannels.contains(channel)) { + Bukkit.getScheduler().runTaskLater(Atlas.getInstance(), () -> injectPlayer(e.getPlayer()), 1L); //We delay it on the main thread since servers do occasionally lag. + } + } + + @EventHandler + public final void onPluginDisable(PluginDisableEvent e) { + if (e.getPlugin().equals(plugin)) { + close(); + } + } + + }; + + plugin.getServer().getPluginManager().registerEvents(listener, plugin); + } + + @SuppressWarnings("unchecked") + private void registerChannelHandler() { + Object mcServer = getMinecraftServer.get(Bukkit.getServer()); + Object serverConnection = getServerConnection.get(mcServer); + boolean looking = true; + + // We need to synchronize against this list + networkManagers = (List) getNetworkMarkers.invoke(null, serverConnection); + createServerChannelHandler(); + + // Find the correct list, or implicitly throw an exception + for (int i = 0; looking; i++) { + List list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection); + + for (Object item : list) { + //if (!ChannelFuture.class.isInstance(item)) + // break; + + // Channel future that contains the server connection + Channel serverChannel = ((ChannelFuture) item).channel(); + + serverChannels.add(serverChannel);; + serverChannel.pipeline().addFirst(serverChannelHandler); + System.out.println("Server channel handler injected (" + serverChannel + ")"); + looking = false; + } + } + } + + private void unregisterChannelHandler() { + if (serverChannelHandler == null) + return; + + for (Channel serverChannel : serverChannels) { + final ChannelPipeline pipeline = serverChannel.pipeline(); + + // Remove channel handler + serverChannel.eventLoop().execute(() -> { + try { + pipeline.remove(serverChannelHandler); + } catch (NoSuchElementException e) { + // That's fine + } + }); + } + } + + private void registerPlayers(Plugin plugin) { + for (Player player : plugin.getServer().getOnlinePlayers()) { + injectPlayer(player); + } + } + + /** + * Invoked when the server is starting to send a packet to a player. + *

+ * Note that this is not executed on the main thread. + * + * @param receiver - the receiving player, NULL for early login/status packets. + * @param packet - the packet being sent. + * @return The packet to send instead, or NULL to cancel the transmission. + */ + public Object onPacketOutAsync(Player receiver, Object packet) { + return packet; + } + + /** + * Invoked when the server has received a packet from a given player. + *

+ * Use {@link Channel#remoteAddress()} to get the remote address of the client. + * + * @param sender - the player that sent the packet, NULL for early login/status packets. + * @param packet - the packet being received. + * @return The packet to recieve instead, or NULL to cancel. + */ + public Object onPacketInAsync(Player sender, Object packet) { + return packet; + } + + public Object onHandshake(SocketAddress address, Object packet) { + return packet; + } + + /** + * Send a packet to a particular player. + *

+ * Note that {@link #onPacketOutAsync(Player, Object)} will be invoked with this packet. + * + * @param player - the destination player. + * @param packet - the packet to send. + */ + public void sendPacket(Player player, Object packet) { + sendPacket(getChannel(player), packet); + } + + /** + * Send a packet to a particular client. + *

+ * Note that {@link #onPacketOutAsync(Player, Object)} will be invoked with this packet. + * + * @param channel - client identified by a channel. + * @param packet - the packet to send. + */ + public void sendPacket(Channel channel, Object packet) { + channel.pipeline().writeAndFlush(packet); + } + + /** + * Pretend that a given packet has been received from a player. + *

+ * Note that {@link #onPacketInAsync(Player, Object)} will be invoked with this packet. + * + * @param player - the player that sent the packet. + * @param packet - the packet that will be received by the server. + */ + public void receivePacket(Player player, Object packet) { + receivePacket(getChannel(player), packet); + } + + /** + * Pretend that a given packet has been received from a given client. + *

+ * Note that {@link #onPacketInAsync(Player, Object)} will be invoked with this packet. + * + * @param channel - client identified by a channel. + * @param packet - the packet that will be received by the server. + */ + public void receivePacket(Channel channel, Object packet) { + channel.pipeline().context("encoder").fireChannelRead(packet); + } + + /** + * Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID. + *

+ * Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances. + * + * @return A unique channel handler name. + */ + protected String getHandlerName() { + return "tiny-" + plugin.getName() + "-" + ID.incrementAndGet(); + } + + /** + * Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets. + *

+ * This will automatically be called when a player has logged in. + * + * @param player - the player to inject. + */ + public void injectPlayer(Player player) { + injectChannelInternal(getChannel(player)).player = player; + } + + /** + * Add a custom channel handler to the given channel. + * + * @param channel - the channel to inject. + * @return The intercepted channel, or NULL if it has already been injected. + */ + public void injectChannel(Channel channel) { + injectChannelInternal(channel); + } + + /** + * Add a custom channel handler to the given channel. + * + * @param channel - the channel to inject. + * @return The packet interceptor. + */ + private PacketInterceptor injectChannelInternal(Channel channel) { + try { + PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName); + + // Inject our packet interceptor + if (interceptor == null) { + interceptor = new PacketInterceptor(); + val context = channel.pipeline().context("packet_handler"); + if(context != null) { + channel.pipeline().addBefore("packet_handler", handlerName, interceptor); + uninjectedChannels.remove(channel); + } else { + System.out.println("Context was null. Adding channel to injected!"); + uninjectedChannels.add(channel); + } + } + + return interceptor; + } catch (IllegalArgumentException e) { + // Try again + return (PacketInterceptor) channel.pipeline().get(handlerName); + } + } + + /** + * Retrieve the Netty channel associated with a player. This is cached. + * + * @param player - the player. + * @return The Netty channel. + */ + public Channel getChannel(Player player) { + Channel channel = channelLookup.get(player.getName()); + + // Lookup channel again + if (channel == null) { + Object connection = getConnection.get(getPlayerHandle.invoke(player)); + Object manager = getManager.get(connection); + + channelLookup.put(player.getName(), channel = getChannel.get(manager)); + } + + return channel; + } + + public int getProtocolVersion(Player player) { + Channel channel = channelLookup.get(player.getName()); + + // Lookup channel again + if (channel == null) { + Object connection = getConnection.get(getPlayerHandle.invoke(player)); + Object manager = getManager.get(connection); + + channelLookup.put(player.getName(), channel = getChannel.get(manager)); + } + + Integer protocol = protocolLookup.get(channel); + + int protocolVersion; + try { + Class Via = Class.forName("us.myles.ViaVersion.api.Via"); + Class clazzViaAPI = Class.forName("us.myles.ViaVersion.api.ViaAPI"); + Object ViaAPI = Via.getMethod("getAPI").invoke(null); + Method getPlayerVersion = clazzViaAPI.getMethod("getPlayerVersion", Object.class); + protocolVersion = (int) getPlayerVersion.invoke(ViaAPI, player); + protocolLookup.put(channel, protocolVersion); + return protocolVersion; + } catch (Throwable e) { + + } + if (protocol != null) { + return protocol; + } else return -1; + } + + /** + * Uninject a specific player. + * + * @param player - the injected player. + */ + public void uninjectPlayer(Player player) { + uninjectChannel(getChannel(player)); + } + + /** + * Uninject a specific channel. + *

+ * This will also disable the automatic channel injection that occurs when a player has properly logged in. + * + * @param channel - the injected channel. + */ + public void uninjectChannel(final Channel channel) { + // No need to guard against this if we're closing + if (!closed) { + uninjectedChannels.add(channel); + } + + // See ChannelInjector in ProtocolLib, line 590 + channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName)); + } + + /** + * Determine if the given player has been injected by TinyProtocol. + * + * @param player - the player. + * @return TRUE if it is, FALSE otherwise. + */ + public boolean hasInjected(Player player) { + return hasInjected(getChannel(player)); + } + + /** + * Determine if the given channel has been injected by TinyProtocol. + * + * @param channel - the channel. + * @return TRUE if it is, FALSE otherwise. + */ + public boolean hasInjected(Channel channel) { + return channel.pipeline().get(handlerName) != null; + } + + /** + * Cease listening for packets. This is called automatically when your plugin is disabled. + */ + public final void close() { + if (!closed) { + closed = true; + + // Remove our handlers + for (Player player : plugin.getServer().getOnlinePlayers()) { + uninjectPlayer(player); + } + + // Clean up Bukkit + HandlerList.unregisterAll(listener); + unregisterChannelHandler(); + } + } + + /** + * Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets. + * + * @author Kristian + */ + private final class PacketInterceptor extends ChannelDuplexHandler { + // Updated by the login event + public Player player; + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + // Intercept channel + final Channel channel = ctx.channel(); + if (PACKET_LOGIN_IN_START.isInstance(msg)) { + GameProfile profile = getGameProfile.get(msg); + channelLookup.put(profile.getName(), channel); + } else if (PACKET_SET_PROTOCOL.isInstance(msg)) { + String protocol = protocolType.get(msg).name(); + if (protocol.equalsIgnoreCase("LOGIN")) { + protocolLookup.put(channel, protocolId.get(msg)); + } + } + + if(player != null) { + try { + msg = onPacketInAsync(player, msg); + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e); + } + } else msg = onHandshake(ctx.channel().remoteAddress(), msg); + + if (msg != null) { + super.channelRead(ctx, msg); + } + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + if(player != null) { + try { + msg = onPacketOutAsync(player, msg); + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e); + } + } + + if (msg != null) { + super.write(ctx, msg, promise); + } + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/channelhandler/TinyProtocol1_8.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/channelhandler/TinyProtocol1_8.java new file mode 100644 index 00000000..6cb59530 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/api/packets/channelhandler/TinyProtocol1_8.java @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +/* + * The patches are licensed under MIT. Original credit goes to Kristian. + */ + +package cc.funkemunky.api.tinyprotocol.api.packets.channelhandler; + +import cc.funkemunky.api.tinyprotocol.api.packets.AbstractTinyProtocol; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import cc.funkemunky.api.tinyprotocol.reflection.MethodInvoker; +import cc.funkemunky.api.tinyprotocol.reflection.Reflection; +import com.google.common.collect.Lists; +import com.google.common.collect.MapMaker; +import com.mojang.authlib.GameProfile; +import io.netty.channel.*; +import lombok.val; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; + +import java.lang.reflect.Method; +import java.net.SocketAddress; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; + +/** + * Represents a very tiny alternative to ProtocolLib. + *

+ * It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)! + * + * @author Kristian + */ +public abstract class TinyProtocol1_8 implements AbstractTinyProtocol { + private static final AtomicInteger ID = new AtomicInteger(0); + + // Used in order to lookup a channel + private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle"); + private static final FieldAccessor getConnection = Reflection.getField("{nms}.EntityPlayer", "playerConnection", Object.class); + private static final FieldAccessor getManager = Reflection.getField("{nms}.PlayerConnection", "networkManager", Object.class); + private static final FieldAccessor getChannel = Reflection.getField("{nms}.NetworkManager", Channel.class, 0); + + // Looking up ServerConnection + private static final Class minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer"); + private static final Class serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection"); + private static final FieldAccessor getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0); + private static final FieldAccessor getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0); + private static final MethodInvoker getNetworkMarkers = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass); + + // Packets we have to intercept + private static final Class PACKET_SET_PROTOCOL = Reflection.getMinecraftClass("PacketHandshakingInSetProtocol"); + private static final Class PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart"); + private static final FieldAccessor getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0); + private static final FieldAccessor protocolId = Reflection.getField(PACKET_SET_PROTOCOL, int.class, 0); + private static final FieldAccessor protocolType = Reflection.getField(PACKET_SET_PROTOCOL, Enum.class, 0); + + private List gList; + + // Speedup channel lookup + private Map channelLookup = new MapMaker().weakValues().makeMap(); + private Map protocolLookup = new MapMaker().weakKeys().makeMap(); + private Listener listener; + + // Channels that have already been removed + private Set uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap()); + + // List of network markers + private List networkManagers; + + // Injected channel handlers + private List serverChannels = Lists.newArrayList(); + private ChannelInboundHandlerAdapter serverChannelHandler; + private ChannelInitializer beginInitProtocol; + private ChannelInitializer endInitProtocol; + + // Current handler name + private String handlerName; + + protected volatile boolean closed; + protected Plugin plugin; + private Object serverConnection; + + /** + * Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients. + *

+ * You can construct multiple instances per plugin. + * + * @param plugin - the plugin. + */ + public TinyProtocol1_8(final Plugin plugin) { + this.plugin = plugin; + + // Compute handler name + this.handlerName = getHandlerName(); + + // Prepare existing players + registerBukkitEvents(); + + try { + System.out.println("Attempting to inject into netty"); + registerChannelHandler(); + registerPlayers(plugin); + } catch (IllegalArgumentException ex) { + // Damn you, late bind + plugin.getLogger().info("Attempting to delay injection."); + + new BukkitRunnable() { + @Override + public void run() { + registerChannelHandler(); + registerPlayers(plugin); + plugin.getLogger().info("Injection complete."); + } + }.runTask(plugin); + } + + /*Object ms = CraftReflection.getMinecraftServer(); + + val scMethod = MinecraftReflection.minecraftServer + .getMethodByType(MinecraftReflection.serverConnection.getParent(), 0); + + serverConnection = scMethod.invoke(ms); + + gList = MinecraftReflection.serverConnection.getFieldByType(List.class, 0).get(serverConnection); + + gList.forEach(future -> future.channel().pipeline().addLast(new MessageDecoder()));*/ + } + + private void createServerChannelHandler() { + // Handle connected channels + endInitProtocol = new ChannelInitializer() { + + @Override + protected void initChannel(Channel channel) throws Exception { + try { + // This can take a while, so we need to stop the main thread from interfering + synchronized (networkManagers) { + // Stop injecting channels + if (!closed) { + channel.eventLoop().submit(() -> injectChannelInternal(channel)); + } + } + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e); + } + } + + }; + + // This is executed before Minecraft's channel handler + beginInitProtocol = new ChannelInitializer() { + + @Override + protected void initChannel(Channel channel) throws Exception { + channel.pipeline().addLast(endInitProtocol); + } + + }; + + serverChannelHandler = new ChannelInboundHandlerAdapter() { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + Channel channel = (Channel) msg; + channel.pipeline().addFirst(beginInitProtocol); + ctx.fireChannelRead(msg); + } + + }; + } + + /** + * Register bukkit events. + */ + private void registerBukkitEvents() { + listener = new Listener() { + + @EventHandler(priority = EventPriority.LOWEST) + public final void onPlayerLogin(PlayerJoinEvent e) { + if (closed) + return; + + Channel channel = getChannel(e.getPlayer()); + + // Don't inject players that have been explicitly uninjected + if (!uninjectedChannels.contains(channel)) { + try { + injectPlayer(e.getPlayer()); + } catch (Exception ex) { + + } + } + } + + @EventHandler + public final void onPluginDisable(PluginDisableEvent e) { + if (e.getPlugin().equals(plugin)) { + close(); + } + } + + }; + + plugin.getServer().getPluginManager().registerEvents(listener, plugin); + } + + @SuppressWarnings("unchecked") + private void registerChannelHandler() { + Object mcServer = getMinecraftServer.get(Bukkit.getServer()); + Object serverConnection = null; + boolean looking = true; + + // We need to synchronize against this list + for (Method m : mcServer.getClass().getMethods()) { + if (m.getParameterTypes().length == 0 && m.getReturnType().isAssignableFrom(serverConnectionClass)) { + try { + Object result = m.invoke(mcServer); + if (result != null) serverConnection = result; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + networkManagers = (List) getNetworkMarkers.invoke(null, serverConnection); + createServerChannelHandler(); + + // Find the correct list, or implicitly throw an exception + for (int i = 0; looking; i++) { + List list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection); + + for (Object item : list) { + //if (!ChannelFuture.class.isInstance(item)) + // break; + + // Channel future that contains the server connection + Channel serverChannel = ((ChannelFuture) item).channel(); + + serverChannels.add(serverChannel); + serverChannel.pipeline().addFirst(serverChannelHandler); + System.out.println("Server channel handler injected (" + serverChannel + ")"); + looking = false; + } + } + } + + private void unregisterChannelHandler() { + if (serverChannelHandler == null) + return; + + for (Channel serverChannel : serverChannels) { + final ChannelPipeline pipeline = serverChannel.pipeline(); + + // Remove channel handler + serverChannel.eventLoop().execute(() -> { + try { + pipeline.remove(serverChannelHandler); + } catch (NoSuchElementException e) { + // That's fine + } + }); + } + } + + private void registerPlayers(Plugin plugin) { + for (Player player : plugin.getServer().getOnlinePlayers()) { + injectPlayer(player); + } + } + + /** + * Invoked when the server is starting to send a packet to a player. + *

+ * Note that this is not executed on the main thread. + * + * @param receiver - the receiving player, NULL for early login/status packets. + * @param packet - the packet being sent. + * @return The packet to send instead, or NULL to cancel the transmission. + */ + public Object onPacketOutAsync(Player receiver, Object packet) { + return packet; + } + + /** + * Invoked when the server has received a packet from a given player. + *

+ * Use {@link Channel#remoteAddress()} to get the remote address of the client. + * + * @param sender - the player that sent the packet, NULL for early login/status packets. + * @param packet - the packet being received. + * @return The packet to recieve instead, or NULL to cancel. + */ + public Object onPacketInAsync(Player sender, Object packet) { + return packet; + } + + public Object onHandshake(SocketAddress address, Object packet) { + return packet; + } + + /** + * Send a packet to a particular player. + *

+ * Note that {@link #onPacketOutAsync(Player, Object)} will be invoked with this packet. + * + * @param player - the destination player. + * @param packet - the packet to send. + */ + public void sendPacket(Player player, Object packet) { + sendPacket(getChannel(player), packet); + } + + /** + * Send a packet to a particular client. + *

+ * Note that {@link #onPacketOutAsync(Player, Object)} will be invoked with this packet. + * + * @param channel - client identified by a channel. + * @param packet - the packet to send. + */ + public void sendPacket(Channel channel, Object packet) { + channel.pipeline().writeAndFlush(packet); + } + + /** + * Pretend that a given packet has been received from a player. + *

+ * Note that {@link #onPacketInAsync(Player, Object)} will be invoked with this packet. + * + * @param player - the player that sent the packet. + * @param packet - the packet that will be received by the server. + */ + public void receivePacket(Player player, Object packet) { + receivePacket(getChannel(player), packet); + } + + /** + * Pretend that a given packet has been received from a given client. + *

+ * Note that {@link #onPacketInAsync(Player, Object)} will be invoked with this packet. + * + * @param channel - client identified by a channel. + * @param packet - the packet that will be received by the server. + */ + public void receivePacket(Channel channel, Object packet) { + channel.pipeline().context("encoder").fireChannelRead(packet); + } + + /** + * Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID. + *

+ * Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances. + * + * @return A unique channel handler name. + */ + protected String getHandlerName() { + return "atlas-protocol-handler"; + } + + /** + * Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets. + *

+ * This will automatically be called when a player has logged in. + * + * @param player - the player to inject. + */ + public void injectPlayer(Player player) { + Channel channel = getChannel(player); + channelLookup.put(player.getName(), channel); + injectChannelInternal(channel).player = player; + } + + /** + * Add a custom channel handler to the given channel. + * + * @param channel - the channel to inject. + * @return The intercepted channel, or NULL if it has already been injected. + */ + public void injectChannel(Channel channel) { + injectChannelInternal(channel); + } + + /** + * Add a custom channel handler to the given channel. + * + * @param channel - the channel to inject. + * @return The packet interceptor. + */ + private PacketInterceptor injectChannelInternal(Channel channel) { + try { + PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName); + + // Inject our packet interceptor + if (interceptor == null) { + interceptor = new PacketInterceptor(); + val context = channel.pipeline().context("packet_handler"); + if(context != null) { + channel.pipeline().addBefore("packet_handler", handlerName, interceptor); + uninjectedChannels.remove(channel); + } else { + System.out.println("Context was null. Adding channel to injected!"); + uninjectedChannels.add(channel); + } + } + + return interceptor; + } catch (IllegalArgumentException e) { + // Try again + return (PacketInterceptor) channel.pipeline().get(handlerName); + } + } + + /** + * Retrieve the Netty channel associated with a player. This is cached. + * + * @param player - the player. + * @return The Netty channel. + */ + public Channel getChannel(Player player) { + Channel channel = channelLookup.get(player.getName()); + + // Lookup channel again + if (channel == null) { + Object connection = getConnection.get(getPlayerHandle.invoke(player)); + Object manager = getManager.get(connection); + channel = getChannel.get(manager); + if (channel == null) return null; + channelLookup.put(player.getName(), channel); + } + + return channel; + } + + public int getProtocolVersion(Player player) { + Channel channel = channelLookup.get(player.getName()); + + // Lookup channel again + if (channel == null) { + Object connection = getConnection.get(getPlayerHandle.invoke(player)); + Object manager = getManager.get(connection); + + channelLookup.put(player.getName(), channel = getChannel.get(manager)); + } + + Integer protocol = protocolLookup.get(channel); + int protocolVersion; + try { + Class Via = Class.forName("us.myles.ViaVersion.api.Via"); + Class clazzViaAPI = Class.forName("us.myles.ViaVersion.api.ViaAPI"); + Object ViaAPI = Via.getMethod("getAPI").invoke(null); + Method getPlayerVersion = clazzViaAPI.getMethod("getPlayerVersion", Object.class); + protocolVersion = (int) getPlayerVersion.invoke(ViaAPI, player); + protocolLookup.put(channel, protocolVersion); + return protocolVersion; + } catch (Throwable e) { + + } + if (protocol != null) { + return protocol; + } else return -1; + } + + /** + * Uninject a specific player. + * + * @param player - the injected player. + */ + public void uninjectPlayer(Player player) { + uninjectChannel(getChannel(player)); + } + + /** + * Uninject a specific channel. + *

+ * This will also disable the automatic channel injection that occurs when a player has properly logged in. + * + * @param channel - the injected channel. + */ + public void uninjectChannel(final Channel channel) { + // No need to guard against this if we're closing + if (!closed) { + uninjectedChannels.add(channel); + } + + // See ChannelInjector in ProtocolLib, line 590 + channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName)); + } + + /** + * Determine if the given player has been injected by TinyProtocol. + * + * @param player - the player. + * @return TRUE if it is, FALSE otherwise. + */ + public boolean hasInjected(Player player) { + Channel ch = getChannel(player); + if (ch == null) return false; + return hasInjected(ch); + } + + /** + * Determine if the given channel has been injected by TinyProtocol. + * + * @param channel - the channel. + * @return TRUE if it is, FALSE otherwise. + */ + public boolean hasInjected(Channel channel) { + return channel.pipeline().get(handlerName) != null; + } + + /** + * Cease listening for packets. This is called automatically when your plugin is disabled. + */ + public final void close() { + if (!closed) { + closed = true; + + // Remove our handlers + for (Player player : plugin.getServer().getOnlinePlayers()) { + uninjectPlayer(player); + } + + // Clean up Bukkit + HandlerList.unregisterAll(listener); + unregisterChannelHandler(); + } + } + + /** + * Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets. + * + * @author Kristian + */ + private final class PacketInterceptor extends ChannelDuplexHandler { + // Updated by the login event + public Player player; + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + // Intercept channel + final Channel channel = ctx.channel(); + + if (PACKET_LOGIN_IN_START.isInstance(msg)) { + GameProfile profile = getGameProfile.get(msg); + channelLookup.put(profile.getName(), channel); + } else if (PACKET_SET_PROTOCOL.isInstance(msg)) { + String protocol = protocolType.get(msg).name(); + if (protocol.equalsIgnoreCase("LOGIN")) { + int id = protocolId.get(msg); + protocolLookup.put(channel, id); + } + } + + if(player != null) { + try { + msg = onPacketInAsync(player, msg); + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e); + } + } else { + msg = onHandshake(ctx.channel().remoteAddress(), msg); + } + if (msg != null) { + try { + super.channelRead(ctx, msg); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { + + if(player != null) { + try { + msg = onPacketOutAsync(player, msg); + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e); + } + } + + if (msg != null) { + try { + super.write(ctx, msg, promise); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInAbilitiesPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInAbilitiesPacket.java new file mode 100644 index 00000000..ff3e1061 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInAbilitiesPacket.java @@ -0,0 +1,46 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +//TODO Test 1.15 +public class WrappedInAbilitiesPacket extends NMSObject { + private static final String packet = Client.ABILITIES; + private static FieldAccessor + invulnerableField = fetchField(packet, boolean.class, 0), + flyingField = fetchField(packet, boolean.class, 1), + allowedFlightField = fetchField(packet, boolean.class, 2), + creativeModeField = fetchField(packet, boolean.class, 3); + private static FieldAccessor + flySpeedField = fetchField(packet, float.class, 0), + walkSpeedField = fetchField(packet, float.class, 1); + + @Getter + private boolean invulnerable, flying, allowedFlight, creativeMode; + @Getter + private float flySpeed, walkSpeed; + + + public WrappedInAbilitiesPacket(Object object, Player player) { + super(object, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + invulnerable = fetch(invulnerableField); + flying = fetch(flyingField); + allowedFlight = fetch(allowedFlightField); + creativeMode = fetch(creativeModeField); + flySpeed = fetch(flySpeedField); + walkSpeed = fetch(walkSpeedField); + } + + @Override + public void updateObject() { + setObject(NMSObject.construct(getObject(), + packet, invulnerable, flying, allowedFlight, creativeMode, flySpeed, walkSpeed)); + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInAdvancementsPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInAdvancementsPacket.java new file mode 100644 index 00000000..a11055cd --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInAdvancementsPacket.java @@ -0,0 +1,49 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.WrappedMinecraftKey; +import org.bukkit.entity.Player; + +//TODO Test to see if this works at all. +public class WrappedInAdvancementsPacket extends NMSObject { + + private static final WrappedClass packet = Reflections.getNMSClass(Client.ADVANCEMENTS); + + private static WrappedClass statusClass = Reflections.getNMSClass(Client.ADVANCEMENTS + "$Status"); + + public Status status; + public WrappedMinecraftKey key; + + private static WrappedField fieldStatus = fetchField(packet, statusClass.getParent(), 0), + fieldKey = fetchField(packet, WrappedMinecraftKey.vanilla.getParent(), 0); + + @Override + public void updateObject() { + set(fieldStatus, status.toVanilla()); + key.updateObject(); //Updating any changes set in the key wrapper. + set(fieldKey, key.getObject()); + } + + @Override + public void process(Player player, ProtocolVersion version) { + status = Status.fromVanilla(fetch(fieldStatus)); + key = new WrappedMinecraftKey(fetch(fieldKey)); + } + + public enum Status { + OPENED_TAB, + CLOSED_SCREEN; + + public static Status fromVanilla(Enum obj) { + return valueOf(obj.name()); + } + + public T toVanilla() { + return (T) statusClass.getEnum(name()); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInArmAnimationPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInArmAnimationPacket.java new file mode 100644 index 00000000..63ac8387 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInArmAnimationPacket.java @@ -0,0 +1,48 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +//TODO Test 1.15 +public class WrappedInArmAnimationPacket extends NMSObject { + private static final String packet = Client.ARM_ANIMATION; + + public WrappedInArmAnimationPacket(Object object, Player player) { + super(object, player); + } + + public boolean mainHand; + + private static WrappedClass enumHand, armAnimation; + private static WrappedField mainHandField; + + @Override + public void process(Player player, ProtocolVersion version) { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + Enum enumhand = mainHandField.get(getObject()); + + mainHand = enumhand.name().equals("MAIN_HAND"); + } else mainHand = true; + } + + @Override + public void updateObject() { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + setObject(NMSObject.construct(getObject(), packet, enumHand.getEnum(mainHand ? "MAIN_HAND" : "OFF_HAND"))); + } + } + + static { + armAnimation = Reflections.getNMSClass(packet); + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + enumHand = Reflections.getNMSClass("EnumHand"); + mainHandField = armAnimation.getFieldByType(Enum.class, 0); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInBlockDigPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInBlockDigPacket.java new file mode 100644 index 00000000..48e5feee --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInBlockDigPacket.java @@ -0,0 +1,96 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.BaseBlockPosition; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumDirection; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInBlockDigPacket extends NMSObject { + private static final WrappedClass packet = Reflections.getNMSClass(Client.BLOCK_DIG); + + // 1.8+ Fields + private static WrappedField fieldBlockPosition, fieldDirection, fieldDigType; + + // 1.7.10 and below fields + private static WrappedField fieldPosX, fieldPosY, fieldPosZ, fieldFace, fieldIntAction; + + // Decoded data + private BaseBlockPosition position; + private WrappedEnumDirection direction; + private EnumPlayerDigType action; + + + public WrappedInBlockDigPacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void updateObject() { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + set(fieldPosX, position.getX()); + set(fieldPosY, position.getY()); + set(fieldPosZ, position.getZ()); + set(fieldFace, direction.ordinal()); //TODO Test if this causes errors. + set(fieldIntAction, action.ordinal()); //TODO Test if this causes errors. + } else { + set(fieldBlockPosition, position.getObject()); + set(fieldDirection, direction.toVanilla()); + set(fieldDigType, action.toVanilla()); + } + } + + @Override + public void process(Player player, ProtocolVersion version) { + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + position = new BaseBlockPosition(fetch(fieldPosX), fetch(fieldPosY), fetch(fieldPosZ)); + direction = WrappedEnumDirection.values()[Math.min(fetch(fieldFace), 5)]; + action = EnumPlayerDigType.values()[(int)fetch(fieldIntAction)]; + } else if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.v1_15)){ + position = new BaseBlockPosition(fetch(fieldBlockPosition)); + direction = WrappedEnumDirection.fromVanilla((Enum)fetch(fieldDirection)); + action = EnumPlayerDigType.fromVanilla(fetch(fieldDigType)); + } + } + + public enum EnumPlayerDigType { + START_DESTROY_BLOCK, + ABORT_DESTROY_BLOCK, + STOP_DESTROY_BLOCK, + DROP_ALL_ITEMS, + DROP_ITEM, + RELEASE_USE_ITEM, + SWAP_HELD_ITEMS; + + public static WrappedClass classDigType; + + public static EnumPlayerDigType fromVanilla(Enum obj) { + return valueOf(obj.name()); + } + + public T toVanilla() { + return (T) classDigType.getEnum(name()); + } + } + + static { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + fieldPosX = packet.getFieldByType(int.class, 0); + fieldPosY = packet.getFieldByType(int.class, 1); + fieldPosZ = packet.getFieldByType(int.class, 2); + fieldFace = packet.getFieldByType(int.class, 3); + fieldIntAction = packet.getFieldByType(int.class, 4); + } else { + fieldBlockPosition = packet.getFieldByType(MinecraftReflection.blockPos.getParent(), 0); + fieldDirection = packet.getFieldByType(WrappedEnumDirection.enumDirection.getParent(), 0); + EnumPlayerDigType.classDigType = Reflections.getNMSClass("PacketPlayInBlockDig$EnumPlayerDigType"); + fieldDigType = packet.getFieldByType(EnumPlayerDigType.classDigType.getParent(), 0); + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInBlockPlace1_9.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInBlockPlace1_9.java new file mode 100644 index 00000000..05cbbf43 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInBlockPlace1_9.java @@ -0,0 +1,46 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import org.bukkit.entity.Player; + +public class WrappedInBlockPlace1_9 extends NMSObject { + + private static final String packet = Client.BLOCK_PLACE_1_9; + + private static WrappedClass blockPlace = Reflections.getNMSClass(packet), enumHandClass; + private static WrappedField enumHand, timeStampField; + + public WrappedInBlockPlace1_9(Object object, Player player) { + super(object, player); + } + + public boolean mainHand; + public long timeStamp; + + @Override + public void process(Player player, ProtocolVersion version) { + Enum obj = enumHand.get(getObject()); + + mainHand = obj.name().equals("MAIN_HAND"); + timeStamp = timeStampField.get(getObject()); + } + + @Override + public void updateObject() { + setObject(NMSObject.construct(getObject(), packet, mainHand + ? enumHandClass.getEnum("MAIN_HAND") : enumHandClass.getEnum("OFF_HAND"), + timeStamp)); + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + enumHand = blockPlace.getFieldByType(Enum.class, 0); + timeStampField = blockPlace.getFieldByType(long.class, 0); + enumHandClass = Reflections.getNMSClass("EnumHand"); + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInBlockPlacePacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInBlockPlacePacket.java new file mode 100644 index 00000000..f5ef6ac2 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInBlockPlacePacket.java @@ -0,0 +1,144 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.impl.CraftReflection; +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.BaseBlockPosition; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumDirection; +import lombok.Getter; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +@Getter +//TODO Test 1.15 +public class WrappedInBlockPlacePacket extends NMSObject { + private static final String packet = Client.BLOCK_PLACE; + + // Fields + private static WrappedField fieldFace, fieldFace1_9, fieldBlockPosition, fieldItemStack, enumHand; + private static WrappedField fieldPosX, fieldPosY, fieldPosZ, fieldVecX, fieldVecY, fieldVecZ; + private static WrappedField fieldMissed, fieldMovingObjectBS; + + private static BaseBlockPosition a = new BaseBlockPosition(-1, -1, -1); + + private static WrappedClass movingObjectBSObject, blockPlacePacket, enumHandClass; + + // Decoded data + private WrappedEnumDirection face; + private ItemStack itemStack; + private BaseBlockPosition position; + private boolean mainHand; + private boolean missed; + private float vecX, vecY, vecZ; + + public WrappedInBlockPlacePacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + position = new BaseBlockPosition(fieldPosX.get(getObject()), + fieldPosY.get(getObject()), + fieldPosZ.get(getObject())); + face = WrappedEnumDirection.values()[Math.min(fieldFace.get(getObject()), 5)]; + itemStack = toBukkitStack(fieldItemStack.get(getObject())); + vecX = fieldVecX.get(getObject()); + vecY = fieldVecY.get(getObject()); + vecZ = fieldVecZ.get(getObject()); + mainHand = true; + missed = false; + } else if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + position = new BaseBlockPosition(fieldBlockPosition.get(getObject())); + face = WrappedEnumDirection.values()[Math.min(fieldFace.get(getObject()), 5)]; + itemStack = toBukkitStack(fieldItemStack.get(getObject())); + vecX = fieldVecX.get(getObject()); + vecY = fieldVecY.get(getObject()); + vecZ = fieldVecZ.get(getObject()); + mainHand = true; + missed = false; + } else if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.v1_15)) { + position = new BaseBlockPosition(fieldBlockPosition.get(getObject())); + face = WrappedEnumDirection.values()[((Enum) fieldFace1_9.get(getObject())).ordinal()]; + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_14)) { + vecX = fieldVecX.get(getObject()); + vecY = fieldVecY.get(getObject()); + vecZ = fieldVecZ.get(getObject()); + } + mainHand = ((Enum) enumHand.get(getObject())).name().toLowerCase().contains("main"); + missed = false; + } else { + Object movingBS = fieldMovingObjectBS.get(getObject()); + face = WrappedEnumDirection.values()[((Enum) fieldFace1_9.get(movingBS)).ordinal()]; + position = new BaseBlockPosition(fieldBlockPosition.get(movingBS)); + mainHand = ((Enum) enumHand.get(getObject())).name().toLowerCase().contains("main"); + missed = fieldMissed.get(movingBS); + } + } + + //TODO Redo this method. + @Override + public void updateObject() { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.v1_15)) { + + } + if (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_14)) { + setObject(NMSObject.construct(getObject(), packet, position.getAsBlockPosition(), face.toVanilla(), + mainHand ? enumHandClass.getEnum("MAIN_HAND") : enumHandClass.getEnum("OFF_HAND"))); + } else if (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + setObject(NMSObject.construct(getObject(), packet, position.getAsBlockPosition(), face.toVanilla(), + mainHand ? enumHandClass.getEnum("MAIN_HAND") : enumHandClass.getEnum("OFF_HAND"), + vecX, vecY, vecZ)); + } else if (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + setObject(NMSObject.construct(getObject(), packet, position.getAsBlockPosition(), face.ordinal(), + CraftReflection.getVanillaItemStack(itemStack), vecX, vecY, vecZ)); + } else { + setObject(NMSObject.construct(getObject(), packet, position.getX(), position.getY(), position.getZ(), + CraftReflection.getVanillaItemStack(itemStack), vecX, vecY, vecZ)); + } + } + + static { + if (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.v1_15)) { + movingObjectBSObject = Reflections.getNMSClass("MovingObjectPositionBlock"); + fieldMovingObjectBS = blockPlacePacket.getFieldByType(movingObjectBSObject.getParent(), 0); + fieldFace1_9 = movingObjectBSObject.getFieldByType(WrappedEnumDirection.enumDirection.getParent(), 0); + fieldBlockPosition = movingObjectBSObject.getFieldByType(MinecraftReflection.blockPos.getParent(), 0); + fieldMissed = movingObjectBSObject.getFieldByType(boolean.class, 0); + enumHand = blockPlacePacket.getFieldByType(Enum.class, 0); + } else if (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + blockPlacePacket = Reflections.getNMSClass("PacketPlayInUseItem"); + fieldBlockPosition = blockPlacePacket.getFieldByType(Object.class, 0); + fieldFace1_9 = blockPlacePacket.getFieldByType(Enum.class, 1); + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_14)) { + fieldVecX = blockPlacePacket.getFieldByType(float.class, 0); + fieldVecY = blockPlacePacket.getFieldByType(float.class, 1); + fieldVecZ = blockPlacePacket.getFieldByType(float.class, 2); + } + enumHand = blockPlacePacket.getFieldByType(Enum.class, 0); + enumHandClass = Reflections.getNMSClass("EnumHand"); + } else if (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + blockPlacePacket = Reflections.getNMSClass("PacketPlayInBlockPlace"); + fieldBlockPosition = blockPlacePacket.getFieldByType(MinecraftReflection.blockPos.getParent(), 1); + fieldFace = blockPlacePacket.getFieldByType(int.class, 0); + fieldItemStack = blockPlacePacket.getFieldByType(MinecraftReflection.itemStack.getParent(), 0); + fieldVecX = blockPlacePacket.getFieldByType(float.class, 0); + fieldVecY = blockPlacePacket.getFieldByType(float.class, 1); + fieldVecZ = blockPlacePacket.getFieldByType(float.class, 2); + } else { + blockPlacePacket = Reflections.getNMSClass("PacketPlayInBlockPlace"); + fieldPosX = blockPlacePacket.getFieldByType(int.class, 0); + fieldPosY = blockPlacePacket.getFieldByType(int.class, 1); + fieldPosZ = blockPlacePacket.getFieldByType(int.class, 2); + fieldFace = blockPlacePacket.getFieldByType(int.class, 3); + fieldItemStack = blockPlacePacket.getFieldByType(MinecraftReflection.itemStack.getParent(), 0); + fieldVecX = blockPlacePacket.getFieldByType(float.class, 0); + fieldVecY = blockPlacePacket.getFieldByType(float.class, 1); + fieldVecZ = blockPlacePacket.getFieldByType(float.class, 2); + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInChatPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInChatPacket.java new file mode 100644 index 00000000..749b5a90 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInChatPacket.java @@ -0,0 +1,30 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +public class WrappedInChatPacket extends NMSObject { + private static String packet = Client.CHAT; + + private static FieldAccessor messageAccessor = fetchField(packet, String.class, 0); + + public WrappedInChatPacket(Object object, Player player) { + super(object, player); + } + + @Getter + private String message; + + @Override + public void process(Player player, ProtocolVersion version) { + this.message = fetch(messageAccessor); + } + + @Override + public void updateObject() { + setObject(NMSObject.construct(getObject(), packet, message)); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInClientCommandPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInClientCommandPacket.java new file mode 100644 index 00000000..e6092878 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInClientCommandPacket.java @@ -0,0 +1,41 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInClientCommandPacket extends NMSObject { + private static final String packet = Client.CLIENT_COMMAND; + + // Fields + private static FieldAccessor fieldCommand = fetchField(packet, Enum.class, 0); + + // Decoded data + EnumClientCommand command; + + public WrappedInClientCommandPacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + command = EnumClientCommand.values()[fetch(fieldCommand).ordinal()]; + } + + @Override + public void updateObject() { + //setObject(NMSObject.construct(getObject(), packet, enumClientCommancd)); + } + + public enum EnumClientCommand { + PERFORM_RESPAWN, + REQUEST_STATS, + OPEN_INVENTORY_ACHIEVEMENT; + + private EnumClientCommand() { + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInCloseWindowPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInCloseWindowPacket.java new file mode 100644 index 00000000..74796e29 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInCloseWindowPacket.java @@ -0,0 +1,32 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInCloseWindowPacket extends NMSObject { + private static final String packet = Client.CLOSE_WINDOW; + + // Fields + private static FieldAccessor fieldId = fetchField(packet, int.class, 0); + + // Decoded data + private int id; + + public WrappedInCloseWindowPacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + id = fetch(fieldId); + } + + @Override + public void updateObject() { + setObject(NMSObject.construct(getObject(), packet, id)); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInCustomPayload.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInCustomPayload.java new file mode 100644 index 00000000..5d6304fe --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInCustomPayload.java @@ -0,0 +1,106 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.events.impl.PacketReceiveEvent; +import cc.funkemunky.api.events.impl.PacketSendEvent; +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.WrappedPacketDataSerializer; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInCustomPayload extends NMSObject { + + public WrappedInCustomPayload(Object object) { + super(object); + } + + public WrappedInCustomPayload(Object object, Player player) { + super(object, player); + } + + public WrappedInCustomPayload(PacketReceiveEvent event) { + super(event); + } + + public WrappedInCustomPayload(PacketSendEvent event) { + super(event); + } + + private static WrappedClass wrapped = Reflections.getNMSClass(Client.CUSTOM_PAYLOAD); + + private static WrappedField tagField; + + //1.7.10 + private static WrappedField lengthField; + private static WrappedField dataField; + + //1.8 + private static WrappedClass wrappedPDS; + private static WrappedField dataSerializer; + + //1.13+ + private static WrappedClass minecraftKeyWrapper; + private static WrappedField keyOne, keyTwo; + private static WrappedField mkField; + + private String tag; + private int length; + private byte[] data; + + @Override + public void process(Player player, ProtocolVersion version) { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + tag = tagField.get(getObject()); + length = lengthField.get(getObject()); + data = dataField.get(getObject()); + } else { + Object packetData = dataSerializer.get(getObject()); + + if(packetData != null) { + WrappedPacketDataSerializer wpds = new WrappedPacketDataSerializer((Object) dataSerializer.get(getObject())); + + data = wpds.getData(); + } else data = new byte[0]; + length = data.length; + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) tag = tagField.get(getObject()); + else { + Object mk = mkField.get(getObject()); + tag = keyOne.get(mk) + ":" + keyTwo.get(mk); + } + } + } + + @Override + public void updateObject() { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + setObject(NMSObject.construct(getObject(), Client.CUSTOM_PAYLOAD, tag, length, data)); + } else { + Object serializer = new WrappedPacketDataSerializer(data).getObject(); + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + setObject(NMSObject.construct(getObject(), Client.CUSTOM_PAYLOAD, tag, serializer)); + } else setObject(NMSObject.construct(getObject(), Client.CUSTOM_PAYLOAD, serializer)); + } + } + + static { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + lengthField = wrapped.getFieldByType(int.class, 0); + dataField = wrapped.getFieldByType(byte[].class, 0); + } else { + wrappedPDS = Reflections.getNMSClass("PacketDataSerializer"); + dataSerializer = wrapped.getFieldByType(wrappedPDS.getParent(), 0); + } + + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) { + minecraftKeyWrapper = Reflections.getNMSClass("MinecraftKey"); + keyOne = minecraftKeyWrapper.getFieldByType(String.class, 0); + keyTwo = minecraftKeyWrapper.getFieldByType(String.class, 1); + mkField = wrapped.getFieldByType(minecraftKeyWrapper.getParent(), 0); + } else tagField = wrapped.getFieldByType(String.class, 0); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInEntityActionPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInEntityActionPacket.java new file mode 100644 index 00000000..2ea3656e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInEntityActionPacket.java @@ -0,0 +1,57 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInEntityActionPacket extends NMSObject { + + // Fields + private static final String packet = Client.ENTITY_ACTION; + + // Fields + private static FieldAccessor fieldAction1_7; + private static FieldAccessor fieldAction1_8; + + // Decoded data + private EnumPlayerAction action; + + public WrappedInEntityActionPacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + action = EnumPlayerAction.values()[Math.min(8, fetch(fieldAction1_7) - 1)]; + } else { + action = EnumPlayerAction.values()[fetch(fieldAction1_8).ordinal()]; + } + } + + @Override + public void updateObject() { + + } + + public enum EnumPlayerAction { + START_SNEAKING, + STOP_SNEAKING, + STOP_SLEEPING, + START_SPRINTING, + STOP_SPRINTING, + START_RIDING_JUMP, + STOP_RIDING_JUMP, + OPEN_INVENTORY, + START_FALL_FLYING + } + + static { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + fieldAction1_7 = fetchField(packet, int.class, 1); + } else fieldAction1_8 = fetchField(packet, Enum.class, 0); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInFlyingPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInFlyingPacket.java new file mode 100644 index 00000000..25901473 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInFlyingPacket.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInFlyingPacket extends NMSObject { + private static final WrappedClass packet = Reflections.getNMSClass(Client.FLYING); + + // Fields + private static WrappedField fieldX = fetchField(packet, double.class, 0), + fieldY = fetchField(packet, double.class, 1), + fieldZ = fetchField(packet, double.class, 2), + fieldYaw = fetchField(packet, float.class, 0), + fieldPitch = fetchField(packet, float.class, 1), + fieldGround = fetchField(packet, boolean.class, 0), + hasPos = fetchField(packet, boolean.class, 1), + hasLook = fetchField(packet, boolean.class, 2); + + // Decoded data + private double x, y, z; + private float yaw, pitch; + private boolean look, pos, ground; + + public WrappedInFlyingPacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + x = fetch(fieldX); + y = fetch(fieldY); + z = fetch(fieldZ); + yaw = fetch(fieldYaw); + pitch = fetch(fieldPitch); + ground = fetch(fieldGround); + pos = fetch(hasPos); + look = fetch(hasLook); + } + + @Override + public void updateObject() { + set(fieldX, x); + set(fieldY, y); + set(fieldZ, z); + set(fieldYaw, yaw); + set(fieldPitch, pitch); + set(fieldGround, ground); + set(hasPos, pos); + set(hasLook, look); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInHeldItemSlotPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInHeldItemSlotPacket.java new file mode 100644 index 00000000..68d0ecfc --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInHeldItemSlotPacket.java @@ -0,0 +1,33 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInHeldItemSlotPacket extends NMSObject { + private static final String packet = Client.HELD_ITEM; + + // Fields + private static FieldAccessor fieldHeldSlot = fetchField(packet, int.class, 0); + + // Decoded data + private int slot; + + + public WrappedInHeldItemSlotPacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + slot = fetch(fieldHeldSlot); + } + + @Override + public void updateObject() { + setObject(NMSObject.construct(getObject(), packet, slot)); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInKeepAlivePacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInKeepAlivePacket.java new file mode 100644 index 00000000..e5e4b318 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInKeepAlivePacket.java @@ -0,0 +1,48 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInKeepAlivePacket extends NMSObject { + private static final String packet = Client.KEEP_ALIVE; + + private static WrappedField timeField; + + private long time; + + public WrappedInKeepAlivePacket(long time) { + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_12)) setPacket(packet, (int) time); + else setPacket(packet, time); + } + + public WrappedInKeepAlivePacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + Object object = timeField.get(getObject()); + + if(object instanceof Long) { + time = (long) object; + } else time = (int) object; + } + + @Override + public void updateObject() { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_12)) { + setObject(NMSObject.construct(getObject(), packet, (int) time)); + } else setObject(NMSObject.construct(getObject(), packet, time)); + } + + static { + timeField = Reflections.getNMSClass(packet) + .getFieldByType(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_12) + ? int.class : long.class, 0); + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInSetCreativeSlotPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInSetCreativeSlotPacket.java new file mode 100644 index 00000000..0fa75638 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInSetCreativeSlotPacket.java @@ -0,0 +1,38 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.impl.BukkitReflection; +import cc.funkemunky.api.reflections.impl.CraftReflection; +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +//TODO Test +public class WrappedInSetCreativeSlotPacket extends NMSObject { + + private static WrappedClass setCreativeClass = Reflections.getNMSClass(Client.CREATIVE_SLOT); + private static WrappedField slotField = setCreativeClass.getFieldByType(int.class, 0), + itemStackField = setCreativeClass.getFieldByType(MinecraftReflection.itemStack.getParent(), 0); + + public WrappedInSetCreativeSlotPacket(Object object, Player player) { + super(object, player); + } + + public int slot; + public ItemStack itemStack; + + @Override + public void updateObject() { + setPacket(Client.CREATIVE_SLOT, slot, CraftReflection.getVanillaItemStack(itemStack)); + } + + @Override + public void process(Player player, ProtocolVersion version) { + slot = fetch(slotField); + itemStack = BukkitReflection.getBukkitStackFromVanilla(fetch(itemStackField)); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInSettingsPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInSettingsPacket.java new file mode 100644 index 00000000..f12e92f7 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInSettingsPacket.java @@ -0,0 +1,119 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumHand; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.bukkit.entity.Player; + +public class WrappedInSettingsPacket extends NMSObject { + + //Reflection fields + private static WrappedClass packet = Reflections.getNMSClass(Client.SETTINGS); + + private static WrappedField fieldLocale, fieldView, fieldChatVisibility, fieldChatColors; + //1.7.10 only + private static WrappedField fieldVersion, fieldFlags, fieldShowCape; + //1.9+ only + private static WrappedField fieldMainHand; + //1.8+ only + private static WrappedField fieldSkinParts; + + public String locale; + public int viewDistance; + public WrappedChatVisibility chatVisibility = WrappedChatVisibility.FULL; + public boolean chatColors; + //1.7.10 only + public int version = -1, flags = -1; + public boolean showCape; + //1.8+ only + public int displayedSkinParts; + //1.9+ only + public WrappedEnumHand hand = WrappedEnumHand.MAIN_HAND; + + public WrappedInSettingsPacket(Object object, Player player) { + super(object, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + locale = fetch(fieldLocale); + viewDistance = fetch(fieldView); + chatVisibility = WrappedChatVisibility.fromVanilla(fetch(fieldChatVisibility)); + chatColors = fetch(fieldChatColors); + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + version = fetch(fieldVersion); + flags = fetch(fieldFlags); + showCape = fetch(fieldShowCape); + } else { + displayedSkinParts = fetch(fieldSkinParts); + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8_9)) + hand = WrappedEnumHand.getFromVanilla(fetch(fieldMainHand)); + } + } + + @Override + public void updateObject() { + set(fieldLocale, locale); + set(fieldView, viewDistance); + set(fieldChatVisibility, chatVisibility); + set(fieldChatColors, chatColors); + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + set(fieldVersion, version); + set(fieldFlags, flags); + set(fieldShowCape, showCape); + } else { + set(fieldSkinParts, displayedSkinParts); + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8_9)) + set(fieldMainHand, hand.toEnumHand()); + } + } + + @Getter + @RequiredArgsConstructor + public enum WrappedChatVisibility { + FULL(0, "options.chat.visibility.full"), + SYSTEM(1, "options.chat.visibility.system"), + HIDDEN(2, "options.chat.visibility.hidden"); + + static WrappedClass chatVisibilityClass = Reflections.getNMSClass(ProtocolVersion.getGameVersion() + .isOrBelow(ProtocolVersion.V1_7_10) ? "EnumChatVisibility" : "EntityHuman$EnumChatVisibility"); + + private final int id; + private final String path; + + public T toVanilla() { + return (T) chatVisibilityClass.getEnum(toString()); + } + + public static WrappedChatVisibility fromVanilla(Object o) { + if(o instanceof Enum) valueOf(o.toString()); + + return FULL; + } + } + + static { + fieldLocale = packet.getFieldByType(String.class, 0); + fieldView = packet.getFieldByType(int.class, 0); + fieldChatVisibility = packet.getFieldByType(WrappedChatVisibility.chatVisibilityClass.getParent(), 0); + fieldChatColors = packet.getFieldByType(boolean.class, 0); + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + fieldVersion = packet.getFieldByType(int.class, 1); + fieldFlags = packet.getFieldByType(int.class, 2); + fieldShowCape = packet.getFieldByType(boolean.class, 1); + } else { + fieldSkinParts = packet.getFieldByType(int.class, 1); + + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8_9)) + fieldMainHand = packet.getFieldByType(WrappedEnumHand.enumHandClass.getParent(), 0); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInSteerVehiclePacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInSteerVehiclePacket.java new file mode 100644 index 00000000..2a73f097 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInSteerVehiclePacket.java @@ -0,0 +1,42 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInSteerVehiclePacket extends NMSObject { + private static final WrappedClass packetClass = Reflections.getNMSClass(Client.STEER_VEHICLE); + + // Fields + private float sideways, forward; + private boolean jump, unmount; + + // Decoded data + private static WrappedField sidewaysField = packetClass.getFieldByType(float.class, 0), + forwardField = packetClass.getFieldByType(float.class, 0); + private static WrappedField jumpField = packetClass.getFieldByType(boolean.class, 0), + unmountField = packetClass.getFieldByType(boolean.class, 1); + + public WrappedInSteerVehiclePacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + sideways = sidewaysField.get(getObject()); + forward = forwardField.get(getObject()); + + jump = jumpField.get(getObject()); + unmount = unmountField.get(getObject()); + } + + @Override + public void updateObject() { + setObject(NMSObject.construct(getObject(), Client.STEER_VEHICLE, sideways, forward, jump, unmount)); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInTabComplete.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInTabComplete.java new file mode 100644 index 00000000..ff02ecd6 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInTabComplete.java @@ -0,0 +1,73 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.BaseBlockPosition; +import cc.funkemunky.api.tinyprotocol.packet.types.v1_13.DontImportIfNotLatestThanks; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInTabComplete extends NMSObject { + + private static final String packet = Client.TAB_COMPLETE; + + private static DontImportIfNotLatestThanks stuff; + + public WrappedInTabComplete(Object object, Player player) { + super(object, player); + } + + private static FieldAccessor messageAccessor = fetchField(packet, String.class, 0); + private static FieldAccessor hasToolTipAccessor; + private static FieldAccessor blockPositionAcessor; + private static FieldAccessor idAccessor; + + private String message; + private int id = -1; + private BaseBlockPosition blockPosition; //1.8 and up only. + private boolean hasToolTip; //1.9 and up only. + + @Override + public void process(Player player, ProtocolVersion version) { + message = fetch(messageAccessor); + + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_13)) { + id = fetch(idAccessor); + } else { + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8_9)) { + hasToolTip = fetch(hasToolTipAccessor); + } + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8)) { + Object blockPos = fetch(blockPositionAcessor); + if(blockPos != null) + blockPosition = new BaseBlockPosition(fetch(blockPositionAcessor)); + } + } + } + + @Override + public void updateObject() { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + setPacket(packet, message, hasToolTip, blockPosition.getAsBlockPosition()); + } else if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + setPacket(packet, message, blockPosition.getAsBlockPosition()); + } else setPacket(packet, message); + } + + static { + + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) { + idAccessor = fetchField(packet, int.class, 0); + stuff = new DontImportIfNotLatestThanks(); + } else { + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8_9)) { + hasToolTipAccessor = fetchField(packet, boolean.class, 0); + } + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + blockPositionAcessor = fetchField(packet, Object.class, 1); + } + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInTransactionPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInTransactionPacket.java new file mode 100644 index 00000000..6d29e243 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInTransactionPacket.java @@ -0,0 +1,36 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedInTransactionPacket extends NMSObject { + private static final String packet = Client.TRANSACTION; + + private static FieldAccessor fieldId = fetchField(packet, int.class, 0); + private static FieldAccessor fieldAction = fetchField(packet, short.class, 0); + private static FieldAccessor fieldAccepted = fetchField(packet, boolean.class, 0); + + private int id; + private short action; + private boolean accept; + + public WrappedInTransactionPacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + id = fetch(fieldId); + action = fetch(fieldAction); + accept = fetch(fieldAccepted); + } + + @Override + public void updateObject() { + setObject(NMSObject.construct(getObject(), packet, id, action, accept)); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInUseEntityPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInUseEntityPacket.java new file mode 100644 index 00000000..e80388d6 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInUseEntityPacket.java @@ -0,0 +1,93 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.Vec3D; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumHand; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import java.util.*; + +@Getter +//TODO Test updateObject functionality and additions to the wrapper for 1.8 and 1.9+. +public class WrappedInUseEntityPacket extends NMSObject { + private static String packet = Client.USE_ENTITY; + + private static FieldAccessor fieldId = fetchField(packet, int.class, 0); + private static FieldAccessor fieldAction = fetchField(packet, Enum.class, 0); + private static WrappedClass packetClass = Reflections.getNMSClass(packet), + enumEntityUseAction = Reflections.getNMSClass( + (ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8) + ? "PacketPlayInUseEntity$" : "") + "EnumEntityUseAction"); + private static WrappedField vecField, handField; + + private int id; + private EnumEntityUseAction action; + private Entity entity; + private Vec3D vec; + private WrappedEnumHand enumHand; + + public WrappedInUseEntityPacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + id = Objects.requireNonNull(fetch(fieldId)); + Enum fieldAct = Objects.nonNull(fetch(fieldAction)) ? fetch(fieldAction) : null; + action = fieldAct == null ? EnumEntityUseAction.INTERACT_AT : EnumEntityUseAction.valueOf(fieldAct.name()); + + //We cache the entities so we dont have to loop every single packet for the same entity. + Optional.ofNullable(Atlas.getInstance().getEntityIds().get(id)) + .ifPresent(uuid -> entity = Atlas.getInstance().getEntities().get(uuid)); + + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + Object vec = fetch(vecField); + if(vec != null) + this.vec = new Vec3D(vec); + } + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + enumHand = WrappedEnumHand.getFromVanilla(fetch(handField)); + } else enumHand = WrappedEnumHand.MAIN_HAND; + } + + @Override + public void updateObject() { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + vec.updateObject(); + setPacket(packet, id, enumEntityUseAction.getEnum(action.toString()), + vec.getObject(), enumHand.toEnumHand()); + } else if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + setPacket(packet, id, enumEntityUseAction.getEnum(action.toString()), vec.getObject()); + } else setPacket(packet, id, enumEntityUseAction.getEnum(action.toString())); + } + + public enum EnumEntityUseAction { + INTERACT("INTERACT"), + ATTACK("ATTACK"), + INTERACT_AT("INTERACT_AT"); + + @Getter + private String name; + + EnumEntityUseAction(String name) { + this.name = name; + } + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + vecField = packetClass.getFieldByType(MinecraftReflection.vec3D.getParent(), 0); + } else if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + handField = packetClass.getFieldByType(WrappedEnumHand.enumHandClass.getParent(), 0); + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInWindowClickPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInWindowClickPacket.java new file mode 100644 index 00000000..3f0c7074 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/in/WrappedInWindowClickPacket.java @@ -0,0 +1,140 @@ +package cc.funkemunky.api.tinyprotocol.packet.in; + +import cc.funkemunky.api.reflections.impl.CraftReflection; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +@Getter +public class WrappedInWindowClickPacket extends NMSObject { + private static final String packet = Client.WINDOW_CLICK; + + // Fields + private static FieldAccessor fieldId = fetchField(packet, int.class, 0); + private static FieldAccessor fieldSlot = fetchField(packet, int.class, 1); + private static FieldAccessor fieldButton = fetchField(packet, int.class, 2); + private static FieldAccessor fieldAction = fetchField(packet, short.class, 0); + private static FieldAccessor fieldItemStack = fetchField(packet, Type.ITEMSTACK, 0); + + // Decoded data + private int id; + private short slot; + private int button; + private short counter; + private ClickType action; + private ItemStack item; + private int mode; + + public WrappedInWindowClickPacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + id = fetch(fieldId); + slot = fetch(fieldSlot).shortValue(); + byte button = (byte)(this.button = fetch(fieldButton)); + counter = fetch(fieldAction); + item = toBukkitStack(fetch(fieldItemStack)); + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + FieldAccessor fieldShift = fetchField(packet, int.class, 3); + mode = fetch(fieldShift); + } else { + FieldAccessor fieldShift = fetchField(packet, Enum.class, 0); + mode = fetch(fieldShift).ordinal(); + } + + if (slot == -1) { + action = button == 0 ? ClickType.WINDOW_BORDER_LEFT : ClickType.WINDOW_BORDER_RIGHT; + } else if (mode == 0) { + if (button == 0) { + action = ClickType.LEFT; + } else if (button == 1) { + action = ClickType.RIGHT; + } + } else if (mode == 1) { + if (button == 0) { + action = ClickType.SHIFT_LEFT; + } else if (button == 1) { + action = ClickType.SHIFT_RIGHT; + } + } else if (mode == 2) { + if (button >= 0 && button < 9) { + action = ClickType.NUMBER_KEY; + } + } else if (mode == 3) { + if (button == 2) { + action = ClickType.MIDDLE; + } else { + action = ClickType.UNKNOWN; + } + } else if (mode == 4) { + if (slot >= 0) { + if (button == 0) { + action = ClickType.DROP; + } else if (button == 1) { + action = ClickType.CONTROL_DROP; + } + } else { + // Sane default (because this happens when they are holding nothing. Don't ask why.) + action = ClickType.LEFT; + if (button == 1) { + action = ClickType.RIGHT; + } + } + } else if (mode == 5) { + action = ClickType.DRAG; + } else if (mode == 6) { + action = ClickType.DOUBLE_CLICK; + } + } + + @Override + public void updateObject() { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + setPacket(packet, id, slot, button, counter, CraftReflection.getVanillaItemStack(item), mode); + } else { + setPacket(packet, id, slot, button, counter, CraftReflection.getVanillaItemStack(item)); + } + } + + public enum ClickType { + LEFT, + SHIFT_LEFT, + RIGHT, + SHIFT_RIGHT, + WINDOW_BORDER_LEFT, + WINDOW_BORDER_RIGHT, + MIDDLE, + NUMBER_KEY, + DOUBLE_CLICK, + DROP, + CONTROL_DROP, + CREATIVE, + DRAG, + UNKNOWN; + + public boolean isKeyboardClick() { + return this == NUMBER_KEY || this == DROP || this == CONTROL_DROP; + } + + public boolean isCreativeAction() { + return this == MIDDLE || this == CREATIVE; + } + + public boolean isRightClick() { + return this == RIGHT || this == SHIFT_RIGHT; + } + + public boolean isLeftClick() { + return this == LEFT || this == SHIFT_LEFT || this == DOUBLE_CLICK || this == CREATIVE; + } + public boolean isShiftClick() { + return this == SHIFT_LEFT || this == SHIFT_RIGHT || this == CONTROL_DROP; + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/login/WrappedHandshakingInSetProtocol.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/login/WrappedHandshakingInSetProtocol.java new file mode 100644 index 00000000..167d44ba --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/login/WrappedHandshakingInSetProtocol.java @@ -0,0 +1,38 @@ +package cc.funkemunky.api.tinyprotocol.packet.login; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumProtocol; +import org.bukkit.entity.Player; + +public class WrappedHandshakingInSetProtocol extends NMSObject { + private static WrappedClass packet = Reflections.getNMSClass(Login.HANDSHAKE); + public WrappedHandshakingInSetProtocol(Object object) { + super(object); + } + + public int a, port; + public String hostname; + public WrappedEnumProtocol enumProtocol; + + private static WrappedField aField = packet.getFieldByType(int.class, 0), + hostField = packet.getFieldByType(String.class, 0), + portField = packet.getFieldByType(int.class, 1), + protocolField = packet.getFieldByType(WrappedEnumProtocol.enumProtocol.getParent(), 0); + + @Override + public void process(Player player, ProtocolVersion version) { + a = aField.get(getObject()); + hostname = hostField.get(getObject()); + port = portField.get(getObject()); + enumProtocol = WrappedEnumProtocol.fromVanilla(protocolField.get(getObject())); + } + + @Override + public void updateObject() { + setObject(NMSObject.construct(getObject(), Login.HANDSHAKE, a, hostname, port, enumProtocol.toVanilla())); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/login/WrappedStatusInPing.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/login/WrappedStatusInPing.java new file mode 100644 index 00000000..1fc3e6aa --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/login/WrappedStatusInPing.java @@ -0,0 +1,30 @@ +package cc.funkemunky.api.tinyprotocol.packet.login; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import org.bukkit.entity.Player; + +public class WrappedStatusInPing extends NMSObject { + + public WrappedStatusInPing(Object object) { + super(object); + } + + private static final WrappedClass statusInPing = Reflections.getNMSClass(Login.PING); + private static final WrappedField pingField = statusInPing.getFieldByType(long.class, 0); + + public long ping; + + @Override + public void process(Player player, ProtocolVersion version) { + ping = pingField.get(getObject()); + } + + @Override + public void updateObject() { + setObject(NMSObject.construct(getObject(), Login.PING, ping)); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutAbilitiesPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutAbilitiesPacket.java new file mode 100644 index 00000000..8afa9f00 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutAbilitiesPacket.java @@ -0,0 +1,67 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +public class WrappedOutAbilitiesPacket extends NMSObject { + private static final String packet = Server.ABILITIES; + + private static FieldAccessor + invulnerableField = fetchField(packet, boolean.class, 0), + flyingField = fetchField(packet, boolean.class, 1), + allowedFlightField = fetchField(packet, boolean.class, 2), + creativeModeField = fetchField(packet, boolean.class, 3); + private static FieldAccessor + flySpeedField = fetchField(packet, float.class, 0), + walkSpeedField = fetchField(packet, float.class, 1); + + private static WrappedClass abilitiesClass = Reflections.getNMSClass("PlayerAbilities"); + private static WrappedField invulnerableAcc = abilitiesClass.getFieldByType(boolean.class, 0); + private static WrappedField flyingAcc = abilitiesClass.getFieldByType(boolean.class, 1); + private static WrappedField allowedFlightAcc = abilitiesClass.getFieldByType(boolean.class, 2); + private static WrappedField creativeModeAcc = abilitiesClass.getFieldByType(boolean.class, 3); + private static WrappedField flySpeedAcc = abilitiesClass.getFieldByType(float.class, 0); + private static WrappedField walkSpeedAcc = abilitiesClass.getFieldByType(float.class, 1); + @Getter + private boolean invulnerable, flying, allowedFlight, creativeMode; + @Getter + private float flySpeed, walkSpeed; + + + public WrappedOutAbilitiesPacket(Object object, Player player) { + super(object, player); + } + + public WrappedOutAbilitiesPacket(boolean invulernable, boolean flying, boolean allowedFlight, boolean creativeMode, float flySpeed, float walkSpeed) { + Object abilities = abilitiesClass.getConstructorAtIndex(0).newInstance(); + invulnerableAcc.set(abilities, invulernable); + flyingAcc.set(abilities, flying); + allowedFlightAcc.set(abilities, allowedFlight); + creativeModeAcc.set(abilities, creativeMode); + flySpeedAcc.set(abilities, flySpeed); + walkSpeedAcc.set(abilities, walkSpeed); + + setObject(Reflections.getNMSClass(packet).getConstructor(abilitiesClass.getParent()).newInstance(abilities)); + } + + @Override + public void process(Player player, ProtocolVersion version) { + invulnerable = fetch(invulnerableField); + flying = fetch(flyingField); + allowedFlight = fetch(allowedFlightField); + creativeMode = fetch(creativeModeField); + flySpeed = fetch(flySpeedField); + walkSpeed = fetch(walkSpeedField); + } + + @Override + public void updateObject() { + + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutBlockChange.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutBlockChange.java new file mode 100644 index 00000000..dfcf404d --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutBlockChange.java @@ -0,0 +1,81 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.Packet; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.BaseBlockPosition; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import cc.funkemunky.api.utils.ReflectionsUtil; +import lombok.Getter; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + +@Getter +public class WrappedOutBlockChange extends NMSObject { + private static final String packet = Packet.Server.BLOCK_CHANGE; + + //1.7.10 and below + private static FieldAccessor legacyX; + private static FieldAccessor legacyY; + private static FieldAccessor legacyZ; + private static WrappedField blockChangeBlockField; + private static WrappedField blockDataIntField; + private static WrappedMethod getDataMethod; + + //1.8 and newer + private static FieldAccessor blockPosAccessor; + private static WrappedField iBlockDataField; + + + private static WrappedClass blockChangeClass = Reflections.getNMSClass(packet); + private static WrappedClass nmsBlockClass = Reflections.getNMSClass("Block"); + private static WrappedClass craftBlockClass = Reflections.getCBClass("CraftBlock"); + + private BaseBlockPosition position; + + public WrappedOutBlockChange(Object packet) { + super(packet); + } + + public WrappedOutBlockChange(Block block) { + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_7_10)) { + setPacket(packet, block.getX(), block.getY(), block.getZ(), ReflectionsUtil.getWorldHandle(block.getWorld())); + } else { + setPacket(packet, ReflectionsUtil.getWorldHandle(block.getWorld()), new BaseBlockPosition(block.getX(), block.getY(), block.getZ()).getAsBlockPosition()); + } + } + + @Override + public void process(Player player, ProtocolVersion version) { + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + position = new BaseBlockPosition(fetch(legacyX), fetch(legacyY), fetch(legacyZ)); + } else { + position = new BaseBlockPosition(fetch(blockPosAccessor)); + } + } + + @Override + public void updateObject() { + + } + + static { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + legacyX = fetchField(packet, int.class, 0); + legacyY = fetchField(packet, int.class, 1); + legacyZ = fetchField(packet, int.class, 2); + + + blockChangeBlockField = blockChangeClass.getFirstFieldByType(nmsBlockClass.getParent()); + blockDataIntField = blockChangeClass.getFieldByName("data"); + getDataMethod = Reflections.getNMSClass("World").getMethod("getData", int.class, int.class, int.class); + } else { + blockPosAccessor = fetchField(packet, Object.class, 0); + iBlockDataField = blockChangeClass.getFieldByType(ReflectionsUtil.iBlockData, 0); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutChatPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutChatPacket.java new file mode 100644 index 00000000..1776ff68 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutChatPacket.java @@ -0,0 +1,64 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.WrappedChatMessageType; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedOutChatPacket extends NMSObject { + private final static String packet = Server.CHAT; + + public WrappedOutChatPacket(Object packetObj, Player player) { + super(packetObj, player); + } + + //Constructor (ichatbase, chattype); + public WrappedOutChatPacket(String message, WrappedChatMessageType type) { + setPacket(packet, stcToComponent.invoke(null, message), type.toNMS()); + } + + //Saving your fingers from the most common use for using this wrapper. + public WrappedOutChatPacket(String message) { + this(message, WrappedChatMessageType.CHAT); + } + + private static WrappedClass chatBaseComp = Reflections.getNMSClass("IChatBaseComponent"); + private static WrappedClass outChatClass = Reflections.getNMSClass(packet); + private static WrappedClass chatSerialClass = Reflections.getNMSClass("IChatBaseComponent$ChatSerializer"); + private static WrappedMethod stcToComponent = chatSerialClass.getMethod("a", String.class); + private static WrappedMethod getTextMethod = chatBaseComp.getMethod("getText"); + private static WrappedField chatTypeField; + + private String message; + private WrappedChatMessageType chatType; + + @Override + public void process(Player player, ProtocolVersion version) { + //Getting the message + message = getTextMethod.invoke(getObject()); + + //Getting the chat type. + chatType = WrappedChatMessageType.fromNMS(chatTypeField.get(getObject())); + } + + @Override + public void updateObject() { + + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_12)) { + chatTypeField = outChatClass.getFieldByType(Reflections.getNMSClass("ChatMessageType").getParent(), 0); + } else if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_7_10)) { + chatTypeField = outChatClass.getFieldByType(byte.class, 0); + } else { + chatTypeField = outChatClass.getFieldByType(int.class, 0); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutCloseWindowPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutCloseWindowPacket.java new file mode 100644 index 00000000..763e11a1 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutCloseWindowPacket.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import org.bukkit.entity.Player; + +public class WrappedOutCloseWindowPacket extends NMSObject { + + private static final WrappedClass packet = Reflections.getNMSClass(Server.CLOSE_WINDOW); + private static final WrappedField idField = packet.getFieldByType(int.class, 0); + + public WrappedOutCloseWindowPacket(Object object, Player player) { + super(object, player); + } + + public WrappedOutCloseWindowPacket(int id) { + this.id = id; + updateObject(); + } + + public int id; + + @Override + public void updateObject() { + setObject(NMSObject.construct(getObject(), Server.CLOSE_WINDOW, id)); + } + + @Override + public void process(Player player, ProtocolVersion version) { + id = fetch(idField); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutCustomPayload.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutCustomPayload.java new file mode 100644 index 00000000..1fd73b17 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutCustomPayload.java @@ -0,0 +1,80 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.WrappedPacketDataSerializer; +import lombok.Getter; +import org.bukkit.entity.Player; + +//TODO Make this compatible with 1.13 and newer. +@Getter +public class WrappedOutCustomPayload extends NMSObject { + + public WrappedOutCustomPayload(Object object, Player player) { + super(object, player); + } + + public WrappedOutCustomPayload(String tag, byte[] data) { + setObject(payloadClass.getConstructor().newInstance()); + + this.tag = tag; + this.data = data; + + updateObject(); + } + + private static WrappedClass payloadClass = Reflections.getNMSClass(Server.CUSTOM_PAYLOAD); + private static WrappedField tagField, dataField; + + private String tag; + private byte[] data; + + //1.13+ + private static WrappedClass minecraftKeyWrapper; + private static WrappedField keyOne, keyTwo; + + @Override + public void process(Player player, ProtocolVersion version) { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) { + Object mk = tagField.get(getObject()); + tag = keyOne.get(mk) + ":" + keyTwo.get(mk); + } else tag = tagField.get(getObject()); + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + data = new WrappedPacketDataSerializer(dataField.get(getObject())).getData(); + + } else data = dataField.get(getObject()); + } + + @Override + public void updateObject() { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + dataField.set(getObject(), new WrappedPacketDataSerializer(data).getObject()); + } else dataField.set(getObject(), data); + + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) { + if(tag.contains(":")) { + Object mk = tagField.get(getObject()); + String[] split = tag.split(":"); + keyOne.set(mk, split[0]); + keyTwo.set(mk, split[1]); + } else { + System.out.println("Tag (" + tag + ") must contain a ':' to be valid."); + } + } else tagField.set(getObject(), tag); + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) { + minecraftKeyWrapper = Reflections.getNMSClass("MinecraftKey"); + keyOne = minecraftKeyWrapper.getFieldByType(String.class, 0); + keyTwo = minecraftKeyWrapper.getFieldByType(String.class, 1); + tagField = payloadClass.getFieldByType(minecraftKeyWrapper.getParent(), 0); + } else tagField = payloadClass.getFieldByType(String.class, 0); + if(ProtocolVersion.getGameVersion().isOrBelow(ProtocolVersion.V1_7_10)) { + dataField = payloadClass.getFieldByType(byte[].class, 0); + } else dataField = payloadClass.getFieldByType(WrappedPacketDataSerializer.vanillaClass.getParent(), 0); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutEntityEffectPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutEntityEffectPacket.java new file mode 100644 index 00000000..c315b1a4 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutEntityEffectPacket.java @@ -0,0 +1,56 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import org.bukkit.entity.Player; + +public class WrappedOutEntityEffectPacket extends NMSObject { + + public int entityId; + public byte effectId; + public byte amplifier; + public int duration; + public byte flags; + + private static WrappedClass wrapped = Reflections.getNMSClass(Server.ENTITY_EFFECT); + private static WrappedField fieldEntityId, + fieldEffectId, + fieldAmplifier, + fieldDuration, fieldFlags; + + public WrappedOutEntityEffectPacket(Object object, Player player) { + super(object, player); + } + + @Override + public void updateObject() { + fieldEntityId.set(getObject(), entityId); + fieldEffectId.set(getObject(), effectId); + fieldAmplifier.set(getObject(), amplifier); + fieldDuration.set(getObject(), duration); + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_7_10)) fieldFlags.set(getObject(), flags); + } + + @Override + public void process(Player player, ProtocolVersion version) { + entityId = fieldEntityId.get(getObject()); + effectId = fieldEffectId.get(getObject()); + amplifier = fieldAmplifier.get(getObject()); + duration = ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_7_10) + ? fieldDuration.get(getObject()) : (short) fieldDuration.get(getObject()); + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_7_10))flags = fieldFlags.get(getObject()); + } + + static { + fieldEntityId = wrapped.getFieldByType(int.class, 0); + fieldEffectId = wrapped.getFieldByType(byte.class, 0); + fieldAmplifier = wrapped.getFieldByType(byte.class, 1); + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_7_10)) { + fieldDuration = wrapped.getFieldByType(int.class, 1); + fieldFlags = wrapped.getFieldByType(byte.class, 2); + } else fieldDuration = wrapped.getFieldByType(short.class, 0); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutEntityHeadRotation.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutEntityHeadRotation.java new file mode 100644 index 00000000..b94964cf --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutEntityHeadRotation.java @@ -0,0 +1,42 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedOutEntityHeadRotation extends NMSObject { + private static WrappedClass headRotationClass = Reflections.getNMSClass(Server.ENTITY_HEAD_ROTATION); + private static WrappedField entityIdField = headRotationClass.getFirstFieldByType(int.class); + private static WrappedField yawField = headRotationClass.getFirstFieldByType(byte.class); + + private int entityId; + private byte yaw; + + public WrappedOutEntityHeadRotation(Object object, Player player) { + super(object, player); + } + + public WrappedOutEntityHeadRotation(int entityId, byte byteThing) { + Object headRotation = headRotationClass.getConstructor().newInstance(); + entityIdField.set(headRotation, entityId); + yawField.set(headRotation, byteThing); + + setObject(headRotation); + } + + @Override + public void updateObject() { + + } + + @Override + public void process(Player player, ProtocolVersion version) { + entityId = entityIdField.get(getObject()); + yaw = yawField.get(getObject()); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutEntityMetadata.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutEntityMetadata.java new file mode 100644 index 00000000..4883b773 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutEntityMetadata.java @@ -0,0 +1,52 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.Packet; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +public class WrappedOutEntityMetadata extends NMSObject { + private static final String packet = Packet.Server.ENTITY_METADATA; + + private static FieldAccessor entityidField; + private static FieldAccessor watchableObjectsField; + + private List watchableObjects; + private int entityId; + + public WrappedOutEntityMetadata(Object object, Player player) { + super(object, player); + } + + public WrappedOutEntityMetadata(int entityId, List objects) { + setPacket(packet, entityId, objects); + } + + @Override + public void process(Player player, ProtocolVersion version) { + watchableObjectsField = fetchField(packet, List.class, 0); + entityidField = fetchField(packet, int.class, 0); + + watchableObjects = new ArrayList<>(); + entityId = fetch(entityidField); + + List list = fetch(watchableObjectsField); + + if(list != null) { + list.forEach(object -> watchableObjects.add(object)); + } + } + + @Override + public void updateObject() { + + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutHeldItemSlot.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutHeldItemSlot.java new file mode 100644 index 00000000..4627d0c3 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutHeldItemSlot.java @@ -0,0 +1,40 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedOutHeldItemSlot extends NMSObject { + private static String packet = Server.HELD_ITEM; + private static FieldAccessor slotField = fetchField(packet, int.class, 0); + + private int slot; + + public WrappedOutHeldItemSlot(Object object, Player player) { + super(object, player); + } + + public WrappedOutHeldItemSlot(int slot) { + this.slot = slot; + + setObject(construct(packet, slot)); + } + + @Override + public void process(Player player, ProtocolVersion version) { + slot = fetch(slotField); + } + + @Override + public Object getObject() { + return super.getObject(); + } + + @Override + public void updateObject() { + + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutKeepAlivePacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutKeepAlivePacket.java new file mode 100644 index 00000000..6c5beb7e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutKeepAlivePacket.java @@ -0,0 +1,43 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedOutKeepAlivePacket extends NMSObject { + private static final String packet = Server.KEEP_ALIVE; + + private static FieldAccessor fieldLegacy; + private static FieldAccessor field; + + private long time; + + public WrappedOutKeepAlivePacket(long time) { + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_12)) setPacket(packet, (int) time); + else setPacket(packet, time); + } + + public WrappedOutKeepAlivePacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_12)) { + fieldLegacy = fetchField(packet, int.class, 0); + time = fetch(fieldLegacy); + } + else { + field = fetchField(packet, long.class, 0); + time = fetch(field); + } + } + + @Override + public void updateObject() { + + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutMultiBlockChange.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutMultiBlockChange.java new file mode 100644 index 00000000..3a395b07 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutMultiBlockChange.java @@ -0,0 +1,11 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; + +public class WrappedOutMultiBlockChange extends NMSObject { + + @Override + public void updateObject() { + + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutNamedEntitySpawnPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutNamedEntitySpawnPacket.java new file mode 100644 index 00000000..ad6335c9 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutNamedEntitySpawnPacket.java @@ -0,0 +1,97 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.MathHelper; +import cc.funkemunky.api.tinyprotocol.packet.types.WrappedGameProfile; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.UUID; + +//TODO Add the ability to use this wrapper to spawn a fake entity and implement other field support. +public class WrappedOutNamedEntitySpawnPacket extends NMSObject { + + public WrappedOutNamedEntitySpawnPacket(Object object, Player player) { + super(object, player); + } + + private static WrappedClass packet = Reflections.getNMSClass(Server.NAMED_ENTITY_SPAWN); + + public int entityId; + public UUID uuid; + public double x, y, z; + public byte yaw, pitch; + public int currentItem; + + private static final WrappedField fieldEntityId, fieldUuid, fieldX, fieldY, fieldZ, fieldYaw, fieldPitch, + fieldCurrentItem; + + + @Override + public void process(Player player, ProtocolVersion version) { + entityId = fetch(fieldEntityId); + yaw = fetch(fieldYaw); + pitch = fetch(fieldPitch); + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + uuid = new WrappedGameProfile(fetch(fieldUuid)).id; + } else uuid = fetch(fieldUuid); + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + currentItem = fetch(fieldCurrentItem); + x = (int)fetch(fieldX) / 32.; + y = (int)fetch(fieldY) / 32.; + z = (int)fetch(fieldZ) / 32.; + } else { + x = fetch(fieldX); + y = fetch(fieldY); + z = fetch(fieldZ); + } + } + + @Override + public void updateObject() { + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + Player player = Bukkit.getPlayer(uuid); + set(fieldUuid, player != null ? new WrappedGameProfile(player) : null); + } else set(fieldUuid, uuid); + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + set(fieldCurrentItem, currentItem); + set(fieldX, MathHelper.floor(x * 32.)); + set(fieldY, MathHelper.floor(y * 32.)); + set(fieldZ, MathHelper.floor(z * 32.)); + } else { + set(fieldX, x); + set(fieldY, y); + set(fieldZ, z); + } + } + + static { + fieldEntityId = fetchField(packet, int.class, 0); + fieldYaw = fetchField(packet, byte.class, 0); + fieldPitch = fetchField(packet, byte.class, 1); + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + fieldUuid = fetchField(packet, MinecraftReflection.gameProfile.getParent(), 0); + } else fieldUuid = fetchField(packet, UUID.class, 0); + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + fieldX = fetchField(packet, int.class, 1); + fieldY = fetchField(packet, int.class, 2); + fieldZ = fetchField(packet, int.class, 3); + fieldCurrentItem = fetchField(packet, int.class, 4); + } else { + fieldX = fetchField(packet, double.class, 0); + fieldY = fetchField(packet, double.class, 1); + fieldZ = fetchField(packet, double.class, 2); + fieldCurrentItem = null; + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutOpenWindow.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutOpenWindow.java new file mode 100644 index 00000000..07155c37 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutOpenWindow.java @@ -0,0 +1,53 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.WrappedChatComponent; +import cc.funkemunky.api.tinyprotocol.packet.types.WrappedChatMessage; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedOutOpenWindow extends NMSObject { + + private static String packet = Server.OPEN_WINDOW; + + public WrappedOutOpenWindow(Object object, Player player) { + super(object, player); + } + + public WrappedOutOpenWindow(int id, String name, WrappedChatMessage msg, int size) { + setPacket(packet, id, name, msg.getObject(), size); + } + + private static FieldAccessor idField = fetchField(packet, int.class, 0); + private static FieldAccessor nameField = fetchField(packet, String.class, 0); + private static FieldAccessor chatCompField; + private static FieldAccessor inventorySize = fetchField(packet, int.class, 1); + + private int id; + private String name; + private WrappedChatComponent chatComponent; + private int size; + + @Override + public void process(Player player, ProtocolVersion version) { + id = fetch(idField); + name = fetch(nameField); + size = fetch(inventorySize); + } + + @Override + public void updateObject() { + + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + chatCompField = fetchField(packet, + MinecraftReflection.iChatBaseComponent.getParent(), 0); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutPlayerInfo.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutPlayerInfo.java new file mode 100644 index 00000000..7a3dcbc3 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutPlayerInfo.java @@ -0,0 +1,108 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedConstructor; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.WrappedGameProfile; +import cc.funkemunky.api.tinyprotocol.packet.types.WrappedPlayerInfoData; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumGameMode; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumPlayerInfoAction; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import cc.funkemunky.api.utils.ReflectionsUtil; +import lombok.val; +import org.bukkit.entity.Player; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; + +public class WrappedOutPlayerInfo extends NMSObject { + private static String packet = Server.PLAYER_INFO; + + private static WrappedClass playerInfoClass = Reflections.getNMSClass(packet); + private static WrappedClass playerInfoDataClass; + private static WrappedConstructor constructor; + private static WrappedClass chatBaseComp = Reflections.getNMSClass("IChatBaseComponent"); + private static WrappedClass chatSerialClass = Reflections.getNMSClass("IChatBaseComponent$ChatSerializer"); + + private static WrappedMethod stcToComponent = chatSerialClass.getMethod("a", new Class[]{String.class}); + + public WrappedOutPlayerInfo(Object object, Player player) { + super(object, player); + } + + public WrappedOutPlayerInfo(WrappedEnumPlayerInfoAction action, Player player) { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + val construct = playerInfoClass.getConstructor(WrappedEnumPlayerInfoAction.enumPlayerInfoAction.getParent(), + Array.newInstance(MinecraftReflection.entityPlayer.getParent(), 0).getClass()); + + Object array = Array.newInstance(MinecraftReflection.entityPlayer.getParent(), 1); + Array.set(array, 0, ReflectionsUtil.getEntityPlayer(player)); + setObject(construct.newInstance(action.toVanilla(), array)); + } else { + Object packet = playerInfoClass.getConstructor().newInstance(); + playerInfoClass.getMethod(action.legacyMethodName, ReflectionsUtil.EntityPlayer) + .invoke(packet, ReflectionsUtil.getEntityPlayer(player)); + + setObject(packet); + } + } + + //1.8+ + private static FieldAccessor playerInfoListAccessor; + private static FieldAccessor actionAcessorEnum; + + //1.7.10 + private static FieldAccessor actionAcessorInteger; + private static FieldAccessor gamemodeAccessor; + private static FieldAccessor profileAcessor; + private static FieldAccessor pingAcessor; + + + private List playerInfo = new ArrayList<>(); + private WrappedEnumPlayerInfoAction action; + + @Override + public void process(Player player, ProtocolVersion version) { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + playerInfoListAccessor = fetchField(packet, List.class, 0); + actionAcessorEnum = fetchField(packet, Enum.class, 0); + + List list = fetch(playerInfoListAccessor); + + for (Object object : list) { + playerInfo.add(new WrappedPlayerInfoData(object)); + } + + action = WrappedEnumPlayerInfoAction.valueOf(fetch(actionAcessorEnum).name()); + } else { + actionAcessorInteger = fetchField(packet, Integer.class, 5); + profileAcessor = fetchFieldByName(packet, "player", Object.class); + gamemodeAccessor = fetchField(packet, Integer.class, 6); + pingAcessor = fetchField(packet, Integer.class, 7); + + action = WrappedEnumPlayerInfoAction.values()[fetch(actionAcessorInteger)]; + + WrappedGameProfile profile = new WrappedGameProfile(fetch(profileAcessor)); + WrappedEnumGameMode gamemode = WrappedEnumGameMode.getById(fetch(gamemodeAccessor)); + int ping = fetch(pingAcessor); + playerInfo.add(new WrappedPlayerInfoData(profile, gamemode, ping)); + } + } + + @Override + public void updateObject() { + + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + playerInfoDataClass = Reflections.getNMSClass(packet + "$PlayerInfoData"); + //constructor = playerInfoDataClass.getConstructor(Object.class, int.class, Object.class, Object.class); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutPositionPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutPositionPacket.java new file mode 100644 index 00000000..85e7d7da --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutPositionPacket.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumTeleportFlag; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.bukkit.Location; +import org.bukkit.craftbukkit.libs.jline.internal.Nullable; +import org.bukkit.entity.Player; + +import java.util.*; +import java.util.stream.Collectors; + +@Getter +@NoArgsConstructor +public class WrappedOutPositionPacket extends NMSObject { + private static final String packet = Server.POSITION; + + private static WrappedClass packetClass = Reflections.getNMSClass(packet); + private static WrappedField fieldFlags; + + // Fields + private static FieldAccessor fieldX = fetchField(packet, double.class, 0); + private static FieldAccessor fieldY = fetchField(packet, double.class, 1); + private static FieldAccessor fieldZ = fetchField(packet, double.class, 2); + private static FieldAccessor fieldYaw = fetchField(packet, float.class, 0); + private static FieldAccessor fieldPitch = fetchField(packet, float.class, 1); + + // Decoded data + private double x, y, z; + private float yaw, pitch; + private Set flags = new HashSet<>(); + + public WrappedOutPositionPacket(Object packet, Player player) { + super(packet, player); + } + + public WrappedOutPositionPacket(Location location, int teleportAwait, @Nullable WrappedEnumTeleportFlag... flags) { + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_9)) { + setPacket(packet, location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch(), flags != null ? Arrays.stream(flags).map(WrappedEnumTeleportFlag::getObject).collect(Collectors.toSet()) : new HashSet<>(), teleportAwait); + } else if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_7_10)) { + setPacket(packet, location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch(), flags != null ? Arrays.stream(flags).map(WrappedEnumTeleportFlag::getObject).collect(Collectors.toSet()) : new HashSet<>()); + } else setPacket(packet, location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch(), flags != null); + } + + public WrappedOutPositionPacket(Location location, @Nullable WrappedEnumTeleportFlag... flags) { + this(location, 0, flags); + } + + @Override + public void process(Player player, ProtocolVersion version) { + x = fetch(fieldX); + y = fetch(fieldY); + z = fetch(fieldZ); + yaw = fetch(fieldYaw); + pitch = fetch(fieldPitch); + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + byte flagByte = fetch(fieldFlags); + + if((flagByte & 0x01) == 0x01) { + flags.add(EnumPlayerTeleportFlags.X); + } + if((flagByte & 0x02) == 0x02) { + flags.add(EnumPlayerTeleportFlags.Y); + } + if((flagByte & 0x04) == 0x04) { + flags.add(EnumPlayerTeleportFlags.Z); + } + if((flagByte & 0x08) == 0x08) { + flags.add(EnumPlayerTeleportFlags.Y_ROT); + } + if((flagByte & 0x10) == 0x10) { + flags.add(EnumPlayerTeleportFlags.X_ROT); + } + } else { + Set vflags = fetch(fieldFlags); + + for (Enum vflag : vflags) { + flags.add(EnumPlayerTeleportFlags.valueOf(vflag.name())); + } + } + } + + @Override + public void updateObject() { + + } + + private List toOrdinal(Set enums) { + List ordinals = new ArrayList<>(); + enums.forEach(e -> ordinals.add(e.ordinal())); + return ordinals; + } + + static { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + fieldFlags = packetClass.getFieldByType(byte.class, 0); + } else { + fieldFlags = packetClass.getFieldByType(Set.class, 0); + } + } + + public enum EnumPlayerTeleportFlags { + X(0), + Y(1), + Z(2), + Y_ROT(3), + X_ROT(4); + + private int f; + + private EnumPlayerTeleportFlags(int var3) { + this.f = var3; + } + + private int a() { + return 1 << this.f; + } + + private boolean b(int var1) { + return (var1 & this.a()) == this.a(); + } + + public static Set a(int var0) { + EnumSet var1 = EnumSet.noneOf(EnumPlayerTeleportFlags.class); + EnumPlayerTeleportFlags[] var2 = values(); + int var3 = var2.length; + + for(int var4 = 0; var4 < var3; ++var4) { + EnumPlayerTeleportFlags var5 = var2[var4]; + if (var5.b(var0)) { + var1.add(var5); + } + } + + return var1; + } + + public static int a(Set var0) { + int var1 = 0; + + EnumPlayerTeleportFlags var3; + for(Iterator var2 = var0.iterator(); var2.hasNext(); var1 |= var3.a()) { + var3 = (EnumPlayerTeleportFlags)var2.next(); + } + + return var1; + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutRelativePosition.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutRelativePosition.java new file mode 100644 index 00000000..a6795197 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutRelativePosition.java @@ -0,0 +1,56 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedOutRelativePosition extends NMSObject { + private static final String packet = Server.ENTITY; + + // Fields + private static FieldAccessor fieldId = fetchField(packet, int.class, 0); + private static FieldAccessor fieldX = fetchField(packet, byte.class, 0); + private static FieldAccessor fieldY = fetchField(packet, byte.class, 1); + private static FieldAccessor fieldZ = fetchField(packet, byte.class, 2); + private static FieldAccessor fieldYaw = fetchField(packet, byte.class, 0); + private static FieldAccessor fieldPitch = fetchField(packet, byte.class, 1); + private static FieldAccessor fieldGround = fetchField(packet, boolean.class, 0); + + // Decoded data + private int id; + private byte x, y, z; + private byte yaw, pitch; + private boolean look, pos, ground; + + public WrappedOutRelativePosition(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + String name = getPacketName(); + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + pos = name.equals(Server.LEGACY_REL_POSITION) || name.equals(Server.LEGACY_REL_POSITION_LOOK); + look = name.equals(Server.LEGACY_REL_LOOK) || name.equals(Server.LEGACY_REL_POSITION_LOOK); + } else { + pos = name.equals(Server.REL_POSITION) || name.equals(Server.REL_POSITION_LOOK); + look = name.equals(Server.REL_LOOK) || name.equals(Server.REL_POSITION_LOOK); + } + id = fetch(fieldId); + x = fetch(fieldX); + y = fetch(fieldY); + z = fetch(fieldZ); + yaw = fetch(fieldYaw); + pitch = fetch(fieldPitch); + ground = fetch(fieldGround); + } + + @Override + public void updateObject() { + + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutRespawnPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutRespawnPacket.java new file mode 100644 index 00000000..d261584f --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutRespawnPacket.java @@ -0,0 +1,100 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedConstructor; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumDifficulty; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumGameMode; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.WorldType; +import org.bukkit.entity.Player; + +@Getter +public class WrappedOutRespawnPacket extends NMSObject { + + public WrappedOutRespawnPacket(Object object, Player player) { + super(object, player); + } + + private static String packet = Server.RESPAWN; + + private static FieldAccessor difficultyAcessor; + private static FieldAccessor gamemodeAccessor; + private static FieldAccessor worldTypeAccessor; + private static WrappedClass worldTypeClass, respawnClass = Reflections.getNMSClass(packet); + private static WrappedField worldTypeNameField; + private static WrappedMethod getTypeWorldType; + private static WrappedConstructor emptyConstructor = respawnClass.getConstructor(); + + //Before 1.13 + private static FieldAccessor dimensionAccesor; + + //1.13 and newer version of World ID + private static FieldAccessor dimensionManagerAcceessor; + private static WrappedClass dimensionManagerClass; + private static WrappedField dimensionManagerField; + private static WrappedMethod dimensionManagerFromId; + + private int dimension; + private WrappedEnumGameMode gamemode; + private WrappedEnumDifficulty difficulty; + private WorldType worldType; + + public WrappedOutRespawnPacket() { + setObject(emptyConstructor.newInstance()); + } + + public WrappedOutRespawnPacket(int dimension, WrappedEnumGameMode gamemode, + WrappedEnumDifficulty difficulty, WorldType worldType) { + this.dimension = dimension; + this.gamemode = gamemode; + this.difficulty = difficulty; + this.worldType = worldType; + + updateObject(); + } + + @Override + public void process(Player player, ProtocolVersion version) { + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_13)) { + Object dimensionManager = fetch(dimensionManagerAcceessor); + dimension = dimensionManagerField.get(dimensionManager); + } else { + dimension = fetch(dimensionAccesor); + } + gamemode = WrappedEnumGameMode.fromObject(fetch(gamemodeAccessor)); + difficulty = WrappedEnumDifficulty.fromObject(fetch(difficultyAcessor)); + worldType = WorldType.getByName(worldTypeNameField.get(fetch(worldTypeAccessor))); + } + + @Override + public void updateObject() { + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_13)) { + dimensionManagerAcceessor.set(getObject(), dimensionManagerFromId.invoke(dimension)); + } else dimensionAccesor.set(getObject(), dimension); + gamemodeAccessor.set(getObject(), gamemode.getObject()); + difficultyAcessor.set(getObject(), difficulty.getObject()); + worldTypeAccessor.set(getObject(), getTypeWorldType.invoke(null, worldType.getName())); + } + + static { + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_13)) { + dimensionManagerAcceessor = fetchField(packet, Object.class, 0); + dimensionManagerClass = Reflections.getNMSClass("DimensionManager"); + dimensionManagerField = dimensionManagerClass.getFirstFieldByType(int.class); + dimensionManagerFromId = dimensionManagerClass.getMethod("a", int.class); + } else dimensionAccesor = fetchField(packet, int.class, 0); + + difficultyAcessor = fetchField(packet, Enum.class, 0); + gamemodeAccessor = fetchField(packet, Enum.class, 1); + worldTypeClass = Reflections.getNMSClass("WorldType"); + worldTypeAccessor = fetchField(packet, worldTypeClass.getParent(), 0); + worldTypeNameField = worldTypeClass.getFirstFieldByType(String.class); + getTypeWorldType = worldTypeClass.getMethod("getType", String.class); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutSpawnEntityLivingPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutSpawnEntityLivingPacket.java new file mode 100644 index 00000000..08b9fccb --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutSpawnEntityLivingPacket.java @@ -0,0 +1,109 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.MathHelper; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import java.util.Optional; +import java.util.UUID; + +//TODO Add the ability to use this wrapper to spawn a fake entity and implement other field support. +public class WrappedOutSpawnEntityLivingPacket extends NMSObject { + + public WrappedOutSpawnEntityLivingPacket(Object object, Player player) { + super(object, player); + } + + private static WrappedClass packet = Reflections.getNMSClass(Server.SPAWN_ENTITY_LIVING); + + public Optional entity = Optional.empty(); + public int entityId, type; + public UUID uuid; //1.9+ only + public double x, y, z; //an integer versions below 1.9 + public int yaw, pitch, headPitch; + public byte velocityX, velocityY, velocityZ; + + private static WrappedField fieldEntityId, fieldUuid, fieldType, fieldX, fieldY, fieldZ, + fieldYaw, fieldPitch, fieldHeadPitch, fieldVelocityX, fieldVelocityY, fieldVelocityZ; + + @Override + public void process(Player player, ProtocolVersion version) { + + entityId = fetch(fieldEntityId); + + //if this packet is being sent to this player, the entity will be in the same world. + Optional.ofNullable(Atlas.getInstance().getEntityIds().get(entityId)) + .ifPresent(uuid -> entity = Optional.ofNullable(Atlas.getInstance().getEntities().get(uuid))); + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + x = (int)fetch(fieldX) / 32.; + y = (int)fetch(fieldY) / 32.; + z = (int)fetch(fieldZ) / 32.; + + entity.ifPresent(value -> uuid = value.getUniqueId()); + } else { + x = fetch(fieldX); + y = fetch(fieldY); + z = fetch(fieldZ); + uuid = fetch(fieldUuid); + } + + yaw = fetch(fieldYaw); + pitch = fetch(fieldPitch); + headPitch = fetch(fieldHeadPitch); + velocityX = fetch(fieldVelocityX); + velocityY = fetch(fieldVelocityY); + velocityZ = fetch(fieldVelocityZ); + } + + @Override + public void updateObject() { + set(fieldEntityId, entityId); + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + set(fieldX, MathHelper.floor(x * 32.)); + set(fieldY, MathHelper.floor(y * 32.)); + set(fieldZ, MathHelper.floor(z * 32.)); + } else { + set(fieldX, x); + set(fieldY, y); + set(fieldZ, z); + set(fieldUuid, uuid); + } + + set(fieldYaw, yaw); + set(fieldPitch, pitch); + set(fieldHeadPitch, headPitch); + set(fieldVelocityX, velocityX); + set(fieldVelocityY, velocityY); + set(fieldVelocityZ, velocityZ); + } + + static { + fieldEntityId = fetchField(packet, int.class, 0); + fieldType = fetchField(packet, int.class, 1); + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + fieldX = fetchField(packet, int.class, 2); + fieldY = fetchField(packet, int.class, 3); + fieldZ = fetchField(packet, int.class, 4); + fieldYaw = fetchField(packet, int.class, 5); + fieldPitch = fetchField(packet, int.class, 6); + fieldHeadPitch = fetchField(packet, int.class, 7); + } else { + fieldX = fetchField(packet, double.class, 0); + fieldY = fetchField(packet, double.class, 1); + fieldZ = fetchField(packet, double.class, 2); + fieldYaw = fetchField(packet, int.class, 2); + fieldPitch = fetchField(packet, int.class, 3); + fieldHeadPitch = fetchField(packet, int.class, 4); + fieldUuid = fetchField(packet, UUID.class, 0); + } + fieldVelocityX = fetchField(packet, byte.class, 0); + fieldVelocityY = fetchField(packet, byte.class, 1); + fieldVelocityZ = fetchField(packet, byte.class, 2); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutSpawnEntityPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutSpawnEntityPacket.java new file mode 100644 index 00000000..e9507147 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutSpawnEntityPacket.java @@ -0,0 +1,131 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.GeneralWrapper; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.Packet; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.MathHelper; +import cc.funkemunky.api.utils.MiscUtils; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import java.util.Optional; +import java.util.UUID; + +//TODO 1.15+ compatibility. +public class WrappedOutSpawnEntityPacket extends NMSObject { + + public Optional entity = Optional.empty(); + public int entityId, type; + public UUID uuid; //1.9+ only + public double x, y, z; //an integer versions below 1.9 + public int pitch, yaw, data, velocityX, velocityY, velocityZ; + + private static final WrappedClass packet = Reflections.getNMSClass(Packet.Server.SPAWN_ENTITY); + private static WrappedField fieldEntityId, fieldType, fieldUuid, fieldX, fieldY, fieldZ, fieldYaw, + fieldPitch, fieldData, fieldVelocityX, fieldVelocityY, fieldVelocityZ; + + + public WrappedOutSpawnEntityPacket(Object object, Player player) { + super(object, player); + } + + //TODO Make this so people can create this packet to send. + public WrappedOutSpawnEntityPacket(Entity entity) { + setObject(packet.getConstructor().newInstance()); + this.entityId = entity.getEntityId(); + this.entity = Optional.of(entity); + this.uuid = entity.getUniqueId(); + this.type = entity.getType().getTypeId(); + this.x = entity.getLocation().getX(); + this.y = entity.getLocation().getY(); + this.z = entity.getLocation().getZ(); + this.pitch = MathHelper.d(entity.getLocation().getPitch() * 256.f / 360.f); + this.yaw = MathHelper.d(entity.getLocation().getYaw() * 256.f / 360.f); + + updateObject(); + } + + @Override + public void process(Player player, ProtocolVersion version) { + entityId = fetch(fieldEntityId); + + //if this packet is being sent to this player, the entity will be in the same world. + entity = player.getWorld().getEntities().stream().filter(ent -> ent.getEntityId() == entityId).findFirst(); + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + x = (int)fetch(fieldX) / 32.; + y = (int)fetch(fieldY) / 32.; + z = (int)fetch(fieldZ) / 32.; + entity.ifPresent(ent -> uuid = ent.getUniqueId()); + } else { + x = fetch(fieldX); + y = fetch(fieldY); + z = fetch(fieldZ); + uuid = fetch(fieldUuid); + } + velocityX = fetch(fieldVelocityX); + velocityY = fetch(fieldVelocityY); + velocityZ = fetch(fieldVelocityZ); + pitch = fetch(fieldPitch); + yaw = fetch(fieldYaw); + type = fetch(fieldType); + data = fetch(fieldData); + } + + @Override + public void updateObject() { + set(fieldEntityId, entityId); + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + set(fieldX, MathHelper.floor(x * 32.)); + set(fieldY, MathHelper.floor(y * 32.)); + set(fieldZ, MathHelper.floor(z * 32.)); + } else { + set(fieldX, x); + set(fieldY, y); + set(fieldZ, z); + set(fieldUuid, uuid); + } + + set(fieldVelocityX, velocityX); + set(fieldVelocityY, velocityY); + set(fieldVelocityZ, velocityZ); + set(fieldPitch, pitch); + set(fieldYaw, yaw); + set(fieldType, type); + set(fieldData, data); + } + + static { + fieldEntityId = packet.getFieldByType(int.class, 0); + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + fieldX = packet.getFieldByType(int.class, 1); + fieldY = packet.getFieldByType(int.class, 2); + fieldZ = packet.getFieldByType(int.class, 3); + fieldVelocityX = packet.getFieldByType(int.class, 4); + fieldVelocityY = packet.getFieldByType(int.class, 5); + fieldVelocityZ = packet.getFieldByType(int.class, 6); + fieldPitch = packet.getFieldByType(int.class, 7); + fieldYaw = packet.getFieldByType(int.class, 8); + fieldType = packet.getFieldByType(int.class, 9); + fieldData = packet.getFieldByType(int.class, 10); + } else { + fieldUuid = packet.getFieldByType(UUID.class, 0); + fieldX = packet.getFieldByType(double.class, 0); + fieldY = packet.getFieldByType(double.class, 1); + fieldZ = packet.getFieldByType(double.class, 2); + fieldVelocityX = packet.getFieldByType(int.class, 1); + fieldVelocityY = packet.getFieldByType(int.class, 2); + fieldVelocityZ = packet.getFieldByType(int.class, 3); + fieldPitch = packet.getFieldByType(int.class, 4); + fieldYaw = packet.getFieldByType(int.class, 5); + fieldType = packet.getFieldByType(int.class, 6); + fieldData = packet.getFieldByType(int.class, 7); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutTabComplete.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutTabComplete.java new file mode 100644 index 00000000..e48234d0 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutTabComplete.java @@ -0,0 +1,79 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.v1_13.DontImportIfNotLatestThanks; +import cc.funkemunky.api.tinyprotocol.packet.types.v1_13.WrappedSuggestions; +import org.bukkit.entity.Player; + +public class WrappedOutTabComplete extends NMSObject { + + private static String packet = Server.TAB_COMPLETE; + private static WrappedClass tabClass = Reflections.getNMSClass(packet); + private static WrappedClass suggestionsClass = WrappedSuggestions.suggestionsClass; + private static DontImportIfNotLatestThanks stuff; + + public String[] suggestions; + + //1.13 only + public int id = -1; + + private static WrappedField suggestionsAccessor; + + //1.13 and above + private static WrappedField idAccessor; + + public WrappedOutTabComplete(Object object) { + super(object); + } + + public WrappedOutTabComplete(Object object, Player player) { + super(object, player); + } + + //For everything below 1.13. + public WrappedOutTabComplete(String... result) { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + setPacket(packet, (Object) result); + } + } + + //For 1.13 and above + public WrappedOutTabComplete(int id, String input, String... result) { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) { + Object suggestions = stuff.getSuggestions(input, result); + + setPacket(packet, id, suggestions); + } + } + + @Override + public void process(Player player, ProtocolVersion version) { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + //Getting suggestions. + suggestions = suggestionsAccessor.get(getObject()); + } else { + //Getting suggestions + id = idAccessor.get(getObject()); + suggestions = stuff.getArrayFromSuggestions(suggestionsAccessor.get(getObject())); + } + } + + @Override + public void updateObject() { + + } + + static { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + suggestionsAccessor = tabClass.getFieldByType(String[].class, 0); + } else { + suggestionsAccessor = tabClass.getFieldByType(suggestionsClass.getParent(), 0); + idAccessor = tabClass.getFieldByType(int.class, 0); + stuff = new DontImportIfNotLatestThanks(); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutTransaction.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutTransaction.java new file mode 100644 index 00000000..ced7ee40 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutTransaction.java @@ -0,0 +1,38 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedOutTransaction extends NMSObject { + private static final String packet = Server.TRANSACTION; + private static FieldAccessor fieldId = fetchField(packet, int.class, 0); + private static FieldAccessor fieldAction = fetchField(packet, short.class, 0); + private static FieldAccessor fieldAccepted = fetchField(packet, boolean.class, 0); + private int id; + private short action; + private boolean accept; + + public WrappedOutTransaction(int id, short action, boolean accept) { + setPacket(packet, id, action, accept); + } + + public WrappedOutTransaction(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + id = fetch(fieldId); + action = fetch(fieldAction); + accept = fetch(fieldAccepted); + } + + @Override + public void updateObject() { + + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutVelocityPacket.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutVelocityPacket.java new file mode 100644 index 00000000..01a97823 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedOutVelocityPacket.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.Vec3D; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedOutVelocityPacket extends NMSObject { + private static final String packet = Server.ENTITY_VELOCITY; + + // Fields + private static FieldAccessor fieldId = fetchField(packet, int.class, 0); + private static FieldAccessor fieldX = fetchField(packet, int.class, 1); + private static FieldAccessor fieldY = fetchField(packet, int.class, 2); + private static FieldAccessor fieldZ = fetchField(packet, int.class, 3); + + // Decoded data + private int id; + private double x, y, z; + + //Test to see if this works. + + public WrappedOutVelocityPacket(int entityId, double x, double y, double z) { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_14)) { + setPacket(packet, entityId, x, y, z); + } else setPacket(packet, entityId, new Vec3D(x, y, z).getObject()); //changed to Vec3D for some reason... + } + + public WrappedOutVelocityPacket(Object packet, Player player) { + super(packet, player); + } + + @Override + public void process(Player player, ProtocolVersion version) { + id = fetch(fieldId); + x = fetch(fieldX) / 8000D; + y = fetch(fieldY) / 8000D; + z = fetch(fieldZ) / 8000D; + } + + @Override + public void updateObject() { + set(fieldId, id); + set(fieldX, (int)(x * 8000.)); + set(fieldY, (int)(y * 8000.)); + set(fieldZ, (int)(z * 8000.)); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedPacketPlayOutWorldParticle.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedPacketPlayOutWorldParticle.java new file mode 100644 index 00000000..ab5c2496 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/out/WrappedPacketPlayOutWorldParticle.java @@ -0,0 +1,56 @@ +package cc.funkemunky.api.tinyprotocol.packet.out; + +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.Packet; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumParticle; +import lombok.Getter; + +@Getter +public class WrappedPacketPlayOutWorldParticle extends NMSObject { + + private WrappedEnumParticle type; + private static WrappedClass craftParticle, particle; + private static WrappedMethod toNMS; + private static String packetPlayOutWorldParticle = Packet.Server.WORLD_PARTICLE; + private boolean j; + private float x; + private float y; + private float z; + private float xOffset; + private float yOffset; + private float zOffset; + private float speed; + private int amount; + private int[] data; + + public WrappedPacketPlayOutWorldParticle(WrappedEnumParticle type, boolean var2, float x, float y, float z, float xOffset, float yOffset, float zOffset, float speed, int amount, int... data) { + this.type = type; + this.j = var2; + this.x = x; + this.y = y; + this.z = z; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.speed = speed; + this.amount = amount; + this.data = data; + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_8)) { + setPacket(packetPlayOutWorldParticle, type.getName().toLowerCase(), x, y, z, xOffset, yOffset, zOffset, speed, amount); + } else if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + setPacket(packetPlayOutWorldParticle, type.toNMS(), var2, x, y, z, xOffset, yOffset, zOffset, speed, amount, data); + } else { + setPacket(packetPlayOutWorldParticle, x, y, z, xOffset, yOffset, zOffset, speed, amount, + var2, type.toNMS()); + } + } + + @Override + public void updateObject() { + + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/BaseBlockPosition.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/BaseBlockPosition.java new file mode 100644 index 00000000..380679d4 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/BaseBlockPosition.java @@ -0,0 +1,127 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedConstructor; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; + +public class BaseBlockPosition extends NMSObject { + public static final BaseBlockPosition ZERO = new BaseBlockPosition(0, 0, 0); + private static FieldAccessor fieldX; + private static FieldAccessor fieldY; + private static FieldAccessor fieldZ; + private static WrappedClass baseBlockPositionClass; + private static WrappedClass blockPositionClass; + private static WrappedConstructor blockPosConstructor; + private static WrappedConstructor baseBlockPosConstructor; + private int a; + private int c; + private int d; + + public BaseBlockPosition(Object obj) { + setObject(obj); + this.a = fetch(fieldX); + this.c = fetch(fieldY); + this.d = fetch(fieldZ); + } + + public BaseBlockPosition(int var1, int var2, int var3) { + this.a = var1; + this.c = var2; + this.d = var3; + } + + public BaseBlockPosition(double var1, double var3, double var5) { + this(MathHelper.floor(var1), MathHelper.floor(var3), MathHelper.floor(var5)); + } + + public boolean equals(Object var1) { + if (this == var1) { + return true; + } else if (!(var1 instanceof BaseBlockPosition)) { + return false; + } else { + BaseBlockPosition var2 = (BaseBlockPosition) var1; + if (this.getX() != var2.getX()) { + return false; + } else if (this.getY() != var2.getY()) { + return false; + } else { + return this.getZ() == var2.getZ(); + } + } + } + + public int hashCode() { + return (this.getY() + this.getZ() * 31) * 31 + this.getX(); + } + + public int g(BaseBlockPosition var1) { + if (this.getY() == var1.getY()) { + return this.getZ() == var1.getZ() ? this.getX() - var1.getX() : this.getZ() - var1.getZ(); + } else { + return this.getY() - var1.getY(); + } + } + + public int getX() { + return this.a; + } + + public int getY() { + return this.c; + } + + public int getZ() { + return this.d; + } + + public BaseBlockPosition d(BaseBlockPosition var1) { + return new BaseBlockPosition(this.getY() * var1.getZ() - this.getZ() * var1.getY(), this.getZ() * var1.getX() - this.getX() * var1.getZ(), this.getX() * var1.getY() - this.getY() * var1.getX()); + } + + public double c(double var1, double var3, double var5) { + double var7 = this.getX() - var1; + double var9 = this.getY() - var3; + double var11 = this.getZ() - var5; + return var7 * var7 + var9 * var9 + var11 * var11; + } + + public double d(double var1, double var3, double var5) { + double var7 = this.getX() + 0.5D - var1; + double var9 = this.getY() + 0.5D - var3; + double var11 = this.getZ() + 0.5D - var5; + return var7 * var7 + var9 * var9 + var11 * var11; + } + + public double i(BaseBlockPosition var1) { + return this.c(var1.getX(), var1.getY(), var1.getZ()); + } + + public T getAsBaseBlockPosition() { + return baseBlockPosConstructor.newInstance(getX(), getY(), getZ()); + } + + public T getAsBlockPosition() { + return blockPosConstructor.newInstance(getX(), getY(), getZ()); + } + + @Override + public void updateObject() { + + } + + static { + if(ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_7_10)) { + fieldX = fetchField(Type.BASEBLOCKPOSITION, int.class, 0); + fieldY = fetchField(Type.BASEBLOCKPOSITION, int.class, 1); + fieldZ = fetchField(Type.BASEBLOCKPOSITION, int.class, 2); + baseBlockPositionClass = Reflections.getNMSClass("BaseBlockPosition"); + blockPositionClass = Reflections.getNMSClass("BlockPosition"); + blockPosConstructor = blockPositionClass.getConstructor(int.class, int.class, int.class); + baseBlockPosConstructor = baseBlockPositionClass.getConstructor(int.class, int.class, int.class); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/MathHelper.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/MathHelper.java new file mode 100644 index 00000000..daf7616e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/MathHelper.java @@ -0,0 +1,308 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import java.util.Random; +import java.util.UUID; + +public class MathHelper { + public static final float a = c(2.0F); + private static final float[] b = new float[65536]; + private static final int[] c; + private static final double d; + private static final double[] e; + private static final double[] f; + + static { + int var0; + for (var0 = 0; var0 < 65536; ++var0) { + b[var0] = (float) Math.sin((double) var0 * 3.141592653589793D * 2.0D / 65536.0D); + } + + c = new int[]{0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; + d = Double.longBitsToDouble(4805340802404319232L); + e = new double[257]; + f = new double[257]; + + for (var0 = 0; var0 < 257; ++var0) { + double var1 = (double) var0 / 256.0D; + double var3 = Math.asin(var1); + f[var0] = Math.cos(var3); + e[var0] = var3; + } + + } + + public static float sin(float var0) { + return b[(int) (var0 * 10430.378F) & '\uffff']; + } + + public static float cos(float var0) { + return b[(int) (var0 * 10430.378F + 16384.0F) & '\uffff']; + } + + public static float c(float var0) { + return (float) Math.sqrt((double) var0); + } + + public static float sqrt(double var0) { + return (float) Math.sqrt(var0); + } + + public static int d(float var0) { + int var1 = (int) var0; + return var0 < (float) var1 ? var1 - 1 : var1; + } + + public static int floor(double var0) { + int var2 = (int) var0; + return var0 < (double) var2 ? var2 - 1 : var2; + } + + public static long d(double var0) { + long var2 = (long) var0; + return var0 < (double) var2 ? var2 - 1L : var2; + } + + public static float e(float var0) { + return var0 >= 0.0F ? var0 : -var0; + } + + public static int a(int var0) { + return var0 >= 0 ? var0 : -var0; + } + + public static int f(float var0) { + int var1 = (int) var0; + return var0 > (float) var1 ? var1 + 1 : var1; + } + + public static int f(double var0) { + int var2 = (int) var0; + return var0 > (double) var2 ? var2 + 1 : var2; + } + + public static int clamp(int var0, int var1, int var2) { + if (var0 < var1) { + return var1; + } else { + return var0 > var2 ? var2 : var0; + } + } + + public static float a(float var0, float var1, float var2) { + if (var0 < var1) { + return var1; + } else { + return var0 > var2 ? var2 : var0; + } + } + + public static double a(double var0, double var2, double var4) { + if (var0 < var2) { + return var2; + } else { + return var0 > var4 ? var4 : var0; + } + } + + public static double b(double var0, double var2, double var4) { + if (var4 < 0.0D) { + return var0; + } else { + return var4 > 1.0D ? var2 : var0 + (var2 - var0) * var4; + } + } + + public static double a(double var0, double var2) { + if (var0 < 0.0D) { + var0 = -var0; + } + + if (var2 < 0.0D) { + var2 = -var2; + } + + return var0 > var2 ? var0 : var2; + } + + public static int nextInt(Random var0, int var1, int var2) { + return var1 >= var2 ? var1 : var0.nextInt(var2 - var1 + 1) + var1; + } + + public static float a(Random var0, float var1, float var2) { + return var1 >= var2 ? var1 : var0.nextFloat() * (var2 - var1) + var1; + } + + public static double a(Random var0, double var1, double var3) { + return var1 >= var3 ? var1 : var0.nextDouble() * (var3 - var1) + var1; + } + + public static double a(long[] var0) { + long var1 = 0L; + long[] var3 = var0; + int var4 = var0.length; + + for (int var5 = 0; var5 < var4; ++var5) { + long var6 = var3[var5]; + var1 += var6; + } + + return (double) var1 / (double) var0.length; + } + + public static float g(float var0) { + var0 %= 360.0F; + if (var0 >= 180.0F) { + var0 -= 360.0F; + } + + if (var0 < -180.0F) { + var0 += 360.0F; + } + + return var0; + } + + public static double g(double var0) { + var0 %= 360.0D; + if (var0 >= 180.0D) { + var0 -= 360.0D; + } + + if (var0 < -180.0D) { + var0 += 360.0D; + } + + return var0; + } + + public static int a(String var0, int var1) { + try { + return Integer.parseInt(var0); + } catch (Throwable var3) { + return var1; + } + } + + public static int a(String var0, int var1, int var2) { + return Math.max(var2, a(var0, var1)); + } + + public static double a(String var0, double var1) { + try { + return Double.parseDouble(var0); + } catch (Throwable var4) { + return var1; + } + } + + public static double a(String var0, double var1, double var3) { + return Math.max(var3, a(var0, var1)); + } + + public static int b(int var0) { + int var1 = var0 - 1; + var1 |= var1 >> 1; + var1 |= var1 >> 2; + var1 |= var1 >> 4; + var1 |= var1 >> 8; + var1 |= var1 >> 16; + return var1 + 1; + } + + private static boolean d(int var0) { + return var0 != 0 && (var0 & var0 - 1) == 0; + } + + private static int e(int var0) { + var0 = d(var0) ? var0 : b(var0); + return c[(int) ((long) var0 * 125613361L >> 27) & 31]; + } + + public static int c(int var0) { + return e(var0) - (d(var0) ? 0 : 1); + } + + public static int c(int var0, int var1) { + if (var1 == 0) { + return 0; + } else if (var0 == 0) { + return var1; + } else { + if (var0 < 0) { + var1 *= -1; + } + + int var2 = var0 % var1; + return var2 == 0 ? var0 : var0 + var1 - var2; + } + } + + public static UUID a(Random var0) { + long var1 = var0.nextLong() & -61441L | 16384L; + long var3 = var0.nextLong() & 4611686018427387903L | -9223372036854775808L; + return new UUID(var1, var3); + } + + public static double c(double var0, double var2, double var4) { + return (var0 - var2) / (var4 - var2); + } + + public static double b(double var0, double var2) { + double var4 = var2 * var2 + var0 * var0; + if (Double.isNaN(var4)) { + return 0.0D / 0.0; + } else { + boolean var6 = var0 < 0.0D; + if (var6) { + var0 = -var0; + } + + boolean var7 = var2 < 0.0D; + if (var7) { + var2 = -var2; + } + + boolean var8 = var0 > var2; + double var9; + if (var8) { + var9 = var2; + var2 = var0; + var0 = var9; + } + + var9 = i(var4); + var2 *= var9; + var0 *= var9; + double var11 = d + var0; + int var13 = (int) Double.doubleToRawLongBits(var11); + double var14 = e[var13]; + double var16 = f[var13]; + double var18 = var11 - d; + double var20 = var0 * var16 - var2 * var18; + double var22 = (6.0D + var20 * var20) * var20 * 0.16666666666666666D; + double var24 = var14 + var22; + if (var8) { + var24 = 1.5707963267948966D - var24; + } + + if (var7) { + var24 = 3.141592653589793D - var24; + } + + if (var6) { + var24 = -var24; + } + + return var24; + } + } + + public static double i(double var0) { + double var2 = 0.5D * var0; + long var4 = Double.doubleToRawLongBits(var0); + var4 = 6910469410427058090L - (var4 >> 1); + var0 = Double.longBitsToDouble(var4); + var0 *= 1.5D - var2 * var0 * var0; + return var0; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/Vec3D.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/Vec3D.java new file mode 100644 index 00000000..de99170f --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/Vec3D.java @@ -0,0 +1,149 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.reflections.types.WrappedConstructor; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; + +public class Vec3D extends NMSObject { + private static FieldAccessor fieldX = fetchField("Vec3D", double.class, 0); + private static FieldAccessor fieldY = fetchField("Vec3D", double.class, 1); + private static FieldAccessor fieldZ = fetchField("Vec3D", double.class, 2); + private static WrappedConstructor vec3dConst = MinecraftReflection.vec3D + .getConstructor(double.class, double.class, double.class); + public final double a; + public final double b; + public final double c; + + public Vec3D(Object obj) { + setObject(obj); + this.a = fetch(fieldX); + this.b = fetch(fieldY); + this.c = fetch(fieldZ); + } + + public Vec3D(double var1, double var3, double var5) { + if (var1 == -0.0D) { + var1 = 0.0D; + } + + if (var3 == -0.0D) { + var3 = 0.0D; + } + + if (var5 == -0.0D) { + var5 = 0.0D; + } + + this.a = var1; + this.b = var3; + this.c = var5; + + setObject(vec3dConst.newInstance(a, b, c)); + } + + public Vec3D(BaseBlockPosition var1) { + this(var1.getX(), var1.getY(), var1.getZ()); + } + + public Vec3D a() { + double var1 = MathHelper.sqrt(this.a * this.a + this.b * this.b + this.c * this.c); + return var1 < 1.0E-4D ? new Vec3D(0.0D, 0.0D, 0.0D) : new Vec3D(this.a / var1, this.b / var1, this.c / var1); + } + + public double b(Vec3D var1) { + return this.a * var1.a + this.b * var1.b + this.c * var1.c; + } + + public Vec3D d(Vec3D var1) { + return this.a(var1.a, var1.b, var1.c); + } + + public Vec3D a(double var1, double var3, double var5) { + return this.add(-var1, -var3, -var5); + } + + public Vec3D e(Vec3D var1) { + return this.add(var1.a, var1.b, var1.c); + } + + public Vec3D add(double var1, double var3, double var5) { + return new Vec3D(this.a + var1, this.b + var3, this.c + var5); + } + + public double distanceSquared(Vec3D var1) { + double var2 = var1.a - this.a; + double var4 = var1.b - this.b; + double var6 = var1.c - this.c; + return var2 * var2 + var4 * var4 + var6 * var6; + } + + public double b() { + return MathHelper.sqrt(this.a * this.a + this.b * this.b + this.c * this.c); + } + + public Vec3D a(Vec3D var1, double var2) { + double var4 = var1.a - this.a; + double var6 = var1.b - this.b; + double var8 = var1.c - this.c; + if (var4 * var4 < 1.0000000116860974E-7D) { + return null; + } else { + double var10 = (var2 - this.a) / var4; + return var10 >= 0.0D && var10 <= 1.0D ? new Vec3D(this.a + var4 * var10, this.b + var6 * var10, this.c + var8 * var10) : null; + } + } + + public Vec3D b(Vec3D var1, double var2) { + double var4 = var1.a - this.a; + double var6 = var1.b - this.b; + double var8 = var1.c - this.c; + if (var6 * var6 < 1.0000000116860974E-7D) { + return null; + } else { + double var10 = (var2 - this.b) / var6; + return var10 >= 0.0D && var10 <= 1.0D ? new Vec3D(this.a + var4 * var10, this.b + var6 * var10, this.c + var8 * var10) : null; + } + } + + public Vec3D c(Vec3D var1, double var2) { + double var4 = var1.a - this.a; + double var6 = var1.b - this.b; + double var8 = var1.c - this.c; + if (var8 * var8 < 1.0000000116860974E-7D) { + return null; + } else { + double var10 = (var2 - this.c) / var8; + return var10 >= 0.0D && var10 <= 1.0D ? new Vec3D(this.a + var4 * var10, this.b + var6 * var10, this.c + var8 * var10) : null; + } + } + + public String toString() { + return "(" + this.a + ", " + this.b + ", " + this.c + ")"; + } + + public Vec3D a(float var1) { + float var2 = MathHelper.cos(var1); + float var3 = MathHelper.sin(var1); + double var4 = this.a; + double var6 = this.b * var2 + this.c * var3; + double var8 = this.c * var2 - this.b * var3; + return new Vec3D(var4, var6, var8); + } + + public Vec3D b(float var1) { + float var2 = MathHelper.cos(var1); + float var3 = MathHelper.sin(var1); + double var4 = this.a * var2 + this.c * var3; + double var6 = this.b; + double var8 = this.c * var2 - this.a * var3; + return new Vec3D(var4, var6, var8); + } + + @Override + public void updateObject() { + fieldX.set(getObject(), a); + fieldY.set(getObject(), b); + fieldZ.set(getObject(), c); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChatComponent.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChatComponent.java new file mode 100644 index 00000000..f4c9549e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChatComponent.java @@ -0,0 +1,30 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedChatComponent extends NMSObject { + + private static WrappedMethod getText = MinecraftReflection.iChatBaseComponent.getMethod("getText"); + + public WrappedChatComponent(Object object) { + super(object); + } + + private String text = ""; + + @Override + public void process(Player player, ProtocolVersion version) { + text = getText.invoke(getObject()); + } + + @Override + public void updateObject() { + + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChatMessage.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChatMessage.java new file mode 100644 index 00000000..3f981fbe --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChatMessage.java @@ -0,0 +1,48 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import lombok.Getter; +import org.bukkit.entity.Player; + +@Getter +public class WrappedChatMessage extends NMSObject { + private static String type = Type.CHATMESSAGE; + + private String chatMessage; + private Object[] objects; + + private static WrappedClass chatMessageClass = Reflections.getNMSClass("ChatMessage"); + private static WrappedField messageField = chatMessageClass.getFieldByType(String.class, 0); + private static WrappedField objectsField = chatMessageClass.getFieldByType(Object[].class, 0); + + public WrappedChatMessage(String chatMessage, Object... object) { + this.chatMessage = chatMessage; + this.objects = object; + + setObject(chatMessageClass.getConstructorAtIndex(0).newInstance(chatMessage, object)); + } + + public WrappedChatMessage(String chatMessage) { + this(chatMessage, new Object[]{}); + } + + public WrappedChatMessage(Object object) { + super(object); + } + + @Override + public void process(Player player, ProtocolVersion version) { + chatMessage = fetch(messageField); + objects = fetch(objectsField); + } + + @Override + public void updateObject() { + messageField.set(getObject(), chatMessage); + objectsField.set(getObject(), objects); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChatMessageType.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChatMessageType.java new file mode 100644 index 00000000..944aceb1 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChatMessageType.java @@ -0,0 +1,60 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedConstructor; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +@RequiredArgsConstructor +@Getter +public enum WrappedChatMessageType { + CHAT(0), + SYSTEM(1), + GAME_INFO(2); + + private final int type; + + public byte getTypeAsByte() { + return (byte)type; + } + + public T toNMS() { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_12)) { + return (T)(Byte)getTypeAsByte(); + } else { + return chatMsgConst.newInstance(getTypeAsByte()); + } + } + + private static WrappedClass chatMsgTypeClass; + private static WrappedConstructor chatMsgConst; + private static WrappedField chatMsgByteField; + + public static WrappedChatMessageType fromNMS(Object object) { + if(object instanceof Byte) { + return fromByte((byte)object); + } else if(object instanceof Integer) { + return fromByte((byte)(int)object); + } else { + return fromByte(chatMsgByteField.get(object)); + } + } + + public static WrappedChatMessageType fromByte(byte b) { + return Arrays.stream(values()) + .filter(type -> type.getTypeAsByte() == b).findFirst().orElse(WrappedChatMessageType.CHAT); + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_12)) { + chatMsgTypeClass = Reflections.getNMSClass("ChatMessageType"); + chatMsgTypeClass.getConstructor(byte.class); + chatMsgTypeClass.getFieldByType(byte.class, 0); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChunkCoordIntPair.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChunkCoordIntPair.java new file mode 100644 index 00000000..54c3cc60 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedChunkCoordIntPair.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedConstructor; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.Packet; + +public class WrappedChunkCoordIntPair extends NMSObject { + + private static WrappedClass vanillaClass = Reflections.getClass(Packet.Type.CHUNKCOORDINTPAIR); + + private static WrappedField fieldX = fetchField(vanillaClass, int.class, 0), + fieldZ = fetchField(vanillaClass, int.class, 1); + private static WrappedConstructor constructor = vanillaClass.getConstructor(int.class, int.class); + + public WrappedChunkCoordIntPair(Object object) { + super(object); + } + + public int x, z; + + public WrappedChunkCoordIntPair(int x, int z) { + super((Object)constructor.newInstance(x, z)); + this.x = x; + this.z = z; + } + + @Override + public void updateObject() { + fieldX.set(getObject(), x); + fieldZ.set(getObject(), z); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedGameProfile.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedGameProfile.java new file mode 100644 index 00000000..b12485a2 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedGameProfile.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import cc.funkemunky.api.tinyprotocol.reflection.Reflection; +import cc.funkemunky.api.utils.ReflectionsUtil; +import lombok.Getter; +import org.bukkit.entity.Player; + +import java.util.UUID; + +@Getter +public class WrappedGameProfile extends NMSObject { + private static final String type = Type.GAMEPROFILE; + + // Fields + private static FieldAccessor fieldId = fetchField(type, UUID.class, 0); + private static FieldAccessor fieldName = fetchField(type, String.class, 0); + private static FieldAccessor fieldPropertyMap = fetchField(type, Reflection.getClass(Type.PROPERTYMAP), 0); + + // Decoded data + public UUID id; + public String name; + public Object propertyMap; + + public WrappedGameProfile(Object type) { + super(type); + } + + public WrappedGameProfile(Player player) { + Object entityPlayer = ReflectionsUtil.getEntityPlayer(player); + FieldAccessor gameProfileAcessor = fetchField("EntityHuman", Reflection.NMS_PREFIX + type, 0); + setObject(fetch(gameProfileAcessor)); + id = fieldId.get(getObject()); + name = fieldName.get(getObject()); + propertyMap = fieldPropertyMap.get(getObject()); + } + + @Override + public void process(Player player, ProtocolVersion version) { + id = fieldId.get(getObject()); + name = fieldName.get(getObject()); + propertyMap = fieldPropertyMap.get(getObject()); + } + + @Override + public void updateObject() { + + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedMinecraftKey.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedMinecraftKey.java new file mode 100644 index 00000000..4417af53 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedMinecraftKey.java @@ -0,0 +1,34 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import org.bukkit.entity.Player; + +public class WrappedMinecraftKey extends NMSObject { + + public static WrappedClass vanilla = Reflections.getNMSClass("MinecraftKey"); + + public WrappedMinecraftKey(Object object) { + super(object); + } + + public String namespace = "N/A", key = "N/A"; + + private static WrappedField fieldNameSpace = fetchField(vanilla, String.class, 0), + fieldKey = fetchField(vanilla, String.class, 1); + + @Override + public void process(Player player, ProtocolVersion version) { + namespace = fetch(fieldNameSpace); + key = fetch(fieldKey); + } + + @Override + public void updateObject() { + set(fieldNameSpace, namespace); + set(fieldKey, key); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedPacketDataSerializer.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedPacketDataSerializer.java new file mode 100644 index 00000000..af6891cb --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedPacketDataSerializer.java @@ -0,0 +1,43 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedConstructor; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import lombok.Getter; + +@Getter +public class WrappedPacketDataSerializer extends NMSObject { + + public static WrappedClass vanillaClass = Reflections.getNMSClass("PacketDataSerializer"); + private static WrappedMethod readBytesMethod = vanillaClass.getMethod("array"); + private static WrappedMethod hasArray = vanillaClass.getMethod("hasArray"); + private static WrappedConstructor byteConst = vanillaClass.getConstructor(ByteBuf.class); + + private byte[] data; + + public WrappedPacketDataSerializer(Object object) { + super(object); + + boolean hasArray = WrappedPacketDataSerializer.hasArray.invoke(object); + + if(hasArray) + data = readBytesMethod.invoke(object); + else data = new byte[0]; + } + + @Override + public void updateObject() { + //Empty method + } + + public WrappedPacketDataSerializer(byte[] data) { + Object pds = byteConst.newInstance(Unpooled.wrappedBuffer(data)); + + this.data = data; + setObject(pds); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedPlayerInfoData.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedPlayerInfoData.java new file mode 100644 index 00000000..795d9cbd --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedPlayerInfoData.java @@ -0,0 +1,54 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumGameMode; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.NoArgsConstructor; +import org.bukkit.entity.Player; + +@NoArgsConstructor +public class WrappedPlayerInfoData extends NMSObject { + private static String type = Type.PLAYERINFODATA; + + private static FieldAccessor enumGamemodeAccessor = fetchField(type, Enum.class, 0); + private static FieldAccessor profileAcessor = fetchFieldByName(type, "d", Object.class); + private static FieldAccessor pingAcessor = fetchField(type, Integer.class, 0); + + private int ping; + private WrappedEnumGameMode gameMode; + private WrappedGameProfile gameProfile; + private String username = ""; + + public WrappedPlayerInfoData(Object object, Player player) { + super(object, player); + } + + public WrappedPlayerInfoData(Object object) { + super(object); + ping = fetch(pingAcessor); + gameProfile = new WrappedGameProfile(fetch(profileAcessor)); + gameMode = WrappedEnumGameMode.fromObject(fetch(enumGamemodeAccessor)); + } + + public WrappedPlayerInfoData(WrappedGameProfile gameProfile, WrappedEnumGameMode gameMode, int ping) { + this.ping = ping; + this.gameProfile = gameProfile; + this.gameMode = gameMode; + } + + @Override + public void process(Player player, ProtocolVersion version) { + super.process(player, version); + + ping = fetch(pingAcessor); + gameProfile = new WrappedGameProfile(fetch(profileAcessor)); + gameMode = WrappedEnumGameMode.fromObject(fetch(enumGamemodeAccessor)); + username = player.getName(); + } + + @Override + public void updateObject() { + + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedWatchableObject.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedWatchableObject.java new file mode 100644 index 00000000..ecfacacb --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/WrappedWatchableObject.java @@ -0,0 +1,93 @@ +package cc.funkemunky.api.tinyprotocol.packet.types; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.tinyprotocol.api.NMSObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.FieldAccessor; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.entity.Player; + +@AllArgsConstructor +@Getter +@Setter +public class WrappedWatchableObject extends NMSObject { + private static String type = Type.WATCHABLE_OBJECT; + private static FieldAccessor firstIntField; + private static FieldAccessor dataValueIdField; + private static FieldAccessor dataWatcherObjectField; + private static FieldAccessor dataWatcherObjectIdField; + private static FieldAccessor dataSerializerField; + private static FieldAccessor watchedObjectField; + private static FieldAccessor watchedField; + private static WrappedClass c = Reflections.getNMSClass(type); + + private int firstInt, dataValueId; + private Object watchedObject, dataWatcherObject, serializer; + private boolean watched; + + public WrappedWatchableObject(Object object) { + super(object); + } + + @Override + public void process(Player player, ProtocolVersion version) { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + firstInt = fetch(firstIntField); + dataValueId = fetch(dataValueIdField); + } else { + firstInt = -1; + dataWatcherObject = fetch(dataWatcherObjectField); + dataValueId = dataWatcherObjectIdField.get(dataWatcherObject); + serializer = dataSerializerField.get(dataWatcherObject); + } + watchedObject = fetch(watchedObjectField); + watched = fetch(watchedField); + } + + //For 1.8.9 and below. + public void setPacket(int type, int data, Object watchedObject) { + Object o = c.getConstructor(int.class, int.class, Object.class).newInstance(type, data, watchedObject); + + setObject(o); + } + + //For 1.9 and above. + public void setPacket(Object serializer, int data, Object watchedObject) { + WrappedClass dwoC = Reflections.getNMSClass("DataWatcherObject"), + dwsC = Reflections.getNMSClass("DataWatcherSerializer"); + + setPacket(c.getConstructor(dwoC.getParent(), Object.class) + .newInstance( + dwoC.getConstructor(int.class, dwsC.getParent()) + .newInstance(data, serializer), + watchedObject)); + } + + //For 1.9 and above. + public void setPacket(Object dataWatcherObject, Object watchedObject) { + setObject(c.getConstructor(dataWatcherObject.getClass(), Object.class) + .newInstance(dataWatcherObject, watchedObject)); + } + + @Override + public void updateObject() { + + } + + static { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + firstIntField = fetchField(type, int.class, 0); + dataValueIdField = fetchField(type, int.class, 1); + watchedObjectField = fetchField(type, Object.class, 0); + } else { + dataWatcherObjectField = fetchField(type, Object.class, 0); + watchedObjectField = fetchField(type, Object.class, 1); + dataWatcherObjectIdField = fetchField("DataWatcherObject", int.class, 0); + dataSerializerField = fetchField("DataWatcherObject", Object.class, 0); + } + watchedField = fetchField(type, boolean.class, 0); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumAnimation.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumAnimation.java new file mode 100644 index 00000000..922fff12 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumAnimation.java @@ -0,0 +1,30 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.enums; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; + +public enum WrappedEnumAnimation { + NONE, + EAT, + DRINK, + BLOCK, + BOW, + SPEAR, + CROSSBOW; + + private static WrappedClass enumAnimation; + + public static WrappedEnumAnimation fromNMS(Object vanillaObject) { + Enum vanilla = (Enum) vanillaObject; + + return valueOf(vanilla.name().toUpperCase()); + } + + public Enum toVanilla() { + return enumAnimation.getEnum(name().toUpperCase()); + } + + static { + enumAnimation = Reflections.getNMSClass("EnumAnimation"); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumDifficulty.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumDifficulty.java new file mode 100644 index 00000000..b3f48ef6 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumDifficulty.java @@ -0,0 +1,60 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.enums; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; + +public enum WrappedEnumDifficulty { + PEACEFUL(0, "options.difficulty.peaceful"), + EASY(1, "options.difficulty.easy"), + NORMAL(2, "options.difficulty.normal"), + HARD(3, "options.difficulty.hard"); + + private static final WrappedEnumDifficulty[] e = new WrappedEnumDifficulty[values().length]; + private final int f; + private final String g; + private static final WrappedClass enumDifficulty = Reflections.getNMSClass("EnumDifficulty"); + + private WrappedEnumDifficulty(int var3, String var4) { + this.f = var3; + this.g = var4; + } + + public int a() { + return this.f; + } + + public static WrappedEnumDifficulty getById(int var0) { + return e[var0 % e.length]; + } + + public String b() { + return this.g; + } + + static { + WrappedEnumDifficulty[] var0 = values(); + int var1 = var0.length; + + for(int var2 = 0; var2 < var1; ++var2) { + WrappedEnumDifficulty var3 = var0[var2]; + e[var3.f] = var3; + } + + } + + public static WrappedEnumDifficulty getByName(String name) { + for(WrappedEnumDifficulty var : values()) { + if(!var.name().equals(name)) continue; + return var; + } + return PEACEFUL; + } + + public Object getObject() { + return enumDifficulty.getEnum(this.name()); + } + + public static WrappedEnumDifficulty fromObject(Enum var) { + return getByName(var.name()); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumDirection.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumDirection.java new file mode 100644 index 00000000..081e002c --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumDirection.java @@ -0,0 +1,225 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.enums; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.packet.types.BaseBlockPosition; +import cc.funkemunky.api.tinyprotocol.packet.types.MathHelper; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +public enum WrappedEnumDirection { + DOWN(1, -1, "down", WrappedEnumDirection.EnumAxisDirection.NEGATIVE, WrappedEnumDirection.EnumAxis.Y, new BaseBlockPosition(0, -1, 0)), + UP(0, -1, "up", WrappedEnumDirection.EnumAxisDirection.POSITIVE, WrappedEnumDirection.EnumAxis.Y, new BaseBlockPosition(0, 1, 0)), + NORTH(3, 2, "north", WrappedEnumDirection.EnumAxisDirection.NEGATIVE, WrappedEnumDirection.EnumAxis.Z, new BaseBlockPosition(0, 0, -1)), + SOUTH(2, 0, "south", WrappedEnumDirection.EnumAxisDirection.POSITIVE, WrappedEnumDirection.EnumAxis.Z, new BaseBlockPosition(0, 0, 1)), + WEST(5, 1, "west", WrappedEnumDirection.EnumAxisDirection.NEGATIVE, WrappedEnumDirection.EnumAxis.X, new BaseBlockPosition(-1, 0, 0)), + EAST(4, 3, "east", WrappedEnumDirection.EnumAxisDirection.POSITIVE, WrappedEnumDirection.EnumAxis.X, new BaseBlockPosition(1, 0, 0)); + + private static final WrappedEnumDirection[] n = new WrappedEnumDirection[6]; + private static final WrappedEnumDirection[] o = new WrappedEnumDirection[4]; + private static final Map p = new HashMap<>(); + + static { + WrappedEnumDirection[] var0 = values(); + + for (WrappedEnumDirection var3 : var0) { + n[var3.ordinal()] = var3; + if (var3.k().c()) { + o[var3.i] = var3; + } + + p.put(var3.j().toLowerCase(), var3); + } + + } + + private final int h; + private final int i; + private final String j; + private final WrappedEnumDirection.EnumAxis k; + private final WrappedEnumDirection.EnumAxisDirection l; + private final BaseBlockPosition m; + public static WrappedClass enumDirection; + + private WrappedEnumDirection(int order, int offset, String direction, WrappedEnumDirection.EnumAxisDirection axisDirection, WrappedEnumDirection.EnumAxis axis, BaseBlockPosition offsetPosition) { + this.i = offset; + this.h = order; + this.j = direction; + this.k = axis; + this.l = axisDirection; + this.m = offsetPosition; + } + + public static WrappedEnumDirection fromType1(int var0) { + return n[MathHelper.a(var0 % n.length)]; + } + + public static WrappedEnumDirection fromType2(int var0) { + return o[MathHelper.a(var0 % o.length)]; + } + + public static WrappedEnumDirection fromAngle(double var0) { + return fromType2(MathHelper.floor(var0 / 90.0D + 0.5D) & 3); + } + + public static WrappedEnumDirection a(Random var0) { + return values()[var0.nextInt(values().length)]; + } + + public static WrappedEnumDirection a(WrappedEnumDirection.EnumAxisDirection var0, WrappedEnumDirection.EnumAxis var1) { + WrappedEnumDirection[] var2 = values(); + int var3 = var2.length; + + for (int var4 = 0; var4 < var3; ++var4) { + WrappedEnumDirection var5 = var2[var4]; + if (var5.c() == var0 && var5.k() == var1) { + return var5; + } + } + + throw new IllegalArgumentException("No such direction: " + var0 + " " + var1); + } + + public int b() { + return this.i; + } + + public WrappedEnumDirection.EnumAxisDirection c() { + return this.l; + } + + public WrappedEnumDirection opposite() { + return fromType1(this.h); + } + + public int getAdjacentX() { + return this.k == WrappedEnumDirection.EnumAxis.X ? this.l.a() : 0; + } + + public int getAdjacentY() { + return this.k == WrappedEnumDirection.EnumAxis.Y ? this.l.a() : 0; + } + + public int getAdjacentZ() { + return this.k == WrappedEnumDirection.EnumAxis.Z ? this.l.a() : 0; + } + + public String j() { + return this.j; + } + + public WrappedEnumDirection.EnumAxis k() { + return this.k; + } + + public String toString() { + return this.j; + } + + public String getName() { + return this.j; + } + + public static WrappedEnumDirection fromVanilla(Enum object) { + return Arrays.stream(values()).filter(val -> val.name().equals(object.name())).findFirst() + .orElse(WrappedEnumDirection.UP); + } + + public T toVanilla() { + return (T) enumDirection.getEnum(name()); + } + + public static enum EnumDirectionLimit { + HORIZONTAL, + VERTICAL; + + public boolean a(WrappedEnumDirection var1) { + return var1 != null && var1.k().d() == this; + } + } + + public static enum EnumAxisDirection { + POSITIVE(1, "Towards positive"), + NEGATIVE(-1, "Towards negative"); + + private final int c; + private final String d; + + private EnumAxisDirection(int var3, String var4) { + this.c = var3; + this.d = var4; + } + + public int a() { + return this.c; + } + + public String toString() { + return this.d; + } + } + + public static enum EnumAxis { + X("x", WrappedEnumDirection.EnumDirectionLimit.HORIZONTAL), + Y("y", WrappedEnumDirection.EnumDirectionLimit.VERTICAL), + Z("z", WrappedEnumDirection.EnumDirectionLimit.HORIZONTAL); + + private static final Map d = new HashMap<>(); + + static { + WrappedEnumDirection.EnumAxis[] var0 = values(); + int var1 = var0.length; + + for (int var2 = 0; var2 < var1; ++var2) { + WrappedEnumDirection.EnumAxis var3 = var0[var2]; + d.put(var3.a().toLowerCase(), var3); + } + } + + private final String e; + private final WrappedEnumDirection.EnumDirectionLimit f; + + private EnumAxis(String var3, WrappedEnumDirection.EnumDirectionLimit var4) { + this.e = var3; + this.f = var4; + } + + public String a() { + return this.e; + } + + public boolean b() { + return this.f == WrappedEnumDirection.EnumDirectionLimit.VERTICAL; + } + + public boolean c() { + return this.f == WrappedEnumDirection.EnumDirectionLimit.HORIZONTAL; + } + + public String toString() { + return this.e; + } + + public boolean a(WrappedEnumDirection var1) { + return var1 != null && var1.k() == this; + } + + public WrappedEnumDirection.EnumDirectionLimit d() { + return this.f; + } + + public String getName() { + return this.e; + } + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + enumDirection = Reflections.getNMSClass("EnumDirection"); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumGameMode.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumGameMode.java new file mode 100644 index 00000000..a2bd93c8 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumGameMode.java @@ -0,0 +1,80 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.enums; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; + +public enum WrappedEnumGameMode { + NOT_SET(-1, ""), + SURVIVAL(0, "survival"), + CREATIVE(1, "creative"), + ADVENTURE(2, "adventure"), + SPECTATOR(3, "spectator"); + + int f; + String g; + + private static WrappedClass enumGamemode = Reflections.getNMSClass((ProtocolVersion.getGameVersion() + .isOrAbove(ProtocolVersion.V1_8_5) && ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_10) + ? "WorldSettings$" : "") + + "EnumGamemode"); + + WrappedEnumGameMode(int var3, String var4) { + this.f = var3; + this.g = var4; + } + + public int getId() { + return this.f; + } + + public String b() { + return this.g; + } + + public boolean c() { + return this == ADVENTURE || this == SPECTATOR; + } + + public boolean d() { + return this == CREATIVE; + } + + public boolean e() { + return this == SURVIVAL || this == ADVENTURE; + } + + public static WrappedEnumGameMode getById(int var0) { + WrappedEnumGameMode[] var1 = values(); + int var2 = var1.length; + + for(int var3 = 0; var3 < var2; ++var3) { + WrappedEnumGameMode var4 = var1[var3]; + if (var4.f == var0) { + return var4; + } + } + + return SURVIVAL; + } + + public static WrappedEnumGameMode getByName(String name) { + for(WrappedEnumGameMode var : values()) { + if(!var.name().equals(name)) continue; + return var; + } + return SURVIVAL; + } + + public T getObject(WrappedEnumGameMode gamemode) { + return (T) enumGamemode.getEnum(gamemode.name()); + } + + public Object getObject() { + return getObject(getById(f)); + } + + public static WrappedEnumGameMode fromObject(Enum var) { + return getByName(var.name()); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumHand.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumHand.java new file mode 100644 index 00000000..05dc9ec3 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumHand.java @@ -0,0 +1,31 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.enums; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; + +public enum WrappedEnumHand { + MAIN_HAND, + OFF_HAND; + + public static WrappedClass enumHandClass; + + public static WrappedEnumHand getFromVanilla(Object object) { + if(enumHandClass == null) return WrappedEnumHand.MAIN_HAND; + + if(object instanceof Enum) + return valueOf(object.toString()); + + return WrappedEnumHand.MAIN_HAND; + } + + public T toEnumHand() { + return (T) enumHandClass.getEnum(name()); + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + enumHandClass = Reflections.getNMSClass("EnumHand"); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumParticle.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumParticle.java new file mode 100644 index 00000000..f34d09e5 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumParticle.java @@ -0,0 +1,105 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.enums; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import lombok.Getter; +import org.bukkit.Particle; + +import java.util.Arrays; + +@Getter +public enum WrappedEnumParticle { + EXPLOSION_NORMAL, + EXPLOSION_LARGE, + EXPLOSION_HUGE, + FIREWORKS_SPARK, + WATER_BUBBLE, + WATER_SPLASH, + WATER_WAKE, + SUSPENDED, + SUSPENDED_DEPTH, + CRIT, + CRIT_MAGIC, + SMOKE_NORMAL, + SMOKE_LARGE, + SPELL, + SPELL_INSTANT, + SPELL_MOB, + SPELL_MOB_AMBIENT, + SPELL_WITCH, + DRIP_WATER, + DRIP_LAVA, + VILLAGER_ANGRY, + VILLAGER_HAPPY, + TOWN_AURA, + NOTE, + PORTAL, + ENCHANTMENT_TABLE, + FLAME, + LAVA, + CLOUD, + REDSTONE, + SNOWBALL, + SNOW_SHOVEL, + SLIME, + HEART, + BARRIER, + ITEM_CRACK, + BLOCK_CRACK, + BLOCK_DUST, + WATER_DROP, + MOB_APPEARANCE, + DRAGON_BREATH, + END_ROD, + DAMAGE_INDICATOR, + SWEEP_ATTACK, + FALLING_DUST, + TOTEM, + SPIT, + SQUID_INK, + BUBBLE_POP, + CURRENT_DOWN, + BUBBLE_COLUMN_UP, + NAUTILUS, + DOLPHIN, + LEGACY_BLOCK_CRACK, + LEGACY_BLOCK_DUST, + LEGACY_FALLING_DUST; + + private static WrappedClass particle, craftParticle, nmsParticle; + private static WrappedMethod toNMS; + + public static WrappedEnumParticle getByName(String name) { + return Arrays.stream(values()).filter(val -> val.getName().equalsIgnoreCase(name)) + .findFirst().orElse(null); + } + + public T toNMS() { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { + return (T) Reflections.getNMSClass("EnumParticle").getEnum(name()); + } + return toNMS.invoke(null, Particle.valueOf(getName())); + } + + public String getName() { + String name = this.name(); + + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + name = name.replace("LEGACY_", ""); + } + + return name; + } + + static { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) { + particle = Reflections.getClass("org.bukkit.Particle"); + craftParticle = Reflections.getCBClass("CraftParticle"); + nmsParticle = Reflections.getNMSClass(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13) + ? "EnumParticle" : "Particle"); + toNMS = craftParticle.getMethod("toNMS", Particle.class); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumPlayerInfoAction.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumPlayerInfoAction.java new file mode 100644 index 00000000..f7312c5a --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumPlayerInfoAction.java @@ -0,0 +1,24 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.enums; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; + +public enum WrappedEnumPlayerInfoAction { + ADD_PLAYER("addPlayer"), + UPDATE_GAME_MODE("updateGamemode"), + UPDATE_LATENCY("updatePing"), + UPDATE_DISPLAY_NAME("updateDisplayName"), + REMOVE_PLAYER("removePlayer"); + + public String legacyMethodName; + public static WrappedClass enumPlayerInfoAction = + Reflections.getNMSClass("PacketPlayOutPlayerInfo$EnumPlayerInfoAction"); + + WrappedEnumPlayerInfoAction(String legacyMethodName) { + this.legacyMethodName = legacyMethodName; + } + + public T toVanilla() { + return (T) enumPlayerInfoAction.getEnum(name()); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumProtocol.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumProtocol.java new file mode 100644 index 00000000..6277b76c --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumProtocol.java @@ -0,0 +1,31 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.enums; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; + +import java.util.Arrays; + +public enum WrappedEnumProtocol { + + HANDSHAKING(-1), + PLAY(0), + STATUS(1), + LOGIN(2), + UNKNOWN(-69); //Not an actual vanilla object. + + public static WrappedClass enumProtocol = Reflections.getNMSClass("EnumProtocol"); + int id; + + WrappedEnumProtocol(int id) { + this.id = id; + } + + public T toVanilla() { + return (T) enumProtocol.getEnum(name()); + } + + public static WrappedEnumProtocol fromVanilla(Enum object) { + return Arrays.stream(values()).filter(val -> val.name().equals(object.name())).findFirst() + .orElse(WrappedEnumProtocol.UNKNOWN); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumTeleportFlag.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumTeleportFlag.java new file mode 100644 index 00000000..062f4bee --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/enums/WrappedEnumTeleportFlag.java @@ -0,0 +1,66 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.enums; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import net.minecraft.server.v1_8_R3.PacketPlayOutPosition; + +import java.util.EnumSet; +import java.util.Iterator; +import java.util.Set; + +public enum WrappedEnumTeleportFlag { + X(0), + Y(1), + Z(2), + Y_ROT(3), + X_ROT(4); + + private int f; + private static final WrappedClass enumTeleportFlag = Reflections.getNMSClass("EnumTeleportFlag"); + + WrappedEnumTeleportFlag(int var3) { + this.f = var3; + } + + private int a() { + return 1 << this.f; + } + + private boolean b(int var1) { + return (var1 & this.a()) == this.a(); + } + + public static Set a(int var0) { + EnumSet var1 = EnumSet.noneOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class); + WrappedEnumTeleportFlag[] var2 = values(); + int var3 = var2.length; + + for(int var4 = 0; var4 < var3; ++var4) { + WrappedEnumTeleportFlag var5 = var2[var4]; + if (var5.b(var0)) { + var1.add(var5); + } + } + + return var1; + } + + public static int a(Set var0) { + int var1 = 0; + + WrappedEnumTeleportFlag var3; + for(Iterator var2 = var0.iterator(); var2.hasNext(); var1 |= var3.a()) { + var3 = var2.next(); + } + + return var1; + } + + public static WrappedEnumTeleportFlag fromObject(Enum var) { + return values()[var.ordinal()]; + } + + public T getObject() { + return (T) enumTeleportFlag.getEnum(this.name()); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/DontImportIfNotLatestThanks.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/DontImportIfNotLatestThanks.java new file mode 100644 index 00000000..b23d47e8 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/DontImportIfNotLatestThanks.java @@ -0,0 +1,63 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.v1_13; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.impl.CraftReflection; +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.LiteralMessage; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import lombok.var; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +public class DontImportIfNotLatestThanks { + + private static WrappedClass commandDispatcherClass = Reflections.getNMSClass("CommandDispatcher"); + private Object commandDispatcher; + private CommandDispatcher bukkitDispatcher; + private WrappedMethod updateCommands = new WrappedClass(Player.class).getMethod("updateCommands"); + + public DontImportIfNotLatestThanks() { + commandDispatcher = + MinecraftReflection.minecraftServer + .getFieldByName("commandDispatcher") + .get(CraftReflection.getMinecraftServer()); + + bukkitDispatcher = commandDispatcherClass.getFieldByType(CommandDispatcher.class, 0) + .get(commandDispatcher); + } + public T getSuggestions(String input, String... options) { + int start = input.startsWith("/") ? 1 : 0; + + var suggest = new SuggestionsBuilder(input, start); + + for (int i = 0; i < options.length; i++) { + String option = options[i]; + + suggest = suggest.suggest(i, new LiteralMessage(option)); + } + + return (T) suggest; + } + + public String[] getArrayFromSuggestions(Suggestions suggestions) { + return suggestions.getList().stream() + .map(sug -> sug.getTooltip().getString()) + .toArray(String[]::new); + } + + public void registerTabComplete(String... args) { + LiteralArgumentBuilder builder = LiteralArgumentBuilder.literal(args[0]); + + for (String arg : args) { + builder = (LiteralArgumentBuilder) builder.then(LiteralArgumentBuilder.literal(arg)); + } + + bukkitDispatcher.register(builder); + + Bukkit.getOnlinePlayers().forEach(pl -> updateCommands.invoke(pl)); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/WrappedStringRange.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/WrappedStringRange.java new file mode 100644 index 00000000..df0be684 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/WrappedStringRange.java @@ -0,0 +1,42 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.v1_13; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.GeneralObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; + +public class WrappedStringRange extends GeneralObject { + + public static WrappedClass srClass; + private static WrappedField startField; + private static WrappedField endField; + private static boolean canUse; + + public int start, end; + + public WrappedStringRange(int start, int end) { + super(srClass); + this.start = start; + this.end = end; + + if(canUse) wrap(start, end); + } + + public WrappedStringRange(Object object) { + super(srClass); + + if(canUse) { + start = startField.get(object); + end = endField.get(object); + } + } + + static { + if(canUse = ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) { + srClass = Reflections.getClass("com.mojang.brigadier.context.StringRange"); + startField = srClass.getFieldByName("start"); + endField = srClass.getFieldByName("end"); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/WrappedSuggestion.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/WrappedSuggestion.java new file mode 100644 index 00000000..1f8ca97e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/WrappedSuggestion.java @@ -0,0 +1,55 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.v1_13; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.GeneralObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; + +//Add Message object for tooltip functionality later. +public class WrappedSuggestion extends GeneralObject { + public static WrappedClass suggestionClass; + private static WrappedField sRangeAccessor; + private static WrappedField textAccessor; + private static boolean canBeUsed; + + public WrappedStringRange range; + public String text; + + public WrappedSuggestion(WrappedStringRange range, String text) { + super(suggestionClass); + + this.range = range; + this.text = text; + + if(canBeUsed) wrap(range.getObject(), text); + } + + public WrappedSuggestion(String string) { + super(suggestionClass); + + this.range = new WrappedStringRange(0, string.length()); + this.text = string; + + if(canBeUsed) wrap(range.getObject(), text); + } + + public WrappedSuggestion(Object object) { + super(object, suggestionClass); + + range = new WrappedStringRange(sRangeAccessor.get(object)); + text = textAccessor.get(object); + } + + public WrappedSuggestion build() { + return wrap(range.getObject(), text); + } + + static { + if((canBeUsed = ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13))) { + suggestionClass = Reflections.getClass("com.mojang.brigadier.suggestion.Suggestion"); + sRangeAccessor = suggestionClass.getFieldByType(WrappedStringRange.srClass.getParent(), 0); + textAccessor = suggestionClass.getFieldByType(String.class, 0); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/WrappedSuggestions.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/WrappedSuggestions.java new file mode 100644 index 00000000..762b763f --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/packet/types/v1_13/WrappedSuggestions.java @@ -0,0 +1,119 @@ +package cc.funkemunky.api.tinyprotocol.packet.types.v1_13; + +import cc.funkemunky.api.reflections.Reflections; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedField; +import cc.funkemunky.api.tinyprotocol.GeneralObject; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class WrappedSuggestions extends GeneralObject { + public static WrappedClass suggestionsClass; + private static WrappedField suggestionListField; + private static WrappedField sRangeField; + private static boolean canBeUsed; + + public List suggestions; + public WrappedStringRange stringRange; + + public WrappedSuggestions(WrappedStringRange range, WrappedSuggestion... suggestions) { + this(range, Arrays.asList(suggestions)); + } + + public WrappedSuggestions(WrappedStringRange range, List suggestions) { + super(suggestions); + + if(canBeUsed) wrap(range, suggestions.stream() + .map(WrappedSuggestion::getObject) + .collect(Collectors.toList())); + } + + public WrappedSuggestions(Object object) { + super(object, suggestionsClass); + + if(canBeUsed) { + List suggestionObjects = suggestionListField.get(object); + + suggestions = suggestionObjects + .stream() + .map(WrappedSuggestion::new) + .collect(Collectors.toList()); + suggestionObjects.clear(); + + stringRange = new WrappedStringRange(sRangeField.get(object)); + } + } + + static { + if((canBeUsed = ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13))) { + suggestionsClass = Reflections.getClass("com.mojang.brigadier.suggestion.Suggestions"); + suggestionListField = suggestionsClass.getFieldByType(WrappedSuggestion.suggestionClass.getParent(), 0); + sRangeField = suggestionsClass.getFieldByType(WrappedStringRange.srClass.getParent(), 0); + } + } + + public static class SuggestionsBuilder extends GeneralObject { + private final String input; + private final int start; + private final String remaining; + private final List result = new ArrayList<>(); + private static WrappedClass wrapped; + + public SuggestionsBuilder(final String input, final int start) { + this.input = input; + this.start = start; + this.remaining = input.substring(start); + } + + public String getInput() { + return input; + } + + public int getStart() { + return start; + } + + public String getRemaining() { + return remaining; + } + + public WrappedSuggestions build() { + return new WrappedSuggestions(suggestionsClass + .getMethod("create", String.class, List.class) + .invoke(null, input, result.stream() + .map(WrappedSuggestion::getObject) + .collect(Collectors.toList()))); + } + + public SuggestionsBuilder suggest(final String text) { + if (text.equals(remaining)) { + return this; + } + result.add(new WrappedSuggestion(new WrappedStringRange(start, input.length()), text)); + return this; + } + + public SuggestionsBuilder add(final SuggestionsBuilder other) { + result.addAll(other.result); + return this; + } + + public SuggestionsBuilder createOffset(final int start) { + return new SuggestionsBuilder(input, start); + } + + public SuggestionsBuilder restart() { + return new SuggestionsBuilder(input, start); + } + + static { + if (canBeUsed) { + wrapped = Reflections.getClass("com.mojang.brigadier.suggestion.SuggestionsBuilder"); + } + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/ConstructorInvoker.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/ConstructorInvoker.java new file mode 100644 index 00000000..fbd93ef6 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/ConstructorInvoker.java @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.reflection; + +public interface ConstructorInvoker { + /** + * Invoke a constructor for a specific class. + * + * @param arguments - the arguments to pass to the constructor. + * @return The constructed object. + */ + public Object invoke(Object... arguments); +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/FieldAccessor.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/FieldAccessor.java new file mode 100644 index 00000000..7f4d8b53 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/FieldAccessor.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.reflection; + +public interface FieldAccessor { + /** + * Retrieve the content of a field. + * + * @param target - the target object, or NULL for a static field. + * @return The value of the field. + */ + public T get(Object target); + + /** + * Set the content of a field. + * + * @param target - the target object, or NULL for a static field. + * @param value - the new value of the field. + */ + public void set(Object target, Object value); + + /** + * Determine if the given object has this field. + * + * @param target - the object to test. + * @return TRUE if it does, FALSE otherwise. + */ + public boolean hasField(Object target); +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/MethodInvoker.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/MethodInvoker.java new file mode 100644 index 00000000..fd716a26 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/MethodInvoker.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + +package cc.funkemunky.api.tinyprotocol.reflection; + +public interface MethodInvoker { + /** + * Invoke a method on a specific target object. + * + * @param target - the target object, or NULL for a static method. + * @param arguments - the arguments to pass to the method. + * @return The return value, or NULL if is void. + */ + public Object invoke(Object target, Object... arguments); +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/Reflection.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/Reflection.java new file mode 100644 index 00000000..c2e1986b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/tinyprotocol/reflection/Reflection.java @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2018 NGXDEV.COM. Licensed under MIT. + */ + + +package cc.funkemunky.api.tinyprotocol.reflection; + +import org.bukkit.Bukkit; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * An utility class that simplifies reflection in Bukkit plugins. + * + * @author Kristian + */ +public final class Reflection { + // Deduce the net.minecraft.server.v* package + public static String OBC_PREFIX = Bukkit.getServer().getClass().getPackage().getName(); + public static String NMS_PREFIX = OBC_PREFIX.replace("org.bukkit.craftbukkit", "net.minecraft.server"); + public static String VERSION = OBC_PREFIX.replace("org.bukkit.craftbukkit", "") + .replace(".", ""); + + // Variable replacement + private static Pattern MATCH_VARIABLE = Pattern.compile("\\{([^\\}]+)\\}"); + + private Reflection() { + // Seal class + } + + /** + * Retrieve a field accessor for a specific field type and name. + * + * @param target - the target type. + * @param name - the name of the field, or NULL to ignore. + * @param fieldType - a compatible field type. + * @return The field accessor. + */ + public static FieldAccessor getField(Class target, String name, Class fieldType) { + return getField(target, name, fieldType, 0); + } + + /** + * Retrieve a field accessor for a specific field type and name. + * + * @param className - lookup name of the class, see {@link #getClass(String)}. + * @param name - the name of the field, or NULL to ignore. + * @param fieldType - a compatible field type. + * @return The field accessor. + */ + public static FieldAccessor getField(String className, String name, Class fieldType) { + return getField(getClass(className), name, fieldType, 0); + } + + /** + * Retrieve a field accessor for a specific field type and name. + * + * @param target - the target type. + * @param fieldType - a compatible field type. + * @param index - the number of compatible fields to skip. + * @return The field accessor. + */ + public static FieldAccessor getField(Class target, Class fieldType, int index) { + return getField(target, null, fieldType, index); + } + + /** + * Retrieve a field accessor for a specific field type and name. + * + * @param className - lookup name of the class, see {@link #getClass(String)}. + * @param fieldType - a compatible field type. + * @param index - the number of compatible fields to skip. + * @return The field accessor. + */ + public static FieldAccessor getField(String className, Class fieldType, int index) { + return getField(getClass(className), fieldType, index); + } + + public static FieldAccessor getFieldSafe(String className, Class fieldType, int index) { + try { + return getField(getClass(className), fieldType, index); + } catch (Exception e) { + System.out.println("[WARN] Failed to find field at " + index + " in " + className + " with type " + fieldType.getSimpleName()); + return null; + } + } + + // Common method + private static FieldAccessor getField(Class target, String name, Class fieldType, int index) { + for (Field[] fields : new Field[][]{target.getDeclaredFields(), target.getFields()}) { + for (final Field field : fields) { + if ((name == null || field.getName().equals(name)) && fieldType.isAssignableFrom(field.getType()) && index-- <= 0) { + field.setAccessible(true); + + // A function for retrieving a specific field value + return new FieldAccessor() { + + @Override + @SuppressWarnings("unchecked") + public T get(Object target) { + try { + return (T) field.get(target); + } catch (IllegalAccessException e) { + throw new RuntimeException("Cannot access reflection.", e); + } + } + + @Override + public void set(Object target, Object value) { + try { + field.set(target, value); + } catch (IllegalAccessException e) { + throw new RuntimeException("Cannot access reflection.", e); + } + } + + @Override + public boolean hasField(Object target) { + // target instanceof DeclaringClass + return field.getDeclaringClass().isAssignableFrom(target.getClass()); + } + }; + } + } + } + + // Search in parent classes + if (target.getSuperclass() != null) + return getField(target.getSuperclass(), name, fieldType, index); + + throw new IllegalArgumentException("Cannot find field with type " + fieldType); + } + + public static FieldAccessor getField(Class target, String name, int index) { + for (Field[] fields : new Field[][]{target.getDeclaredFields(), target.getFields()}) { + for (final Field field : fields) { + if ((name == null || field.getName().equals(name)) && index-- <= 0) { + field.setAccessible(true); + + // A function for retrieving a specific field value + return new FieldAccessor() { + + @Override + @SuppressWarnings("unchecked") + public T get(Object target) { + try { + return (T) field.get(target); + } catch (IllegalAccessException e) { + throw new RuntimeException("Cannot access reflection.", e); + } + } + + @Override + public void set(Object target, Object value) { + try { + field.set(target, value); + } catch (IllegalAccessException e) { + throw new RuntimeException("Cannot access reflection.", e); + } + } + + @Override + public boolean hasField(Object target) { + // target instanceof DeclaringClass + return field.getDeclaringClass().isAssignableFrom(target.getClass()); + } + }; + } + } + } + + // Search in parent classes + if (target.getSuperclass() != null) + return getField(target.getSuperclass(), name, index); + + throw new IllegalArgumentException("Cannot find field"); + } + + /** + * Search for the first publicly and privately defined method of the given name and parameter count. + * + * @param className - lookup name of the class, see {@link #getClass(String)}. + * @param methodName - the method name, or NULL to skip. + * @param params - the expected parameters. + * @return An object that invokes this specific method. + * @throws IllegalStateException If we cannot find this method. + */ + public static MethodInvoker getMethod(String className, String methodName, Class... params) { + return getTypedMethod(getClass(className), methodName, null, params); + } + + /** + * Search for the first publicly and privately defined method of the given name and parameter count. + * + * @param clazz - a class to start with. + * @param methodName - the method name, or NULL to skip. + * @param params - the expected parameters. + * @return An object that invokes this specific method. + * @throws IllegalStateException If we cannot find this method. + */ + public static MethodInvoker getMethod(Class clazz, String methodName, Class... params) { + return getTypedMethod(clazz, methodName, null, params); + } + + public static MethodInvoker getMethod(Class clazz, int index, Class... params) { + return getTypedMethod(clazz, index, null, params); + } + + public static MethodInvoker getMethod(Class clazz, Class returnType, int index, Class... params) { + return getTypedMethod(clazz, index, returnType, params); + } + + /** + * Search for the first publicly and privately defined method of the given name and parameter count. + * + * @param clazz - a class to start with. + * @param methodName - the method name, or NULL to skip. + * @param returnType - the expected return type, or NULL to ignore. + * @param params - the expected parameters. + * @return An object that invokes this specific method. + * @throws IllegalStateException If we cannot find this method. + */ + public static MethodInvoker getTypedMethod(Class clazz, String methodName, Class returnType, Class... params) { + for (final Method method : clazz.getDeclaredMethods()) { + if ((methodName == null || method.getName().equals(methodName)) + && (returnType == null || method.getReturnType().equals(returnType)) + && Arrays.equals(method.getParameterTypes(), params)) { + method.setAccessible(true); + + return new MethodInvoker() { + + @Override + public Object invoke(Object target, Object... arguments) { + try { + return method.invoke(target, arguments); + } catch (Exception e) { + throw new RuntimeException("Cannot invoke method " + method, e); + } + } + + }; + } + } + + // Search in every superclass + if (clazz.getSuperclass() != null) + return getMethod(clazz.getSuperclass(), methodName, params); + + throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, Arrays.asList(params))); + } + + public static MethodInvoker getTypedMethod(Class clazz, int index, Class returnType, Class... params) { + for (final Method method : clazz.getDeclaredMethods()) { + if ((returnType == null || method.getReturnType().equals(returnType)) + && Arrays.equals(method.getParameterTypes(), params) && index-- <= 0) { + method.setAccessible(true); + + return new MethodInvoker() { + + @Override + public Object invoke(Object target, Object... arguments) { + try { + return method.invoke(target, arguments); + } catch (Exception e) { + throw new RuntimeException("Cannot invoke method " + method, e); + } + } + + }; + } + } + + // Search in every superclass + if (clazz.getSuperclass() != null) + return getMethod(clazz.getSuperclass(), index, params); + + throw new IllegalStateException(String.format("Unable to find method %s (%s).", index, Arrays.asList(params))); + } + + /** + * Search for the first publically and privately defined constructor of the given name and parameter count. + * + * @param className - lookup name of the class, see {@link #getClass(String)}. + * @param params - the expected parameters. + * @return An object that invokes this constructor. + * @throws IllegalStateException If we cannot find this method. + */ + public static ConstructorInvoker getConstructor(String className, Class... params) { + return getConstructor(getClass(className), params); + } + + /** + * Search for the first publically and privately defined constructor of the given name and parameter count. + * + * @param clazz - a class to start with. + * @param params - the expected parameters. + * @return An object that invokes this constructor. + * @throws IllegalStateException If we cannot find this method. + */ + public static ConstructorInvoker getConstructor(Class clazz, Class... params) { + for (final Constructor constructor : clazz.getDeclaredConstructors()) { + if (Arrays.equals(constructor.getParameterTypes(), params)) { + constructor.setAccessible(true); + + return new ConstructorInvoker() { + + @Override + public Object invoke(Object... arguments) { + try { + return constructor.newInstance(arguments); + } catch (Exception e) { + throw new RuntimeException("Cannot invoke constructor " + constructor, e); + } + } + + }; + } + } + + throw new IllegalStateException(String.format("Unable to find constructor for %s (%s).", clazz, Arrays.asList(params))); + } + + /** + * Retrieve a class from its full name, without knowing its type on compile time. + *

+ * This is useful when looking up fields by a NMS or OBC type. + *

+ * + * @param lookupName - the class name with variables. + * @return The class. + * @see {@link #getClass()} for more information. + */ + public static Class getUntypedClass(String lookupName) { + @SuppressWarnings({"rawtypes", "unchecked"}) + Class clazz = (Class) getClass(lookupName); + return clazz; + } + + /** + * Retrieve a class from its full name. + *

+ * Strings enclosed with curly brackets - such as {TEXT} - will be replaced according to the following table: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
VariableContent
{nms}Actual package name of net.minecraft.server.VERSION
{obc}Actual pacakge name of org.bukkit.craftbukkit.VERSION
{version}The current Minecraft package VERSION, if any.
+ * + * @param lookupName - the class name with variables. + * @return The looked up class. + * @throws IllegalArgumentException If a variable or class could not be found. + */ + public static Class getClass(String lookupName) { + return getCanonicalClass(expandVariables(lookupName)); + } + + /** + * Retrieve a class in the net.minecraft.server.VERSION.* package. + * + * @param name - the name of the class, excluding the package. + * @throws IllegalArgumentException If the class doesn't exist. + */ + public static Class getMinecraftClass(String name) { + return getCanonicalClass(NMS_PREFIX + "." + name); + } + + /** + * Retrieve a class in the org.bukkit.craftbukkit.VERSION.* package. + * + * @param name - the name of the class, excluding the package. + * @throws IllegalArgumentException If the class doesn't exist. + */ + public static Class getCraftBukkitClass(String name) { + return getCanonicalClass(OBC_PREFIX + "." + name); + } + + /** + * Retrieve a class by its canonical name. + * + * @param canonicalName - the canonical name. + * @return The class. + */ + private static Class getCanonicalClass(String canonicalName) { + try { + return Class.forName(canonicalName); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Cannot find " + canonicalName, e); + } + } + + /** + * Expand variables such as "{nms}" and "{obc}" to their corresponding packages. + * + * @param name - the full name of the class. + * @return The expanded string. + */ + private static String expandVariables(String name) { + StringBuffer output = new StringBuffer(); + Matcher matcher = MATCH_VARIABLE.matcher(name); + + while (matcher.find()) { + String variable = matcher.group(1); + String replacement = ""; + + // Expand all detected variables + if ("nms".equalsIgnoreCase(variable)) + replacement = NMS_PREFIX; + else if ("obc".equalsIgnoreCase(variable)) + replacement = OBC_PREFIX; + else if ("version".equalsIgnoreCase(variable)) + replacement = VERSION; + else + throw new IllegalArgumentException("Unknown variable: " + variable); + + // Assume the expanded variables are all packages, and append a dot + if (replacement.length() > 0 && matcher.end() < name.length() && name.charAt(matcher.end()) != '.') + replacement += "."; + matcher.appendReplacement(output, Matcher.quoteReplacement(replacement)); + } + + matcher.appendTail(output); + return output.toString(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/updater/Updater.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/updater/Updater.java new file mode 100644 index 00000000..94c2ff70 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/updater/Updater.java @@ -0,0 +1,62 @@ +package cc.funkemunky.api.updater; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.utils.ConfigSetting; +import dev.brighten.db.utils.json.JSONException; +import dev.brighten.db.utils.json.JSONObject; +import dev.brighten.db.utils.json.JsonReader; +import lombok.Getter; + +import java.io.*; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +@Getter +public class Updater { + private String downloadLink = "N/A"; + private String viewLink = "N/A"; + private String releaseDate = "N/A"; + private final String currentUpdate = Atlas.getInstance().getDescription().getVersion(); + private String latestUpdate = "N/A"; + private File pluginLocation; + + @ConfigSetting(path = "updater") + private static boolean checkForUpdates = true; + + public Updater() { + runUpdateCheck(); + } + + public void runUpdateCheck() { + if(checkForUpdates) { + try { + JSONObject object = JsonReader + .readJsonFromUrl("https://api.github.com/repos/funkemunky/Atlas/releases/latest"); + + latestUpdate = object.getString("tag_name"); + viewLink = object.getString("html_url"); + releaseDate = object.getString("published_at"); + downloadLink = object.getJSONArray("assets").getJSONObject(0) + .getString("browser_download_url"); + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + } + } + + public boolean needsToUpdate() { + return !currentUpdate.equals(latestUpdate); + } + + public void downloadNewVersion() { + pluginLocation = UpdaterUtils.findPluginFile(Atlas.getInstance().getDescription().getName()); + try { + InputStream in = new URL(downloadLink).openStream(); + Files.copy(in, Paths.get(pluginLocation.getPath()), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/updater/UpdaterListener.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/updater/UpdaterListener.java new file mode 100644 index 00000000..d016c9c9 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/updater/UpdaterListener.java @@ -0,0 +1,29 @@ +package cc.funkemunky.api.updater; + + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.utils.Color; +import cc.funkemunky.api.utils.ConfigSetting; +import cc.funkemunky.api.utils.Init; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +@Init +public class UpdaterListener implements Listener { + + @ConfigSetting(path = "updater") + private static boolean notifyOnJoin = true; + /*We set the event priority to lowest so it appears after (if no other plugin sets it to this) + every other message a player is sent on join.*/ + @EventHandler(priority = EventPriority.LOWEST) + public void onEvent(PlayerJoinEvent event) { + if(event.getPlayer().hasPermission("api.admin") + && notifyOnJoin && Atlas.getInstance().getUpdater().needsToUpdate()) { + event.getPlayer().sendMessage(Color + .translate("&8[&a&lAtlas&8] &7A new version of Atlas has been released (&f" + + Atlas.getInstance().getUpdater().getLatestUpdate() + "&7)!")); + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/updater/UpdaterUtils.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/updater/UpdaterUtils.java new file mode 100644 index 00000000..371aa003 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/updater/UpdaterUtils.java @@ -0,0 +1,42 @@ +package cc.funkemunky.api.updater; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.utils.ReflectionsUtil; +import org.bukkit.plugin.InvalidDescriptionException; +import org.bukkit.plugin.PluginDescriptionFile; + +import java.io.File; +import java.util.Objects; + +public class UpdaterUtils { + + public static File findPluginFile(String name) { + File pluginDir = getPluginDirectory(); + File pluginFile = new File(pluginDir, name + ".jar"); + if (!pluginFile.isFile()) { + for (final File f : Objects.requireNonNull(pluginDir.listFiles())) { + try { + if (f.getName().endsWith(".jar")) { + final PluginDescriptionFile pdf = Atlas.getInstance().getPluginLoader().getPluginDescription(f); + if (pdf.getName().equalsIgnoreCase(name)) { + pluginFile = f; + break; + } + } + } + catch (InvalidDescriptionException e2) { + e2.printStackTrace(); + } + } + } + return pluginFile; + } + + public static File getPluginDirectory() { + File pluginDir = new File("plugins"); + if (!pluginDir.isDirectory()) { + pluginDir = ReflectionsUtil.getPluginFolder(); + } + return pluginDir; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/AutoLoad.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/AutoLoad.java new file mode 100644 index 00000000..f5f4c2ad --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/AutoLoad.java @@ -0,0 +1,10 @@ +package cc.funkemunky.api.utils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface AutoLoad { + boolean commands() default true; + boolean listeners() default true; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/BlockBounds.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/BlockBounds.java new file mode 100644 index 00000000..920be0b9 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/BlockBounds.java @@ -0,0 +1,14 @@ +package cc.funkemunky.api.utils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class BlockBounds { + public List bounds = new ArrayList<>(); + public int id; + + public BlockBounds(int id, BoundingBox... boxes) { + bounds.addAll(Arrays.asList(boxes)); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/BlockUtils.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/BlockUtils.java new file mode 100644 index 00000000..ecc1ee1a --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/BlockUtils.java @@ -0,0 +1,422 @@ +package cc.funkemunky.api.utils; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.Map; + +public class BlockUtils { + + public static Map collisionBoundingBoxes = new HashMap<>();; + public static Map blockBounds = new HashMap<>(); + + public static Block getBlock(Location location) { + if (Atlas.getInstance().getBlockBoxManager().getBlockBox().isChunkLoaded(location)) { + return location.getBlock(); + } else { + return null; + } + } + + public static boolean isSolid(Block block) { + int type = block.getType().getId(); + + switch (type) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 7: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 29: + case 34: + case 33: + case 35: + case 36: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + case 48: + case 49: + case 52: + case 53: + case 54: + case 56: + case 57: + case 58: + case 60: + case 61: + case 62: + case 64: + case 65: + case 67: + case 71: + case 73: + case 74: + case 78: + case 79: + case 80: + case 81: + case 82: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 91: + case 92: + case 93: + case 94: + case 95: + case 96: + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + case 103: + case 106: + case 107: + case 108: + case 109: + case 110: + case 111: + case 112: + case 113: + case 114: + case 116: + case 117: + case 118: + case 120: + case 121: + case 122: + case 123: + case 124: + case 125: + case 126: + case 127: + case 128: + case 129: + case 130: + case 133: + case 134: + case 135: + case 136: + case 137: + case 138: + case 139: + case 140: + case 144: + case 145: + case 146: + case 149: + case 150: + case 151: + case 152: + case 153: + case 154: + case 155: + case 156: + case 158: + case 159: + case 160: + case 161: + case 162: + case 163: + case 164: + case 165: + case 166: + case 167: + case 168: + case 169: + case 170: + case 171: + case 172: + case 173: + case 174: + case 178: + case 179: + case 180: + case 181: + case 182: + case 183: + case 184: + case 185: + case 186: + case 187: + case 188: + case 189: + case 190: + case 191: + case 192: + case 193: + case 194: + case 195: + case 196: + case 197: + case 198: + case 199: + case 200: + case 201: + case 202: + case 203: + case 204: + case 205: + case 206: + case 207: + case 208: + case 210: + case 211: + case 212: + case 213: + case 214: + case 215: + case 216: + case 218: + case 219: + case 220: + case 221: + case 222: + case 223: + case 224: + case 225: + case 226: + case 227: + case 228: + case 229: + case 230: + case 231: + case 232: + case 233: + case 234: + case 235: + case 236: + case 237: + case 238: + case 239: + case 240: + case 241: + case 242: + case 243: + case 244: + case 245: + case 246: + case 247: + case 248: + case 249: + case 250: + case 251: + case 252: + case 255: + case 397: + case 355: + return true; + + } + return false; + } + + public static boolean isLiquid(Block block) { + return block.getType().toString().contains("WATER") || block.getType().toString().contains("LAVA"); + } + + public static boolean isClimbableBlock(Block block) { + return block.getType().toString().contains("LADDER") || block.getType().toString().contains("VINE"); + } + + public static boolean isIce(Block block) { + return block.getType().toString().contains("ICE"); + } + + public static boolean isFence(Block block) { + return (block.getType().toString().contains("FENCE") && !block.getType().toString().contains("GATE")) | block.getType().toString().contains("WALL"); + } + + public static boolean isDoor(Block block) { + return block.getType().toString().contains("DOOR") && !block.getType().toString().contains("TRAP"); + } + + public static boolean isBed(Block block) { + return block.getType().toString().contains("BED"); + } + + public static boolean isTrapDoor(Block block) { + return block.getType().toString().contains("DOOR") && block.getType().toString().contains("TRAP"); + } + + public static boolean isChest(Block block) { + return block.getType().toString().contains("CHEST") || block.getType().toString().contains("SHULKER"); + } + + public static boolean isWall(Block block) { + return block.getType().toString().contains("WALL"); + } + + public static boolean isPiston(Block block) { + return block.getType().getId() == 36 || block.getType().getId() == 34 || block.getType().getId() == 33 || block.getType().getId() == 29; + } + + public static boolean isFenceGate(Block block) { + return block.getType().toString().contains("FENCE") && block.getType().toString().contains("GATE"); + } + + public static boolean isStair(Block block) { + return block.getType().toString().contains("STAIR"); + } + + public static boolean isSlab(Block block) { + return block.getType().toString().contains("STEP") || block.getType().toString().contains("SLAB"); + } + + public static boolean isTool(ItemStack stack) { + String name = stack.getType().name().toLowerCase(); + + return name.contains("axe") || name.contains("spade") || name.contains("shovel") || name.contains("shear") || name.contains("sword"); + } + + public static Location findGround(World world, Location point) { + for (int y = point.toVector().getBlockY(); y > 0; y--) { + Location loc = new Location(world, point.getX(), y, point.getZ()); + Block block = BlockUtils.getBlock(loc); + + if (block.getType().isBlock() && block.getType().isSolid() && !block.isEmpty()) { + Location toReturn = loc.clone(); + + toReturn.setY(y + 1); + + return toReturn; + } + } + return point; + } + + private static void setupCollisionBB() { + if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + collisionBoundingBoxes.put(Material.getMaterial("FIRE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("STONE_PLATE"), new BoundingBox((float) 0.0625, (float) 0.0, (float) 0.0625, (float) 0.9375, (float) 0.0625, (float) 0.9375)); + collisionBoundingBoxes.put(Material.getMaterial("GRAVEL"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("COBBLESTONE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("NETHER_BRICK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("PUMPKIN"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("CARROT"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 0.25, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("TNT"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("SOUL_SAND"), new BoundingBox(0f, 0f,0f, 1f, 0.875f, 1f)); + collisionBoundingBoxes.put(Material.getMaterial("SAND"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("WOOD_PLATE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("SIGN_POST"), new BoundingBox((float) 0.25, (float) 0.0, (float) 0.25, (float) 0.75, (float) 1.0, (float) 0.75)); + collisionBoundingBoxes.put(Material.getMaterial("COCOA"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("DETECTOR_RAIL"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 0.125, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("HARD_CLAY"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("NETHERRACK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("STONE_BUTTON"), new BoundingBox((float) 0.3125, (float) 0.0, (float) 0.375, (float) 0.6875, (float) 0.125, (float) 0.625)); + collisionBoundingBoxes.put(Material.getMaterial("CLAY"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("QUARTZ_BLOCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("HUGE_MUSHROOM_1"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("HUGE_MUSHROOM_2"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("LAVA"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("BEACON"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("GRASS"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("DEAD_BUSH"), new BoundingBox((float) 0.09999999403953552, (float) 0.0, (float) 0.09999999403953552, (float) 0.8999999761581421, (float) 0.800000011920929, (float) 0.8999999761581421)); + collisionBoundingBoxes.put(Material.getMaterial("GLOWSTONE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("ICE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("BRICK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("REDSTONE_TORCH_ON"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("REDSTONE_TORCH_OFF"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("POWERED_RAIL"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 0.125, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("DISPENSER"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("JUKEBOX"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("EMERALD_BLOCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("STONE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("BOOKSHELF"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("MYCEL"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("OBSIDIAN"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("PORTAL"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("GOLD_PLATE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("COAL_BLOCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("GOLD_BLOCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("STAINED_CLAY"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("MOB_SPAWNER"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("BEDROCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("IRON_ORE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("REDSTONE_BLOCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("SIGN"), new BoundingBox((float) 0.25, (float) 0.0, (float) 0.25, (float) 0.75, (float) 1.0, (float) 0.75)); + collisionBoundingBoxes.put(Material.getMaterial("IRON_PLATE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("GOLD_ORE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("POTATO"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 0.25, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("MOSSY_COBBLESTONE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("RAILS"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 0.125, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("HAY_BLOCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("TORCH"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("CARPET"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 0.0625, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("DIRT"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("EMERALD_ORE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("REDSTONE_LAMP_ON"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("REDSTONE_LAMP_OFF"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("NETHER_WARTS"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 0.25, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("SPONGE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("WORKBENCH"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("SANDSTONE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("LAPIS_BLOCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("NOTE_BLOCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("WOOL"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("COMMAND"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("ENDER_STONE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("TRIPWIRE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 0.15625, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("SAPLING"), new BoundingBox((float) 0.09999999403953552, (float) 0.0, (float) 0.09999999403953552, (float) 0.8999999761581421, (float) 0.800000011920929, (float) 0.8999999761581421)); + collisionBoundingBoxes.put(Material.getMaterial("PACKED_ICE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("LAPIS_ORE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("SMOOTH_BRICK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("RED_MUSHROOM"), new BoundingBox((float) 0.30000001192092896, (float) 0.0, (float) 0.30000001192092896, (float) 0.699999988079071, (float) 0.4000000059604645, (float) 0.699999988079071)); + collisionBoundingBoxes.put(Material.getMaterial("BROWN_MUSHROOM"), new BoundingBox((float) 0.30000001192092896, (float) 0.0, (float) 0.30000001192092896, (float) 0.699999988079071, (float) 0.4000000059604645, (float) 0.699999988079071)); + collisionBoundingBoxes.put(Material.getMaterial("DIAMOND_BLOCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("CROPS"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 0.25, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("IRON_BLOCK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("MELON"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("DIAMOND_ORE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("LEVER"), new BoundingBox((float) 0.25, (float) 0.0, (float) 0.25, (float) 0.75, (float) 0.6000000238418579, (float) 0.75)); + collisionBoundingBoxes.put(Material.getMaterial("SUGAR_CANE"), new BoundingBox((float) 0.125, (float) 0.0, (float) 0.125, (float) 0.875, (float) 1.0, (float) 0.875)); + collisionBoundingBoxes.put(Material.getMaterial("COAL_ORE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("WATER_LILY"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 0.015625, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("QUARTZ_ORE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("GLASS"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("TRIPWIRE_HOOK"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("VINE"), new BoundingBox((float) 0.0, (float) 0.0, (float) 0.0, (float) 1.0, (float) 1.0, (float) 1.0)); + collisionBoundingBoxes.put(Material.getMaterial("WEB"), new BoundingBox(0, 0, 0, 1, 1, 1)); + collisionBoundingBoxes.put(Material.getMaterial("WATER"), new BoundingBox(0, 0, 0, 0.9f, 0.9f, 0.9f)); + collisionBoundingBoxes.put(Material.getMaterial("STATIONARY_WATER"), new BoundingBox(0, 0, 0, 0.9f, 0.9f, 0.9f)); + collisionBoundingBoxes.put(Material.getMaterial("STATIONARY_LAVA"), new BoundingBox(0, 0, 0, 0.9f, 0.9f, 0.9f)); + } + } + + static { + setupCollisionBB(); + } +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/BoundingBox.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/BoundingBox.java new file mode 100644 index 00000000..5c043a5a --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/BoundingBox.java @@ -0,0 +1,320 @@ +package cc.funkemunky.api.utils; + +import cc.funkemunky.api.reflections.impl.MinecraftReflection; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import java.util.ArrayList; +import java.util.List; + +public class BoundingBox { + + public float minX, minY, minZ, maxX, maxY, maxZ; + + public BoundingBox(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + this.minX = minX; + this.minY = minY; + this.minZ = minZ; + this.maxX = maxX; + this.maxY = maxY; + this.maxZ = maxZ; + } + + public BoundingBox(Vector min, Vector max) { + this.minX = (float) Math.min(min.getX(), max.getX()); + this.minY = (float) Math.min(min.getY(), max.getY()); + this.minZ = (float) Math.min(min.getZ(), max.getZ()); + this.maxX = (float) Math.max(min.getX(), max.getX()); + this.maxY = (float) Math.max(min.getY(), max.getY()); + this.maxZ = (float) Math.max(min.getZ(), max.getZ()); + } + + public BoundingBox(BoundingBox one, BoundingBox two) { + this.minX = Math.min(one.minX, two.minX); + this.minY = Math.min(one.minY, two.minY); + this.minZ = Math.min(one.minZ, two.minZ); + this.maxX = Math.max(one.maxX, two.maxX); + this.maxY = Math.max(one.maxY, two.maxY); + this.maxZ = Math.max(one.maxZ, two.maxZ); + } + + public BoundingBox add(float x, float y, float z) { + float newMinX = minX + x; + float newMaxX = maxX + x; + float newMinY = minY + y; + float newMaxY = maxY + y; + float newMinZ = minZ + z; + float newMaxZ = maxZ + z; + + return new BoundingBox(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ); + } + + public BoundingBox add(Vector vector) { + float x = (float) vector.getX(), y = (float) vector.getY(), z = (float) vector.getZ(); + + float newMinX = minX + x; + float newMaxX = maxX + x; + float newMinY = minY + y; + float newMaxY = maxY + y; + float newMinZ = minZ + z; + float newMaxZ = maxZ + z; + + return new BoundingBox(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ); + } + + public BoundingBox grow(float x, float y, float z) { + float newMinX = minX - x; + float newMaxX = maxX + x; + float newMinY = minY - y; + float newMaxY = maxY + y; + float newMinZ = minZ - z; + float newMaxZ = maxZ + z; + + return new BoundingBox(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ); + } + + public BoundingBox shrink(float x, float y, float z) { + float newMinX = minX + x; + float newMaxX = maxX - x; + float newMinY = minY + y; + float newMaxY = maxY - y; + float newMinZ = minZ + z; + float newMaxZ = maxZ - z; + + return new BoundingBox(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ); + } + + public BoundingBox add(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + return new BoundingBox(this.minX + minX, this.minY + minY, this.minZ + minZ, this.maxX + maxX, this.maxY + maxY, this.maxZ + maxZ); + } + + public BoundingBox subtract(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) { + return new BoundingBox(this.minX - minX, this.minY - minY, this.minZ - minZ, this.maxX - maxX, this.maxY - maxY, this.maxZ - maxZ); + } + + public boolean intersectsWithBox(Vector vector) { + return (vector.getX() > this.minX && vector.getX() < this.maxX) && ((vector.getY() > this.minY && vector.getY() < this.maxY) && (vector.getZ() > this.minZ && vector.getZ() < this.maxZ)); + } + + public Vector getMinimum() { + return new Vector(minX, minY, minZ); + } + + public Vector getMaximum() { + return new Vector(maxX, maxY, maxZ); + } + + public List getAllBlocks(Player player) { + Location min = new Location(player.getWorld(), MathUtils.floor(minX), MathUtils.floor(minY), MathUtils.floor(minZ)); + Location max = new Location(player.getWorld(), MathUtils.floor(maxX), MathUtils.floor(maxY), MathUtils.floor(maxZ)); + List all = new ArrayList<>(); + for (float x = (float) min.getX(); x < max.getX(); x++) { + for (float y = (float) min.getY(); y < max.getY(); y++) { + for (float z = (float) min.getZ(); z < max.getZ(); z++) { + Block block = BlockUtils.getBlock(new Location(player.getWorld(), x, y, z)); + if (block != null && block.getType().getId() != 0) { + all.add(block); + } + } + } + } + return all; + } + + public boolean intersectsWithBox(Object other) { + if (other instanceof BoundingBox) { + BoundingBox otherBox = (BoundingBox) other; + return otherBox.maxX > this.minX && otherBox.minX < this.maxX && otherBox.maxY > this.minY && otherBox.minY < this.maxY && otherBox.maxZ > this.minZ && otherBox.minZ < this.maxZ; + } else { + float otherMinX = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "a"), other); + float otherMinY = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "b"), other); + float otherMinZ = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "c"), other); + float otherMaxX = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "d"), other); + float otherMaxY = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "e"), other); + float otherMaxZ = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "f"), other); + return otherMaxX > minX && otherMinX < maxX && otherMaxY > minY && otherMinY < maxY && otherMaxZ > minZ && otherMinZ < maxZ; + } + } + + public boolean collides(Vector vector) { + return (vector.getX() >= this.minX && vector.getX() <= this.maxX) && ((vector.getY() >= this.minY && vector.getY() <= this.maxY) && (vector.getZ() >= this.minZ && vector.getZ() <= this.maxZ)); + } + + public boolean collides(Object other) { + if (other instanceof BoundingBox) { + BoundingBox otherBox = (BoundingBox) other; + return otherBox.maxX >= this.minX && otherBox.minX <= this.maxX && otherBox.maxY >= this.minY && otherBox.minY <= this.maxY && otherBox.maxZ >= this.minZ && otherBox.minZ <= this.maxZ; + } else { + float otherMinX = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "a"), other); + float otherMinY = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "b"), other); + float otherMinZ = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "c"), other); + float otherMaxX = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "d"), other); + float otherMaxY = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "e"), other); + float otherMaxZ = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "f"), other); + return otherMaxX >= minX && otherMinX <= maxX && otherMaxY >= minY && otherMinY <= maxY && otherMaxZ >= minZ && otherMinZ <= maxZ; + } + } + + public boolean collidesHorizontally(Vector vector) { + return (vector.getX() >= this.minX && vector.getX() <= this.maxX) && ((vector.getY() > this.minY && vector.getY() < this.maxY) && (vector.getZ() >= this.minZ && vector.getZ() <= this.maxZ)); + } + + public boolean collidesHorizontally(Object other) { + if (other instanceof BoundingBox) { + BoundingBox otherBox = (BoundingBox) other; + return otherBox.maxX >= this.minX && otherBox.minX <= this.maxX && otherBox.maxY > this.minY && otherBox.minY < this.maxY && otherBox.maxZ >= this.minZ && otherBox.minZ <= this.maxZ; + } else { + float otherMinX = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "a"), other); + float otherMinY = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "b"), other); + float otherMinZ = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "c"), other); + float otherMaxX = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "d"), other); + float otherMaxY = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "e"), other); + float otherMaxZ = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "f"), other); + return otherMaxX >= minX && otherMinX <= maxX && otherMaxY > minY && otherMinY < maxY && otherMaxZ >= minZ && otherMinZ <= maxZ; + } + } + + public boolean collidesVertically(Vector vector) { + return (vector.getX() > this.minX && vector.getX() < this.maxX) && ((vector.getY() >= this.minY && vector.getY() <= this.maxY) && (vector.getZ() > this.minZ && vector.getZ() < this.maxZ)); + } + + public boolean collidesVertically(Object other) { + if (other instanceof BoundingBox) { + BoundingBox otherBox = (BoundingBox) other; + return otherBox.maxX > this.minX && otherBox.minX < this.maxX && otherBox.maxY >= this.minY && otherBox.minY <= this.maxY && otherBox.maxZ > this.minZ && otherBox.minZ < this.maxZ; + } else { + float otherMinX = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "a"), other); + float otherMinY = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "b"), other); + float otherMinZ = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "c"), other); + float otherMaxX = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "d"), other); + float otherMaxY = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "e"), other); + float otherMaxZ = (float) (double) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(other.getClass(), "f"), other); + return otherMaxX > minX && otherMinX < maxX && otherMaxY >= minY && otherMinY <= maxY && otherMaxZ > minZ && otherMinZ < maxZ; + } + } + + /** + * if instance and the argument bounding boxes overlap in the Y and Z dimensions, calculate the offset between them + * in the X dimension. return var2 if the bounding boxes do not overlap or if var2 is closer to 0 then the + * calculated offset. Otherwise return the calculated offset. + */ + public double calculateXOffset(BoundingBox other, double offsetX) { + if (other.maxY > this.minY && other.minY < this.maxY && other.maxZ > this.minZ && other.minZ < this.maxZ) { + if (offsetX > 0.0D && other.maxX <= this.minX) { + double d1 = this.minX - other.maxX; + + if (d1 < offsetX) { + offsetX = d1; + } + } else if (offsetX < 0.0D && other.minX >= this.maxX) { + double d0 = this.maxX - other.minX; + + if (d0 > offsetX) { + offsetX = d0; + } + } + + return offsetX; + } else { + return offsetX; + } + } + + /** + * if instance and the argument bounding boxes overlap in the X and Z dimensions, calculate the offset between them + * in the Y dimension. return var2 if the bounding boxes do not overlap or if var2 is closer to 0 then the + * calculated offset. Otherwise return the calculated offset. + */ + public double calculateYOffset(BoundingBox other, double offsetY) { + if (other.maxX > this.minX && other.minX < this.maxX && other.maxZ > this.minZ && other.minZ < this.maxZ) { + if (offsetY > 0.0D && other.maxY <= this.minY) { + double d1 = this.minY - other.maxY; + + if (d1 < offsetY) { + offsetY = d1; + } + } else if (offsetY < 0.0D && other.minY >= this.maxY) { + double d0 = this.maxY - other.minY; + + if (d0 > offsetY) { + offsetY = d0; + } + } + + return offsetY; + } else { + return offsetY; + } + } + + /** + * if instance and the argument bounding boxes overlap in the Y and X dimensions, calculate the offset between them + * in the Z dimension. return var2 if the bounding boxes do not overlap or if var2 is closer to 0 then the + * calculated offset. Otherwise return the calculated offset. + */ + public double calculateZOffset(BoundingBox other, double offsetZ) { + if (other.maxX > this.minX && other.minX < this.maxX && other.maxY > this.minY && other.minY < this.maxY) { + if (offsetZ > 0.0D && other.maxZ <= this.minZ) { + double d1 = this.minZ - other.maxZ; + + if (d1 < offsetZ) { + offsetZ = d1; + } + } else if (offsetZ < 0.0D && other.minZ >= this.maxZ) { + double d0 = this.maxZ - other.minZ; + + if (d0 > offsetZ) { + offsetZ = d0; + } + } + + return offsetZ; + } else { + return offsetZ; + } + } + + public BoundingBox addCoord(float x, float y, float z) { + float d0 = this.minX; + float d1 = this.minY; + float d2 = this.minZ; + float d3 = this.maxX; + float d4 = this.maxY; + float d5 = this.maxZ; + + if (x < 0.0D) { + d0 += x; + } else if (x > 0.0D) { + d3 += x; + } + + if (y < 0.0D) { + d1 += y; + } else if (y > 0.0D) { + d4 += y; + } + + if (z < 0.0D) { + d2 += z; + } else if (z > 0.0D) { + d5 += z; + } + + return new BoundingBox(d0,d1,d2,d3,d4,d5); + } + + public T toAxisAlignedBB() { + return MinecraftReflection.toAABB(this); + } + + public SimpleCollisionBox toCollisionBox() { + return new SimpleCollisionBox(minX, minY, minZ, maxX, maxY, maxZ); + } + + public String toString() { + return "[" + minX + ", " + minY + ", " + minZ + ", " + maxX + ", " + maxY + ", " + maxZ + "]"; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ClassScanner.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ClassScanner.java new file mode 100644 index 00000000..4dc6edc2 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ClassScanner.java @@ -0,0 +1,157 @@ +package cc.funkemunky.api.utils; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.tree.AnnotationNode; +import jdk.internal.org.objectweb.asm.tree.ClassNode; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * This is copied from somewhere, can't remember from where thought. Modified. + * */ +public class ClassScanner { + private static final PathMatcher CLASS_FILE = create("glob:*.class"); + private static final PathMatcher ARCHIVE = create("glob:*.{jar}"); + + public static Set scanFile(String file, File f) { + URL[] urls; + try { + urls = new URL[]{f.toURI().toURL()}; + } catch (MalformedURLException e) { + e.printStackTrace(); + return new HashSet<>(); + } + return scanFile(file, urls); + } + + public static Set scanFile(String file, Class clazz) { + return scanFile(file, new URL[]{clazz.getProtectionDomain().getCodeSource().getLocation()}); + } + + public static Set scanFile(String file, URL[] urls) { + Set sources = new HashSet<>(); + Set plugins = new HashSet<>(); + + + for (URL url : urls) { + if (!url.getProtocol().equals("file")) { + continue; + } + + URI source; + try { + source = url.toURI(); + } catch (URISyntaxException e) { + continue; + } + + if (sources.add(source)) { + scanPath(file, Paths.get(source), plugins); + } + } + + return plugins; + } + + private static void scanPath(String file, Path path, Set plugins) { + if (Files.exists(path)) { + if (Files.isDirectory(path)) { + scanDirectory(file, path, plugins); + } else { + scanZip(file, path, plugins); + } + } + } + + private static void scanDirectory(String file, Path dir, final Set plugins) { + try { + Files.walkFileTree(dir, newHashSet(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { + if (CLASS_FILE.matches(path.getFileName())) { + try (InputStream in = Files.newInputStream(path)) { + String plugin = findPlugin(file, in); + if (plugin != null) { + plugins.add(plugin); + } + } + } + + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static HashSet newHashSet(E... elements) { + HashSet set = new HashSet<>(); + Collections.addAll(set, elements); + return set; + } + + + private static void scanZip(String file, Path path, Set plugins) { + if (!ARCHIVE.matches(path.getFileName())) { + return; + } + + try (ZipFile zip = new ZipFile(path.toFile())) { + Enumeration entries = zip.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + if (entry.isDirectory() || !entry.getName().endsWith(".class")) { + continue; + } + + try (InputStream in = zip.getInputStream(entry)) { + String plugin = findPlugin(file, in); + if (plugin != null) { + plugins.add(plugin); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static String findPlugin(String file, InputStream in) { + try { + ClassReader reader = new ClassReader(in); + ClassNode classNode = new ClassNode(); + reader.accept(classNode, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + String className = classNode.name.replace('/', '.'); + if (classNode.visibleAnnotations != null) { + for (Object node : classNode.visibleAnnotations) { + AnnotationNode annotation = (AnnotationNode) node; + if ((file == null && annotation.desc.equals("L" + Init.class.getName().replace(".", "/") + ";")) + || (file != null && annotation.desc.equals("L" + file.replace(".", "/") + ";"))) return className; + } + } + if (classNode.superName != null && (classNode.superName.equals(file))) return className; + } catch (Exception e) { + //System.out.println("Failed to scan: " + in.toString()); + } + return null; + } + + public static PathMatcher create(String pattern) { + return FileSystems.getDefault().getPathMatcher(pattern); + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Color.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Color.java new file mode 100644 index 00000000..12c0c1d3 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Color.java @@ -0,0 +1,52 @@ +package cc.funkemunky.api.utils; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; + +import java.util.logging.Level; + +public class Color { + + public static final String Red = ChatColor.RED.toString(); + public static final String Yellow = ChatColor.YELLOW.toString(); + public static final String Gold = ChatColor.GOLD.toString(); + public static final String Green = ChatColor.GREEN.toString(); + public static final String Aqua = ChatColor.AQUA.toString(); + public static final String Gray = ChatColor.GRAY.toString(); + public static final String Dark_Gray = ChatColor.DARK_GRAY.toString(); + public static final String Bold = ChatColor.BOLD.toString(); + public static final String Italics = ChatColor.ITALIC.toString(); + public static final String Strikethrough = ChatColor.STRIKETHROUGH.toString(); + public static final String White = ChatColor.WHITE.toString(); + public static final String Dark_Red = ChatColor.DARK_RED.toString(); + public static final String Dark_Green = ChatColor.DARK_GREEN.toString(); + public static final String Blue = ChatColor.BLUE.toString(); + public static final String Dark_Blue = ChatColor.DARK_BLUE.toString(); + public static final String Pink = ChatColor.LIGHT_PURPLE.toString(); + public static final String Purple = ChatColor.DARK_PURPLE.toString(); + public static final String Black = ChatColor.BLACK.toString(); + public static final String Underline = ChatColor.UNDERLINE.toString(); + + public static String translate(String string) { + return ChatColor.translateAlternateColorCodes('&', string); + } + + public static String strip(String string) { + return ChatColor.stripColor(string); + } + + public static String getColorFromString(String string) { + if (string.contains("&")) { + return ChatColor.translateAlternateColorCodes('&', string); + } else { + String color = (String) ReflectionsUtil.getFieldValue(ReflectionsUtil.getFieldByName(null, string), null); + + if (color == null) { + Bukkit.getLogger().log(Level.WARNING, "The color '" + string + "' does not exist."); + return Strikethrough; + } + return color; + } + } +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Commands.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Commands.java new file mode 100644 index 00000000..1b9e239b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Commands.java @@ -0,0 +1,9 @@ +package cc.funkemunky.api.utils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Commands { + String[] commands() default ""; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ConfigDefault.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ConfigDefault.java new file mode 100644 index 00000000..df1f06f1 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ConfigDefault.java @@ -0,0 +1,28 @@ +package cc.funkemunky.api.utils; + +import lombok.AllArgsConstructor; +import org.bukkit.plugin.Plugin; + +@AllArgsConstructor +public class ConfigDefault { + + private final A defaultValue; + private final String path; + private final Plugin plugin; + + public A get() { + if(plugin.getConfig().get(path) != null) + return (A) plugin.getConfig().get(path); + else { + plugin.getConfig().set(path, defaultValue); + plugin.saveConfig(); + return defaultValue; + } + } + + public A set(A value) { + plugin.getConfig().set(path, value); + + return value; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ConfigSetting.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ConfigSetting.java new file mode 100644 index 00000000..587711f4 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ConfigSetting.java @@ -0,0 +1,15 @@ +package cc.funkemunky.api.utils; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.TYPE}) +public @interface ConfigSetting { + String path() default ""; + String name() default ""; + String comment() default ""; + boolean hide() default false; +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ConfigUtils.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ConfigUtils.java new file mode 100644 index 00000000..84158d7a --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ConfigUtils.java @@ -0,0 +1,111 @@ +package cc.funkemunky.api.utils; + +public class ConfigUtils { + + /*public static void addCommentToLine(File file, String line, String comment) { + + } + + private static void save(File file) throws IOException { + Validate.notNull(file, "File cannot be null"); + Files.createParentDirs(file); + String data = this.saveToString(); + OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), UTF8_OVERRIDE && !UTF_BIG ? Charsets.UTF_8 : Charset.defaultCharset()); + + try { + writer.write(data); + } finally { + writer.close(); + } + + } + + private static String saveToString(YamlConfiguration yaml) { + val field = ReflectionsUtil.getFieldByName(YamlConfiguration.class, "yamlOptions"); + val yamlOptions = (DumperOptions) ReflectionsUtil.getFieldValue(field, yaml); + val rField = ReflectionsUtil.getFieldByName(YamlConfiguration.class, "yamlRepresenter"); + val yamlRepresenter = (Representer) ReflectionsUtil.getFieldValue(rField, yaml); + yamlOptions.setIndent(options(yaml).indent()); + yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + yamlOptions.setAllowUnicode("UTF-8"); + yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + String header = buildHeader(yaml); + String dump = dump(this.getValues(false)); + if (dump.equals("{}\n")) { + dump = ""; + } + + return header + dump; + } + + private static String dump(YamlConfiguration atlasConfig, Object data) { + List list = new ArrayList(1); + list.add(data); + return dumpAll(list.iterator()); + } + + public static String dumpAll(Iterator data) { + StringWriter buffer = new StringWriter(); + dumpAll(data, buffer, null); + return buffer.toString(); + } + + public void dumpAll(Iterator data, Writer output) { + this.dumpAll(data, output, (Tag)null); + } + + private static void dumpAll(Iterator data, Writer output, Tag rootTag) { + Serializer serializer = new Serializer(new Emitter(output, this.dumperOptions), this.resolver, this.dumperOptions, rootTag); + + try { + serializer.open(); + + while(data.hasNext()) { + Node node = this.representer.represent(data.next()); + serializer.serialize(node); + } + + serializer.close(); + } catch (IOException var6) { + throw new YAMLException(var6); + } + } + + private static YamlConfigurationOptions options(FileConfiguration atlasConfig) { + val method = ReflectionsUtil.getMethod(YamlConfiguration.class, "options"); + return (YamlConfigurationOptions) ReflectionsUtil.getMethodValue(method, atlasConfig); + } + + protected String buildHeader(YamlConfiguration atlasConfig) { + String header = this.options(atlasConfig).header(); + if (this.options(atlasConfig).copyHeader()) { + Configuration def = atlasConfig.getDefaults(); + if (def != null && def instanceof FileConfiguration) { + FileConfiguration filedefaults = (FileConfiguration)def; + String defaultsHeader = buildHeader(atlasConfig); + if (defaultsHeader != null && defaultsHeader.length() > 0) { + return defaultsHeader; + } + } + } + + if (header == null) { + return ""; + } else { + StringBuilder builder = new StringBuilder(); + String[] lines = header.split("\r?\n", -1); + boolean startedHeader = false; + + for(int i = lines.length - 1; i >= 0; --i) { + builder.insert(0, "\n"); + if (startedHeader || lines[i].length() != 0) { + builder.insert(0, lines[i]); + builder.insert(0, "# "); + startedHeader = true; + } + } + + return builder.toString(); + } + }*/ +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Dummy.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Dummy.java new file mode 100644 index 00000000..4dc8ef91 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Dummy.java @@ -0,0 +1,4 @@ +package cc.funkemunky.api.utils; + +public class Dummy { +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/FunkeFile.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/FunkeFile.java new file mode 100644 index 00000000..7e688d56 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/FunkeFile.java @@ -0,0 +1,127 @@ +package cc.funkemunky.api.utils; + +import cc.funkemunky.api.Atlas; +import org.bukkit.plugin.Plugin; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + +public class FunkeFile { + public List lines = new ArrayList<>(); + private File file; + private String name; + + public FunkeFile(Plugin Plugin, String Path, String Name) { + this.file = new File(Plugin.getDataFolder() + File.separator + Path); + this.file.mkdirs(); + this.file = new File(Plugin.getDataFolder() + File.separator + Path, Name); + if(!file.exists()) { + try { + this.file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + this.name = Name; + + readFile(); + } + + public FunkeFile(String name) { + this.file = Atlas.getInstance().getDataFolder(); + this.file.mkdirs(); + this.file = new File(Atlas.getInstance().getDataFolder(), name); + + if(!file.exists()) { + try { + this.file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + this.name = name; + + readFile(); + } + + public FunkeFile(File file) { + this.file = file; + + if(!file.exists()) { + try { + this.file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + this.name = name; + + readFile(); + } + + public synchronized void clear() { + this.lines.clear(); + if(file.delete()) { + try { + file.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + public synchronized void addLine(String line) { + this.lines.add(line); + } + + public synchronized void write() { + try { + FileWriter fw = new FileWriter(this.file, false); + BufferedWriter bw = new BufferedWriter(fw); + for (String line : this.lines) { + bw.write(line); + bw.newLine(); + } + bw.close(); + fw.close(); + } catch (Exception localException) { + localException.printStackTrace(); + } + } + + public synchronized void readFile() { + this.lines.clear(); + try { + FileReader fr = new FileReader(this.file); + BufferedReader br = new BufferedReader(fr); + String line; + while ((line = br.readLine()) != null) { + this.lines.add(line); + } + br.close(); + fr.close(); + } catch (Exception exx) { + exx.printStackTrace(); + } + } + + public String getName() { + return this.name; + } + + public String getText() { + String text = ""; + for (int i = 0; i < this.lines.size(); i++) { + String line = (String) this.lines.get(i); + + text = text + line + (this.lines.size() - 1 == i ? "" : "\n"); + } + return text; + } + + public List getLines() { + return this.lines; + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Helper.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Helper.java new file mode 100644 index 00000000..edb99135 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Helper.java @@ -0,0 +1,170 @@ +package cc.funkemunky.api.utils; + +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.utils.handlers.PlayerSizeHandler; +import cc.funkemunky.api.utils.world.BlockData; +import cc.funkemunky.api.utils.world.CollisionBox; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class Helper { + + public static int angularDistance(double alpha, double beta) { + while (alpha < 0) alpha += 360; + while (beta < 0) beta += 360; + double phi = Math.abs(beta - alpha) % 360; + return (int) (phi > 180 ? 360 - phi : phi); + } + + public static Vector vector(double yaw, double pitch) { + Vector vector = new Vector(); + vector.setY(-Math.sin(Math.toRadians(pitch))); + double xz = Math.cos(Math.toRadians(pitch)); + vector.setX(-xz * Math.sin(Math.toRadians(yaw))); + vector.setZ(xz * Math.cos(Math.toRadians(yaw))); + return vector; + } + + public static SimpleCollisionBox getMovementHitbox(Player player, double x, double y, double z) { + return PlayerSizeHandler.instance.bounds(player, x, y, z); + } + + public static SimpleCollisionBox getMovementHitbox(Player player) { + return PlayerSizeHandler.instance.bounds(player); + } + + public static SimpleCollisionBox getCombatHitbox(Player player, ProtocolVersion version) { + return version.isBelow(ProtocolVersion.V1_9) + ? PlayerSizeHandler.instance.bounds(player).expand(.1, 0, .1) + : PlayerSizeHandler.instance.bounds(player); + } + + public static Block getBlockAt(World world, int x, int y, int z) { + return world.isChunkLoaded(x >> 4, z >> 4) + ? world.getChunkAt(x >> 4, z >> 4).getBlock(x & 15, y, z & 15) + : null; + } + + public static SimpleCollisionBox wrap(SimpleCollisionBox a, SimpleCollisionBox b) { + double minX = Math.min(a.xMin, b.xMin); + double minY = Math.min(a.yMin, b.yMin); + double minZ = Math.min(a.zMin, b.zMin); + double maxX = Math.max(a.xMax, b.xMax); + double maxY = Math.max(a.yMax, b.yMax); + double maxZ = Math.max(a.zMax, b.zMax); + return new SimpleCollisionBox(minX, minY, minZ, maxX, maxY, maxZ); + } + + public static SimpleCollisionBox wrap(List box) { + if (!box.isEmpty()) { + SimpleCollisionBox wrap = box.get(0).copy(); + for (int i = 1; i < box.size(); i++) { + SimpleCollisionBox a = box.get(i); + if (wrap.xMin > a.xMin) wrap.xMin = a.xMin; + if (wrap.yMin > a.yMin) wrap.yMin = a.yMin; + if (wrap.zMin > a.zMin) wrap.zMin = a.zMin; + if (wrap.xMax < a.xMax) wrap.xMax = a.xMax; + if (wrap.yMax < a.yMax) wrap.yMax = a.yMax; + if (wrap.zMax < a.zMax) wrap.zMax = a.zMax; + } + return wrap; + } + return null; + } + + public static List blockCollisions(List blocks, CollisionBox box) { + return blocks.stream() + .filter(b -> BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion()).isCollided(box)) + .collect(Collectors.toCollection(LinkedList::new)); + } + + public static boolean isCollided(SimpleCollisionBox toCheck, CollisionBox other) { + List downcasted = new ArrayList<>(); + + other.downCast(downcasted); + + return downcasted.stream().anyMatch(box -> box.xMax >= toCheck.xMin && box.xMin <= toCheck.xMax + && box.yMax >= toCheck.yMin && box.yMin <= toCheck.yMax && box.zMax >= toCheck.zMin + && box.zMin <= toCheck.zMax); + } + + public static List blockCollisions(List blocks, CollisionBox box, int material) { + return blocks.stream().filter(b -> Materials.checkFlag(b.getType(), material)) + .filter(b -> BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion()).isCollided(box)) + .collect(Collectors.toCollection(LinkedList::new)); + } + + + public static List collisions(List boxes, CollisionBox box) { + return boxes.stream().filter(b -> b.isCollided(box)) + .collect(Collectors.toCollection(LinkedList::new)); + } + + public static List getBlocksNearby2(World world, SimpleCollisionBox collisionBox, int mask) { + int x1 = (int) Math.floor(collisionBox.xMin); + int y1 = (int) Math.floor(collisionBox.yMin); + int z1 = (int) Math.floor(collisionBox.zMin); + int x2 = (int) Math.ceil(collisionBox.xMax); + int y2 = (int) Math.ceil(collisionBox.yMax); + int z2 = (int) Math.ceil(collisionBox.zMax); + List blocks = new LinkedList<>(); + Block block; + for (int x = x1; x <= x2; x++) + for (int y = y1; y <= y2; y++) + for (int z = z1; z <= z2; z++) + if ((block = getBlockAt(world, x, y, z)) != null + && block.getType()!= XMaterial.AIR.parseMaterial()) + if (Materials.checkFlag(block.getType(),mask)) + blocks.add(block); + return blocks; + } + + private static final int[] decimalPlaces = {0, 10, 100, 1000, 10000, 100000, 1000000, + 10000000, 100000000, 1000000000}; + + public static double format(double d, int dec) { + return (long) (d * decimalPlaces[dec] + 0.5) / (double) decimalPlaces[dec]; + } + + public static String drawUsage(long max, long time) { + double chunk = max / 50.; + String line = IntStream.range(0, 50).mapToObj(i -> (chunk * i < time ? "§c" : "§7") + "❘") + .collect(Collectors.joining("", "[", "")); + String zeros = "00"; + String nums = Integer.toString((int) ((time / (double) max) * 100)); + return line + "§f] §c" + zeros.substring(0, 3 - nums.length()) + nums + "% §f❘"; + } + + public static String drawUsage(long max, double time) { + double chunk = max / 50.; + String line = IntStream.range(0, 50).mapToObj(i -> (chunk * i < time ? "§c" : "§7") + "❘") + .collect(Collectors.joining("", "[", "")); + String nums = String.valueOf(format((time / (double) max) * 100, 3)); + return line + "§f] §c" + nums + "%"; + } + + public static List toCollisions(List blocks) { + return blocks.stream().map(b -> BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion())) + .collect(Collectors.toCollection(LinkedList::new)); + } + + public static List toCollisionsDowncasted(List blocks) { + List collisions = new LinkedList<>(); + blocks.forEach(b -> BlockData.getData(b.getType()) + .getBox(b, ProtocolVersion.getGameVersion()).downCast(collisions)); + return collisions; + } + + public static CollisionBox toCollisions(Block b) { + return BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion()); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Init.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Init.java new file mode 100644 index 00000000..60ff4b5d --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Init.java @@ -0,0 +1,17 @@ +package cc.funkemunky.api.utils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Init { + Priority priority() default Priority.NORMAL; + boolean commands() default false; + String[] requirePlugins() default {}; + RequireType requireType() default RequireType.ALL; + + enum RequireType { + ALL, + ONE + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Instance.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Instance.java new file mode 100644 index 00000000..a27f2b9a --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Instance.java @@ -0,0 +1,11 @@ +package cc.funkemunky.api.utils; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.TYPE}) +public @interface Instance { +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Invoke.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Invoke.java new file mode 100644 index 00000000..94b3f35f --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Invoke.java @@ -0,0 +1,11 @@ +package cc.funkemunky.api.utils; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +public @interface Invoke { +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ItemBuilder.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ItemBuilder.java new file mode 100644 index 00000000..0d9d7f20 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ItemBuilder.java @@ -0,0 +1,239 @@ +package cc.funkemunky.api.utils; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.material.MaterialData; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * This is a chainable builder for {@link ItemStack}s in {@link Bukkit}
+ * Example Usage:
+ * {@code ItemStack is = new ItemBuilder(Material.LEATHER_HELMET).amount(2).data(4).durability(4).enchantment(Enchantment.ARROW_INFINITE).enchantment(Enchantment.LUCK, 2).name(ChatColor.RED + "the name").lore(ChatColor.GREEN + "line 1").lore(ChatColor.BLUE + "line 2").color(Color.MAROON).build(); + * + * @author MiniDigger, edited by Alexandeh + * @version 1.3 + */ +public class ItemBuilder { + private ItemStack is; + /** + * Inits the builder with the given {@link Material} + * + * @param mat the {@link Material} to start the builder from + * @since 1.0 + */ + public ItemBuilder(Material mat) { + is = new ItemStack(mat); + } + + /** + * Inits the builder with the given {@link ItemStack} + * + * @param is the {@link ItemStack} to start the builder from + * @since 1.0 + */ + public ItemBuilder(ItemStack is) { + this.is = is; + } + + /** + * Changes the amount of the {@link ItemStack} + * + * @param amount the new amount to set + * @return this builder for chaining + * @since 1.0 + */ + public ItemBuilder amount(int amount) { + is.setAmount(amount); + return this; + } + + /** + * Changes the display name of the {@link ItemStack} + * + * @param name the new display name to set + * @return this builder for chaining + * @since 1.0 + */ + public ItemBuilder name(String name) { + ItemMeta meta = is.getItemMeta(); + meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', name)); + is.setItemMeta(meta); + return this; + } + + public ItemBuilder owner(String name) { + final SkullMeta meta = (SkullMeta) is.getItemMeta(); + meta.setOwner(name); + is.setItemMeta(meta); + return this; + } + + /** + * Adds a new line to the lore of the {@link ItemStack} + * + * @param name the new line to add + * @return this builder for chaining + * @since 1.0 + */ + public ItemBuilder lore(String name) { + ItemMeta meta = is.getItemMeta(); + List lore = meta.getLore(); + if (lore == null) { + lore = new ArrayList(); + } + lore.add(name); + meta.setLore(lore); + is.setItemMeta(meta); + return this; + } + + public ItemBuilder lore(String... lore) { + ItemMeta meta = is.getItemMeta(); + List lores = Arrays.stream(lore).map(s -> ChatColor.translateAlternateColorCodes('&', s)).collect(Collectors.toList()); + meta.setLore(lores); + is.setItemMeta(meta); + return this; + } + + /** + * sets the lore of the {@link ItemStack} + * + * @param lore the loret o set + * @return this builder for chaining + * @since 1.2 + */ + public ItemBuilder lore(List lore) { + ItemMeta meta = is.getItemMeta(); + meta.setLore(lore); + is.setItemMeta(meta); + return this; + } + + /** + * Changes the durability of the {@link ItemStack} + * + * @param durability the new durability to set + * @return this builder for chaining + * @since 1.0 + */ + public ItemBuilder durability(int durability) { + is.setDurability((short) durability); + return this; + } + + /** + * Changes the data of the {@link ItemStack} + * + * @param data the new data to set + * @return this builder for chaining + * @since 1.0 + */ + @SuppressWarnings("deprecation") + public ItemBuilder data(int data) { + is.setData(new MaterialData(is.getType(), (byte) data)); + return this; + } + + /** + * Adds an {@link Enchantment} with the given level to the {@link ItemStack} + * + * @param enchantment the enchantment to add + * @param level the level of the enchantment + * @return this builder for chaining + * @since 1.0 + */ + public ItemBuilder enchantment(Enchantment enchantment, int level) { + is.addUnsafeEnchantment(enchantment, level); + return this; + } + + /** + * Adds an {@link Enchantment} with the level 1 to the {@link ItemStack} + * + * @param enchantment the enchantment to add + * @return this builder for chaining + * @since 1.0 + */ + public ItemBuilder enchantment(Enchantment enchantment) { + is.addUnsafeEnchantment(enchantment, 1); + return this; + } + + /** + * Changes the {@link Material} of the {@link ItemStack} + * + * @param material the new material to set + * @return this builder for chaining + * @since 1.0 + */ + public ItemBuilder type(Material material) { + is.setType(material); + return this; + } + + /** + * Clears the lore of the {@link ItemStack} + * + * @return this builder for chaining + * @since 1.0 + */ + public ItemBuilder clearLore() { + ItemMeta meta = is.getItemMeta(); + meta.setLore(new ArrayList<>()); + is.setItemMeta(meta); + return this; + } + + /** + * Clears the list of {@link Enchantment}s of the {@link ItemStack} + * + * @return this builder for chaining + * @since 1.0 + */ + public ItemBuilder clearEnchantments() { + is.getEnchantments().keySet().forEach(e -> is.removeEnchantment(e)); + return this; + } + + /** + * Sets the {@link Color} of a part of leather armor + * + * @param color the {@link Color} to use + * @return this builder for chaining + * @since 1.1 + */ + public ItemBuilder color(Color color) { + if (is.getType() == XMaterial.LEATHER_BOOTS.parseMaterial() + || is.getType() == XMaterial.LEATHER_CHESTPLATE .parseMaterial() + || is.getType() == XMaterial.LEATHER_HELMET.parseMaterial() + || is.getType() == XMaterial.LEATHER_LEGGINGS.parseMaterial()) { + LeatherArmorMeta meta = (LeatherArmorMeta) is.getItemMeta(); + meta.setColor(color); + is.setItemMeta(meta); + return this; + } else { + throw new IllegalArgumentException("color() only applicable for leather armor!"); + } + } + + /** + * Builds the {@link ItemStack} + * + * @return the created {@link ItemStack} + * @since 1.0 + */ + public ItemStack build() { + return is; + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/JsonMessage.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/JsonMessage.java new file mode 100644 index 00000000..d47fc9b0 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/JsonMessage.java @@ -0,0 +1,143 @@ +package cc.funkemunky.api.utils; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.Constructor; +import java.util.*; + +public class JsonMessage { + private final List Text = new ArrayList<>(); + + public AMText addText(String Message) { + AMText Text = new AMText(Message); + this.Text.add(Text); + return Text; + } + + private String getFormattedMessage() { + StringBuilder Chat = new StringBuilder("[\"\","); + for (AMText Text : this.Text) { + Chat.append(Text.getFormattedMessage()).append(","); + } + Chat = new StringBuilder(Chat.substring(0, Chat.length() - 1)); + Chat.append("]"); + return Chat.toString(); + } + + public void sendToPlayer(Player player) { + try { + Object base; + Constructor titleConstructor = ReflectionsUtil.getNMSClass("PacketPlayOutChat").getConstructor(ReflectionsUtil.getNMSClass("IChatBaseComponent")); + base = ReflectionsUtil.isBukkitVerison("1_7") || ReflectionsUtil.isBukkitVerison("1_8_R1") ? ReflectionsUtil.getNMSClass("ChatSerializer").getMethod("a", String.class).invoke(null, this.getFormattedMessage()) : ReflectionsUtil.getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", String.class).invoke(null, this.getFormattedMessage()); + Object packet = titleConstructor.newInstance(base); + this.sendPacket(player, packet); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + + private void sendPacket(Player player, Object packet) { + try { + Object handle = player.getClass().getMethod("getHandle", new Class[0]).invoke(player); + Object playerConnection = handle.getClass().getField("playerConnection").get(handle); + playerConnection.getClass().getMethod("sendPacket", ReflectionsUtil.getNMSClass("Packet")).invoke(playerConnection, packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private Class getCBClass(String name) { + String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; + try { + return Class.forName("org.bukkit.craftbukkit." + version + "." + name); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + public enum ClickableType { + RunCommand("run_command"), + SuggestCommand("suggest_command"), + OpenURL("open_url"); + + final String Action; + + ClickableType(String Action) { + this.Action = Action; + } + } + + public class AMText { + private final Map> Modifiers; + private String Message; + + AMText(String Text) { + this.Message = ""; + this.Modifiers = new HashMap<>(); + this.Message = Text; + } + + public String getMessage() { + return this.Message; + } + + String getFormattedMessage() { + StringBuilder Chat = new StringBuilder("{\"text\":\"" + this.Message + "\""); + for (String Event2 : this.Modifiers.keySet()) { + Map.Entry Modifier = this.Modifiers.get(Event2); + Chat.append(",\"").append(Event2).append("\":{\"action\":\"").append(Modifier.getKey()).append("\",\"value\":").append(Modifier.getValue()).append("}"); + } + Chat.append("}"); + return Chat.toString(); + } + + public /* varargs */ AMText addHoverText(String... Text) { + String Event2 = "hoverEvent"; + String Key = "show_text"; + StringBuilder Value = new StringBuilder(); + if (Text.length == 1) { + Value = new StringBuilder("{\"text\":\"" + Text[0] + "\"}"); + } else { + Value = new StringBuilder("{\"text\":\"\",\"extra\":["); + for (String Message : Text) { + Value.append("{\"text\":\"").append(Message).append("\"},"); + } + Value = new StringBuilder(Value.substring(0, Value.length() - 1)); + Value.append("]}"); + } + AbstractMap.SimpleEntry Values2 = new AbstractMap.SimpleEntry<>(Key, Value.toString()); + this.Modifiers.put(Event2, Values2); + return this; + } + + public AMText addHoverItem(ItemStack Item) { + try { + String Event2 = "hoverEvent"; + String Key = "show_item"; + Class craftItemStack = ReflectionsUtil.getCBClass("CraftItemStack"); + Class items = Class.forName("org.bukkit.inventory.ItemStack"); + Object NMS = craftItemStack.getClass().getMethod("asNMSCopy", items).invoke(Item); + String Value = NMS.getClass().getMethod("getTag", new Class[0]).toString(); + AbstractMap.SimpleEntry Values2 = new AbstractMap.SimpleEntry<>(Key, Value); + this.Modifiers.put(Event2, Values2); + return this; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public AMText setClickEvent(ClickableType Type2, String Value) { + String Event2 = "clickEvent"; + String Key = Type2.Action; + AbstractMap.SimpleEntry Values2 = new AbstractMap.SimpleEntry<>(Key, "\"" + Value + "\""); + this.Modifiers.put(Event2, Values2); + return this; + } + } + +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/KLocation.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/KLocation.java new file mode 100644 index 00000000..0820cb8d --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/KLocation.java @@ -0,0 +1,58 @@ +package cc.funkemunky.api.utils; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.util.Vector; + +public class KLocation { + public double x, y, z; + public float yaw, pitch; + public long timeStamp; + + public KLocation(double x, double y, double z, float yaw, float pitch, long timeStamp) { + this.x = x; + this.y = y; + this.z = z; + this.yaw = yaw; + this.pitch = pitch; + this.timeStamp = timeStamp; + } + + public KLocation(double x, double y, double z, float yaw, float pitch) { + this.x = x; + this.y = y; + this.z = z; + this.yaw = yaw; + this.pitch = pitch; + this.timeStamp = System.currentTimeMillis(); + } + + public KLocation(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + + this.timeStamp = System.currentTimeMillis(); + } + + public KLocation(Location location) { + this.x = location.getX(); + this.y = location.getY(); + this.z = location.getZ(); + this.yaw = location.getYaw(); + this.pitch = location.getPitch(); + this.timeStamp = System.currentTimeMillis(); + } + + public Vector toVector() { + return new Vector(x, y, z); + } + + public Location toLocation(World world) { + return new Location(world, x, y, z, yaw, pitch); + } + + public KLocation clone() { + return new KLocation(x, y, z, yaw, pitch, timeStamp); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Materials.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Materials.java new file mode 100644 index 00000000..93912299 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Materials.java @@ -0,0 +1,93 @@ +package cc.funkemunky.api.utils; + +import org.bukkit.Material; + +public class Materials { + private static final int[] MATERIAL_FLAGS = new int[Material.values().length]; + + public static final int SOLID = 0b00000000000000000000000000001; + public static final int LADDER = 0b00000000000000000000000000010; + public static final int WALL = 0b00000000000000000000000000100; + public static final int STAIRS = 0b00000000000000000000000001000; + public static final int SLABS = 0b00000000000000000000000010000; + public static final int WATER = 0b00000000000000000000000100000; + public static final int LAVA = 0b00000000000000000000001000000; + public static final int LIQUID = 0b00000000000000000000001100000; + public static final int ICE = 0b00000000000000000000010000000; + public static final int FENCE = 0b00000000000000000000100000000; + + static { + for (int i = 0; i < MATERIAL_FLAGS.length; i++) { + Material material = Material.values()[i]; + + if (material.isSolid()) { + MATERIAL_FLAGS[i] |= SOLID; + } + if (material.name().endsWith("_STAIRS")) { + MATERIAL_FLAGS[i] |= STAIRS; + } + + if (material.name().contains("SLAB") || material.name().contains("STEP")) { + MATERIAL_FLAGS[i] |= SLABS; + } + } + + // fix some types where isSolid() returns the wrong value + MATERIAL_FLAGS[XMaterial.SLIME_BLOCK.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.COMPARATOR.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.REDSTONE_COMPARATOR_OFF.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.REDSTONE_COMPARATOR_ON.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.REPEATER.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.DIODE_BLOCK_OFF.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.DIODE_BLOCK_ON.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.SNOW.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.ANVIL.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.LILY_PAD.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.SKELETON_SKULL.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.SKELETON_WALL_SKULL.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.WITHER_SKELETON_SKULL.parseMaterial().ordinal()] = SOLID; + MATERIAL_FLAGS[XMaterial.WITHER_SKELETON_WALL_SKULL.parseMaterial().ordinal()] = SOLID; + + // liquids + MATERIAL_FLAGS[XMaterial.WATER.parseMaterial().ordinal()] |= LIQUID | WATER; + MATERIAL_FLAGS[XMaterial.LAVA.parseMaterial().ordinal()] |= LIQUID | LAVA; + MATERIAL_FLAGS[XMaterial.STATIONARY_LAVA.parseMaterial().ordinal()] |= LIQUID | LAVA; + MATERIAL_FLAGS[XMaterial.STATIONARY_WATER.parseMaterial().ordinal()] |= LIQUID | WATER; + + // ladders + MATERIAL_FLAGS[XMaterial.LADDER.parseMaterial().ordinal()] |= LADDER | SOLID; + MATERIAL_FLAGS[XMaterial.VINE.parseMaterial().ordinal()] |= LADDER | SOLID; + for (Material mat : Material.values()) { + if (mat.name().contains("FENCE")) { + if(!mat.name().contains("GATE")) MATERIAL_FLAGS[mat.ordinal()] |= FENCE | WALL; + else MATERIAL_FLAGS[mat.ordinal()] |= WALL; + } + if(mat.name().contains("WALL")) MATERIAL_FLAGS[mat.ordinal()] |= WALL; + if(mat.name().contains("PLATE")) MATERIAL_FLAGS[mat.ordinal()] = 0; + if(mat.name().contains("BED") && !mat.name().contains("ROCK")) MATERIAL_FLAGS[mat.ordinal()] |= SLABS; + if(mat.name().contains("ICE")) MATERIAL_FLAGS[mat.ordinal()] |= ICE; + if(mat.name().contains("CARPET")) MATERIAL_FLAGS[mat.ordinal()] = SOLID; + if(mat.name().contains("SIGN")) MATERIAL_FLAGS[mat.ordinal()] = 0; + } + } + + public static int getBitmask(Material material) { + return MATERIAL_FLAGS[material.ordinal()]; + } + + private Materials() { + } + + public static boolean checkFlag(Material material, int flag) { + return (MATERIAL_FLAGS[material.ordinal()] & flag) == flag; + } + + public static boolean isUsable(Material material) { + String nameLower = material.name().toLowerCase(); + return material.isEdible() + || nameLower.contains("bow") + || nameLower.contains("sword") + || nameLower.contains("trident"); + } + +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/MathHelper.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/MathHelper.java new file mode 100644 index 00000000..614483d6 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/MathHelper.java @@ -0,0 +1,501 @@ +package cc.funkemunky.api.utils; + + +import java.util.Random; +import java.util.UUID; + +public class MathHelper { + public static final float SQRT_2 = sqrt_float(2.0F); + public static final float PI = (float) Math.PI; + public static final float PI2 = ((float) Math.PI * 2F); + public static final float PId2 = ((float) Math.PI / 2F); + public static final float deg2Rad = 0.017453292F; + private static final int SIN_BITS = 12; + private static final int SIN_MASK = 4095; + private static final int SIN_COUNT = 4096; + private static final float radFull = ((float) Math.PI * 2F); + private static final float degFull = 360.0F; + private static final float radToIndex = 651.8986F; + private static final float degToIndex = 11.377778F; + private static final float[] SIN_TABLE_FAST = new float[4096]; + /** + * A table of sin values computed from 0 (inclusive) to 2*pi (exclusive), with steps of 2*PI / 65536. + */ + private static final float[] SIN_TABLE = new float[65536]; + /** + * Though it looks like an array, this is really more like a mapping. Key (index of this array) is the upper 5 bits + * of the result of multiplying a 32-bit unsigned integer by the B(2, 5) De Bruijn sequence 0x077CB531. Value + * (value stored in the array) is the unique index (from the right) of the leftmost one-bit in a 32-bit unsigned + * integer that can cause the upper 5 bits to get that value. Used for highly optimized "find the log-base-2 of + * this number" calculations. + */ + private static final int[] multiplyDeBruijnBitPosition; + private static final double field_181163_d; + private static final double[] field_181164_e; + private static final double[] field_181165_f; + private static final String __OBFID = "CL_00001496"; + public static boolean fastMath = false; + + static { + for (int i = 0; i < 65536; ++i) { + SIN_TABLE[i] = (float) Math.sin((double) i * Math.PI * 2.0D / 65536.0D); + } + + for (int j = 0; j < 4096; ++j) { + SIN_TABLE_FAST[j] = (float) Math.sin((double) (((float) j + 0.5F) / 4096.0F * ((float) Math.PI * 2F))); + } + + for (int l = 0; l < 360; l += 90) { + SIN_TABLE_FAST[(int) ((float) l * 11.377778F) & 4095] = (float) Math.sin((double) ((float) l * 0.017453292F)); + } + + multiplyDeBruijnBitPosition = new int[]{0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; + field_181163_d = Double.longBitsToDouble(4805340802404319232L); + field_181164_e = new double[257]; + field_181165_f = new double[257]; + + for (int k = 0; k < 257; ++k) { + double d1 = (double) k / 256.0D; + double d0 = Math.asin(d1); + field_181165_f[k] = Math.cos(d0); + field_181164_e[k] = d0; + } + } + + /** + * sin looked up in a table + */ + public static float sin(float p_76126_0_) { + return fastMath ? SIN_TABLE_FAST[(int) (p_76126_0_ * 651.8986F) & 4095] : SIN_TABLE[(int) (p_76126_0_ * 10430.378F) & 65535]; + } + + /** + * cos looked up in the sin table with the appropriate offset + */ + public static float cos(float value) { + return fastMath ? SIN_TABLE_FAST[(int) ((value + ((float) Math.PI / 2F)) * 651.8986F) & 4095] : SIN_TABLE[(int) (value * 10430.378F + 16384.0F) & 65535]; + } + + public static float sqrt_float(float value) { + return (float) Math.sqrt((double) value); + } + + public static float sqrt_double(double value) { + return (float) Math.sqrt(value); + } + + /** + * Returns the greatest integer less than or equal to the float argument + */ + public static int floor_float(float value) { + int i = (int) value; + return value < (float) i ? i - 1 : i; + } + + /** + * returns par0 cast as an int, and no greater than Integer.MAX_VALUE-1024 + */ + public static int truncateDoubleToInt(double value) { + return (int) (value + 1024.0D) - 1024; + } + + /** + * Returns the greatest integer less than or equal to the double argument + */ + public static int floor_double(double value) { + int i = (int) value; + return value < (double) i ? i - 1 : i; + } + + /** + * Long version of floor_double + */ + public static long floor_double_long(double value) { + long i = (long) value; + return value < (double) i ? i - 1L : i; + } + + public static int func_154353_e(double value) { + return (int) (value >= 0.0D ? value : -value + 1.0D); + } + + public static float abs(float value) { + return value >= 0.0F ? value : -value; + } + + /** + * Returns the unsigned value of an int. + */ + public static int abs_int(int value) { + return value >= 0 ? value : -value; + } + + public static int ceiling_float_int(float value) { + int i = (int) value; + return value > (float) i ? i + 1 : i; + } + + public static int ceiling_double_int(double value) { + int i = (int) value; + return value > (double) i ? i + 1 : i; + } + + /** + * Returns the value of the first parameter, clamped to be within the lower and upper limits given by the second and + * third parameters. + */ + public static int clamp_int(int num, int min, int max) { + return num < min ? min : (num > max ? max : num); + } + + /** + * Returns the value of the first parameter, clamped to be within the lower and upper limits given by the second and + * third parameters + */ + public static float clamp_float(float num, float min, float max) { + return num < min ? min : (num > max ? max : num); + } + + public static double clamp_double(double num, double min, double max) { + return num < min ? min : (num > max ? max : num); + } + + public static double denormalizeClamp(double p_151238_0_, double p_151238_2_, double p_151238_4_) { + return p_151238_4_ < 0.0D ? p_151238_0_ : (p_151238_4_ > 1.0D ? p_151238_2_ : p_151238_0_ + (p_151238_2_ - p_151238_0_) * p_151238_4_); + } + + /** + * Maximum of the absolute value of two numbers. + */ + public static double abs_max(double p_76132_0_, double p_76132_2_) { + if (p_76132_0_ < 0.0D) { + p_76132_0_ = -p_76132_0_; + } + + if (p_76132_2_ < 0.0D) { + p_76132_2_ = -p_76132_2_; + } + + return p_76132_0_ > p_76132_2_ ? p_76132_0_ : p_76132_2_; + } + + /** + * Buckets an integer with specifed bucket sizes. Args: i, bucketSize + */ + public static int bucketInt(int p_76137_0_, int p_76137_1_) { + return p_76137_0_ < 0 ? -((-p_76137_0_ - 1) / p_76137_1_) - 1 : p_76137_0_ / p_76137_1_; + } + + public static int getRandomIntegerInRange(Random p_76136_0_, int p_76136_1_, int p_76136_2_) { + return p_76136_1_ >= p_76136_2_ ? p_76136_1_ : p_76136_0_.nextInt(p_76136_2_ - p_76136_1_ + 1) + p_76136_1_; + } + + public static float randomFloatClamp(Random p_151240_0_, float p_151240_1_, float p_151240_2_) { + return p_151240_1_ >= p_151240_2_ ? p_151240_1_ : p_151240_0_.nextFloat() * (p_151240_2_ - p_151240_1_) + p_151240_1_; + } + + public static double getRandomDoubleInRange(Random p_82716_0_, double p_82716_1_, double p_82716_3_) { + return p_82716_1_ >= p_82716_3_ ? p_82716_1_ : p_82716_0_.nextDouble() * (p_82716_3_ - p_82716_1_) + p_82716_1_; + } + + public static double average(long[] values) { + long i = 0L; + + for (long j : values) { + i += j; + } + + return (double) i / (double) values.length; + } + + public static boolean epsilonEquals(float p_180185_0_, float p_180185_1_) { + return abs(p_180185_1_ - p_180185_0_) < 1.0E-5F; + } + + public static int normalizeAngle(int p_180184_0_, int p_180184_1_) { + return (p_180184_0_ % p_180184_1_ + p_180184_1_) % p_180184_1_; + } + + /** + * the angle is reduced to an angle between -180 and +180 by mod, and a 360 check + */ + public static float wrapAngleTo180_float(float value) { + value = value % 360.0F; + + if (value >= 180.0F) { + value -= 360.0F; + } + + if (value < -180.0F) { + value += 360.0F; + } + + return value; + } + + /** + * the angle is reduced to an angle between -180 and +180 by mod, and a 360 check + */ + public static double wrapAngleTo180_double(double value) { + value = value % 360.0D; + + if (value >= 180.0D) { + value -= 360.0D; + } + + if (value < -180.0D) { + value += 360.0D; + } + + return value; + } + + /** + * parses the string as integer or returns the second parameter if it fails + */ + public static int parseIntWithDefault(String p_82715_0_, int p_82715_1_) { + try { + return Integer.parseInt(p_82715_0_); + } catch (Throwable var3) { + return p_82715_1_; + } + } + + /** + * parses the string as integer or returns the second parameter if it fails. this value is capped to par2 + */ + public static int parseIntWithDefaultAndMax(String p_82714_0_, int p_82714_1_, int p_82714_2_) { + return Math.max(p_82714_2_, parseIntWithDefault(p_82714_0_, p_82714_1_)); + } + + /** + * parses the string as double or returns the second parameter if it fails. + */ + public static double parseDoubleWithDefault(String p_82712_0_, double p_82712_1_) { + try { + return Double.parseDouble(p_82712_0_); + } catch (Throwable var4) { + return p_82712_1_; + } + } + + public static double parseDoubleWithDefaultAndMax(String p_82713_0_, double p_82713_1_, double p_82713_3_) { + return Math.max(p_82713_3_, parseDoubleWithDefault(p_82713_0_, p_82713_1_)); + } + + /** + * Returns the input value rounded up to the next highest power of two. + */ + public static int roundUpToPowerOfTwo(int value) { + int i = value - 1; + i = i | i >> 1; + i = i | i >> 2; + i = i | i >> 4; + i = i | i >> 8; + i = i | i >> 16; + return i + 1; + } + + /** + * Is the given value a power of two? (1, 2, 4, 8, 16, ...) + */ + private static boolean isPowerOfTwo(int value) { + return value != 0 && (value & value - 1) == 0; + } + + /** + * Uses a B(2, 5) De Bruijn sequence and a lookup table to efficiently calculate the log-base-two of the given + * value. Optimized for cases where the input value is a power-of-two. If the input value is not a power-of-two, + * then subtract 1 from the return value. + */ + private static int calculateLogBaseTwoDeBruijn(int value) { + value = isPowerOfTwo(value) ? value : roundUpToPowerOfTwo(value); + return multiplyDeBruijnBitPosition[(int) ((long) value * 125613361L >> 27) & 31]; + } + + /** + * Efficiently calculates the floor of the base-2 log of an integer value. This is effectively the index of the + * highest bit that is set. For example, if the number in binary is 0...100101, this will return 5. + */ + public static int calculateLogBaseTwo(int value) { + return calculateLogBaseTwoDeBruijn(value) - (isPowerOfTwo(value) ? 0 : 1); + } + + public static int func_154354_b(int p_154354_0_, int p_154354_1_) { + if (p_154354_1_ == 0) { + return 0; + } else if (p_154354_0_ == 0) { + return p_154354_1_; + } else { + if (p_154354_0_ < 0) { + p_154354_1_ *= -1; + } + + int i = p_154354_0_ % p_154354_1_; + return i == 0 ? p_154354_0_ : p_154354_0_ + p_154354_1_ - i; + } + } + + public static int func_180183_b(float p_180183_0_, float p_180183_1_, float p_180183_2_) { + return func_180181_b(floor_float(p_180183_0_ * 255.0F), floor_float(p_180183_1_ * 255.0F), floor_float(p_180183_2_ * 255.0F)); + } + + public static int func_180181_b(int p_180181_0_, int p_180181_1_, int p_180181_2_) { + int i = (p_180181_0_ << 8) + p_180181_1_; + i = (i << 8) + p_180181_2_; + return i; + } + + public static int func_180188_d(int p_180188_0_, int p_180188_1_) { + int i = (p_180188_0_ & 16711680) >> 16; + int j = (p_180188_1_ & 16711680) >> 16; + int k = (p_180188_0_ & 65280) >> 8; + int l = (p_180188_1_ & 65280) >> 8; + int i1 = (p_180188_0_ & 255) >> 0; + int j1 = (p_180188_1_ & 255) >> 0; + int k1 = (int) ((float) i * (float) j / 255.0F); + int l1 = (int) ((float) k * (float) l / 255.0F); + int i2 = (int) ((float) i1 * (float) j1 / 255.0F); + return p_180188_0_ & -16777216 | k1 << 16 | l1 << 8 | i2; + } + + public static double func_181162_h(double p_181162_0_) { + return p_181162_0_ - Math.floor(p_181162_0_); + } + + public static long getCoordinateRandom(int x, int y, int z) { + long i = (long) (x * 3129871) ^ (long) z * 116129781L ^ (long) y; + i = i * i * 42317861L + i * 11L; + return i; + } + + public static UUID getRandomUuid(Random rand) { + long i = rand.nextLong() & -61441L | 16384L; + long j = rand.nextLong() & 4611686018427387903L | Long.MIN_VALUE; + return new UUID(i, j); + } + + public static double func_181160_c(double p_181160_0_, double p_181160_2_, double p_181160_4_) { + return (p_181160_0_ - p_181160_2_) / (p_181160_4_ - p_181160_2_); + } + + public static double func_181159_b(double p_181159_0_, double p_181159_2_) { + double d0 = p_181159_2_ * p_181159_2_ + p_181159_0_ * p_181159_0_; + + if (Double.isNaN(d0)) { + return Double.NaN; + } else { + boolean flag = p_181159_0_ < 0.0D; + + if (flag) { + p_181159_0_ = -p_181159_0_; + } + + boolean flag1 = p_181159_2_ < 0.0D; + + if (flag1) { + p_181159_2_ = -p_181159_2_; + } + + boolean flag2 = p_181159_0_ > p_181159_2_; + + if (flag2) { + double d1 = p_181159_2_; + p_181159_2_ = p_181159_0_; + p_181159_0_ = d1; + } + + double d9 = func_181161_i(d0); + p_181159_2_ = p_181159_2_ * d9; + p_181159_0_ = p_181159_0_ * d9; + double d2 = field_181163_d + p_181159_0_; + int i = (int) Double.doubleToRawLongBits(d2); + double d3 = field_181164_e[i]; + double d4 = field_181165_f[i]; + double d5 = d2 - field_181163_d; + double d6 = p_181159_0_ * d4 - p_181159_2_ * d5; + double d7 = (6.0D + d6 * d6) * d6 * 0.16666666666666666D; + double d8 = d3 + d7; + + if (flag2) { + d8 = (Math.PI / 2D) - d8; + } + + if (flag1) { + d8 = Math.PI - d8; + } + + if (flag) { + d8 = -d8; + } + + return d8; + } + } + + public static double func_181161_i(double p_181161_0_) { + double d0 = 0.5D * p_181161_0_; + long i = Double.doubleToRawLongBits(p_181161_0_); + i = 6910469410427058090L - (i >> 1); + p_181161_0_ = Double.longBitsToDouble(i); + p_181161_0_ = p_181161_0_ * (1.5D - d0 * p_181161_0_ * p_181161_0_); + return p_181161_0_; + } + + public static int func_181758_c(float p_181758_0_, float p_181758_1_, float p_181758_2_) { + int i = (int) (p_181758_0_ * 6.0F) % 6; + float f = p_181758_0_ * 6.0F - (float) i; + float f1 = p_181758_2_ * (1.0F - p_181758_1_); + float f2 = p_181758_2_ * (1.0F - f * p_181758_1_); + float f3 = p_181758_2_ * (1.0F - (1.0F - f) * p_181758_1_); + float f4; + float f5; + float f6; + + switch (i) { + case 0: + f4 = p_181758_2_; + f5 = f3; + f6 = f1; + break; + + case 1: + f4 = f2; + f5 = p_181758_2_; + f6 = f1; + break; + + case 2: + f4 = f1; + f5 = p_181758_2_; + f6 = f3; + break; + + case 3: + f4 = f1; + f5 = f2; + f6 = p_181758_2_; + break; + + case 4: + f4 = f3; + f5 = f1; + f6 = p_181758_2_; + break; + + case 5: + f4 = p_181758_2_; + f5 = f1; + f6 = f2; + break; + + default: + throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + p_181758_0_ + ", " + p_181758_1_ + ", " + p_181758_2_); + } + + int j = clamp_int((int) (f4 * 255.0F), 0, 255); + int k = clamp_int((int) (f5 * 255.0F), 0, 255); + int l = clamp_int((int) (f6 * 255.0F), 0, 255); + return j << 16 | k << 8 | l; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/MathUtils.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/MathUtils.java new file mode 100644 index 00000000..99a0049f --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/MathUtils.java @@ -0,0 +1,487 @@ +package cc.funkemunky.api.utils; + +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.util.*; + +public class MathUtils { + + public static double offset(Vector from, Vector to) { + from.setY(0); + to.setY(0); + + return to.subtract(from).length(); + } + + public static boolean playerMoved(Location from, Location to) { + return playerMoved(from.toVector(), to.toVector()); + } + + public static byte getByte(int num) { + if(num > Byte.MAX_VALUE || num < Byte.MIN_VALUE) { + throw new NumberFormatException("Integer " + num + " too large to cast to data format byte!" + + " (max=" + Byte.MAX_VALUE + " min=" + Byte.MIN_VALUE + ")"); + } + + return (byte) num; + } + + public static short getShort(int num) { + if(num > Short.MAX_VALUE || num < Short.MIN_VALUE) { + throw new NumberFormatException("Integer " + num + " too large to cast to data format short!" + + " (max=" + Short.MAX_VALUE + " min=" + Short.MIN_VALUE + ")"); + } + return (short) num; + } + + /* Stolen from Bukkit */ + public static Vector getDirection(KLocation loc) { + Vector vector = new Vector(); + double rotX = loc.yaw; + double rotY = loc.pitch; + vector.setY(-Math.sin(Math.toRadians(rotY))); + double xz = Math.cos(Math.toRadians(rotY)); + vector.setX(-xz * Math.sin(Math.toRadians(rotX))); + vector.setZ(xz * Math.cos(Math.toRadians(rotX))); + return vector; + } + + public static boolean approxEquals(double accuracy, double equalTo, double... equals) { + return Arrays.stream(equals).allMatch(equal -> MathUtils.getDelta(equalTo, equal) < accuracy); + } + + public static boolean approxEquals(double accuracy, int equalTo, int... equals) { + return Arrays.stream(equals).allMatch(equal -> MathUtils.getDelta(equalTo, equal) < accuracy); + } + + public static boolean approxEquals(double accuracy, long equalTo, long... equals) { + return Arrays.stream(equals).allMatch(equal -> MathUtils.getDelta(equalTo, equal) < accuracy); + } + + public static double getDistanceToBox(Vector vec, BoundingBox box) { + return vec.distance(getCenterOfBox(box)); + } + + public static Vector getCenterOfBox(BoundingBox box) { + return box.getMinimum().midpoint(box.getMaximum()); + } + + //Returns -1 if fails. + public static T tryParse(String string) { + try { + return (T)(Number)Double.parseDouble(string); + } catch(NumberFormatException e) { + + } + return (T)(Number)(-1); + } + + //A lighter version of the Java hypotenuse function. + public static double hypot(double... value) { + double total = 0; + + for (double val : value) { + total += (val * val); + } + + return Math.sqrt(total); + } + + public static float hypot(float... value) { + float total = 0; + + for (float val : value) { + total += (val * val); + } + + return (float) Math.sqrt(total); + } + + public static double get3DDistance(Vector one, Vector two) { + return hypot(one.getX() - two.getX(), one.getY() - two.getY(), one.getZ() - two.getZ()); + } + + public static boolean playerMoved(Vector from, Vector to) { + return from.distance(to) > 0; + } + + public static boolean playerLooked(Location from, Location to) { + return (from.getYaw() - to.getYaw() != 0) || (from.getPitch() - to.getPitch() != 0); + } + public static boolean elapsed(long time, long needed) { + return Math.abs(System.currentTimeMillis() - time) >= needed; + } + + //Euclid's algorithim + public static long gcd(long a, long b) + { + while (b > 0) + { + long temp = b; + b = a % b; // % is remainder + a = temp; + } + return a; + } + + //Euclid's algorithim + public static long gcd(long... input) + { + long result = input[0]; + for(int i = 1; i < input.length; i++) result = gcd(result, input[i]); + return result; + } + + // Returns the absolute value of n-mid*mid*mid + static double diff(double n,double mid) + { + if (n > (mid*mid*mid)) + return (n-(mid*mid*mid)); + else + return ((mid*mid*mid) - n); + } + + // Returns cube root of a no n + public static double cbrt(double n) + { + // Set start and end for binary search + double start = 0, end = n; + + // Set precision + double e = 0.0000001; + + double mid = -1; + double error = 1000; + + long ticks = 0; + while (error > e) + { + mid = (start + end)/2; + error = diff(n, mid); + + // If error is less than e then mid is + // our answer so return mid + + // If mid*mid*mid is greater than n set + // end = mid + if ((mid*mid*mid) > n) + end = mid; + + // If mid*mid*mid is less than n set + // start = mid + else + start = mid; + + if(error > e && ticks++ > 3E4) { + return -1; + } + } + return mid; + } + + //A much lighter but very slightly less accurate Math.sqrt. + public static double sqrt(double number) { + if(number == 0) return 0; + double t; + double squareRoot = number / 2; + + do { + t = squareRoot; + squareRoot = (t + (number / t)) / 2; + } while ((t - squareRoot) != 0); + + return squareRoot; + } + + public static Vector getDirection(double yaw, double pitch) { + Vector vector = new Vector(); + vector.setY(-Math.sin(Math.toRadians(pitch))); + double xz = Math.cos(Math.toRadians(pitch)); + vector.setX(-xz * Math.sin(Math.toRadians(yaw))); + vector.setZ(xz * Math.cos(Math.toRadians(yaw))); + return vector; + } + + public static float sqrt(float number) { + if(number == 0) return 0; + float t; + + float squareRoot = number / 2; + + do { + t = squareRoot; + squareRoot = (t + (number / t)) / 2; + } while ((t - squareRoot) != 0); + + return squareRoot; + } + + public static float normalizeAngle(float yaw) { + return yaw % 360; + } + + public static double normalizeAngle(double yaw) { + return yaw % 360; + } + + public static float getAngleDelta(float one, float two) { + float delta = getDelta(one, two) % 360f; + + if(delta > 180) delta = 360 - delta; + return delta; + } + + //Euclid's algorithim + public static long lcm(long a, long b) + { + return a * (b / gcd(a, b)); + } + + //Euclid's algorithim + public static long lcm(long... input) + { + long result = input[0]; + for(int i = 1; i < input.length; i++) result = lcm(result, input[i]); + return result; + } + + public static float getDelta(float one, float two) { + return Math.abs(one - two); + } + + public static double getDelta(double one, double two) { + return Math.abs(one - two); + } + + public static long getDelta(long one, long two) { + return Math.abs(one - two); + } + + public static long getDelta(int one, int two) { + return Math.abs(one - two); + } + + public static long elapsed(long time) { + return Math.abs(System.currentTimeMillis() - time); + } + + public static double getHorizontalDistance(Location from, Location to) { + double deltaX = to.getX() - from.getX(), deltaZ = to.getZ() - from.getZ(); + return sqrt(deltaX * deltaX + deltaZ * deltaZ); + } + + public static double stdev(Collection list) { + double sum = 0.0; + double mean; + double num = 0.0; + double numi; + double deno = 0.0; + + for (double i : list) { + sum += i; + } + mean = sum / list.size(); + + for (double i : list) { + numi = Math.pow(i - mean, 2); + num += numi; + } + + return sqrt(num / list.size()); + } + + public static int millisToTicks(long millis) { + return (int) Math.ceil(millis / 50D); + } + + public static double getVerticalDistance(Location from, Location to) { + return Math.abs(from.getY() - to.getY()); + } + + public static int getDistanceToGround(Player p) { + Location loc = p.getLocation().clone(); + double y = loc.getBlockY(); + int distance = 0; + for (double i = y; i >= 0.0; i -= 1.0) { + loc.setY(i); + if (BlockUtils.getBlock(loc).getType().isSolid() || BlockUtils.getBlock(loc).isLiquid()) break; + ++distance; + } + return distance; + } + + public static double trim(int degree, double d) { + String format = "#.#"; + for (int i = 1; i < degree; ++i) { + format = String.valueOf(format) + "#"; + } + DecimalFormat twoDForm = new DecimalFormat(format); + return Double.parseDouble(twoDForm.format(d).replaceAll(",", ".")); + } + + public static float trimFloat(int degree, float d) { + String format = "#.#"; + for (int i = 1; i < degree; ++i) { + format = String.valueOf(format) + "#"; + } + DecimalFormat twoDForm = new DecimalFormat(format); + return Float.parseFloat(twoDForm.format(d).replaceAll(",", ".")); + } + + public static double getYawDifference(Location one, Location two) { + return Math.abs(one.getYaw() - two.getYaw()); + } + + public static double round(double value, int places) { + if (places < 0) { + throw new IllegalArgumentException(); + } + + if(Double.isNaN(value) || Double.isInfinite(value)) return value; + + BigDecimal bd = new BigDecimal(value); + bd = bd.setScale(places, RoundingMode.HALF_UP); + return bd.doubleValue(); + } + + //May not be the best on performance. Let me know if you have a better way to calculate mode. + public static T getMode(Collection collect) { + Map repeated = new HashMap<>(); + + //Sorting each value by how to repeat into a map. + collect.forEach(val -> { + int number = repeated.getOrDefault(val, 0); + + repeated.put(val, number + 1); + }); + + //Calculating the largest value to the key, which would be the mode. + return (T) repeated.keySet().stream() + .map(key -> new Tuple<>(key, repeated.get(key))) //We map it into a Tuple for easier sorting. + .max(Comparator.comparing(tup -> tup.two, Comparator.naturalOrder())) + .orElseThrow(NullPointerException::new).one; + } + + public static double round(double value, int places, RoundingMode mode) { + if (places < 0) { + throw new IllegalArgumentException(); + } + BigDecimal bd = new BigDecimal(value); + bd = bd.setScale(places, mode); + return bd.doubleValue(); + } + + public static double round(double value) { + BigDecimal bd = new BigDecimal(value); + bd = bd.setScale(0, RoundingMode.UP); + return bd.doubleValue(); + } + + public static float round(float value, int places) { + if (places < 0) { + throw new IllegalArgumentException(); + } + BigDecimal bd = new BigDecimal(value); + bd = bd.setScale(places, RoundingMode.HALF_UP); + return bd.floatValue(); + } + + public static float round(float value, int places, RoundingMode mode) { + if (places < 0) { + throw new IllegalArgumentException(); + } + BigDecimal bd = new BigDecimal(value); + bd = bd.setScale(places, mode); + return bd.floatValue(); + } + + public static float round(float value) { + BigDecimal bd = new BigDecimal(value); + bd = bd.setScale(0, RoundingMode.UP); + return bd.floatValue(); + } + + public static int floor(double var0) { + int var2 = (int) var0; + return var0 < var2 ? var2 - 1 : var2; + } + + public static float yawTo180F(float flub) { + if ((flub %= 360.0f) >= 180.0f) { + flub -= 360.0f; + } + if (flub < -180.0f) { + flub += 360.0f; + } + return flub; + } + + public static double yawTo180D(double dub) { + if ((dub %= 360.0) >= 180.0) { + dub -= 360.0; + } + if (dub < -180.0) { + dub += 360.0; + } + return dub; + } + + public static double getDirection(Location from, Location to) { + if (from == null || to == null) { + return 0.0; + } + double difX = to.getX() - from.getX(); + double difZ = to.getZ() - from.getZ(); + return MathUtils.yawTo180F((float) (Math.atan2(difZ, difX) * 180.0 / 3.141592653589793) - 90.0f); + } + + public static float[] getRotations(Location one, Location two) { + double diffX = two.getX() - one.getX(); + double diffZ = two.getZ() - one.getZ(); + double diffY = two.getY() + 2.0 - 0.4 - (one.getY() + 2.0); + double dist = sqrt(diffX * diffX + diffZ * diffZ); + float yaw = (float) (Math.atan2(diffZ, diffX) * 180.0 / 3.141592653589793) - 90.0f; + float pitch = (float) (-Math.atan2(diffY, dist) * 180.0 / 3.141592653589793); + return new float[]{yaw, pitch}; + } + + public static float[] getRotations(LivingEntity origin, LivingEntity point) { + Location two = point.getLocation(), one = origin.getLocation(); + double diffX = two.getX() - one.getX(); + double diffZ = two.getZ() - one.getZ(); + double diffY = two.getY() + 2.0 - 0.4 - (one.getY() + 2.0); + double dist = sqrt(diffX * diffX + diffZ * diffZ); + float yaw = (float) (Math.atan2(diffZ, diffX) * 180.0 / 3.141592653589793) - 90.0f; + float pitch = (float) (-Math.atan2(diffY, dist) * 180.0 / 3.141592653589793); + return new float[]{yaw, pitch}; + } + + public static boolean isLookingTowardsEntity(Location from, Location to, LivingEntity entity) { + float[] rotFrom = getRotations(from, entity.getLocation()), rotTo = getRotations(to, entity.getLocation()); + float deltaOne = getDelta(from.getYaw(), rotTo[0]), deltaTwo = getDelta(to.getYaw(), rotTo[1]); + float offsetFrom = getDelta(yawTo180F(from.getYaw()), yawTo180F(rotFrom[0])), offsetTo = getDelta(yawTo180F(to.getYaw()), yawTo180F(rotTo[0])); + + return (deltaOne > deltaTwo && offsetTo > 15) || (MathUtils.getDelta(offsetFrom, offsetTo) < 1 && offsetTo < 10); + } + + public static double[] getOffsetFromEntity(Player player, LivingEntity entity) { + double yawOffset = Math.abs(MathUtils.yawTo180F(player.getEyeLocation().getYaw()) - MathUtils.yawTo180F(MathUtils.getRotations(player.getLocation(), entity.getLocation())[0])); + double pitchOffset = Math.abs(Math.abs(player.getEyeLocation().getPitch()) - Math.abs(MathUtils.getRotations(player.getLocation(), entity.getLocation())[1])); + return new double[]{yawOffset, pitchOffset}; + } + + public static double[] getOffsetFromLocation(Location one, Location two) { + double yaw = MathUtils.getRotations(one, two)[0]; + double pitch = MathUtils.getRotations(one, two)[1]; + double yawOffset = Math.abs(yaw - MathUtils.yawTo180F(one.getYaw())); + double pitchOffset = Math.abs(pitch - one.getPitch()); + return new double[]{yawOffset, pitchOffset}; + } +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/MiscUtils.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/MiscUtils.java new file mode 100644 index 00000000..6a470a6f --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/MiscUtils.java @@ -0,0 +1,477 @@ +package cc.funkemunky.api.utils; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.api.TinyProtocolHandler; +import cc.funkemunky.api.tinyprotocol.packet.out.WrappedPacketPlayOutWorldParticle; +import cc.funkemunky.api.tinyprotocol.packet.types.enums.WrappedEnumParticle; +import cc.funkemunky.api.utils.world.types.RayCollision; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.command.PluginCommand; +import org.bukkit.command.SimpleCommandMap; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.plugin.*; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.util.Vector; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.util.*; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class MiscUtils { + + public static Material[] array = Arrays.stream(Material.values()) + .filter(mat -> mat.name().contains("LEGACY")) + .toArray(Material[]::new); + + public static Map entityDimensions = new HashMap<>();; + + public static boolean containsIgnoreCase(String toCheck, String contains) { + return toCheck.toLowerCase().contains(contains.toLowerCase()); + } + + public static int getOridinal(Material material) { + int i = 0; + for (Material mat : array) { + if(mat.getId() == material.getId()) { + return i; + } + i++; + } + return -1; + } + + public static String injectColor(String string, String color) { + String[] split = string.split(""); + + return Arrays.stream(split).map(s -> color + s).collect(Collectors.joining()); + } + + public static Material getById(int id) { + return Arrays.stream(Material.values()).filter(mat -> mat.getId() == id).findFirst() + .orElse(Material.getMaterial("AIR")); + } + + public static String line(String color) { + return color + Color.Strikethrough + "-----------------------------------------------------"; + } + + public static String line() { + return Color.Strikethrough + "-----------------------------------------------------"; + } + + public static String lineNoStrike(String color) { + return color + "-----------------------------------------------------"; + } + + public static long copy(InputStream from, OutputStream to) throws IOException { + if(from == null || to == null) return 0; + + byte[] buf = new byte[4096]; + long total = 0L; + + int r ; + while((r = from.read(buf)) != -1) { + to.write(buf, 0, r); + total += r; + } + return total; + } + + private static WrappedClass materialClass = new WrappedClass(Material.class); + public static Material match(String material) { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13)) { + return materialClass + .getMethod("matchMaterial", String.class, boolean.class) + .invoke(null, material, material.contains("LEGACY_")); + } return Material.getMaterial(material.replace("LEGACY_", "")); + } + + public static List combine(List one, List two) { + one.addAll(two); + + return one; + } + + public static String trimEnd(String string) { + if(string.length() <= 1) { + return string; + } + return string.substring(0, string.length() - 1); + } + + public static void drawRay(RayCollision collision, WrappedEnumParticle particle, Collection players) { + for (double i = 0; i < 8; i += 0.2) { + float fx = (float) (collision.originX + (collision.directionX * i)); + float fy = (float) (collision.originY + (collision.directionY * i)); + float fz = (float) (collision.originZ + (collision.directionZ * i)); + Object packet = new WrappedPacketPlayOutWorldParticle(particle, true, fx, fy, fz, + 0F, 0F, 0F, 0, 0).getObject(); + players.forEach(p -> TinyProtocolHandler.sendPacket(p, packet)); + } + } + + public static String[] splitIntoLine(String input, int maxCharInLine) { + + StringTokenizer tok = new StringTokenizer(input, " "); + StringBuilder output = new StringBuilder(input.length()); + int lineLen = 0; + while (tok.hasMoreTokens()) { + String word = tok.nextToken(); + + while (word.length() > maxCharInLine) { + output.append(word.substring(0, maxCharInLine - lineLen) + "\n"); + word = word.substring(maxCharInLine - lineLen); + lineLen = 0; + } + + if (lineLen + word.length() > maxCharInLine) { + output.append("\n"); + lineLen = 0; + } + output.append("&f" + word + " "); + + lineLen += word.length() + 1; + } + // output.split(); + // return output.toString(); + return output.toString().split("\n"); + } + + public static T getResult(Supplier consumer) { + return consumer.get(); + } + + public static String lineNoStrike() { + return "-----------------------------------------------------"; + } + + public static void createParticlesForBoundingBox(Player player, BoundingBox box) { + for (float x = box.minX; x < box.maxX + 0.2; x += 0.2f) { + for (float y = box.minY; y < box.maxY + 0.2; y += 0.2f) { + for (float z = box.minZ; z < box.maxZ + 0.2; z += 0.2f) { + WrappedPacketPlayOutWorldParticle packet = new WrappedPacketPlayOutWorldParticle(WrappedEnumParticle.FLAME, true, x, y, z, 0f, 0f, 0f, 0f, 1, null); + TinyProtocolHandler.sendPacket(player, packet.getObject()); + } + } + } + } + + public static void createParticlesForBoundingBox(Player player, BoundingBox box, WrappedEnumParticle type) { + for (float x = box.minX; x < box.maxX + 0.2; x += 0.2f) { + for (float y = box.minY; y < box.maxY + 0.2; y += 0.2f) { + for (float z = box.minZ; z < box.maxZ + 0.2; z += 0.2f) { + WrappedPacketPlayOutWorldParticle packet = new WrappedPacketPlayOutWorldParticle(type, true, x, y, z, 0f, 0f, 0f, 0f, 1, null); + TinyProtocolHandler.sendPacket(player, packet.getObject()); + } + } + } + } + + public static void createParticlesForBoundingBox(Player player, BoundingBox box, WrappedEnumParticle type, float accuracy) { + for (float x = box.minX; x < box.maxX + accuracy; x += accuracy) { + for (float y = box.minY; y < box.maxY + accuracy; y += accuracy) { + for (float z = box.minZ; z < box.maxZ + accuracy; z += accuracy) { + WrappedPacketPlayOutWorldParticle packet = new WrappedPacketPlayOutWorldParticle(type, true, x, y, z, 0f, 0f, 0f, 0f, 1, null); + TinyProtocolHandler.sendPacket(player, packet.getObject()); + } + } + } + } + + public static void drawCuboid(SimpleCollisionBox box, WrappedEnumParticle particle, Collection players) { + Step.GenericStepper x = Step.step((float) box.xMin, 0.241f, (float) box.xMax); + Step.GenericStepper y = Step.step((float) box.yMin, 0.241f, (float) box.yMax); + Step.GenericStepper z = Step.step((float) box.zMin, 0.241f, (float) box.zMax); + for (float fx : x) { + for (float fy : y) { + for (float fz : z) { + int check = 0; + if (x.first() || x.last()) check++; + if (y.first() || y.last()) check++; + if (z.first() || z.last()) check++; + if (check >= 2) { + Object packet = new WrappedPacketPlayOutWorldParticle(particle, true, fx, fy, fz, + 0F, 0F, 0F, 0, 1).getObject(); + for (Player p : players) { + TinyProtocolHandler.sendPacket(p, packet); + } + } + } + } + } + } + + public static void drawPoint(Vector point, WrappedEnumParticle particle, Collection players) { + Object packet = new WrappedPacketPlayOutWorldParticle(particle, true, (float) point.getX(), (float) point.getY(), (float) point.getZ(), + 0F, 0F, 0F, 0, 0).getObject(); + for (Player p : players) TinyProtocolHandler.sendPacket(p, packet); + } + + public static String unloadPlugin(String pl) { + PluginManager pm = Bukkit.getServer().getPluginManager(); + SimplePluginManager spm = (SimplePluginManager)pm; + SimpleCommandMap cmdMap = null; + List plugins = null; + Map names = null; + Map commands = null; + Map listeners = null; + boolean reloadlisteners = true; + if(spm != null) { + try { + Field tp = spm.getClass().getDeclaredField("plugins"); + tp.setAccessible(true); + plugins = (List)tp.get(spm); + Field arr$ = spm.getClass().getDeclaredField("lookupNames"); + arr$.setAccessible(true); + names = (Map)arr$.get(spm); + + Field len$; + try { + len$ = spm.getClass().getDeclaredField("listeners"); + len$.setAccessible(true); + listeners = (Map)len$.get(spm); + } catch (Exception var19) { + reloadlisteners = false; + } + + len$ = spm.getClass().getDeclaredField("commandMap"); + len$.setAccessible(true); + cmdMap = (SimpleCommandMap)len$.get(spm); + Field i$ = cmdMap.getClass().getDeclaredField("knownCommands"); + i$.setAccessible(true); + commands = (Map)i$.get(cmdMap); + } catch (IllegalAccessException | NoSuchFieldException var20) { + return "Failed to unload plugin!"; + } + } + + String var21 = ""; + Plugin[] var22 = Bukkit.getServer().getPluginManager().getPlugins(); + int var23 = var22.length; + + for(int var24 = 0; var24 < var23; ++var24) { + Plugin p = var22[var24]; + if(p.getDescription().getName().equalsIgnoreCase(pl)) { + pm.disablePlugin(p); + var21 = var21 + p.getName() + " "; + if(plugins != null && plugins.contains(p)) { + plugins.remove(p); + } + + if(names != null && names.containsKey(pl)) { + names.remove(pl); + } + + Iterator it; + if(listeners != null && reloadlisteners) { + it = listeners.values().iterator(); + + while(it.hasNext()) { + SortedSet entry = (SortedSet)it.next(); + Iterator c = entry.iterator(); + + while(c.hasNext()) { + RegisteredListener value = (RegisteredListener)c.next(); + if(value.getPlugin() == p) { + c.remove(); + } + } + } + } + + if(cmdMap != null) { + it = commands.entrySet().iterator(); + + while(it.hasNext()) { + Map.Entry var25 = (Map.Entry) it.next(); + if(var25.getValue() instanceof PluginCommand) { + PluginCommand var26 = (PluginCommand)var25.getValue(); + if(var26.getPlugin() == p) { + var26.unregister(cmdMap); + it.remove(); + } + } + } + } + } + } + + return var21 + "has been unloaded and disabled!"; + } + + //Stolen from Luke + public static boolean contains(Object[] array, Object obj) { + for (Object object : array) if (object != null && object.equals(obj)) return true; + return false; + } + + public static T parseObjectFromString(String s, Class clazz) throws Exception { + return clazz.getConstructor(new Class[] {String.class}).newInstance(s); + } + + public static BoundingBox getEntityBoundingBox(LivingEntity entity) { + if (entityDimensions.containsKey(entity.getType())) { + Vector entityVector = entityDimensions.get(entity.getType()); + + float minX = (float) Math.min(-entityVector.getX() + entity.getLocation().getX(), entityVector.getX() + entity.getLocation().getX()); + float minY = (float) Math.min(entity.getLocation().getY(), entityVector.getY() + entity.getLocation().getY()); + float minZ = (float) Math.min(-entityVector.getZ() + entity.getLocation().getZ(), entityVector.getZ() + entity.getLocation().getZ()); + float maxX = (float) Math.max(-entityVector.getX() + entity.getLocation().getX(), entityVector.getX() + entity.getLocation().getX()); + float maxY = (float) Math.max(entity.getLocation().getY(), entityVector.getY() + entity.getLocation().getY()); + float maxZ = (float) Math.max(-entityVector.getZ() + entity.getLocation().getZ(), entityVector.getZ() + entity.getLocation().getZ()); + return new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ); + } + return ReflectionsUtil.toBoundingBox(ReflectionsUtil.getBoundingBox(entity)); + } + + /* MAKE SURE TO ONLY RUN THIS METHOD IN onLoad() AND NO WHERE ELSE */ + public static void registerCommand(String name, JavaPlugin plugin) { + plugin.getDescription().getCommands().put(name, new HashMap<>()); + } + + public static ItemStack createItem(Material material, int amount, String name, String... lore) { + ItemStack thing = new ItemStack(material, amount); + ItemMeta thingm = thing.getItemMeta(); + thingm.setDisplayName(Color.translate(name)); + ArrayList loreList = new ArrayList<>(); + for (String string : lore) { + loreList.add(Color.translate(string)); + } + thingm.setLore(loreList); + thing.setItemMeta(thingm); + return thing; + } + + public static boolean arraysSimilar(String[] one, String[] two) { + if(one.length != two.length) return false; + + for (int i = 0; i < one.length; i++) { + String a1 = one[i], a2 = two[i]; + + if(!a1.equalsIgnoreCase(a2)) { + return false; + } + } + return true; + } + + public static List getAtlasDependingPlugins() { + List plugins = new ArrayList<>(); + + final File pluginDir = new File("plugins"); + if (!pluginDir.isDirectory()) { + return plugins; + } + for (final File f : pluginDir.listFiles()) { + try { + if (f.getName().endsWith(".jar")) { + final PluginDescriptionFile pdf = Atlas.getInstance().getPluginLoader().getPluginDescription(f); + if (pdf.getDepend().contains("Atlas")) { + plugins.add(f); + } + } + } + catch (InvalidDescriptionException e2) { + //Empty catch block. + } + } + + return plugins; + } + + public static void loadPlugin(final String pl) { + Plugin targetPlugin = null; + String msg = ""; + final File pluginDir = new File("plugins"); + if (!pluginDir.isDirectory()) { + return; + } + File pluginFile = new File(pluginDir, pl + ".jar"); + if (!pluginFile.isFile()) { + for (final File f : pluginDir.listFiles()) { + try { + if (f.getName().endsWith(".jar")) { + final PluginDescriptionFile pdf = Atlas.getInstance().getPluginLoader().getPluginDescription(f); + if (pdf.getName().equalsIgnoreCase(pl)) { + pluginFile = f; + msg = "(via search) "; + break; + } + } + } + catch (InvalidDescriptionException e2) { + return; + } + } + } + try { + Atlas.getInstance().getServer().getPluginManager().loadPlugin(pluginFile); + targetPlugin = getPlugin(pl); + Atlas.getInstance().getServer().getPluginManager().enablePlugin(targetPlugin); + } + catch (UnknownDependencyException | InvalidPluginException | InvalidDescriptionException e3) { + e3.printStackTrace(); + } + } + + + private static Plugin getPlugin(final String p) { + for (final Plugin pl : Atlas.getInstance().getServer().getPluginManager().getPlugins()) { + if (pl.getDescription().getName().equalsIgnoreCase(p)) { + return pl; + } + } + return null; + } + + public static T getArgOrNull(T[] array, int index) { + if(array.length > index) { + return array[index]; + } + return null; + } + + public static void printToConsole(String string) { + Atlas.getInstance().getConsoleSender().sendMessage(Color.translate(string)); + } + + static { + entityDimensions.put(EntityType.WOLF, new Vector(0.31, 0.8, 0.31)); + entityDimensions.put(EntityType.SHEEP, new Vector(0.45, 1.3, 0.45)); + entityDimensions.put(EntityType.COW, new Vector(0.45, 1.3, 0.45)); + entityDimensions.put(EntityType.PIG, new Vector(0.45, 0.9, 0.45)); + entityDimensions.put(EntityType.MUSHROOM_COW, new Vector(0.45, 1.3, 0.45)); + entityDimensions.put(EntityType.WITCH, new Vector(0.31, 1.95, 0.31)); + entityDimensions.put(EntityType.BLAZE, new Vector(0.31, 1.8, 0.31)); + entityDimensions.put(EntityType.PLAYER, new Vector(0.3, 1.8, 0.3)); + entityDimensions.put(EntityType.VILLAGER, new Vector(0.31, 1.8, 0.31)); + entityDimensions.put(EntityType.CREEPER, new Vector(0.31, 1.8, 0.31)); + entityDimensions.put(EntityType.GIANT, new Vector(1.8, 10.8, 1.8)); + entityDimensions.put(EntityType.SKELETON, new Vector(0.31, 1.8, 0.31)); + entityDimensions.put(EntityType.ZOMBIE, new Vector(0.31, 1.8, 0.31)); + entityDimensions.put(EntityType.SNOWMAN, new Vector(0.35, 1.9, 0.35)); + entityDimensions.put(EntityType.HORSE, new Vector(0.7, 1.6, 0.7)); + entityDimensions.put(EntityType.ENDER_DRAGON, new Vector(1.5, 1.5, 1.5)); + entityDimensions.put(EntityType.ENDERMAN, new Vector(0.31, 2.9, 0.31)); + entityDimensions.put(EntityType.CHICKEN, new Vector(0.2, 0.7, 0.2)); + entityDimensions.put(EntityType.OCELOT, new Vector(0.31, 0.7, 0.31)); + entityDimensions.put(EntityType.SPIDER, new Vector(0.7, 0.9, 0.7)); + entityDimensions.put(EntityType.WITHER, new Vector(0.45, 3.5, 0.45)); + entityDimensions.put(EntityType.IRON_GOLEM, new Vector(0.7, 2.9, 0.7)); + entityDimensions.put(EntityType.GHAST, new Vector(2, 4, 2)); + } +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Pastebin.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Pastebin.java new file mode 100644 index 00000000..b4445708 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Pastebin.java @@ -0,0 +1,119 @@ +package cc.funkemunky.api.utils; + +import lombok.Getter; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; + +public class Pastebin { + + static String api_user_key = "15479eb626106167cade921b7d2b7e3c"; //Insert your own api_user_key if you have one. + static String pasteURL = "http://www.pastebin.com/api/api_post.php"; + + public Pastebin() + { + } + + static String checkResponse(String response) + { + if (response.substring(0, 15).equals("Bad API request")) { + return response.substring(17); + } + return ""; + } + + static public String makePaste(String body, String name, Privacy privacy) + throws UnsupportedEncodingException + { + String content = URLEncoder.encode(body, "UTF-8"); + String title = URLEncoder.encode(name + " report", "UTF-8"); + String data = "api_option=paste&api_user_key=" + Pastebin.api_user_key + + "&api_paste_private=" + privacy.getPrivacy() + "&api_paste_name=" + title + + "&api_paste_expire_date=N&api_paste_format=" + "text" + + "&api_dev_key=" + api_user_key + "&api_paste_code=" + content; + return getString(data); + } + + private static String getString(String data) { + String response = Pastebin.page(Pastebin.pasteURL, data); + String check = Pastebin.checkResponse(response); + if (!check.equals("")) { + return check; + } + return response; + } + + static public String makePaste(String body, String name, Privacy privacy, String expire) + throws UnsupportedEncodingException + { + String content = URLEncoder.encode(body, "UTF-8"); + String title = URLEncoder.encode(name + " report", "UTF-8"); + String data = "api_option=paste&api_user_key=" + Pastebin.api_user_key + + "&api_paste_private=" + privacy.getPrivacy() + "&api_paste_name=" + title + + "&api_paste_expire_date=" + expire + "&api_paste_format=" + "text" + + "&api_dev_key=" + api_user_key + "&api_paste_code=" + content; + return getString(data); + } + + static String page(String uri, String urlParameters) + { + URL url; + HttpURLConnection connection = null; + try { + // Create connection + url = new URL(uri); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", + "application/x-www-form-urlencoded"); + + connection.setRequestProperty("Content-Length", + "" + Integer.toString(urlParameters.getBytes().length)); + connection.setRequestProperty("Content-Language", "en-US"); + + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setDoOutput(true); + + // Send request + DataOutputStream wr = new DataOutputStream( + connection.getOutputStream()); + wr.writeBytes(urlParameters); + wr.flush(); + wr.close(); + + // Get Response + InputStream is = connection.getInputStream(); + BufferedReader rd = new BufferedReader(new InputStreamReader(is)); + String line; + StringBuffer response = new StringBuffer(); + while ((line = rd.readLine()) != null) { + response.append(line); + } + rd.close(); + return response.toString(); + + } catch (Exception e) { + e.printStackTrace(); + return null; + + } finally { + + if (connection != null) { + connection.disconnect(); + } + } + } + + @Getter + public static enum Privacy { + PUBLIC(0), UNLISTED(1), PRIVATE(2); + + private int privacy; + Privacy(int privacy) { + this.privacy = privacy; + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/PlayerUtils.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/PlayerUtils.java new file mode 100644 index 00000000..c44b691d --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/PlayerUtils.java @@ -0,0 +1,106 @@ +package cc.funkemunky.api.utils; + +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import lombok.val; +import org.bukkit.Location; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +public class PlayerUtils { + + private static Enchantment DEPTH; + + public static int getDepthStriderLevel(Player player) { + if(DEPTH == null) return 0; + + val boots = player.getInventory().getBoots(); + + if(boots == null) return 0; + + return boots.getEnchantmentLevel(DEPTH); + } + + public static boolean hasBlocksAround(Location loc) { + Location one = loc.clone().subtract(1, 0, 1), two = loc.clone().add(1, 1, 1); + + int minX = Math.min(one.getBlockX(), two.getBlockX()), minY = Math.min(one.getBlockY(), two.getBlockY()), minZ = Math.min(one.getBlockZ(), two.getBlockZ()); + int maxX = Math.max(one.getBlockX(), two.getBlockX()), maxY = Math.max(one.getBlockY(), two.getBlockY()), maxZ = Math.max(one.getBlockZ(), two.getBlockZ()); + + for (int x = minX; x < maxX; x++) { + for (int y = minY; y < maxY; y++) { + for (int z = minZ; z < maxZ; z++) { + Location blockLoc = new Location(loc.getWorld(), x, y, z); + + if (BlockUtils.isSolid(BlockUtils.getBlock(blockLoc))) { + return true; + } + } + } + } + return false; + } + + public static boolean facingOpposite(Entity one, Entity two) { + return one.getLocation().getDirection().distance(two.getLocation().getDirection()) < 0.5; + } + + public static boolean isGliding(Player p) { + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) return false; + + boolean isGliding = false; + try { + isGliding = (boolean) p.getClass().getMethod("isGliding", new Class[0]).invoke(p, new Object[0]); + } catch (Exception e) { + e.printStackTrace(); + } + return isGliding; + } + + public static double getAccurateDistance(LivingEntity attacked, LivingEntity entity) { + Location origin = attacked.getEyeLocation(), point; + if (entity.getLocation().getY() > attacked.getLocation().getBlockY()) { + point = entity.getLocation(); + } else { + point = entity.getEyeLocation(); + } + + + return origin.distance(point); + } + + public static double getAccurateDistance(Location origin, Location point) { + return origin.distance(point) * Math.cos(origin.getPitch()); + } + + public static int getPotionEffectLevel(Player player, PotionEffectType pet) { + for (PotionEffect pe : player.getActivePotionEffects()) { + if (!pe.getType().getName().equals(pet.getName())) continue; + return pe.getAmplifier() + 1; + } + return 0; + } + + public static float getJumpHeight(Player player) { + float baseHeight = 0.42f; + + if(player.hasPotionEffect(PotionEffectType.JUMP)) { + baseHeight+= PlayerUtils.getPotionEffectLevel(player, PotionEffectType.JUMP) * 0.1f; + } + + return baseHeight; + } + + static { + try { + if(ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + DEPTH = Enchantment.getByName("DEPTH_STRIDER"); + } + } catch(Exception e) { + DEPTH = null; + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Priority.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Priority.java new file mode 100644 index 00000000..17633718 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Priority.java @@ -0,0 +1,14 @@ +package cc.funkemunky.api.utils; + +import lombok.Getter; + +@Getter +public enum Priority { + LOWEST(1), LOW(2), NORMAL(3), HIGH(4), HIGHEST(5); + + int priority; + + Priority(int priority) { + this.priority = priority; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ReflectionsUtil.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ReflectionsUtil.java new file mode 100644 index 00000000..80eee0a5 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/ReflectionsUtil.java @@ -0,0 +1,594 @@ +package cc.funkemunky.api.utils; + +import cc.funkemunky.api.Atlas; +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.Step; +import org.bukkit.material.WoodenStep; +import org.bukkit.util.Vector; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; + +public class ReflectionsUtil { + public static Class blockPosition = null; + private static String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + public static Class EntityPlayer = getNMSClass("EntityPlayer"); + public static Class Entity = getNMSClass("Entity"); + public static Class CraftPlayer = getCBClass("entity.CraftPlayer"); + public static Class CraftEntity = getCBClass("entity.CraftEntity"); + public static Class CraftWorld = getCBClass("CraftWorld"); + private static Class craftServer = getCBClass("CraftServer"); + public static Class World = getNMSClass("World"); + public static Class worldServer = getNMSClass("WorldServer"); + public static Class playerConnection = getNMSClass("PlayerConnection"); + public static Class networkManager = getNMSClass("NetworkManager"); + public static Class minecraftServer = getNMSClass("MinecraftServer"), nmsItemStack = getNMSClass("ItemStack"); + public static Class packet = getNMSClass("Packet"); + public static Class iBlockData = null; + public static Class iBlockAccess = null; + private static Class vanillaBlock = getNMSClass("Block"); + private static Method getCubes = getMethod(World, "a", getNMSClass("AxisAlignedBB")); + private static Method getCubes1_12 = getMethod(World, "getCubes", getNMSClass("Entity"), getNMSClass("AxisAlignedBB")); + + public static Object getEntityPlayer(Player player) { + return getMethodValue(getMethod(CraftPlayer, "getHandle"), player); + } + + public static Object getEntity(org.bukkit.entity.Entity entity) { + return getMethodValue(getMethod(CraftEntity, "getHandle"), entity); + } + + public static Object getExpandedBoundingBox(Object box, double x, double y, double z) { + return getMethodValue(getMethod(box.getClass(), "grow", double.class, double.class, double.class), box, x, y, z); + } + + public static Object modifyBoundingBox(Object box, double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + double newminX = (double) getFieldValue(getFieldByName(box.getClass(), "a"), box) - minX; + double newminY = (double) getFieldValue(getFieldByName(box.getClass(), "b"), box) - minY; + double newminZ = (double) getFieldValue(getFieldByName(box.getClass(), "c"), box) - minZ; + double newmaxX = (double) getFieldValue(getFieldByName(box.getClass(), "d"), box) + maxX; + double newmaxY = (double) getFieldValue(getFieldByName(box.getClass(), "e"), box) + maxY; + double newmaxZ = (double) getFieldValue(getFieldByName(box.getClass(), "f"), box) + maxZ; + + return newInstance(getNMSClass("AxisAlignedBB"), newminX, newminY, newminZ, newmaxX, newmaxY, newmaxZ); + } + + private static Vector getBoxMin(Object box) { + if (hasField(box.getClass(), "a")) { + double x = (double) getFieldValue(getFieldByName(box.getClass(), "a"), box); + double y = (double) getFieldValue(getFieldByName(box.getClass(), "b"), box); + double z = (double) getFieldValue(getFieldByName(box.getClass(), "c"), box); + return new Vector(x, y, z); + } else { + double x = (double) getFieldValue(getFieldByName(box.getClass(), "minX"), box); + double y = (double) getFieldValue(getFieldByName(box.getClass(), "minY"), box); + double z = (double) getFieldValue(getFieldByName(box.getClass(), "minZ"), box); + return new Vector(x, y, z); + } + } + + public static Object getMinecraftServer() { + return getMethodValue(getMethod(craftServer, "getServer"), Bukkit.getServer()); + } + + private static Vector getBoxMax(Object box) { + if (hasField(box.getClass(), "d")) { + double x = (double) getFieldValue(getFieldByName(box.getClass(), "d"), box); + double y = (double) getFieldValue(getFieldByName(box.getClass(), "e"), box); + double z = (double) getFieldValue(getFieldByName(box.getClass(), "f"), box); + return new Vector(x, y, z); + } else { + double x = (double) getFieldValue(getFieldByName(box.getClass(), "maxX"), box); + double y = (double) getFieldValue(getFieldByName(box.getClass(), "maxY"), box); + double z = (double) getFieldValue(getFieldByName(box.getClass(), "maxZ"), box); + return new Vector(x, y, z); + } + } + + public static BoundingBox toBoundingBox(Object aaBB) { + Vector min = getBoxMin(aaBB); + Vector max = getBoxMax(aaBB); + + return new BoundingBox((float) min.getX(), (float) min.getY(), (float) min.getZ(), (float) max.getX(), (float) max.getY(), (float) max.getZ()); + } + + public static float getBlockDurability(Block block) { + Object vanillaBlock = getVanillaBlock(block); + return (float) getFieldValue(getFieldByName(getNMSClass("Block"), "strength"), vanillaBlock); + } + + public static boolean canDestroyBlock(Player player, Block block) { + Object inventory = getVanillaInventory(player); + return (boolean) getMethodValue(getMethod(getNMSClass("PlayerInventory"), "b", getNMSClass("Block")), inventory, ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8_9) ? getBlockData(block) : getVanillaBlock(block)); + } + + public static Object getVanillaInventory(Player player) { + return getMethodValue(getMethod(getCBClass("inventory.CraftInventoryPlayer"), "getInventory"), player.getInventory()); + } + + private static Field frictionFactorField = getFieldByName(vanillaBlock, "frictionFactor"); + public static float getFriction(Block block) { + Object blockNMS = getVanillaBlock(block); + + return (float) getFieldValue(frictionFactorField, blockNMS); + } + + public static Object getBlockPosition(Location location) { + if (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + return newInstance(blockPosition, location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + return null; + } + + public static List getEntitiesInWorld(org.bukkit.World world) { + Object worldHandle = getWorldHandle(world); + List toReturn = new ArrayList<>(); + List entityList = new ArrayList<>((List) getFieldValue(getFieldByName(getNMSClass("World"), "entityList"), worldHandle)); + + Class entity = getNMSClass("Entity"); + entityList.forEach(object -> { + Object bEntity = getMethodValue(getMethod(entity, "getBukkitEntity"), object); + if(bEntity != null) { + toReturn.add((org.bukkit.entity.Entity) bEntity); + } + }); + return toReturn; + } + + public static BoundingBox getBlockBoundingBox(Block block) { + try { + if (!isBukkitVerison("1_7")) { + Object bPos = blockPosition.getConstructor(int.class, int.class, int.class).newInstance(block.getLocation().getBlockX(), block.getLocation().getBlockY(), block.getLocation().getBlockZ()); + Object world = getWorldHandle(block.getWorld()); + Object data = getMethodValue(getMethod(world.getClass(), "getType", blockPosition), world, bPos); + Object blockNMS = getMethodValue(getMethod(getNMSClass("IBlockData"), "getBlock"), data); + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + if (!isNewVersion()) { + + if (getMethodValueNoST(getMethodNoST(blockNMS.getClass(), "a", World, blockPosition, iBlockData), blockNMS, world, bPos, data) != null + && !BlockUtils.isSlab(block)) { + BoundingBox box = toBoundingBox(getMethodValue(getMethod(blockNMS.getClass(), "a", World, blockPosition, iBlockData), blockNMS, world, bPos, data)); + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + if (block.getType().toString().contains("STEP") && !block.getType().toString().contains("WOOD")) { + Step slab = (Step) block.getType().getNewData(block.getData()); + + box.minY = block.getY(); + box.maxY = block.getY(); + if (slab.isInverted()) { + box = box.add(0, 0.5f, 0, 0, 1f, 0); + } else { + box = box.add(0, 0f, 0, 0, 0.5f, 0); + } + } else if (block.getType().toString().contains("STEP")) { + WoodenStep slab = (WoodenStep) block.getType().getNewData(block.getData()); + + box.minY = block.getY(); + box.maxY = block.getY(); + if (slab.isInverted()) { + box = box.add(0, 0.5f, 0, 0, 1f, 0); + } else { + box = box.add(0, 0f, 0, 0, 0.5f, 0); + } + } + } + return box; + } else if (getMethodValueNoST(getMethodNoST(vanillaBlock, "a", World, blockPosition, iBlockData), blockNMS, world, bPos, data) != null) { + BoundingBox box = toBoundingBox(getMethodValue(getMethod(vanillaBlock, "a", World, blockPosition, iBlockData), blockNMS, world, bPos, data)); + + if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_13)) { + if (block.getType().toString().contains("STEP") && !block.getType().toString().contains("WOOD")) { + Step slab = (Step) block.getType().getNewData(block.getData()); + + box.minY = block.getY(); + box.maxY = block.getY(); + if (slab.isInverted()) { + box = box.add(0, 0.5f, 0, 0, 1f, 0); + } else { + box = box.add(0, 0f, 0, 0, 0.5f, 0); + } + } else if (block.getType().toString().contains("STEP")) { + WoodenStep slab = (WoodenStep) block.getType().getNewData(block.getData()); + + box.minY = block.getY(); + box.maxY = block.getY(); + if (slab.isInverted()) { + box = box.add(0, 0.5f, 0, 0, 1f, 0); + } else { + box = box.add(0, 0f, 0, 0, 0.5f, 0); + } + } + } + return box; + } else { + return new BoundingBox(block.getX(), block.getY(), block.getZ(), block.getX(), block.getY(), block.getZ()); + } + } else { + if (getMethodValueNoST(getMethodNoST(blockNMS.getClass(), "a", iBlockData, getNMSClass("IBlockAccess"), blockPosition), blockNMS, data, world, bPos) != null) { + return toBoundingBox(getMethodValue(getMethod(blockNMS.getClass(), "a", iBlockData, getNMSClass("IBlockAccess"), blockPosition), blockNMS, data, world, bPos)).add(block.getX(), block.getY(), block.getZ(), block.getX(), block.getY(), block.getZ()); + } else if (getMethodValueNoST(getMethodNoST(vanillaBlock, "a", iBlockData, getNMSClass("IBlockAccess"), blockPosition), blockNMS, data, world, bPos) != null) { + return toBoundingBox(getMethodValue(getMethod(vanillaBlock, "a", iBlockData, getNMSClass("IBlockAccess"), blockPosition), blockNMS, data, world, bPos)).add(block.getX(), block.getY(), block.getZ(), block.getX(), block.getY(), block.getZ()); + } else { + return new BoundingBox(block.getX(), block.getY(), block.getZ(), block.getX(), block.getY(), block.getZ()); + } + } + } else { + Object voxelShape = getMethodValue(getMethod(vanillaBlock, "a", iBlockData, getNMSClass("IBlockAccess"), blockPosition), blockNMS, data, world, bPos); + Object axisAlignedBB = getMethodValue(getMethod(getNMSClass("VoxelShape"), "a"), voxelShape); + + + return toBoundingBox(axisAlignedBB); + + } + } else { + Object blockNMS = getVanillaBlock(block); + Object world = getWorldHandle(block.getWorld()); + if (getMethodValueNoST(getMethodNoST(vanillaBlock, "a", getNMSClass("World"), int.class, int.class, int.class), blockNMS, world, block.getLocation().getBlockX(), block.getLocation().getBlockY(), block.getLocation().getBlockZ()) != null) { + return toBoundingBox(getMethodValue(getMethod(vanillaBlock, "a", getNMSClass("World"), int.class, int.class, int.class), blockNMS, world, block.getLocation().getBlockX(), block.getLocation().getBlockY(), block.getLocation().getBlockZ())); + } else { + //Bukkit.broadcastMessage(block.getType().name()); + return new BoundingBox(block.getX(), block.getY(), block.getZ(), block.getX(), block.getY(), block.getZ()); + } + } + } catch (Exception e) { + Bukkit.getLogger().log(Level.SEVERE, "Error occured with block: " + block.getType().toString()); + e.printStackTrace(); + } + return null; + } + + public static double getTPS(Server server) { + Object handle = getMethodValue(getMethod(getCBClass("CraftServer"), "getHandle"), server); + + return (int) getFieldValue(getFieldByName(getNMSClass("MinecraftServer"), "TPS"), handle); + } + + public static float getBlockHardness(final Material material) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + if (!material.isBlock()) + return 0; + + final int blockId = material.getId(); + final Object nmsBlock = getNMSClass("Block").getMethod("getById", Integer.TYPE).invoke(null, blockId); + + try { + final Field field = nmsBlock.getClass().getDeclaredField("strength"); + field.setAccessible(true); + return (float) field.get(nmsBlock); + } catch (final NoSuchFieldException e) { + return 0.0F; + } + } + + public static float getDestroySpeed(Block block, Player player) { + + if (ProtocolVersion.getGameVersion().isAbove(ProtocolVersion.V1_8_9)) { + Object item = getVanillaItem(player.getItemInHand()); + return (float) getMethodValue(getMethod(getNMSClass("Item"), "getDestroySpeed", nmsItemStack, getNMSClass("IBlockData")), item, getVanillaItemStack(player.getItemInHand()), getBlockData(block)); + } else { + Object item = getVanillaItem(player.getInventory().getItemInHand()); + return (float) getMethodValue(getMethod(getNMSClass("Item"), "getDestroySpeed", nmsItemStack, getNMSClass("Block")), item, getVanillaItemStack(player.getInventory().getItemInHand()), getVanillaBlock(block)); + } + } + + private static Method getItemMethod = getMethod(nmsItemStack, "getItem"); + public static Object getVanillaItem(ItemStack itemStack) { + return getMethodValue(getMethod(nmsItemStack, "getItem"), getVanillaItemStack(itemStack)); + } + + public static Object getVanillaItemStack(ItemStack itemStack) { + return getMethodValue(getMethod(getCBClass("inventory.CraftItemStack"), "asNMSCopy", getClass("org.bukkit.inventory.ItemStack")), itemStack, itemStack); + } + + private static Method getBlockMethod = null, + getTypeMethod = null; + public static Object getVanillaBlock(Block block) { + if (!isBukkitVerison("1_7")) { + if(getBlockMethod == null) getBlockMethod = getMethod(iBlockData, "getBlock"); + Object getType = getBlockData(block); + return getMethodValue(getBlockMethod, getType); + } else { + if(getTypeMethod == null) getTypeMethod = getMethod(worldServer, "getType", int.class, int.class, int.class); + Object world = getWorldHandle(block.getWorld()); + return getMethodValue(getTypeMethod, world, block.getLocation().getBlockX(), block.getLocation().getBlockY(), block.getLocation().getBlockZ()); + } + } + + private static Constructor blockPosConstructor = null; + private static Method getTypeMethod2 = null; + public static Object getBlockData(Block block) { + try { + if (!isBukkitVerison("1_7")) { + if(blockPosConstructor == null) blockPosConstructor = blockPosition.getConstructor(int.class, int.class, int.class); + Object bPos = blockPosConstructor.newInstance(block.getX(), block.getY(), block.getZ()); + Object world = getWorldHandle(block.getWorld()); + if(getTypeMethod2 == null) getTypeMethod2 = getMethod(worldServer, "getType", blockPosition); + return getMethodValue(getTypeMethod2, world, bPos); + } else { + Object world = getWorldHandle(block.getWorld()); + if(getTypeMethod2 == null) getTypeMethod2 = getMethod(worldServer, "getType", int.class, int.class, int.class); + return getMethodValue(getTypeMethod2, world, block.getX(), block.getY(), block.getZ()); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static Object getBelowBox(Player player, double below) { + Object box = getBoundingBox(player); + double minX = (double) getFieldValue(getFieldByName(box.getClass(), "a"), box); + double minY = (double) getFieldValue(getFieldByName(box.getClass(), "b"), box) - below; + double minZ = (double) getFieldValue(getFieldByName(box.getClass(), "c"), box); + double maxX = (double) getFieldValue(getFieldByName(box.getClass(), "d"), box); + double maxY = (double) getFieldValue(getFieldByName(box.getClass(), "e"), box); + double maxZ = (double) getFieldValue(getFieldByName(box.getClass(), "f"), box); + + try { + return getNMSClass("AxisAlignedBB").getConstructor(double.class, double.class, double.class, double.class, double.class, double.class).newInstance(minX, minY, minZ, maxX, maxY, maxZ); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static Object getBoundingBox(Player player) { + return getBoundingBox((org.bukkit.entity.Entity) player); + } + + public static Object getBoundingBox(org.bukkit.entity.Entity entity) { + return isBukkitVerison("1_7") ? getFieldValue(getFieldByName(Entity, "boundingBox"), getEntity(entity)) : getMethodValue(getMethod(Entity, "getBoundingBox"), getEntity(entity)); + } + + public static boolean isBukkitVerison(String version) { + return ProtocolVersion.getGameVersion().getServerVersion().contains(version); + } + + public static File getPluginFolder() { + Object console = getMethodValue(getMethod(getCBClass("CraftServer"), "console"), Atlas.getInstance().getServer()); + Object options = getFieldValue(getFieldByName(getNMSClass("MinecraftServer"), "options"), console); + return (File) getMethodValue(getMethod(getNMSClass("OptionSet"), "valueOf", String.class), options, "plugins"); + } + + public static boolean isNewVersion() { + return isBukkitVerison("1_9") || isBukkitVerison("1_1"); + } + + public static Class getCBClass(String string) { + return getClass("org.bukkit.craftbukkit." + version + "." + string); + } + + + public static Object newAxisAlignedBB(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + try { + return isBukkitVerison("1_7") ? getMethodValue(getMethod(getNMSClass("AxisAlignedBB"), "a", double.class, double.class, double.class, double.class, double.class, double.class), null, minX, minY, minZ, maxX, maxY, maxZ) : getNMSClass("AxisAlignedBB").getConstructor(double.class, double.class, double.class, double.class, double.class, double.class).newInstance(minX, minY, minZ, maxX, maxY, maxZ); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + e.printStackTrace(); + } + return null; + } + + public static Object newVoxelShape(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { + try { + return getNMSClass("AxisAlignedBB").getConstructor(double.class, double.class, double.class, double.class, double.class, double.class).newInstance(minX, minY, minZ, maxX, maxY, maxZ); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + e.printStackTrace(); + } + return null; + } + + public static double getMotionY(Player player) { + double motionY = 0; + try { + motionY = (double) ReflectionsUtil.getEntityPlayer(player).getClass().getField("motY").get(ReflectionsUtil.getEntityPlayer(player)); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + + return motionY; + } + + public static Object newAxisAlignedBB(Location from, Location to) { + double minX = Math.min(from.getX(), to.getX()); + double minY = Math.min(from.getY(), to.getY()); + double minZ = Math.min(from.getZ(), to.getZ()); + double maxX = Math.max(from.getX(), to.getX()); + double maxY = Math.max(from.getY(), to.getY()); + double maxZ = Math.max(from.getZ(), to.getZ()); + + try { + return getNMSClass("AxisAlignedBB").getConstructor(double.class, double.class, double.class, double.class, double.class, double.class).newInstance(minX, minY, minZ, maxX, maxY, maxZ); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + e.printStackTrace(); + } + return null; + } + + public static Class getClass(String string) { + try { + return Class.forName(string); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return null; + } + + @SuppressWarnings("unchecked") + public static Enum getEnum(Class clazz, String enumName) { + return Enum.valueOf((Class) clazz, enumName); + } + + public static Field getFieldByName(Class clazz, String fieldName) { + try { + Field field = clazz.getDeclaredField(fieldName) != null ? clazz.getDeclaredField(fieldName) : clazz.getSuperclass().getDeclaredField(fieldName); + field.setAccessible(true); + + return field; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static Object setFieldValue(Object object, Field field, Object value) { + try { + field.set(object, value); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + return field.getDeclaringClass(); + } + + + public static boolean inBlock(Player player, Object axisAlignedBB) { + return getCollidingBlocks(player, axisAlignedBB).size() > 0; + } + + /** + * Method removed in 1.12 and later versions in NMS + **/ + public static Collection getCollidingBlocks(Player player, Object axisAlignedBB) { + Object world = getWorldHandle(player.getWorld()); + return (Collection) (isNewVersion() + ? getMethodValue(getCubes1_12, world, null, axisAlignedBB) + : getMethodValue(getCubes, world, axisAlignedBB)); + } + + private static Method craftWorldHandle = getMethod(CraftWorld, "getHandle"); + public static Object getWorldHandle(org.bukkit.World world) { + return getMethodValue(craftWorldHandle, world); + } + + public static Field getFirstFieldByType(Class clazz, Class type) { + try { + for (Field field : clazz.getDeclaredFields()) { + if (field.getType().equals(type)) { + field.setAccessible(true); + return field; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static Method getMethod(Class clazz, String methodName, Class... args) { + try { + Method method = clazz.getMethod(methodName, args); + method.setAccessible(true); + return method; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private static Method getMethodNoST(Class clazz, String methodName, Class... args) { + try { + Method method = clazz.getMethod(methodName, args); + method.setAccessible(true); + return method; + } catch (Exception e) { + } + return null; + } + + public static boolean hasMethod(Class clazz, Method method) { + return Arrays.stream(clazz.getMethods()).anyMatch(methodLoop -> methodLoop.getName().equals(method.getName())); + } + + public static boolean hasMethod(Class clazz, String methodName) { + return Arrays.stream(clazz.getMethods()).anyMatch(methodLoop -> methodLoop.getName().equals(methodName)); + } + + public static Object getMethodValue(Method method, Object object, Object... args) { + try { + return method.invoke(object, args); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static boolean hasField(Class object, String fieldName) { + return Arrays.stream(object.getFields()).anyMatch(field -> field.getName().equalsIgnoreCase(fieldName)); + } + + public static Object getMethodValueNoST(Method method, Object object, Object... args) { + try { + return method.invoke(object, args); + } catch (Exception e) { + return null; + } + } + + public static Object getFieldValue(Field field, Object object) { + try { + field.setAccessible(true); + return field.get(object); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static Object getFieldValueNoST(Field field, Object object) { + try { + field.setAccessible(true); + return field.get(object); + } catch (Exception e) { + return null; + } + } + + public static Field getFieldByNameNoST(Class clazz, String fieldName) { + try { + Field field = clazz.getDeclaredField(fieldName) != null ? clazz.getDeclaredField(fieldName) : clazz.getSuperclass().getDeclaredField(fieldName); + field.setAccessible(true); + + return field; + } catch (Exception e) { + return null; + } + } + + public static Object newInstance(Class objectClass, Object... args) { + try { + return objectClass.getConstructor(args.getClass()).newInstance(args); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + e.printStackTrace(); + } + return null; + } + + public static Class getNMSClass(String string) { + return getClass("net.minecraft.server." + version + "." + string); + } + + static { + if (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_8)) { + iBlockData = getNMSClass("IBlockData"); + blockPosition = getNMSClass("BlockPosition"); + iBlockAccess = getNMSClass("IBlockAccess"); + } + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/RunUtils.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/RunUtils.java new file mode 100644 index 00000000..dc2c40c6 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/RunUtils.java @@ -0,0 +1,86 @@ +package cc.funkemunky.api.utils; + +import cc.funkemunky.api.Atlas; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitTask; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +/* + The whole purpose of this class is just to save disk space and make development more efficient + with the use of lambdas and with less verbose conventions. This does not affect performance. + */ +public class RunUtils { + + public static BukkitTask taskTimer(Runnable runnable, Plugin plugin, long delay, long interval) { + return Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, interval); + } + + public static BukkitTask taskTimer(Runnable runnable, long delay, long interval) { + return taskTimer(runnable, Atlas.getInstance(), delay, interval); + } + + public static BukkitTask taskTimerAsync(Runnable runnable, Plugin plugin, long delay, long interval) { + return Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay, interval); + } + + public static BukkitTask taskTimerAsync(Runnable runnable, long delay, long interval) { + return taskTimerAsync(runnable, Atlas.getInstance(), delay, interval); + } + + public static BukkitTask task(Runnable runnable, Plugin plugin) { + return Bukkit.getScheduler().runTask(plugin, runnable); + } + + public static BukkitTask task(Runnable runnable) { + return task(runnable, Atlas.getInstance()); + } + + public static BukkitTask taskAsync(Runnable runnable, Plugin plugin) { + return Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable); + } + + public static BukkitTask taskAsync(Runnable runnable) { + return taskAsync(runnable, Atlas.getInstance()); + } + + public static BukkitTask taskLater(Runnable runnable, Plugin plugin, long delay) { + return Bukkit.getScheduler().runTaskLater(plugin, runnable, delay); + } + + public static BukkitTask taskLater(Runnable runnable, long delay) { + return taskLater(runnable, Atlas.getInstance(), delay); + } + + public static BukkitTask taskLaterAsync(Runnable runnable, Plugin plugin, long delay) { + return Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay); + } + + public static BukkitTask taskLaterAsync(Runnable runnable, long delay) { + return taskLaterAsync(runnable, Atlas.getInstance(), delay); + } + + public static Future callLater(Future runnable, long delay, Consumer onComplete) { + return Atlas.getInstance().getSchedular().schedule(() -> { + try { + onComplete.accept(runnable.get()); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + }, delay, TimeUnit.MILLISECONDS); + } + + public static Future call(Future runnable, Consumer onComplete) { + return Atlas.getInstance().getSchedular().submit(() -> { + try { + onComplete.accept(runnable.get()); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + }); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Step.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Step.java new file mode 100644 index 00000000..c1423168 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Step.java @@ -0,0 +1,99 @@ +package cc.funkemunky.api.utils; + +import java.util.Iterator; + +public class Step { + + public static GenericStepper step(float start, float incr, float end) { + Link first = new Link<>(); + Link cur = first; + Link last = first; + + first.value = start; + while (start < end) { + last = cur; + cur = new Link<>(); + cur.value = start+=incr; + last.next = cur; + } + cur = new Link<>(); + cur.value =end; + last.next = cur; + return new GenericStepper<>(first); + } + + public static GenericStepper step(double start, double incr, double end) { + Link first = new Link<>(); + Link cur = first; + Link last = first; + first.value = start; + while (start < end) { + last = cur; + cur = new Link<>(); + start+=incr; + cur.value = start; + last.next = cur; + } + cur = new Link<>(); + cur.value = end; + last.next = cur; + return new GenericStepper<>(first); + } + + public static class GenericStepper implements Iterator, Iterable { + + private Link first; + private Link link; + + public GenericStepper(Link link) { + this.link = link; + this.first = link; + } + + @Override + public boolean hasNext() { + return link!=null; + } + + @Override + public T next() { + T v = link.value; + link = link.next; + return v; + } + + public boolean first() { + return link == first || link == first.next; + } + + public boolean last() { + return link==null; + } + + public int count_() { + int i =0; + Link t = first; + while (t!=null) { + i++; + t = t.next; + } + return i; + } + + public void reset() { + this.link = first; + } + + @Override + public Iterator iterator() { + reset(); + return this; + } + } + + private static class Link { + private T value; + private Link next; + } + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/TickTimer.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/TickTimer.java new file mode 100644 index 00000000..c89cb94a --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/TickTimer.java @@ -0,0 +1,36 @@ +package cc.funkemunky.api.utils; + + +import cc.funkemunky.api.Atlas; + +public class TickTimer { + private int ticks = Atlas.getInstance().getCurrentTicks(), defaultPassed; + + public TickTimer(int defaultPassed) { + this.defaultPassed = defaultPassed; + } + + public void reset() { + ticks = Atlas.getInstance().getCurrentTicks(); + } + + public boolean hasPassed() { + return Atlas.getInstance().getCurrentTicks() - ticks > defaultPassed; + } + + public boolean hasPassed(int amount) { + return Atlas.getInstance().getCurrentTicks() - ticks > amount; + } + + public boolean hasNotPassed() { + return Atlas.getInstance().getCurrentTicks() - ticks <= defaultPassed; + } + + public boolean hasNotPassed(int amount) { + return Atlas.getInstance().getCurrentTicks() - ticks <= amount; + } + + public int getPassed() { + return Atlas.getInstance().getCurrentTicks() - ticks; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Tuple.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Tuple.java new file mode 100644 index 00000000..cbe63ea9 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/Tuple.java @@ -0,0 +1,14 @@ +package cc.funkemunky.api.utils; + +import lombok.NoArgsConstructor; + +@NoArgsConstructor +public class Tuple { + public A one; + public B two; + + public Tuple(A one, B two) { + this.one = one; + this.two = two; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/XMaterial.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/XMaterial.java new file mode 100644 index 00000000..c083df32 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/XMaterial.java @@ -0,0 +1,1019 @@ +/** The MIT License (MIT) +* +* Copyright (c) 2018 Hex_27 +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +**/ + +package cc.funkemunky.api.utils; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.Map; + +public enum XMaterial { + ACACIA_BOAT(0, "BOAT_ACACIA", "BOAT"), + ACACIA_BUTTON(0, "WOOD_BUTTON"), + ACACIA_DOOR(0, "ACACIA_DOOR","ACACIA_DOOR_ITEM"), + ACACIA_FENCE(0, "ACACIA_FENCE"), + ACACIA_FENCE_GATE(0, "ACACIA_FENCE_GATE"), + ACACIA_LEAVES(0, "LEAVES_2"), + ACACIA_LOG(0, "LOG_2"), + ACACIA_PLANKS(4, "WOOD"), + ACACIA_PRESSURE_PLATE(0, "WOOD_PLATE"), + ACACIA_SAPLING(4, "SAPLING"), + ACACIA_SLAB(4,"WOODEN_SLAB", "WOOD_STEP", "WOOD_DOUBLE_STEP"), + ACACIA_STAIRS(4, "ACACIA_STAIRS"), + ACACIA_TRAPDOOR(0, "TRAP_DOOR"), + ACACIA_WOOD(0, "LOG_2"), + ACTIVATOR_RAIL(0, "ACTIVATOR_RAIL"), + AIR(0, "AIR"), + ALLIUM(2, "RED_ROSE"), + ANDESITE(5, "STONE"), + ANVIL(0, "ANVIL"), + APPLE(0, "APPLE"), + ARMOR_STAND(0, "ARMOR_STAND"), + ARROW(0, "ARROW"), + ATTACHED_MELON_STEM(7, "MELON_STEM"), + ATTACHED_PUMPKIN_STEM(7, "PUMPKIN_STEM"), + AZURE_BLUET(3, "RED_ROSE"), + BAKED_POTATO(0, "BAKED_POTATO"), + BARRIER(0, "BARRIER"), + BAT_SPAWN_EGG(0, "MONSTER_EGG"), + BEACON(0, "BEACON"), + BEDROCK(0, "BEDROCK"), + BEEF(0, "RAW_BEEF"), + BEETROOT(0, "BEETROOT"), + BEETROOTS(0, "BEETROOT", "BEETROOT_BLOCK"), + BEETROOT_SEEDS(0, "BEETROOT_SEEDS"), + BEETROOT_SOUP(0, "BEETROOT_SOUP"), + BIRCH_BOAT(0, "BOAT_BIRCH", "BOAT"), + BIRCH_BUTTON(0, "WOOD_BUTTON"), + BIRCH_DOOR(0, "BIRCH_DOOR", "BIRCH_DOOR_ITEM"), + BIRCH_FENCE(0, "BIRCH_FENCE"), + BIRCH_FENCE_GATE(0, "BIRCH_FENCE_GATE"), + BIRCH_LEAVES(2, "LEAVES"), + BIRCH_LOG(2, "LOG"), + BIRCH_PLANKS(2, "WOOD"), + BIRCH_PRESSURE_PLATE(0, "WOOD_PLATE"), + BIRCH_SAPLING(2, "SAPLING"), + BIRCH_SLAB(2,"WOODEN_SLAB", "WOOD_STEP", "WOOD_DOUBLE_STEP"), + BIRCH_STAIRS(0, "BIRCH_WOOD_STAIRS"), + BIRCH_TRAPDOOR(0, "TRAP_DOOR"), + BIRCH_WOOD(2, "LOG"), + BLACK_BANNER(0, "BANNER", "STANDING_BANNER"), + BLACK_BED(15, "BED_BLOCK", "BED"), + BLACK_CARPET(15, "CARPET"), + BLACK_CONCRETE(15, "CONCRETE"), + BLACK_CONCRETE_POWDER(15, "CONCRETE_POWDER"), + BLACK_GLAZED_TERRACOTTA(0, "BLACK_GLAZED_TERRACOTTA"), + BLACK_SHULKER_BOX(0, "BLACK_SHULKER_BOX"), + BLACK_STAINED_GLASS(15, "STAINED_GLASS"), + BLACK_STAINED_GLASS_PANE(15, "STAINED_GLASS_PANE"), + BLACK_TERRACOTTA(15, "STAINED_CLAY"), + BLACK_WALL_BANNER(0, "WALL_BANNER"), + BLACK_WOOL(15, "WOOL"), + BLAZE_POWDER(0, "BLAZE_POWDER"), + BLAZE_ROD(0, "BLAZE_ROD"), + BLAZE_SPAWN_EGG(0, "MONSTER_EGG"), + BLUE_BANNER(11, "BANNER", "STANDING_BANNER"), + BLUE_BED(4, "BED_BLOCK", "BED"), + BLUE_CARPET(11, "CARPET"), + BLUE_CONCRETE(11, "CONCRETE"), + BLUE_CONCRETE_POWDER(11, "CONCRETE_POWDER"), + BLUE_GLAZED_TERRACOTTA(0, "BLUE_GLAZED_TERRACOTTA"), + BLUE_ICE(0, "PACKED_ICE"), + BLUE_ORCHID(1, "RED_ROSE"), + BLUE_SHULKER_BOX(0, "BLUE_SHULKER_BOX"), + BLUE_STAINED_GLASS(11, "STAINED_GLASS"), + BLUE_STAINED_GLASS_PANE(11, "STAINED_GLASS_PANE"), + BLUE_TERRACOTTA(11, "STAINED_CLAY"), + BLUE_WALL_BANNER(11, "WALL_BANNER"), + BLUE_WOOL(11, "WOOL"), + BONE(0, "BONE"), + BONE_BLOCK(0, "BONE_BLOCK"), + BONE_MEAL(15, "INK_SACK"), + BOOK(0, "BOOK"), + BOOKSHELF(0, "BOOKSHELF"), + BOW(0, "BOW"), + BOWL(0, "BOWL"), + BRAIN_CORAL(0, "STONE"), + BRAIN_CORAL_BLOCK(0, "STONE"), + BRAIN_CORAL_FAN(0, "STONE"), + BREAD(0, "BREAD"), + BREWING_STAND(0, "BREWING_STAND", "BREWING_STAND_ITEM"), + BRICK(0, "CLAY_BRICK"), + BRICKS(0, "BRICK"), + BRICK_SLAB(4, "STEP"), + BRICK_STAIRS(0, "BRICK_STAIRS"), + BROWN_BANNER(3, "BANNER", "STANDING_BANNER"), + BROWN_BED(12, "BED_BLOCK", "BED"), + BROWN_CARPET(12, "CARPET"), + BROWN_CONCRETE(12, "CONCRETE"), + BROWN_CONCRETE_POWDER(12, "CONCRETE_POWDER"), + BROWN_GLAZED_TERRACOTTA(0, "BROWN_GLAZED_TERRACOTTA"), + BROWN_MUSHROOM(0, "BROWN_MUSHROOM"), + BROWN_MUSHROOM_BLOCK(0, "BROWN_MUSHROOM", "HUGE_MUSHROOM_1"), + BROWN_SHULKER_BOX(0, "BROWN_SHULKER_BOX"), + BROWN_STAINED_GLASS(12, "STAINED_GLASS"), + BROWN_STAINED_GLASS_PANE(12, "STAINED_GLASS_PANE"), + BROWN_TERRACOTTA(12, "STAINED_CLAY"), + BROWN_WALL_BANNER(3, "WALL_BANNER"), + BROWN_WOOL(12, "WOOL"), + BUBBLE_COLUMN(0, "STONE"), + BUBBLE_CORAL(0, "STONE"), + BUBBLE_CORAL_BLOCK(0, "STONE"), + BUBBLE_CORAL_FAN(0, "STONE"), + BUCKET(0, "BUCKET"), + CACTUS(0, "CACTUS"), + CACTUS_GREEN(2, "INK_SACK"), + CAKE(0, "CAKE", "CAKE_BLOCK"), + CARROT(0, "CARROT_ITEM"), + CARROTS(0, "CARROT"), + CARROT_ON_A_STICK(0, "CARROT_STICK"), + CARVED_PUMPKIN(0, "PUMPKIN"), + CAULDRON(0, "CAULDRON", "CAULDRON_ITEM"), + CAVE_AIR(0, "AIR"), + CAVE_SPIDER_SPAWN_EGG(0, "MONSTER_EGG"), + CHAINMAIL_BOOTS(0, "CHAINMAIL_BOOTS"), + CHAINMAIL_CHESTPLATE(0, "CHAINMAIL_CHESTPLATE"), + CHAINMAIL_HELMET(0, "CHAINMAIL_HELMET"), + CHAINMAIL_LEGGINGS(0, "CHAINMAIL_LEGGINGS"), + CHAIN_COMMAND_BLOCK(0, "COMMAND_CHAIN"), + CHARCOAL(1, "COAL"), + CHEST(0, "CHEST", "LOCKED_CHEST"), + CHEST_MINECART(0, "STORAGE_MINECART"), + CHICKEN(0, "RAW_CHICKEN"), + CHICKEN_SPAWN_EGG(0, "MONSTER_EGG"), + CHIPPED_ANVIL(1, "ANVIL"), + CHISELED_QUARTZ_BLOCK(1, "QUARTZ_BLOCK"), + CHISELED_RED_SANDSTONE(1, "RED_SANDSTONE"), + CHISELED_SANDSTONE(1, "SANDSTONE"), + CHISELED_STONE_BRICKS(3, "SMOOTH_BRICK"), + CHORUS_FLOWER(0, "CHORUS_FLOWER"), + CHORUS_FRUIT(0, "CHORUS_FRUIT"), + CHORUS_PLANT(0, "CHORUS_PLANT"), + CLAY(0, "CLAY"), + CLAY_BALL(0, "CLAY_BALL"), + CLOCK(0, "WATCH"), + COAL(0, "COAL"), + COAL_BLOCK(0, "COAL_BLOCK"), + COAL_ORE(0, "COAL_ORE"), + COARSE_DIRT(1, "DIRT"), + COBBLESTONE(0, "COBBLESTONE"), + COBBLESTONE_SLAB(3, "STEP"), + COBBLESTONE_STAIRS(0, "COBBLESTONE_STAIRS"), + COBBLESTONE_WALL(0, "COBBLE_WALL"), + COBWEB(0, "WEB"), + COCOA(0, "COCOA"), + COCOA_BEANS(3, "INK_SACK"), + COD(0, "RAW_FISH"), + COD_BUCKET(0, "BUCKET"), + COD_SPAWN_EGG(0, "MONSTER_EGG"), + COMMAND_BLOCK(0, "COMMAND"), + COMMAND_BLOCK_MINECART(0, "COMMAND_MINECART"), + REDSTONE_COMPARATOR_ON(0, "COMPARATOR", "REDSTONE_COMPARATOR"), + REDSTONE_COMPARATOR_OFF(0, "COMPARATOR", "REDSTONE_COMPARATOR"), + COMPARATOR(0, "REDSTONE_COMPARATOR", "REDSTONE_COMPARATOR_ON", "REDSTONE_COMPARATOR_OFF"), + COMPASS(0, "COMPASS"), + CONDUIT(0, "STONE"), + COOKED_BEEF(0, "COOKED_BEEF"), + COOKED_CHICKEN(0, "COOKED_CHICKEN"), + COOKED_COD(0, "COOKED_FISH"), + COOKED_MUTTON(0, "COOKED_MUTTON"), + COOKED_PORKCHOP(0, "GRILLED_PORK"), + COOKED_RABBIT(0, "COOKED_RABBIT"), + COOKED_SALMON(1, "COOKED_FISH"), + COOKIE(0, "COOKIE"), + COW_SPAWN_EGG(0, "MONSTER_EGG"), + CRACKED_STONE_BRICKS(2, "SMOOTH_BRICK"), + CRAFTING_TABLE(0, "WORKBENCH"), + CREEPER_HEAD(0, "SKULL","SKULL_ITEM"), + CREEPER_SPAWN_EGG(0, "MONSTER_EGG"), + CREEPER_WALL_HEAD(0, "SKULL","SKULL_ITEM"), + CUT_RED_SANDSTONE(0, "STONE"), + CUT_SANDSTONE(0, "STONE"), + CYAN_BANNER(6, "BANNER", "STANDING_BANNER"), + CYAN_BED(9, "BED_BLOCK", "BED"), + CYAN_CARPET(9, "CARPET"), + CYAN_CONCRETE(9, "CONCRETE"), + CYAN_CONCRETE_POWDER(9, "CONCRETE_POWDER"), + CYAN_DYE(6, "INK_SACK"), + CYAN_GLAZED_TERRACOTTA(0, "CYAN_GLAZED_TERRACOTTA"), + CYAN_SHULKER_BOX(0, "CYAN_SHULKER_BOX"), + CYAN_STAINED_GLASS(9, "STAINED_GLASS"), + CYAN_STAINED_GLASS_PANE(9, "STAINED_GLASS_PANE"), + CYAN_TERRACOTTA(9, "STAINED_CLAY"), + CYAN_WALL_BANNER(0, "WALL_BANNER"), + CYAN_WOOL(9, "WOOL"), + DAMAGED_ANVIL(2, "ANVIL"), + DANDELION(0, "YELLOW_FLOWER"), + DANDELION_YELLOW(11, "INK_SACK"), + DARK_OAK_BOAT(0, "BOAT_DARK_OAK", "BOAT"), + DARK_OAK_BUTTON(0, "WOOD_BUTTON"), + DARK_OAK_DOOR(0, "DARK_OAK_DOOR", "DARK_OAK_DOOR_ITEM"), + DARK_OAK_FENCE(0, "DARK_OAK_FENCE"), + DARK_OAK_FENCE_GATE(0, "DARK_OAK_FENCE_GATE"), + DARK_OAK_LEAVES(1, "LEAVES_2"), + DARK_OAK_LOG(1, "LOG_2"), + DARK_OAK_PLANKS(5, "WOOD"), + DARK_OAK_PRESSURE_PLATE(0, "WOOD_PLATE"), + DARK_OAK_SAPLING(5, "SAPLING"), + DARK_OAK_SLAB(0,"WOODEN_SLAB", "WOOD_STEP", "WOOD_DOUBLE_STEP"), + DARK_OAK_STAIRS(0, "DARK_OAK_STAIRS"), + DARK_OAK_TRAPDOOR(0, "TRAP_DOOR"), + DARK_OAK_WOOD(1, "LOG_2"), + DARK_PRISMARINE(2, "PRISMARINE"), + DARK_PRISMARINE_SLAB(0, "STONE"), + DARK_PRISMARINE_STAIRS(0, "STONE"), + DAYLIGHT_DETECTOR(0, "DAYLIGHT_DETECTOR", "DAYLIGHT_DETECTOR_INVERTED"), + DAYLIGHT_DETECTOR_INVERTED(0, "DAYLIGHT_DETECTOR_INVERTED"), + DEAD_BRAIN_CORAL_BLOCK(0, "STONE"), + DEAD_BUBBLE_CORAL_BLOCK(0, "STONE"), + DEAD_BUSH(0, "DEAD_BUSH"), + DEAD_FIRE_CORAL_BLOCK(0, "STONE"), + DEAD_HORN_CORAL_BLOCK(0, "STONE"), + DEAD_TUBE_CORAL_BLOCK(0, "STONE"), + DEBUG_STICK(0, "STICK"), + DETECTOR_RAIL(0, "DETECTOR_RAIL"), + DIAMOND(0, "DIAMOND"), + DIAMOND_AXE(0, "DIAMOND_AXE"), + DIAMOND_BLOCK(0, "DIAMOND_BLOCK"), + DIAMOND_BOOTS(0, "DIAMOND_BOOTS"), + DIAMOND_CHESTPLATE(0, "DIAMOND_CHESTPLATE"), + DIAMOND_HELMET(0, "DIAMOND_HELMET"), + DIAMOND_HOE(0, "DIAMOND_HOE"), + DIAMOND_HORSE_ARMOR(0, "DIAMOND_BARDING"), + DIAMOND_LEGGINGS(0, "DIAMOND_LEGGINGS"), + DIAMOND_ORE(0, "DIAMOND_ORE"), + DIAMOND_PICKAXE(0, "DIAMOND_PICKAXE"), + DIAMOND_SHOVEL(0, "DIAMOND_SPADE"), + DIAMOND_SWORD(0, "DIAMOND_SWORD"), + DIORITE(3, "STONE"), + DIRT(0, "DIRT"), + DISPENSER(0, "DISPENSER"), + DOLPHIN_SPAWN_EGG(0, "MONSTER_EGG"), + DONKEY_SPAWN_EGG(0, "MONSTER_EGG"), + DRAGON_BREATH(0, "DRAGONS_BREATH"), + DRAGON_EGG(0, "DRAGON_EGG"), + DRAGON_HEAD(5, "SKULL","SKULL_ITEM"), + DRAGON_WALL_HEAD(0, "SKULL","SKULL_ITEM"), + DRIED_KELP(0, "STONE"), + DRIED_KELP_BLOCK(0, "STONE"), + DROPPER(0, "DROPPER"), + DROWNED_SPAWN_EGG(0, "MONSTER_EGG"), + EGG(0, "EGG"), + ELDER_GUARDIAN_SPAWN_EGG(0, "MONSTER_EGG"), + ELYTRA(0, "ELYTRA"), + EMERALD(0, "EMERALD"), + EMERALD_BLOCK(0, "EMERALD_BLOCK"), + EMERALD_ORE(0, "EMERALD_ORE"), + ENCHANTED_BOOK(0, "ENCHANTED_BOOK"), + ENCHANTED_GOLDEN_APPLE(1, "GOLDEN_APPLE"), + ENCHANTING_TABLE(0, "ENCHANTMENT_TABLE"), + ENDERMAN_SPAWN_EGG(0, "MONSTER_EGG"), + ENDERMITE_SPAWN_EGG(0, "MONSTER_EGG"), + ENDER_CHEST(0, "ENDER_CHEST"), + ENDER_EYE(0, "EYE_OF_ENDER"), + ENDER_PEARL(0, "ENDER_PEARL"), + END_CRYSTAL(0, "END_CRYSTAL"), + END_GATEWAY(0, "END_GATEWAY"), + END_PORTAL(0, "ENDER_PORTAL"), + END_PORTAL_FRAME(0, "ENDER_PORTAL_FRAME"), + END_ROD(0, "END_ROD"), + END_STONE(0, "ENDER_STONE"), + END_STONE_BRICKS(0, "END_BRICKS"), + EVOKER_SPAWN_EGG(0, "MONSTER_EGG"), + EXPERIENCE_BOTTLE(0, "EXP_BOTTLE"), + FARMLAND(0, "SOIL"), + FEATHER(0, "FEATHER"), + FERMENTED_SPIDER_EYE(0, "FERMENTED_SPIDER_EYE"), + FERN(2, "LONG_GRASS"), + FILLED_MAP(0, "MAP"), + FIRE(0, "FIRE"), + FIREWORK_ROCKET(0, "FIREWORK"), + FIREWORK_STAR(0, "FIREWORK_CHARGE"), + FIRE_CHARGE(0, "FIREBALL"), + FIRE_CORAL(0, "STONE"), + FIRE_CORAL_BLOCK(0, "STONE"), + FIRE_CORAL_FAN(0, "STONE"), + FISHING_ROD(0, "FISHING_ROD"), + FLINT(0, "FLINT"), + FLINT_AND_STEEL(0, "FLINT_AND_STEEL"), + FLOWER_POT(0, "FLOWER_POT","FLOWER_POT_ITEM"), + FROSTED_ICE(0, "FROSTED_ICE"), + FURNACE(0, "FURNACE", "BURNING_FURNACE"), + FURNACE_MINECART(0, "POWERED_MINECART"), + GHAST_SPAWN_EGG(0, "MONSTER_EGG"), + GHAST_TEAR(0, "GHAST_TEAR"), + GLASS(0, "GLASS"), + GLASS_BOTTLE(0, "GLASS_BOTTLE"), + GLASS_PANE(0, "THIN_GLASS"), + GLISTERING_MELON_SLICE(0, "SPECKLED_MELON"), + GLOWSTONE(0, "GLOWSTONE"), + GLOWSTONE_DUST(0, "GLOWSTONE_DUST"), + GOLDEN_APPLE(0, "GOLDEN_APPLE"), + GOLDEN_AXE(0, "GOLD_AXE"), + GOLDEN_BOOTS(0, "GOLD_BOOTS"), + GOLDEN_CARROT(0, "GOLDEN_CARROT"), + GOLDEN_CHESTPLATE(0, "GOLD_CHESTPLATE"), + GOLDEN_HELMET(0, "GOLD_HELMET"), + GOLDEN_HOE(0, "GOLD_HOE"), + GOLDEN_HORSE_ARMOR(0, "GOLD_BARDING"), + GOLDEN_LEGGINGS(0, "GOLD_LEGGINGS"), + GOLDEN_PICKAXE(0, "GOLD_PICKAXE"), + GOLDEN_SHOVEL(0, "GOLD_SPADE"), + GOLDEN_SWORD(0, "GOLD_SWORD"), + GOLD_BLOCK(0, "GOLD_BLOCK"), + GOLD_INGOT(0, "GOLD_INGOT"), + GOLD_NUGGET(0, "GOLD_NUGGET"), + GOLD_ORE(0, "GOLD_ORE"), + GRANITE(1, "STONE"), + LONG_GRASS(0, "LONG_GRASS", "GRASS"), + GRASS_BLOCK(0, "GRASS"), + GRASS_PATH(0, "GRASS_PATH"), + GRAVEL(0, "GRAVEL"), + GRAY_BANNER(8, "BANNER", "STANDING_BANNER"), + GRAY_BED(7, "BED_BLOCK", "BED"), + GRAY_CARPET(7, "CARPET"), + GRAY_CONCRETE(7, "CONCRETE"), + GRAY_CONCRETE_POWDER(7, "CONCRETE_POWDER"), + GRAY_DYE(8, "INK_SACK"), + GRAY_GLAZED_TERRACOTTA(0, "GRAY_GLAZED_TERRACOTTA"), + GRAY_SHULKER_BOX(0, "GRAY_SHULKER_BOX"), + GRAY_STAINED_GLASS(7, "STAINED_GLASS"), + GRAY_STAINED_GLASS_PANE(7, "STAINED_GLASS_PANE"), + GRAY_TERRACOTTA(7, "STAINED_CLAY"), + GRAY_WALL_BANNER(0, "WALL_BANNER"), + GRAY_WOOL(7, "WOOL"), + GREEN_BANNER(2, "BANNER", "STANDING_BANNER"), + GREEN_BED(13, "BED_BLOCK", "BED"), + GREEN_CARPET(13, "CARPET"), + GREEN_CONCRETE(13, "CONCRETE"), + GREEN_CONCRETE_POWDER(13, "CONCRETE_POWDER"), + GREEN_GLAZED_TERRACOTTA(0, "GREEN_GLAZED_TERRACOTTA"), + GREEN_SHULKER_BOX(0, "GREEN_SHULKER_BOX"), + GREEN_STAINED_GLASS(13, "STAINED_GLASS"), + GREEN_STAINED_GLASS_PANE(13, "STAINED_GLASS_PANE"), + GREEN_TERRACOTTA(13, "STAINED_CLAY"), + GREEN_WALL_BANNER(0, "WALL_BANNER"), + GREEN_WOOL(13, "WOOL"), + GUARDIAN_SPAWN_EGG(0, "MONSTER_EGG"), + GUNPOWDER(0, "SULPHUR"), + HAY_BLOCK(0, "HAY_BLOCK"), + HEART_OF_THE_SEA(0, "STONE"), + HEAVY_WEIGHTED_PRESSURE_PLATE(0, "IRON_PLATE"), + HOPPER(0, "HOPPER"), + HOPPER_MINECART(0, "HOPPER_MINECART"), + HORN_CORAL(0, "STONE"), + HORN_CORAL_BLOCK(0, "STONE"), + HORN_CORAL_FAN(0, "STONE"), + HORSE_SPAWN_EGG(0, "MONSTER_EGG"), + HUSK_SPAWN_EGG(0, "MONSTER_EGG"), + ICE(0, "ICE"), + INFESTED_CHISELED_STONE_BRICKS(5, "MONSTER_EGGS"), + INFESTED_COBBLESTONE(1, "MONSTER_EGGS"), + INFESTED_CRACKED_STONE_BRICKS(4, "MONSTER_EGGS"), + INFESTED_MOSSY_STONE_BRICKS(3, "MONSTER_EGGS"), + INFESTED_STONE(0, "MONSTER_EGGS"), + INFESTED_STONE_BRICKS(2, "MONSTER_EGGS"), + INK_SAC(0, "INK_SACK"), + IRON_AXE(0, "IRON_AXE"), + IRON_BARS(0, "IRON_FENCE"), + IRON_BLOCK(0, "IRON_BLOCK"), + IRON_BOOTS(0, "IRON_BOOTS"), + IRON_CHESTPLATE(0, "IRON_CHESTPLATE"), + IRON_DOOR(0, "IRON_DOOR", "IRON_DOOR_BLOCK"), + IRON_HELMET(0, "IRON_HELMET"), + IRON_HOE(0, "IRON_HOE"), + IRON_HORSE_ARMOR(0, "IRON_BARDING"), + IRON_INGOT(0, "IRON_INGOT"), + IRON_LEGGINGS(0, "IRON_LEGGINGS"), + IRON_NUGGET(0, "IRON_NUGGET"), + IRON_ORE(0, "IRON_ORE"), + IRON_PICKAXE(0, "IRON_PICKAXE"), + IRON_SHOVEL(0, "IRON_SPADE"), + IRON_SWORD(0, "IRON_SWORD"), + IRON_TRAPDOOR(0, "IRON_TRAPDOOR"), + ITEM_FRAME(0, "ITEM_FRAME"), + JACK_O_LANTERN(0, "JACK_O_LANTERN"), + JUKEBOX(0, "JUKEBOX"), + JUNGLE_BOAT(0, "BOAT_JUNGLE", "BOAT"), + JUNGLE_BUTTON(0, "WOOD_BUTTON"), + JUNGLE_DOOR(0, "JUNGLE_DOOR", "JUNGLE_DOOR_ITEM"), + JUNGLE_FENCE(0, "JUNGLE_FENCE"), + JUNGLE_FENCE_GATE(0, "JUNGLE_FENCE_GATE"), + JUNGLE_LEAVES(3, "LEAVES"), + JUNGLE_LOG(3, "LOG"), + JUNGLE_PLANKS(3, "WOOD"), + JUNGLE_PRESSURE_PLATE(0, "WOOD_PLATE"), + JUNGLE_SAPLING(3, "SAPLING"), + JUNGLE_SLAB(3,"WOODEN_SLAB", "WOOD_STEP", "WOOD_DOUBLE_STEP"), + JUNGLE_STAIRS(0, "JUNGLE_WOOD_STAIRS"), + JUNGLE_TRAPDOOR(0, "TRAP_DOOR"), + JUNGLE_WOOD(3, "LOG"), + KELP(0, "STONE"), + KELP_PLANT(0, "STONE"), + KNOWLEDGE_BOOK(0, "KNOWLEDGE_BOOK"), + LADDER(0, "LADDER"), + LAPIS_BLOCK(0, "LAPIS_BLOCK"), + LAPIS_LAZULI(4, "INK_SACK"), + LAPIS_ORE(0, "LAPIS_ORE"), + LARGE_FERN(3, "DOUBLE_PLANT"), + LAVA(0, "LAVA", "STATIONARY_LAVA"), + STATIONARY_LAVA(0, "LAVA"), + LAVA_BUCKET(0, "LAVA_BUCKET"), + LEAD(0, "LEASH"), + LEATHER(0, "LEATHER"), + LEATHER_BOOTS(0, "LEATHER_BOOTS"), + LEATHER_CHESTPLATE(0, "LEATHER_CHESTPLATE"), + LEATHER_HELMET(0, "LEATHER_HELMET"), + LEATHER_LEGGINGS(0, "LEATHER_LEGGINGS"), + LEVER(0, "LEVER"), + LIGHT_BLUE_BANNER(12, "BANNER", "STANDING_BANNER"), + LIGHT_BLUE_BED(3, "BED_BLOCK", "BED"), + LIGHT_BLUE_CARPET(3, "CARPET"), + LIGHT_BLUE_CONCRETE(3, "CONCRETE"), + LIGHT_BLUE_CONCRETE_POWDER(3, "CONCRETE_POWDER"), + LIGHT_BLUE_DYE(12, "INK_SACK"), + LIGHT_BLUE_GLAZED_TERRACOTTA(0, "LIGHT_BLUE_GLAZED_TERRACOTTA"), + LIGHT_BLUE_SHULKER_BOX(0, "LIGHT_BLUE_SHULKER_BOX"), + LIGHT_BLUE_STAINED_GLASS(3, "STAINED_GLASS"), + LIGHT_BLUE_STAINED_GLASS_PANE(3, "STAINED_GLASS_PANE"), + LIGHT_BLUE_TERRACOTTA(3, "STAINED_CLAY"), + LIGHT_BLUE_WALL_BANNER(0, "BANNER", "STANDING_BANNER"), + LIGHT_BLUE_WOOL(3, "WOOL"), + LIGHT_GRAY_BANNER(7, "BANNER", "STANDING_BANNER"), + LIGHT_GRAY_BED(8, "BED_BLOCK", "BED"), + LIGHT_GRAY_CARPET(8, "CARPET"), + LIGHT_GRAY_CONCRETE(8, "CONCRETE"), + LIGHT_GRAY_CONCRETE_POWDER(8, "CONCRETE_POWDER"), + LIGHT_GRAY_DYE(7, "INK_SACK"), + LIGHT_GRAY_GLAZED_TERRACOTTA(0, "SILVER_GLAZED_TERRACOTTA"), + LIGHT_GRAY_SHULKER_BOX(0, "SILVER_SHULKER_BOX"), + LIGHT_GRAY_STAINED_GLASS(8, "STAINED_GLASS"), + LIGHT_GRAY_STAINED_GLASS_PANE(8, "STAINED_GLASS_PANE"), + LIGHT_GRAY_TERRACOTTA(8, "STAINED_CLAY"), + LIGHT_GRAY_WALL_BANNER(0, "WALL_BANNER"), + LIGHT_GRAY_WOOL(8, "WOOL"), + LIGHT_WEIGHTED_PRESSURE_PLATE(0, "GOLD_PLATE"), + LILAC(1, "DOUBLE_PLANT"), + LILY_PAD(0, "WATER_LILY"), + LIME_BANNER(10, "BANNER", "STANDING_BANNER"), + LIME_BED(5, "BED_BLOCK", "BED"), + LIME_CARPET(5, "CARPET"), + LIME_CONCRETE(5, "CONCRETE"), + LIME_CONCRETE_POWDER(5, "CONCRETE_POWDER"), + LIME_DYE(10, "INK_SACK"), + LIME_GLAZED_TERRACOTTA(0, "LIME_GLAZED_TERRACOTTA"), + LIME_SHULKER_BOX(0, "LIME_SHULKER_BOX"), + LIME_STAINED_GLASS(5, "STAINED_GLASS"), + LIME_STAINED_GLASS_PANE(5, "STAINED_GLASS_PANE"), + LIME_TERRACOTTA(5, "STAINED_CLAY"), + LIME_WALL_BANNER(0, "WALL_BANNER"), + LIME_WOOL(5, "WOOL"), + LINGERING_POTION(0, "LINGERING_POTION"), + LLAMA_SPAWN_EGG(0, "MONSTER_EGG"), + MAGENTA_BANNER(13, "BANNER", "STANDING_BANNER"), + MAGENTA_BED(2, "BED_BLOCK", "BED"), + MAGENTA_CARPET(2, "CARPET"), + MAGENTA_CONCRETE(2, "CONCRETE"), + MAGENTA_CONCRETE_POWDER(2, "CONCRETE_POWDER"), + MAGENTA_DYE(13, "INK_SACK"), + MAGENTA_GLAZED_TERRACOTTA(0, "MAGENTA_GLAZED_TERRACOTTA"), + MAGENTA_SHULKER_BOX(0, "MAGENTA_SHULKER_BOX"), + MAGENTA_STAINED_GLASS(2, "STAINED_GLASS"), + MAGENTA_STAINED_GLASS_PANE(2, "STAINED_GLASS_PANE"), + MAGENTA_TERRACOTTA(2, "STAINED_CLAY"), + MAGENTA_WALL_BANNER(0, "WALL_BANNER"), + MAGENTA_WOOL(2, "WOOL"), + MAGMA_BLOCK(0, "MAGMA"), + MAGMA_CREAM(0, "MAGMA_CREAM"), + MAGMA_CUBE_SPAWN_EGG(0, "MONSTER_EGG"), + MAP(0, "EMPTY_MAP", "MAP"), + MELON(0, "MELON_BLOCK"), + MELON_SEEDS(0, "MELON_SEEDS"), + MELON_SLICE(0, "MELON"), + MELON_STEM(0, "MELON_STEM"), + MILK_BUCKET(0, "MILK_BUCKET"), + MINECART(0, "MINECART"), + MOOSHROOM_SPAWN_EGG(0, "MONSTER_EGG"), + MOSSY_COBBLESTONE(0, "MOSSY_COBBLESTONE"), + MOSSY_COBBLESTONE_WALL(1, "COBBLE_WALL"), + MOSSY_STONE_BRICKS(1, "SMOOTH_BRICK"), + MOVING_PISTON(0, "PISTON_MOVING_PIECE"), + MULE_SPAWN_EGG(0, "MONSTER_EGG"), + MUSHROOM_STEM(0, "BROWN_MUSHROOM"), + MUSHROOM_STEW(0, "MUSHROOM_SOUP"), + MUSIC_DISC_11(0, "GOLD_RECORD"), + MUSIC_DISC_13(0, "GREEN_RECORD"), + MUSIC_DISC_BLOCKS(0, "RECORD_3"), + MUSIC_DISC_CAT(0, "RECORD_4"), + MUSIC_DISC_CHIRP(0, "RECORD_5"), + MUSIC_DISC_FAR(0, "RECORD_6"), + MUSIC_DISC_MALL(0, "RECORD_7"), + MUSIC_DISC_MELLOHI(0, "RECORD_8"), + MUSIC_DISC_STAL(0, "RECORD_9"), + MUSIC_DISC_STRAD(0, "RECORD_10"), + MUSIC_DISC_WAIT(0, "RECORD_11"), + MUSIC_DISC_WARD(0, "RECORD_12"), + MUTTON(0, "MUTTON"), + MYCELIUM(0, "MYCEL"), + NAME_TAG(0, "NAME_TAG"), + NAUTILUS_SHELL(0, "STONE"), + NETHERRACK(0, "NETHERRACK"), + NETHER_BRICK(0, "NETHER_BRICK"), + NETHER_BRICKS(0, "NETHER_BRICK"), + NETHER_BRICK_FENCE(0, "NETHER_FENCE"), + NETHER_BRICK_SLAB(6, "STEP"), + NETHER_BRICK_STAIRS(0, "NETHER_BRICK_STAIRS"), + NETHER_PORTAL(0, "PORTAL"), + NETHER_QUARTZ_ORE(0, "QUARTZ_ORE"), + NETHER_STAR(0, "NETHER_STAR"), + NETHER_WART(0, "NETHER_STALK"), + NETHER_WART_BLOCK(0, "NETHER_WART_BLOCK", "NETHER_WARTS"), + NOTE_BLOCK(0, "NOTE_BLOCK"), + OAK_BOAT(0, "BOAT", "BOAT"), + OAK_BUTTON(0, "WOOD_BUTTON"), + OAK_DOOR(0, "WOODEN_DOOR", "WOOD_DOOR"), + OAK_FENCE(0, "FENCE"), + OAK_FENCE_GATE(0, "FENCE_GATE"), + OAK_LEAVES(0, "LEAVES"), + OAK_LOG(0, "LOG"), + OAK_PLANKS(0, "WOOD"), + OAK_PRESSURE_PLATE(0, "WOOD_PLATE"), + OAK_SAPLING(0, "SAPLING"), + OAK_SLAB(0,"WOODEN_SLAB", "WOOD_STEP", "WOOD_DOUBLE_STEP"), + OAK_STAIRS(0, "WOOD_STAIRS"), + OAK_TRAPDOOR(0, "TRAP_DOOR"), + OAK_WOOD(0, "LOG"), + OBSERVER(0, "OBSERVER"), + OBSIDIAN(0, "OBSIDIAN"), + OCELOT_SPAWN_EGG(0, "RECORD_12"), + ORANGE_BANNER(14, "BANNER", "STANDING_BANNER"), + ORANGE_BED(1, "BED_BLOCK", "BED"), + ORANGE_CARPET(1, "CARPET"), + ORANGE_CONCRETE(1, "CONCRETE"), + ORANGE_CONCRETE_POWDER(1, "CONCRETE_POWDER"), + ORANGE_DYE(14, "INK_SACK"), + ORANGE_GLAZED_TERRACOTTA(0, "ORANGE_GLAZED_TERRACOTTA"), + ORANGE_SHULKER_BOX(0, "ORANGE_SHULKER_BOX"), + ORANGE_STAINED_GLASS(1, "STAINED_GLASS"), + ORANGE_STAINED_GLASS_PANE(1, "STAINED_GLASS_PANE"), + ORANGE_TERRACOTTA(1, "STAINED_CLAY"), + ORANGE_TULIP(5, "RED_ROSE"), + ORANGE_WALL_BANNER(0, "WALL_BANNER"), + ORANGE_WOOL(1, "WOOL"), + OXEYE_DAISY(8, "RED_ROSE"), + PACKED_ICE(0, "PACKED_ICE"), + PAINTING(0, "PAINTING"), + PAPER(0, "PAPER"), + PARROT_SPAWN_EGG(0, "MONSTER_EGG"), + PEONY(5, "DOUBLE_PLANT"), + PETRIFIED_OAK_SLAB(0, "STONE"), + PHANTOM_MEMBRANE(0, "STONE"), + PHANTOM_SPAWN_EGG(0, "MONSTER_EGG"), + PIG_SPAWN_EGG(0, "MONSTER_EGG"), + PINK_BANNER(9, "BANNER", "STANDING_BANNER"), + PINK_BED(6, "BED_BLOCK", "BED"), + PINK_CARPET(6, "CARPET"), + PINK_CONCRETE(6, "CONCRETE"), + PINK_CONCRETE_POWDER(6, "CONCRETE_POWDER"), + PINK_DYE(9, "INK_SACK"), + PINK_GLAZED_TERRACOTTA(0, "PINK_GLAZED_TERRACOTTA"), + PINK_SHULKER_BOX(0, "PINK_SHULKER_BOX"), + PINK_STAINED_GLASS(6, "STAINED_GLASS"), + PINK_STAINED_GLASS_PANE(6, "STAINED_GLASS_PANE"), + PINK_TERRACOTTA(6, "STAINED_CLAY"), + PINK_TULIP(7, "RED_ROSE"), + PINK_WALL_BANNER(0, "WALL_BANNER"), + PINK_WOOL(6, "WOOL"), + PISTON(0, "PISTON_BASE"), + PISTON_HEAD(0, "PISTON_EXTENSION"), + PLAYER_HEAD(0, "SKULL","SKULL_ITEM"), + PLAYER_WALL_HEAD(0, "SKULL","SKULL_ITEM"), + PODZOL(2, "DIRT"), + POISONOUS_POTATO(0, "POISONOUS_POTATO"), + POLAR_BEAR_SPAWN_EGG(0, "MONSTER_EGG"), + POLISHED_ANDESITE(6, "STONE"), + POLISHED_DIORITE(4, "STONE"), + POLISHED_GRANITE(2, "STONE"), + POPPED_CHORUS_FRUIT(0, "CHORUS_FRUIT_POPPED"), + POPPY(0, "RED_ROSE"), + PORKCHOP(0, "PORK"), + POTATO(0, "POTATO_ITEM"), + POTATOES(0, "POTATO"), + POTION(0, "POTION"), + POTTED_ACACIA_SAPLING(0, "FLOWER_POT"), + POTTED_ALLIUM(0, "FLOWER_POT"), + POTTED_AZURE_BLUET(0, "FLOWER_POT"), + POTTED_BIRCH_SAPLING(0, "FLOWER_POT"), + POTTED_BLUE_ORCHID(0, "FLOWER_POT"), + POTTED_BROWN_MUSHROOM(0, "FLOWER_POT"), + POTTED_CACTUS(0, "FLOWER_POT"), + POTTED_DANDELION(0, "FLOWER_POT"), + POTTED_DARK_OAK_SAPLING(0, "FLOWER_POT"), + POTTED_DEAD_BUSH(0, "FLOWER_POT"), + POTTED_FERN(0, "FLOWER_POT"), + POTTED_JUNGLE_SAPLING(0, "FLOWER_POT"), + POTTED_OAK_SAPLING(0, "FLOWER_POT"), + POTTED_ORANGE_TULIP(0, "FLOWER_POT"), + POTTED_OXEYE_DAISY(0, "FLOWER_POT"), + POTTED_PINK_TULIP(0, "FLOWER_POT"), + POTTED_POPPY(0, "FLOWER_POT"), + POTTED_RED_MUSHROOM(0, "FLOWER_POT"), + POTTED_RED_TULIP(0, "FLOWER_POT"), + POTTED_SPRUCE_SAPLING(0, "FLOWER_POT"), + POTTED_WHITE_TULIP(0, "FLOWER_POT"), + POWERED_RAIL(0, "POWERED_RAIL"), + PRISMARINE(0, "PRISMARINE"), + PRISMARINE_BRICKS(1, "PRISMARINE"), + PRISMARINE_BRICK_SLAB(0, "STONE"), + PRISMARINE_BRICK_STAIRS(0, "STONE"), + PRISMARINE_CRYSTALS(0, "PRISMARINE_CRYSTALS"), + PRISMARINE_SHARD(0, "PRISMARINE_SHARD"), + PRISMARINE_SLAB(0, "STONE"), + PRISMARINE_STAIRS(0, "STONE"), + PUFFERFISH(3, "RAW_FISH"), + PUFFERFISH_BUCKET(0, "STONE"), + PUFFERFISH_SPAWN_EGG(0, "MONSTER_EGG"), + PUMPKIN(0, "PUMPKIN"), + PUMPKIN_PIE(0, "PUMPKIN_PIE"), + PUMPKIN_SEEDS(0, "PUMPKIN_SEEDS"), + PUMPKIN_STEM(0, "PUMPKIN_STEM"), + PURPLE_BANNER(5, "BANNER", "STANDING_BANNER"), + PURPLE_BED(10, "BED_BLOCK", "BED"), + PURPLE_CARPET(10, "CARPET"), + PURPLE_CONCRETE(10, "CONCRETE"), + PURPLE_CONCRETE_POWDER(10, "CONCRETE_POWDER"), + PURPLE_DYE(5, "INK_SACK"), + PURPLE_GLAZED_TERRACOTTA(0, "PURPLE_GLAZED_TERRACOTTA"), + PURPLE_SHULKER_BOX(0, "PURPLE_SHULKER_BOX"), + PURPLE_STAINED_GLASS(10, "STAINED_GLASS"), + PURPLE_STAINED_GLASS_PANE(10, "STAINED_GLASS_PANE"), + PURPLE_TERRACOTTA(10, "STAINED_CLAY"), + PURPLE_WALL_BANNER(0, "WALL_BANNER"), + PURPLE_WOOL(10, "WOOL"), + PURPUR_BLOCK(0, "PURPUR_BLOCK"), + PURPUR_PILLAR(0, "PURPUR_PILLAR"), + PURPUR_SLAB(0, "PURPUR_SLAB", "PURPUR_DOUBLE_SLAB"), + PURPUR_STAIRS(0, "PURPUR_STAIRS"), + QUARTZ(0, "QUARTZ"), + QUARTZ_BLOCK(0, "QUARTZ_BLOCK"), + QUARTZ_PILLAR(2, "QUARTZ_BLOCK"), + QUARTZ_SLAB(7, "STEP"), + QUARTZ_STAIRS(0, "QUARTZ_STAIRS"), + RABBIT(0, "RABBIT"), + RABBIT_FOOT(0, "RABBIT_FOOT"), + RABBIT_HIDE(0, "RABBIT_HIDE"), + RABBIT_SPAWN_EGG(0, "MONSTER_EGG"), + RABBIT_STEW(0, "RABBIT_STEW"), + RAIL(0, "RAILS"), + REDSTONE(0, "REDSTONE"), + REDSTONE_BLOCK(0, "REDSTONE_BLOCK"), + REDSTONE_LAMP(0, "REDSTONE_LAMP_ON", "REDSTONE_LAMP_OFF"), + REDSTONE_ORE(0, "REDSTONE_ORE", "GLOWING_REDSTONE_ORE"), + REDSTONE_TORCH(0, "REDSTONE_TORCH_ON", "REDSTONE_TORCH_OFF"), + REDSTONE_WALL_TORCH(1, "REDSTONE_TORCH_ON", "REDSTONE_TORCH_OFF"), + REDSTONE_WIRE(0, "REDSTONE_WIRE"), + RED_BANNER(1, "BANNER", "STANDING_BANNER"), + RED_BED(14, "BED_BLOCK", "BED"), + RED_CARPET(14, "CARPET"), + RED_CONCRETE(14, "CONCRETE"), + RED_CONCRETE_POWDER(14, "CONCRETE_POWDER"), + RED_GLAZED_TERRACOTTA(0, "RED_GLAZED_TERRACOTTA"), + RED_MUSHROOM(0, "RED_MUSHROOM"), + RED_MUSHROOM_BLOCK(0, "RED_MUSHROOM", "HUGE_MUSHROOM_2"), + RED_NETHER_BRICKS(0, "RED_NETHER_BRICK"), + RED_SAND(1, "SAND"), + RED_SANDSTONE(0, "RED_SANDSTONE"), + RED_SANDSTONE_SLAB(0, "STONE_SLAB2", "DOUBLE_STONE_SLAB2"), + RED_SANDSTONE_STAIRS(0, "RED_SANDSTONE_STAIRS"), + RED_SHULKER_BOX(0, "RED_SHULKER_BOX"), + RED_STAINED_GLASS(14, "STAINED_GLASS"), + RED_STAINED_GLASS_PANE(14, "STAINED_GLASS_PANE"), + RED_TERRACOTTA(14, "STAINED_CLAY"), + RED_TULIP(4, "RED_ROSE"), + RED_WALL_BANNER(0, "WALL_BANNER"), + RED_WOOL(14, "WOOL"), + DIODE_BLOCK_ON(0, "REPEATER", "DIODE"), + DIODE_BLOCK_OFF(0, "REPEATER", "DIODE"), + REPEATER(0, "DIODE", "DIODE_BLOCK_ON", "DIODE_BLOCK_OFF"), + REPEATING_COMMAND_BLOCK(0, "COMMAND_REPEATING"), + ROSE_BUSH(4, "DOUBLE_PLANT"), + ROSE_RED(1, "INK_SACK"), + ROTTEN_FLESH(0, "ROTTEN_FLESH"), + SADDLE(0, "SADDLE"), + SALMON(1, "RAW_FISH"), + SALMON_BUCKET(0, "BUCKET"), + SALMON_SPAWN_EGG(0, "MONSTER_EGG"), + SAND(0, "SAND"), + SANDSTONE(0, "SANDSTONE"), + SANDSTONE_SLAB(1, "STONE_SLAB", "STEP", "DOUBLE_STEP"), + SANDSTONE_STAIRS(0, "SANDSTONE_STAIRS"), + SCUTE(0, "STONE"), + SEAGRASS(0, "STONE"), + SEA_LANTERN(0, "SEA_LANTERN"), + SEA_PICKLE(0, "STONE"), + SHEARS(0, "SHEARS"), + SHEEP_SPAWN_EGG(0, "MONSTER_EGG"), + SHIELD(0, "SHIELD"), + SHULKER_BOX(0, "PURPLE_SHULKER_BOX"), + SHULKER_SHELL(0, "SHULKER_SHELL"), + SHULKER_SPAWN_EGG(0, "MONSTER_EGG"), + SIGN(0, "SIGN"), + SILVERFISH_SPAWN_EGG(0, "MONSTER_EGG"), + SKELETON_HORSE_SPAWN_EGG(0, "MONSTER_EGG"), + SKULL(0, "SKELETON_SKULL", "SKULL_ITEM"), + SKULL_ITEM(0, "SKELETON_SKULL", "SKULL"), + SKELETON_SKULL(0, "SKULL","SKULL_ITEM"), + SKELETON_SPAWN_EGG(0, "MONSTER_EGG"), + SKELETON_WALL_SKULL(0, "SKULL","SKULL_ITEM"), + SLIME_BALL(0, "SLIME_BALL", "AIR"), + SLIME_BLOCK(0, "SLIME_BLOCK", "STONE"), + SLIME_SPAWN_EGG(0, "MONSTER_EGG"), + SMOOTH_QUARTZ(0, "STONE"), + SMOOTH_RED_SANDSTONE(2, "RED_SANDSTONE"), + SMOOTH_SANDSTONE(2, "SANDSTONE"), + SMOOTH_STONE(0, "STEP"), + SNOW(0, "SNOW"), + SNOWBALL(0, "SNOW_BALL"), + SNOW_BLOCK(0, "SNOW_BLOCK"), + SOUL_SAND(0, "SOUL_SAND"), + SPAWNER(0, "MOB_SPAWNER"), + SPECTRAL_ARROW(0, "SPECTRAL_ARROW"), + SPIDER_EYE(0, "SPIDER_EYE"), + SPIDER_SPAWN_EGG(0, "MONSTER_EGG"), + SPLASH_POTION(0, "SPLASH_POTION"), + SPONGE(0, "SPONGE"), + SPRUCE_BOAT(0, "BOAT_SPRUCE", "BOAT"), + SPRUCE_BUTTON(0, "WOOD_BUTTON"), + SPRUCE_DOOR(0, "SPRUCE_DOOR", "SPRUCE_DOOR_ITEM"), + SPRUCE_FENCE(0, "SPRUCE_FENCE"), + SPRUCE_FENCE_GATE(0, "SPRUCE_FENCE_GATE"), + SPRUCE_LEAVES(1, "LEAVES"), + SPRUCE_LOG(1, "LOG"), + SPRUCE_PLANKS(1, "WOOD"), + SPRUCE_PRESSURE_PLATE(0, "WOOD_PLATE"), + SPRUCE_SAPLING(1, "SAPLING"), + SPRUCE_SLAB(1,"WOODEN_SLAB", "WOOD_STEP", "WOOD_DOUBLE_STEP"), + SPRUCE_STAIRS(0, "SPRUCE_WOOD_STAIRS"), + SPRUCE_TRAPDOOR(0, "TRAP_DOOR"), + SPRUCE_WOOD(1, "LOG"), + SQUID_SPAWN_EGG(0, "MONSTER_EGG"), + STICK(0, "STICK"), + STICKY_PISTON(0, "PISTON_STICKY_BASE"), + STONE(0, "STONE"), + STONE_AXE(0, "STONE_AXE"), + STONE_BRICKS(0, "SMOOTH_BRICK"), + STONE_BRICK_SLAB(5, "STONE_SLAB", "STEP", "DOUBLE_STEP"), + STONE_BRICK_STAIRS(0, "SMOOTH_STAIRS"), + STONE_BUTTON(0, "STONE_BUTTON"), + STONE_HOE(0, "STONE_HOE"), + STONE_PICKAXE(0, "STONE_PICKAXE"), + STONE_PRESSURE_PLATE(0, "STONE_PLATE"), + STONE_SHOVEL(0, "STONE_SPADE"), + STONE_SLAB(0, "STONE_SLAB", "STEP", "DOUBLE_STEP"), + STONE_SWORD(0, "STONE_SWORD"), + STRAY_SPAWN_EGG(0, "MONSTER_EGG"), + STRING(0, "STRING"), + STRIPPED_ACACIA_LOG(0, "STONE"), + STRIPPED_ACACIA_WOOD(0, "STONE"), + STRIPPED_BIRCH_LOG(0, "STONE"), + STRIPPED_BIRCH_WOOD(0, "STONE"), + STRIPPED_DARK_OAK_LOG(0, "STONE"), + STRIPPED_DARK_OAK_WOOD(0, "STONE"), + STRIPPED_JUNGLE_LOG(0, "STONE"), + STRIPPED_JUNGLE_WOOD(0, "STONE"), + STRIPPED_OAK_LOG(0, "STONE"), + STRIPPED_OAK_WOOD(0, "STONE"), + STRIPPED_SPRUCE_LOG(0, "STONE"), + STRIPPED_SPRUCE_WOOD(0, "STONE"), + STRUCTURE_BLOCK(0, "STRUCTURE_BLOCK"), + STRUCTURE_VOID(0, "STRUCTURE_VOID"), + SUGAR(0, "SUGAR"), + SUGAR_CANE(0, "SUGAR_CANE", "SUGAR_CANE_BLOCK"), + SUNFLOWER(0, "DOUBLE_PLANT"), + TALL_GRASS(2, "DOUBLE_PLANT"), + TALL_SEAGRASS(0, "STONE"), + TERRACOTTA(0, "HARD_CLAY"), + TIPPED_ARROW(0, "TIPPED_ARROW"), + TNT(0, "TNT"), + TNT_MINECART(0, "EXPLOSIVE_MINECART"), + TORCH(0, "TORCH"), + TOTEM_OF_UNDYING(0, "TOTEM"), + TRAPPED_CHEST(0, "TRAPPED_CHEST"), + TRIDENT(0, "STONE"), + TRIPWIRE(0, "TRIPWIRE"), + TRIPWIRE_HOOK(0, "TRIPWIRE_HOOK"), + TROPICAL_FISH(0, "RAW_FISH"), + TROPICAL_FISH_BUCKET(0, "BUCKET"), + TROPICAL_FISH_SPAWN_EGG(0, "MONSTER_EGG"), + TUBE_CORAL(0, "STONE"), + TUBE_CORAL_BLOCK(0, "STONE"), + TUBE_CORAL_FAN(0, "STONE"), + TURTLE_EGG(0, "MONSTER_EGG"), + TURTLE_HELMET(0, "STONE"), + TURTLE_SPAWN_EGG(0, "MONSTER_EGG"), + VEX_SPAWN_EGG(0, "MONSTER_EGG"), + VILLAGER_SPAWN_EGG(0, "MONSTER_EGG"), + VINDICATOR_SPAWN_EGG(0, "MONSTER_EGG"), + VINE(0, "VINE"), + VOID_AIR(0, "AIR"), + LEGACY_SIGN_POST(0, "SIGN_POST"), + WALL_SIGN(0, "WALL_SIGN", "SIGN_POST"), + WALL_TORCH(1, "TORCH"), + WATER(0, "WATER", "STATIONARY_WATER"), + STATIONARY_WATER(0, "WATER"), + WATER_BUCKET(0, "WATER_BUCKET"), + WET_SPONGE(1, "SPONGE"), + WHEAT(0, "WHEAT", "CROPS"), + WHEAT_SEEDS(0, "WHEAT_SEEDS", "SEEDS"), + WHITE_BANNER(15, "BANNER", "STANDING_BANNER"), + WHITE_BED(0, "BED_BLOCK", "BED"), + WHITE_CARPET(0, "CARPET"), + WHITE_CONCRETE(0, "CONCRETE"), + WHITE_CONCRETE_POWDER(0, "CONCRETE_POWDER"), + WHITE_GLAZED_TERRACOTTA(0, "WHITE_GLAZED_TERRACOTTA"), + WHITE_SHULKER_BOX(0, "WHITE_SHULKER_BOX"), + WHITE_STAINED_GLASS(0, "STAINED_GLASS"), + WHITE_STAINED_GLASS_PANE(0, "STAINED_GLASS_PANE"), + WHITE_TERRACOTTA(0, "TERRACOTTA"), + WHITE_TULIP(6, "RED_ROSE"), + WHITE_WALL_BANNER(0, "WALL_BANNER"), + WHITE_WOOL(0, "WOOL"), + WITCH_SPAWN_EGG(0, "MONSTER_EGG"), + WITHER_SKELETON_SKULL(0, "SKULL","SKULL_ITEM"), + WITHER_SKELETON_SPAWN_EGG(0, "MONSTER_EGG"), + WITHER_SKELETON_WALL_SKULL(0, "SKULL","SKULL_ITEM"), + WOLF_SPAWN_EGG(0, "MONSTER_EGG"), + WOODEN_AXE(0, "WOOD_AXE"), + WOODEN_HOE(0, "WOOD_HOE"), + WOODEN_PICKAXE(0, "WOOD_PICKAXE"), + WOODEN_SHOVEL(0, "WOOD_SPADE"), + WOODEN_SWORD(0, "WOOD_SWORD"), + WRITABLE_BOOK(0, "BOOK_AND_QUILL"), + WRITTEN_BOOK(0, "WRITTEN_BOOK"), + YELLOW_BANNER(11, "BANNER", "STANDING_BANNER"), + YELLOW_BED(4, "BED_BLOCK", "BED"), + YELLOW_CARPET(4, "CARPET"), + YELLOW_CONCRETE(4, "CONCRETE"), + YELLOW_CONCRETE_POWDER(4, "CONCRETE_POWDER"), + YELLOW_GLAZED_TERRACOTTA(0, "YELLOW_GLAZED_TERRACOTTA"), + YELLOW_SHULKER_BOX(0, "YELLOW_SHULKER_BOX"), + YELLOW_STAINED_GLASS(4, "STAINED_GLASS"), + YELLOW_STAINED_GLASS_PANE(4, "STAINED_GLASS_PANE"), + YELLOW_TERRACOTTA(4, "STAINED_CLAY"), + YELLOW_WALL_BANNER(0, "WALL_BANNER"), + YELLOW_WOOL(4, "WOOL"), + ZOMBIE_HEAD(0, "SKULL","SKULL_ITEM"), + ZOMBIE_HORSE_SPAWN_EGG(0, "MONSTER_EGG"), + ZOMBIE_PIGMAN_SPAWN_EGG(0, "MONSTER_EGG"), + ZOMBIE_SPAWN_EGG(0, "MONSTER_EGG"), + ZOMBIE_VILLAGER_SPAWN_EGG(0, "MONSTER_EGG"), + ZOMBIE_WALL_HEAD(0, "SKULL","SKULL_ITEM"), + ; + public final String[] names; + public final int data; + + XMaterial(int data, String... names){ + this.names = names; + this.data = data; + } + + public ItemStack parseItem(){ + Material mat = parseMaterial(); + if(isNewVersion()){ + return new ItemStack(mat); + } + return new ItemStack(mat,1,(byte) data); + } + public static boolean isNewVersion(){ + Material mat = Material.getMaterial("RED_WOOL"); + return mat != null; + } + + private static Map cachedSearch = new HashMap<>(); + private static Map cachedParse = new HashMap<>(); + + public static XMaterial requestXMaterial(String name, byte data){ + if(cachedSearch.containsKey(name.toUpperCase()+","+data)){ + return cachedSearch.get(name.toUpperCase()+","+data); + } + for(XMaterial mat:XMaterial.values()){ + for(String test:mat.names){ + if(name.toUpperCase().equals(test) && ((byte)mat.data) == data){ + cachedSearch.put(test+","+data,mat); + return mat; + } + } + } + return null; + } + + public boolean isSameMaterial(ItemStack comp){ + if(isNewVersion()){ + return comp.getType() == this.parseMaterial(); + } + if(comp.getType() == this.parseMaterial() && + (int) comp.getData().getData() == (int) this.data){ + return true; + } + XMaterial xmat = fromMaterial(comp.getType()); + if(isDamageable(xmat)){ + if(this.parseMaterial() == comp.getType()){ + return true; + } + } + return false; + } + + public XMaterial fromMaterial(Material mat){ + try{ + return XMaterial.valueOf(mat.toString()); + }catch(IllegalArgumentException e){ + for(XMaterial xmat:XMaterial.values()){ + for(String test:xmat.names){ + if(test.equalsIgnoreCase(mat.toString())){ + return xmat; + } + } + } + } + return null; + } + + public static XMaterial fromString(String key){ + XMaterial xmat = null; + try{ + xmat = XMaterial.valueOf(key); + return xmat; + }catch(IllegalArgumentException e){ + String[] split = key.split(":"); + if(split.length == 1){ + xmat = requestXMaterial(key,(byte) 0); + }else{ + xmat = requestXMaterial(split[0],(byte) Integer.parseInt(split[1])); + } + return xmat; + } + + } + + public boolean isDamageable(XMaterial type){ + if(type == null) return false; + String[] split = type.toString().split("_"); + int length = split.length; + switch(split[length-1]) { + case "HELMET": + case "CHESTPLATE": + case "LEGGINGS": + case "BOOTS": + case "SWORD": + case "AXE": + case "PICKAXE": + case "SHOVEL": + case "HOE": + case "ELYTRA": + case "TURTLE_HELMET": + case "TRIDENT": + case "HORSE_ARMOR": + case "SHEARS": + return true; + default: + return false; + } + } + + public Material parseMaterial() { + return cachedParse.computeIfAbsent(this, key -> { + Material mat = MiscUtils.match(this.toString()); + if(mat == null) { + for(int i = 0 ; i < names.length ; i++) { + if((mat = MiscUtils.match(names[i])) != null) break; + } + } + + return mat; + }); + } + +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/BlockBox.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/BlockBox.java new file mode 100644 index 00000000..3a86c14c --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/BlockBox.java @@ -0,0 +1,15 @@ +package cc.funkemunky.api.utils.blockbox; + +import org.bukkit.Location; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public interface BlockBox { + + boolean isChunkLoaded(Location loc); + + boolean isRiptiding(LivingEntity entity); + + float getMovementFactor(Player player); +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/BlockBoxManager.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/BlockBoxManager.java new file mode 100644 index 00000000..3b26dc1c --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/BlockBoxManager.java @@ -0,0 +1,19 @@ +package cc.funkemunky.api.utils.blockbox; + +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.tinyprotocol.reflection.Reflection; +import lombok.Getter; + +@Getter +@Deprecated +public class BlockBoxManager { + private BlockBox blockBox; + + public BlockBoxManager() { + try { + blockBox = (BlockBox) Reflection.getClass("cc.funkemunky.api.utils.blockbox.boxes.BlockBox" + ProtocolVersion.getGameVersion().getServerVersion().replaceAll("v", "")).newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + + } + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_10_R1.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_10_R1.java new file mode 100644 index 00000000..4ba9cdf4 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_10_R1.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_10_R1.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_10_R1.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_10_R1 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + net.minecraft.server.v1_10_R1.World world = + ((org.bukkit.craftbukkit.v1_10_R1.CraftWorld) loc.getWorld()).getHandle(); + + return !world.isClientSide + && world.isLoaded( + new net.minecraft.server.v1_10_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + && world.getChunkAtWorldCoords( + new net.minecraft.server.v1_10_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())).p(); + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle() + .getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_11_R1.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_11_R1.java new file mode 100644 index 00000000..92cec8bf --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_11_R1.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_11_R1.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_11_R1.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_11_R1 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + net.minecraft.server.v1_11_R1.World world = + ((org.bukkit.craftbukkit.v1_11_R1.CraftWorld) loc.getWorld()).getHandle(); + + return !world.isClientSide + && world.isLoaded( + new net.minecraft.server.v1_11_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + && world.getChunkAtWorldCoords( + new net.minecraft.server.v1_11_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())).p(); + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle() + .getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_12_R1.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_12_R1.java new file mode 100644 index 00000000..007ffbd0 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_12_R1.java @@ -0,0 +1,34 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_12_R1.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_12_R1 implements BlockBox { + @Override + public boolean isChunkLoaded(Location loc) { + net.minecraft.server.v1_12_R1.World world = + ((org.bukkit.craftbukkit.v1_12_R1.CraftWorld) loc.getWorld()).getHandle(); + + return !world.isClientSide + && world.isLoaded( + new net.minecraft.server.v1_12_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + && world.areChunksLoaded( + new net.minecraft.server.v1_12_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ()), 4); + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle() + .getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_13_R1.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_13_R1.java new file mode 100644 index 00000000..402bf53b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_13_R1.java @@ -0,0 +1,38 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_13_R1.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_13_R1.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_13_R1.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_13_R1 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + net.minecraft.server.v1_13_R1.World world = + ((org.bukkit.craftbukkit.v1_13_R1.CraftWorld) loc.getWorld()).getHandle(); + + return !world.isClientSide + && world.isLoaded( + new net.minecraft.server.v1_13_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + && world.getChunkAtWorldCoords( + new net.minecraft.server.v1_13_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + .y(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return ((CraftLivingEntity) entity).getHandle().cO(); + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle() + .getAttributeInstance(GenericAttributes.MOVEMENT_SPEED) + .getValue(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_13_R2.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_13_R2.java new file mode 100644 index 00000000..2166640e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_13_R2.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_13_R2.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_13_R2.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_13_R2 implements BlockBox { + @Override + public boolean isChunkLoaded(Location loc) { + net.minecraft.server.v1_13_R2.World world = + ((org.bukkit.craftbukkit.v1_13_R2.CraftWorld) loc.getWorld()).getHandle(); + + return !world.isClientSide + && world.isLoaded( + new net.minecraft.server.v1_13_R2.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + && world.getChunkAtWorldCoords( + new net.minecraft.server.v1_13_R2.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())).y(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return ((CraftLivingEntity) entity).getHandle().isRiptiding(); + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle() + .getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_14_R1.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_14_R1.java new file mode 100644 index 00000000..d286531a --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_14_R1.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_15_R1.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_15_R1.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_14_R1 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + net.minecraft.server.v1_15_R1.World world = ((org.bukkit.craftbukkit.v1_15_R1.CraftWorld) loc.getWorld()) + .getHandle(); + + return !world.isClientSide + && world.isLoaded(new net.minecraft.server.v1_15_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + && world.getChunkAtWorldCoords( + new net.minecraft.server.v1_15_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())).r(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return ((CraftLivingEntity) entity).getHandle().isRiptiding(); + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle().getAttributeInstance(GenericAttributes.MOVEMENT_SPEED) + .getValue(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_15_R1.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_15_R1.java new file mode 100644 index 00000000..51ed71c2 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_15_R1.java @@ -0,0 +1,37 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_15_R1.GenericAttributes; +import net.minecraft.server.v1_15_R1.World; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_15_R1.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_15_R1 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + World world = ((CraftWorld) loc.getWorld()) + .getHandle(); + + return !world.isClientSide + && world.isLoaded(new net.minecraft.server.v1_15_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + && world.getChunkAtWorldCoords( + new net.minecraft.server.v1_15_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())).r(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return ((CraftLivingEntity) entity).getHandle().isRiptiding(); + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle().getAttributeInstance(GenericAttributes.MOVEMENT_SPEED) + .getValue(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_7_R4.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_7_R4.java new file mode 100644 index 00000000..8d2f00b6 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_7_R4.java @@ -0,0 +1,32 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_7_R4.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_7_R4 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + net.minecraft.server.v1_7_R4.World world = + ((org.bukkit.craftbukkit.v1_7_R4.CraftWorld) loc.getWorld()).getHandle(); + + return !world.isStatic + && world.isLoaded(loc.getBlockX(), 0, loc.getBlockZ()) + && world.getChunkAtWorldCoords(loc.getBlockX(), loc.getBlockZ()).d; + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle().getAttributeInstance(GenericAttributes.d).getValue(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_8_R1.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_8_R1.java new file mode 100644 index 00000000..de917c6b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_8_R1.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_8_R1.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_8_R1 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + + net.minecraft.server.v1_8_R1.World world = + ((org.bukkit.craftbukkit.v1_8_R1.CraftWorld) loc.getWorld()).getHandle(); + + return !world.isStatic + && world.isLoaded( + new net.minecraft.server.v1_8_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + && world.getChunkAtWorldCoords( + new net.minecraft.server.v1_8_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())).o(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle().getAttributeInstance(GenericAttributes.d).getValue(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_8_R2.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_8_R2.java new file mode 100644 index 00000000..354441d0 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_8_R2.java @@ -0,0 +1,30 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_8_R2.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_8_R2 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + + net.minecraft.server.v1_8_R2.World world = ((org.bukkit.craftbukkit.v1_8_R2.CraftWorld) loc.getWorld()).getHandle(); + + return !world.isClientSide && world.isLoaded(new net.minecraft.server.v1_8_R2.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) && world.getChunkAtWorldCoords(new net.minecraft.server.v1_8_R2.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())).o(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle().getAttributeInstance(GenericAttributes.d).getValue(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_8_R3.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_8_R3.java new file mode 100644 index 00000000..774b8709 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_8_R3.java @@ -0,0 +1,32 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_8_R3 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + + net.minecraft.server.v1_8_R3.World world = ((CraftWorld) loc.getWorld()).getHandle(); + + return !world.isClientSide && world.isLoaded(new BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())); + } + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle() + .getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue(); + } +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_9_R1.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_9_R1.java new file mode 100644 index 00000000..c96f4976 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_9_R1.java @@ -0,0 +1,34 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_9_R1.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_9_R1.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_9_R1 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + net.minecraft.server.v1_9_R1.World world = ((org.bukkit.craftbukkit.v1_9_R1.CraftWorld) loc.getWorld()).getHandle(); + + return !world.isClientSide + && world.isLoaded( + new net.minecraft.server.v1_9_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + && world.getChunkAtWorldCoords( + new net.minecraft.server.v1_9_R1.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())).p(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle().getAttributeInstance(GenericAttributes.MOVEMENT_SPEED) + .getValue(); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_9_R2.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_9_R2.java new file mode 100644 index 00000000..fa728757 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/blockbox/boxes/BlockBox1_9_R2.java @@ -0,0 +1,34 @@ +package cc.funkemunky.api.utils.blockbox.boxes; + +import cc.funkemunky.api.utils.blockbox.BlockBox; +import net.minecraft.server.v1_9_R2.GenericAttributes; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_9_R2.entity.CraftPlayer; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +@Deprecated +public class BlockBox1_9_R2 implements BlockBox { + + @Override + public boolean isChunkLoaded(Location loc) { + net.minecraft.server.v1_9_R2.World world = ((org.bukkit.craftbukkit.v1_9_R2.CraftWorld) loc.getWorld()).getHandle(); + + return !world.isClientSide + && world.isLoaded( + new net.minecraft.server.v1_9_R2.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())) + && world.getChunkAtWorldCoords( + new net.minecraft.server.v1_9_R2.BlockPosition(loc.getBlockX(), 0, loc.getBlockZ())).p(); + } + + @Override + public float getMovementFactor(Player player) { + return (float) ((CraftPlayer) player).getHandle() + .getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).getValue(); + } + + @Override + public boolean isRiptiding(LivingEntity entity) { + return false; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/CompileUtil.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/CompileUtil.java new file mode 100644 index 00000000..4dc98935 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/CompileUtil.java @@ -0,0 +1,39 @@ +package cc.funkemunky.api.utils.compiler; + +public class CompileUtil { + + /*public Object invoke(Object instance, String methodName, boolean isVoid, Object... args) { + String getterName = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); + String packageName = CompileUtil.class.getPackage().getName() + + ".generated." + instance.getClass().getSimpleName() + methodName; + String simpleClassName = instance.getClass().getSimpleName() + "$" + methodName; + String fullClassName = packageName + "." + simpleClassName; + AtomicInteger integer = new AtomicInteger(0); + String[] argsString = Arrays.stream(args) + .map(arg -> arg.getClass().getSimpleName() + " " + integer.incrementAndGet()).toArray(String[]::new); + final String source = "package " + packageName + ";\n" + + "public class " + simpleClassName + " implements " + MethodInvoker.class.getName() + " {\n" + + " public Object invoke(Object instance, " + (args.length > 0 ? String.join(", ", argsString) + + ") {\n" + + (!isVoid ? + " return \n": "") + + "((" +instance.getClass().getName() + ")instance)." + methodName + "();\n" + + (isVoid ? "return null;\n" : "") + + " }\n" + + "}"; + StringGeneratedJavaCompilerFacade compilerFacade = new StringGeneratedJavaCompilerFacade( + JavaCompilerBeanPropertyReaderFactory.class.getClassLoader()); + Class compiledClass = compilerFacade.compile( + fullClassName, source, BeanPropertyReader.class); + try { + return compiledClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException("The generated class (" + fullClassName + ") failed to instantiate.", e); + } + } + + public interface MethodInvoker { + Object invoke(Object instance, Object... objects); + }*/ + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedClassFileObject.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedClassFileObject.java new file mode 100755 index 00000000..e6029563 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedClassFileObject.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cc.funkemunky.api.utils.compiler.compiler; + +import javax.tools.SimpleJavaFileObject; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; + +public final class StringGeneratedClassFileObject extends SimpleJavaFileObject { + + private ByteArrayOutputStream classOutputStream; + + public StringGeneratedClassFileObject(String fullClassName) { + super(URI.create("bytes:///" + fullClassName), Kind.CLASS); + } + + @Override + public InputStream openInputStream() { + return new ByteArrayInputStream(getClassBytes()); + } + + @Override + public OutputStream openOutputStream() { + classOutputStream = new ByteArrayOutputStream(); + return classOutputStream; + } + + public byte[] getClassBytes() { + return classOutputStream.toByteArray(); + } + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedClassLoader.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedClassLoader.java new file mode 100755 index 00000000..c3cb07a5 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedClassLoader.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cc.funkemunky.api.utils.compiler.compiler; + +import java.util.HashMap; +import java.util.Map; + +public final class StringGeneratedClassLoader extends ClassLoader { + + private final Map fileObjectMap = new HashMap<>(); + + public StringGeneratedClassLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected Class findClass(String fullClassName) throws ClassNotFoundException { + StringGeneratedClassFileObject fileObject = fileObjectMap.get(fullClassName); + if (fileObject != null) { + byte[] classBytes = fileObject.getClassBytes(); + return defineClass(fullClassName, classBytes, 0, classBytes.length); + } + return super.findClass(fullClassName); + } + + public void addJavaFileObject(String qualifiedName, StringGeneratedClassFileObject fileObject) { + fileObjectMap.put(qualifiedName, fileObject); + } + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedJavaCompilerFacade.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedJavaCompilerFacade.java new file mode 100755 index 00000000..7458094e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedJavaCompilerFacade.java @@ -0,0 +1,80 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cc.funkemunky.api.utils.compiler.compiler; + +import javax.tools.*; +import javax.tools.JavaCompiler.CompilationTask; +import java.io.IOException; +import java.util.Collections; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public final class StringGeneratedJavaCompilerFacade { + + private final StringGeneratedClassLoader classLoader; + private final JavaCompiler compiler; + private final DiagnosticCollector diagnosticCollector; + + public StringGeneratedJavaCompilerFacade(ClassLoader loader) { + compiler = ToolProvider.getSystemJavaCompiler(); + if (compiler == null) { + throw new IllegalStateException("Cannot find the system Java compiler.\n" + + "Maybe you're using the JRE without the JDK: either the classpath lacks a jar (tools.jar)" + + " xor the modulepath lacks a module (java.compiler)."); + } + classLoader = new StringGeneratedClassLoader(loader); + diagnosticCollector = new DiagnosticCollector<>(); + } + + public synchronized Class compile(String fullClassName, String javaSource, Class superType) { + StringGeneratedSourceFileObject fileObject; + fileObject = new StringGeneratedSourceFileObject(fullClassName, javaSource); + + JavaFileManager standardFileManager = compiler.getStandardFileManager(diagnosticCollector, null, null); + try (StringGeneratedJavaFileManager javaFileManager = new StringGeneratedJavaFileManager(standardFileManager, classLoader)) { + CompilationTask task = compiler.getTask(null, javaFileManager, diagnosticCollector, + null, null, Collections.singletonList(fileObject)); + boolean success = task.call(); + if (!success) { + final Pattern linePattern = Pattern.compile("\n"); + String compilationMessages = diagnosticCollector.getDiagnostics().stream() + .map(d -> d.getKind() + ":[" + d.getLineNumber() + "," + d.getColumnNumber() +"] " + d.getMessage(null) + + "\n " + (d.getLineNumber() <= 0 ? "" : linePattern.splitAsStream(javaSource).skip(d.getLineNumber() - 1).findFirst().orElse(""))) + .collect(Collectors.joining("\n")); + throw new IllegalStateException("The generated class (" + fullClassName + ") failed to compile.\n" + + compilationMessages); + } + } catch (IOException e) { + throw new IllegalStateException("The generated class (" + fullClassName + ") failed to compile because the " + + JavaFileManager.class.getSimpleName() + " didn't close.", e); + } + Class compiledClass; + try { + compiledClass = (Class) classLoader.loadClass(fullClassName); + } catch (ClassNotFoundException e) { + throw new IllegalStateException("The generated class (" + fullClassName + + ") compiled, but failed to load.", e); + } + if (!superType.isAssignableFrom(compiledClass)) { + throw new ClassCastException("The generated compiledClass (" + compiledClass + + ") cannot be assigned to the superclass/interface (" + superType + ")."); + } + return compiledClass; + } + +} + diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedJavaFileManager.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedJavaFileManager.java new file mode 100755 index 00000000..6eb117d0 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedJavaFileManager.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cc.funkemunky.api.utils.compiler.compiler; + +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; + +public final class StringGeneratedJavaFileManager extends ForwardingJavaFileManager { + + private final StringGeneratedClassLoader classLoader; + + public StringGeneratedJavaFileManager(JavaFileManager fileManager, StringGeneratedClassLoader classLoader) { + super(fileManager); + this.classLoader = classLoader; + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, String qualifiedName, Kind kind, FileObject sibling) { + if (kind != Kind.CLASS) { + throw new IllegalArgumentException("Unsupported kind (" + kind + ") for class (" + qualifiedName + ")."); + } + StringGeneratedClassFileObject fileObject = new StringGeneratedClassFileObject(qualifiedName); + classLoader.addJavaFileObject(qualifiedName, fileObject); + return fileObject; + } + + @Override + public ClassLoader getClassLoader(Location location) { + return classLoader; + } + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedSourceFileObject.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedSourceFileObject.java new file mode 100755 index 00000000..39f6633a --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/compiler/compiler/StringGeneratedSourceFileObject.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Red Hat, Inc. and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cc.funkemunky.api.utils.compiler.compiler; + +import javax.tools.SimpleJavaFileObject; +import java.net.URI; + +public final class StringGeneratedSourceFileObject extends SimpleJavaFileObject { + + private final String javaSource; + + public StringGeneratedSourceFileObject(String fullClassName, String javaSource) { + super(URI.create("string:///" + fullClassName.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); + this.javaSource = javaSource; + } + + @Override + public String getCharContent(boolean ignoreEncodingErrors) { + return javaSource; + } + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/exceptions/InvalidObjectException.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/exceptions/InvalidObjectException.java new file mode 100644 index 00000000..aab185c2 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/exceptions/InvalidObjectException.java @@ -0,0 +1,12 @@ +package cc.funkemunky.api.utils.exceptions; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class InvalidObjectException extends Exception { + + public InvalidObjectException(Object object, Class... expected) { + super("Object " + object.getClass().getSimpleName() + " was not expected. Expected {" + + Stream.of(expected).map(Class::getSimpleName).collect(Collectors.joining(", ")) + "}"); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/exceptions/StringFormatException.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/exceptions/StringFormatException.java new file mode 100644 index 00000000..805dab6a --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/exceptions/StringFormatException.java @@ -0,0 +1,8 @@ +package cc.funkemunky.api.utils.exceptions; + +public class StringFormatException extends Exception { + + public StringFormatException(String message) { + super("Error formatting string! " + message); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/exceptions/impl/ColorFormatException.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/exceptions/impl/ColorFormatException.java new file mode 100644 index 00000000..801a4845 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/exceptions/impl/ColorFormatException.java @@ -0,0 +1,10 @@ +package cc.funkemunky.api.utils.exceptions.impl; + +import cc.funkemunky.api.utils.exceptions.StringFormatException; + +public class ColorFormatException extends StringFormatException { + + public ColorFormatException(String message) { + super(message); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/handlers/PlayerSizeHandler.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/handlers/PlayerSizeHandler.java new file mode 100644 index 00000000..340c3f49 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/handlers/PlayerSizeHandler.java @@ -0,0 +1,40 @@ +package cc.funkemunky.api.utils.handlers; + +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public interface PlayerSizeHandler { + + PlayerSizeHandler instance = getInstance(); + + double height(Player player); + double width(Player player); + + boolean isGliding(Player player); + + default SimpleCollisionBox bounds(Player player) { + Location l = player.getLocation(); + return bounds(player,l.getX(),l.getY(),l.getZ()); + } + + default SimpleCollisionBox bounds(Player player, double x, double y, double z) { + double width = width(player); + return new SimpleCollisionBox().offset(x,y,z).expand(width,0,width).expandMax(0,height(player),0); + } + + static PlayerSizeHandler getInstance() { + if (instance!=null) + return instance; + + try { + return ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_12) + ? new PlayerSizeHandlerModern() + : new PlayerSizeHandlerLegacy(); + } catch(Exception e) { + return new PlayerSizeHandlerLegacy(); + } + } + +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/handlers/PlayerSizeHandlerLegacy.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/handlers/PlayerSizeHandlerLegacy.java new file mode 100644 index 00000000..62530f2e --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/handlers/PlayerSizeHandlerLegacy.java @@ -0,0 +1,32 @@ +package cc.funkemunky.api.utils.handlers; + +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class PlayerSizeHandlerLegacy implements PlayerSizeHandler { + + @Override + public double height(Player player) { + return 1.8; + } + + @Override + public double width(Player player) { + return 0.6; + } + + @Override + public boolean isGliding(Player player) { + return false; + } + + public SimpleCollisionBox bounds(Player player) { + Location l = player.getLocation(); + return new SimpleCollisionBox().offset(l.getX(), l.getY(), l.getZ()).expand(.3,0,.3).expandMax(0,1.8,0); + } + public SimpleCollisionBox bounds(Player player, double x, double y, double z) { + return new SimpleCollisionBox().offset(x,y,z).expand(.3,0,.3).expandMax(0,1.8,0); + } + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/handlers/PlayerSizeHandlerModern.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/handlers/PlayerSizeHandlerModern.java new file mode 100644 index 00000000..fd8c0efe --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/handlers/PlayerSizeHandlerModern.java @@ -0,0 +1,58 @@ +package cc.funkemunky.api.utils.handlers; + +import cc.funkemunky.api.reflections.types.WrappedClass; +import cc.funkemunky.api.reflections.types.WrappedMethod; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import lombok.SneakyThrows; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +public class PlayerSizeHandlerModern implements PlayerSizeHandler { + + private final WrappedMethod width; + private final WrappedMethod height; + private final WrappedMethod gliding; + private static WrappedClass entityClass = new WrappedClass(Entity.class); + + public PlayerSizeHandlerModern() { + width = entityClass.getMethod("getWidth"); + height = entityClass.getMethod("getHeight"); + gliding = entityClass.getMethod("isGliding"); + } + + @Override + @SneakyThrows + public double height(Player player) { + return (double) height.invoke(player); + } + + @Override + @SneakyThrows + public double width(Player player) { + return (double) width.invoke(player); + } + + @Override + @SneakyThrows + public boolean isGliding(Player player) { + return (boolean) gliding.invoke(player); + } + + @SneakyThrows + public SimpleCollisionBox bounds(Player player) { + Location l = player.getLocation(); + double width = (double) this.width.invoke(player)/2; + double height = this.height.invoke(player); + return new SimpleCollisionBox().offset(l.getX(), l.getY(), l.getZ()).expand(width,0,width).expandMax(0,height,0); + } + + @Override + @SneakyThrows + public SimpleCollisionBox bounds(Player player, double x, double y, double z) { + double width = (double) this.width.invoke(player)/2; + double height = this.height.invoke(player); + return new SimpleCollisionBox().offset(x,y,z).expand(width,0,width).expandMax(0,height,0); + } + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/Average.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/Average.java new file mode 100644 index 00000000..a8a626e3 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/Average.java @@ -0,0 +1,41 @@ +package cc.funkemunky.api.utils.math; + +import java.util.HashSet; +import java.util.Set; + +public class Average { + + private final Set values; + private final int limit; + + + public Average(int limit) { + this.limit = limit; + values = new HashSet<>(); + } + + public void addValue(double value) { + if (value != 0) values.add(value); + } + + public void clearValues() { + values.clear(); + } + + public boolean isAtLimit() { + return values.size() >= limit; + } + + public double getAverage(boolean clear) { + double output = 0; + int amount = 0; + for (double value : values) { + output = output + value; + amount++; + } + + if (isAtLimit()) clearValues(); + + return (output / amount); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/MCSmooth.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/MCSmooth.java new file mode 100644 index 00000000..241dee59 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/MCSmooth.java @@ -0,0 +1,26 @@ +package cc.funkemunky.api.utils.math; + +public class MCSmooth { + + private float x = 0, y = 0, z = 0; + + public float smooth(float toSmooth, float increment) { + x += toSmooth; + toSmooth = (x - y) * increment; + z += (toSmooth - z) * 0.5f; + + if (toSmooth > 0f && toSmooth > z || toSmooth < 0f && toSmooth < z) { + toSmooth = z; + } + + y += toSmooth; + return toSmooth; + } + + public void reset() { + x = 0; + y = 0; + z = 0; + } + +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RayTrace.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RayTrace.java new file mode 100644 index 00000000..2c0c7de7 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RayTrace.java @@ -0,0 +1,146 @@ +package cc.funkemunky.api.utils.math; + +import cc.funkemunky.api.tinyprotocol.api.ProtocolVersion; +import cc.funkemunky.api.utils.world.types.SimpleCollisionBox; +import org.bukkit.Effect; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.util.Vector; + +import java.util.ArrayList; +import java.util.List; + +public class RayTrace { + + //origin = start position + //direction = direction in which the raytrace will go + Vector origin, direction; + + public RayTrace(Vector origin, Vector direction) { + this.origin = origin; + this.direction = direction; + } + + //general intersection detection + public static boolean intersects(Vector position, Vector min, Vector max) { + if (position.getX() < min.getX() || position.getX() > max.getX()) { + return false; + } else if (position.getY() < min.getY() || position.getY() > max.getY()) { + return false; + } else if (position.getZ() < min.getZ() || position.getZ() > max.getZ()) { + return false; + } + return true; + } + + //get a point on the raytrace at X blocks away + public Vector getPostion(double blocksAway) { + return origin.clone().add(direction.clone().multiply(blocksAway)); + } + + //checks if a position is on contained within the position + public boolean isOnLine(Vector position) { + double t = (position.getX() - origin.getX()) / direction.getX(); + ; + if (position.getBlockY() == origin.getY() + (t * direction.getY()) && position.getBlockZ() == origin.getZ() + (t * direction.getZ())) { + return true; + } + return false; + } + + //get all postions on a raytrace + public List traverse(double blocksAway, double accuracy) { + List positions = new ArrayList<>(); + for (double d = 0; d <= blocksAway; d += accuracy) { + positions.add(getPostion(d)); + } + return positions; + } + + public List traverse(double skip, double blocksAway, double accuracy) { + List positions = new ArrayList<>(); + for (double d = skip; d <= blocksAway; d += accuracy) { + positions.add(getPostion(d)); + } + return positions; + } + + public List getBlocks(World world, double blocksAway, double accuracy) { + List blocks = new ArrayList<>(); + + traverse(blocksAway, accuracy).stream().filter(vector -> vector.toLocation(world).getBlock().getType().isSolid()).forEach(vector -> blocks.add(vector.toLocation(world).getBlock())); + return blocks; + } + + //intersection detection for current raytrace with return + public Vector positionOfIntersection(Vector min, Vector max, double blocksAway, double accuracy) { + List positions = traverse(blocksAway, accuracy); + for (Vector position : positions) { + if (intersects(position, min, max)) { + return position; + } + } + return null; + } + + //intersection detection for current raytrace + public boolean intersects(Vector min, Vector max, double blocksAway, double accuracy) { + List positions = traverse(blocksAway, accuracy); + for (Vector position : positions) { + if (intersects(position, min, max)) { + return true; + } + } + return false; + } + + //bounding blockbox instead of vector + public Vector positionOfIntersection(SimpleCollisionBox collisionBox, double blocksAway, double accuracy) { + List positions = traverse(blocksAway, accuracy); + for (Vector position : positions) { + if (intersects(position, collisionBox.min(), collisionBox.max())) { + return position; + } + } + return null; + } + + public Vector positionOfIntersection(SimpleCollisionBox collisionBox, double skip, double blocksAway, double accuracy) { + List positions = traverse(skip, blocksAway, accuracy); + for (Vector position : positions) { + if (intersects(position, collisionBox.min(), collisionBox.max())) { + return position; + } + } + return null; + } + + //bounding blockbox instead of vector + public boolean intersects(SimpleCollisionBox collisionBox, double blocksAway, double accuracy) { + List positions = traverse(blocksAway, accuracy); + for (Vector position : positions) { + if (intersects(position, collisionBox.min(), collisionBox.max())) { + return true; + } + } + return false; + } + + public boolean intersects(SimpleCollisionBox collisionBox, double skip, double blocksAway, double accuracy) { + List positions = traverse(blocksAway, accuracy); + for (Vector position : positions) { + if (intersects(position, collisionBox.min(), collisionBox.max())) { + return true; + } + } + return false; + } + + //debug / effects + public void highlight(World world, double blocksAway, double accuracy) { + for (Vector position : traverse(blocksAway, accuracy)) { + world.playEffect(position.toLocation(world), (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_13) ? Effect.SMOKE : Effect.valueOf("COLOURED_DUST")), 0); + } + } + +} \ No newline at end of file diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RollingAverage.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RollingAverage.java new file mode 100644 index 00000000..30adeca9 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RollingAverage.java @@ -0,0 +1,53 @@ +package cc.funkemunky.api.utils.math; + +public class RollingAverage { + + private final int size; + private double[] samples; + private long[] times; + private long time; + private double total; + private int index = 0; + + public RollingAverage(int size) { + this.size = size; + this.time = (long) size * 1000000000L; + this.total = (double) (20000000000L * (long) size); + this.samples = new double[size]; + this.times = new long[size]; + + for (int i = 0; i < size; ++i) { + this.samples[i] = 20.0D; + this.times[i] = 1000000000L; + } + + } + + public void add(double x, long t) { + this.time -= this.times[this.index]; + this.total -= this.samples[this.index] * (double) this.times[this.index]; + this.samples[this.index] = x; + this.times[this.index] = t; + this.time += t; + this.total += x * (double) t; + if (++this.index == this.size) { + this.index = 0; + } + } + + public void clearValues() { + this.time = (long) size * 1000000000L; + this.total = (double) (20000000000L * (long) size); + this.samples = new double[size]; + this.times = new long[size]; + + for (int i = 0; i < size; ++i) { + this.samples[i] = 20.0D; + this.times[i] = 1000000000L; + } + } + + public double getAverage() { + return this.total / (double) this.time; + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RollingAverageDouble.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RollingAverageDouble.java new file mode 100644 index 00000000..35cd925b --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RollingAverageDouble.java @@ -0,0 +1,44 @@ +package cc.funkemunky.api.utils.math; + +import lombok.Getter; + +import java.util.Arrays; + +public class RollingAverageDouble { + + private final int size; + private double[] array; + + private int index; + + @Getter + private double average; + + public RollingAverageDouble(int size, double initial) { + this.size = size; + array = new double[size]; + average = initial; + initial /= size; + Arrays.fill(array, initial); + } + + public void add(double value) { + value /= size; + average -= array[index]; + average += value; + array[index] = value; + index = (index + 1) % size; + + if(Double.isNaN(average)) { + average = 0; + array = new double[size]; + index = 0; + } + //System.out.println(Arrays.stream(array).mapToObj(d -> String.format("%.2f", d)).collect(Collectors.joining(","))); + } + + public void clearValues() { + average = 0; + Arrays.fill(array, 0); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RollingAverageLong.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RollingAverageLong.java new file mode 100644 index 00000000..392428b8 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/RollingAverageLong.java @@ -0,0 +1,33 @@ +package cc.funkemunky.api.utils.math; + +import lombok.Getter; + +import java.util.Arrays; + +public class RollingAverageLong { + + private final int size; + private final double[] array; + + private int index; + + @Getter + private long average; + + public RollingAverageLong(int size, long initial) { + this.size = size; + array = new double[size]; + average = initial; + initial /= size; + Arrays.fill(array, initial); + } + + public void add(long value) { + value /= size; + average -= array[index]; + average += value; + array[index] = value; + index = (index + 1) % size; + //System.out.println(Arrays.stream(array).mapToObj(d -> String.format("%.2f", d)).collect(Collectors.joining(","))); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxDouble.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxDouble.java new file mode 100644 index 00000000..fb8038aa --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxDouble.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.utils.math.cond; + +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +@RequiredArgsConstructor +public class MaxDouble { + @Setter + private double value; + private final double max; + + public double add(double amount) { + return value = Math.min(max, value + amount); + } + + public double add() { + return add(1); + } + + public double subtract(double amount) { + return value = Math.max(0, value - amount); + } + + public double subtract() { + return subtract(1); + } + + public double value() { + return value; + } + + public String toString() { + return String.valueOf(value); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxFloat.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxFloat.java new file mode 100644 index 00000000..fa62dabc --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxFloat.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.utils.math.cond; + +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +@RequiredArgsConstructor +public class MaxFloat { + @Setter + private float value; + private final float max; + + public float add(float amount) { + return value = Math.min(max, value + amount); + } + + public float add() { + return add(1); + } + + public float subtract(float amount) { + return value = Math.max(0, value - amount); + } + + public float subtract() { + return subtract(1); + } + + public float value() { + return value; + } + + public String toString() { + return String.valueOf(value); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxInteger.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxInteger.java new file mode 100644 index 00000000..f8b70bb3 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxInteger.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.utils.math.cond; + +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +@RequiredArgsConstructor +public class MaxInteger { + @Setter + private int value; + private final int max; + + public int add(int amount) { + return value = Math.min(max, value + amount); + } + + public int add() { + return add(1); + } + + public int subtract(int amount) { + return value = Math.max(0, value - amount); + } + + public int subtract() { + return subtract(1); + } + + public int value() { + return value; + } + + public String toString() { + return String.valueOf(value); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxLong.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxLong.java new file mode 100644 index 00000000..7fcbccee --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/math/cond/MaxLong.java @@ -0,0 +1,35 @@ +package cc.funkemunky.api.utils.math.cond; + +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +@RequiredArgsConstructor +public class MaxLong { + @Setter + private long value; + private final long max; + + public long add(long amount) { + return value = Math.min(max, value + amount); + } + + public long add() { + return add(1); + } + + public long subtract(long amount) { + return value = Math.max(0, value - amount); + } + + public long subtract() { + return subtract(1); + } + + public long value() { + return value; + } + + public String toString() { + return String.valueOf(value); + } +} diff --git a/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/menu/Menu.java b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/menu/Menu.java new file mode 100644 index 00000000..8dd26a82 --- /dev/null +++ b/AtlasParent/Atlas/src/main/java/cc/funkemunky/api/utils/menu/Menu.java @@ -0,0 +1,145 @@ +package cc.funkemunky.api.utils.menu; + +import cc.funkemunky.api.utils.menu.button.Button; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.bukkit.entity.Player; + +import java.util.Optional; +import java.util.function.BiConsumer; + +/** + * @author Missionary (missionarymc@gmail.com) + * @since 3/28/2018 + */ +public interface Menu extends Iterable