From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: violetc <58360096+s-yh-china@users.noreply.github.com> Date: Wed, 16 Feb 2022 12:42:14 +0800 Subject: [PATCH] Add fakeplayer action support diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java index 9c767096ca950d55d6002282c7a3fe2884bcd630..dcae420f13a03c6ec0f8d8cb414dc283bb3d1e88 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -1244,7 +1244,7 @@ public abstract class Player extends LivingEntity { boolean flag3 = false; double d0 = (double) (this.walkDist - this.walkDistO); - if (flag && !flag2 && !flag1 && this.onGround && d0 < (double) this.getSpeed()) { + if (flag && !flag2 && !flag1 && this.isOnGround() && d0 < (double) this.getSpeed()) { // Leaves - use isOnGround method ItemStack itemstack = this.getItemInHand(InteractionHand.MAIN_HAND); if (itemstack.getItem() instanceof SwordItem) { diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java index 7c67667a16262f28655b5413d748cca781683717..d4000ba0a8cce6f3da43e813a283665c5c8ba8ab 100644 --- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java +++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java @@ -63,6 +63,7 @@ public final class LeavesConfig { if (top.leavesmc.leaves.LeavesConfig.fakeplayerSupport) { commands.put("bot", new BotCommand("bot")); + top.leavesmc.leaves.bot.agent.Actions.registerAll(); } } diff --git a/src/main/java/top/leavesmc/leaves/bot/Bot.java b/src/main/java/top/leavesmc/leaves/bot/Bot.java index ebea5607956b1328f928d905e4f35424e5c21546..77713ce098be75aab5ebbeabc324298ded4392f5 100644 --- a/src/main/java/top/leavesmc/leaves/bot/Bot.java +++ b/src/main/java/top/leavesmc/leaves/bot/Bot.java @@ -1,9 +1,12 @@ package top.leavesmc.leaves.bot; +import com.google.common.collect.Lists; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.datafixers.util.Pair; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; +import net.minecraft.Util; import net.minecraft.network.Connection; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; @@ -12,6 +15,7 @@ import net.minecraft.network.protocol.game.ClientboundPlayerInfoPacket; import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.server.MinecraftServer; @@ -22,9 +26,13 @@ import net.minecraft.server.level.TicketType; import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.server.network.ServerPlayerConnection; import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.LevelChunk; @@ -38,14 +46,20 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.inventory.ItemStack; import org.bukkit.util.BoundingBox; import org.bukkit.util.Vector; +import top.leavesmc.leaves.bot.agent.BotAction; import top.leavesmc.leaves.util.MathUtils; import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -54,12 +68,17 @@ public class Bot extends ServerPlayer { private Vector velocity; private Vector oldVelocity; + private BotAction action; + private BotAction newAction; private boolean removeOnDeath; - private byte fireTicks; - private byte groundTicks; - private byte jumpTicks; - private byte noFallTicks; + private int fireTicks; + private int groundTicks; + private int jumpTicks; + private int noFallTicks; + private int noActionTicks; + + private final ItemStack defaultItem; private static final Set bots = new HashSet<>(); @@ -68,9 +87,12 @@ public class Bot extends ServerPlayer { this.entityData.set(new EntityDataAccessor<>(16, EntityDataSerializers.INT), 0xFF); this.velocity = new Vector(0, 0, 0); + this.action = null; this.oldVelocity = velocity.clone(); this.noFallTicks = 60; this.fireTicks = 0; + this.noActionTicks = 0; + this.defaultItem = new ItemStack(Material.AIR); this.removeOnDeath = true; } @@ -156,12 +178,17 @@ public class Bot extends ServerPlayer { } } + private void removeTab() { + sendPacket(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.REMOVE_PLAYER, this)); + } + private void setDead() { sendPacket(new ClientboundRemoveEntitiesPacket(getId())); this.dead = true; this.inventoryMenu.removed(this); this.containerMenu.removed(this); } + // die check end @Override @@ -169,10 +196,6 @@ public class Bot extends ServerPlayer { return groundTicks != 0; } - private void removeTab() { - sendPacket(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.REMOVE_PLAYER, this)); - } - public static boolean solidAt(Location loc) { Block block = loc.getBlock(); BoundingBox box = block.getBoundingBox(); @@ -259,12 +282,24 @@ public class Bot extends ServerPlayer { public void tick() { loadChunks(); // Load chunks super.tick(); + this.doTick(); - if (!isAlive()) return; + if (!isAlive()) { + return; + } - if (fireTicks > 0) --fireTicks; - if (jumpTicks > 0) --jumpTicks; - if (noFallTicks > 0) --noFallTicks; + if (fireTicks > 0) { + --fireTicks; + } + if (jumpTicks > 0) { + --jumpTicks; + } + if (noFallTicks > 0) { + --noFallTicks; + } + if (noActionTicks > 0) { + --noActionTicks; + } if (checkGround()) { if (groundTicks < 5) groundTicks++; @@ -292,7 +327,83 @@ public class Bot extends ServerPlayer { checkOutOfWorld(); + ++this.attackStrengthTicker; + + if (this.getHealth() > 0.0F) { + AABB axisalignedbb; + + if (this.isPassenger() && !this.getVehicle().isRemoved()) { + axisalignedbb = this.getBoundingBox().minmax(this.getVehicle().getBoundingBox()).inflate(1.0D, 0.0D, 1.0D); + } else { + axisalignedbb = this.getBoundingBox().inflate(1.0D, 0.5D, 1.0D); + } + + List list = this.level.getEntities(this, axisalignedbb); + List list1 = Lists.newArrayList(); + + for (Entity entity : list) { + if (entity.getType() == EntityType.EXPERIENCE_ORB) { + list1.add(entity); + } else if (!entity.isRemoved()) { + this.touch(entity); + } + } + + if (!list1.isEmpty()) { + this.touch((Entity) Util.getRandom((List) list1, this.random)); + } + } + oldVelocity = velocity.clone(); + + if (newAction != null) { + action = newAction; + newAction = null; + noActionTicks = 0; + } + + if (action != null && noActionTicks <= 0) { + if (action.isCancel()) { + action = null; + } else { + action.tick(this); + noActionTicks = action.getTickDelay(); + } + } + } + + private void touch(Entity entity) { + entity.playerTouch(this); + } + + @Override + public void onItemPickup(ItemEntity item) { + super.onItemPickup(item); + this.updateItemInMainHand(); + } + + private ItemStack lastItem = new ItemStack(Material.AIR); + public void updateItemInMainHand() { + ItemStack item = this.getInventory().getSelected().asBukkitCopy(); + if (!lastItem.isSimilar(item)) { + this.setItem(item, EquipmentSlot.MAINHAND); + lastItem = item; + } + } + + @Override + public void doTick() { + if (this.hurtTime > 0) { + this.hurtTime -= 1; + } + + baseTick(); + tickEffects(); + + this.lerpSteps = (int) this.zza; + this.animStep = this.run; + this.yRotO = this.getYRot(); + this.xRotO = this.getXRot(); } @Override @@ -325,21 +436,6 @@ public class Bot extends ServerPlayer { } } - @Override - public void doTick() { - if (this.hurtTime > 0) { - this.hurtTime -= 1; - } - - baseTick(); - tickEffects(); - - this.lerpSteps = (int) this.zza; - this.animStep = this.run; - this.yRotO = this.getYRot(); - this.xRotO = this.getXRot(); - } - public Location getLocation() { return getBukkitPlayer().getLocation(); } @@ -431,6 +527,68 @@ public class Bot extends ServerPlayer { this.move(MoverType.SELF, new Vec3(velocity.getX(), y, velocity.getZ())); } + public void faceLocation(Location loc) { + look(loc.toVector().subtract(getLocation().toVector()), false); + } + + private void look(Vector dir, boolean keepYaw) { + float yaw, pitch; + + if (keepYaw) { + yaw = this.getYHeadRot(); + pitch = MathUtils.fetchPitch(dir); + } else { + float[] vals = MathUtils.fetchYawPitch(dir); + yaw = vals[0]; + pitch = vals[1]; + + sendPacket(new ClientboundRotateHeadPacket(this, (byte) (yaw * 256 / 360f))); + } + + setRot(yaw, pitch); + this.getBukkitPlayer().getLocation().setYaw(yaw); + this.getBukkitPlayer().getLocation().setPitch(pitch); + } + + public void punch() { + swing(InteractionHand.MAIN_HAND); + } + + public void attack(Entity target) { + super.attack(target); + punch(); + } + + public void setItem(org.bukkit.inventory.ItemStack item, EquipmentSlot slot) { + if (item == null) { + item = defaultItem; + } + + this.detectEquipmentUpdates(); + if (slot == EquipmentSlot.MAINHAND) { + getBukkitPlayer().getInventory().setItemInMainHand(item); + setItemInHand(InteractionHand.MAIN_HAND, CraftItemStack.asNMSCopy(item)); + } else if (slot == EquipmentSlot.OFFHAND) { + getBukkitPlayer().getInventory().setItemInOffHand(item); + setItemInHand(InteractionHand.OFF_HAND, CraftItemStack.asNMSCopy(item)); + } + + sendPacket(new ClientboundSetEquipmentPacket(getId(), new ArrayList<>(Collections.singletonList( + new Pair<>(slot, CraftItemStack.asNMSCopy(item)) + )))); + } + + public void dropAll() { + getInventory().dropAll(); + for (EquipmentSlot slot : EquipmentSlot.values()) { + setItem(null, slot); + } + } + + public void setBotAction(BotAction botAction) { + this.newAction = botAction; + } + public static Bot getBot(ServerPlayer player) { Bot bot = null; for (Bot b : bots) { diff --git a/src/main/java/top/leavesmc/leaves/bot/BotCommand.java b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java index 17c1db261165bfa22a7e91189f926e0adf8e43f9..e65e4980665211ce170c78afb8dd431f80e73779 100644 --- a/src/main/java/top/leavesmc/leaves/bot/BotCommand.java +++ b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java @@ -5,7 +5,11 @@ import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; +import top.leavesmc.leaves.bot.agent.Actions; +import top.leavesmc.leaves.bot.agent.BotAction; +import top.leavesmc.leaves.util.MathUtils; import java.util.ArrayList; import java.util.List; @@ -15,7 +19,7 @@ public class BotCommand extends Command { public BotCommand(String name) { super(name); this.description = "FakePlayer Command"; - this.usageMessage = "/bot [create | remove]"; + this.usageMessage = "/bot [create | remove | action]"; this.setPermission("bukkit.command.bot"); } @@ -26,13 +30,27 @@ public class BotCommand extends Command { if (args.length <= 1) { list.add("create"); list.add("remove"); - } else { + list.add("action"); + } + + if (args.length == 2) { switch (args[0]) { - case "create" -> list.add("[BotName]"); - case "remove" -> list.addAll(Bot.getBots().stream().map(e -> e.getName().getString()).toList()); + case "create" -> list.add(""); + case "remove", "action" -> list.addAll(Bot.getBots().stream().map(e -> e.getName().getString()).toList()); } } + if (args.length == 3) { + switch (args[0]) { + case "action" -> list.addAll(Actions.getAll().stream().map(BotAction::getName).toList()); + } + } + + if (args.length == 4) { + switch (args[0]) { + case "action" -> list.add("[tickDelay]"); + } + } return list; } @@ -50,6 +68,8 @@ public class BotCommand extends Command { case "remove" -> this.onRemove(sender, args); + case "action" -> this.onAction(sender, args); + default -> { sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); return false; @@ -61,7 +81,7 @@ public class BotCommand extends Command { private void onCreate(CommandSender sender, String[] args) { if (args.length < 2) { - sender.sendMessage(ChatColor.RED + "Use /bot create [name] to create a fakeplayer"); + sender.sendMessage(ChatColor.RED + "Use /bot create to create a fakeplayer"); return; } @@ -80,7 +100,7 @@ public class BotCommand extends Command { private void onRemove(CommandSender sender, String[] args) { if (args.length < 2) { - sender.sendMessage(ChatColor.RED + "Use /bot remove [name] to remove a fakeplayer"); + sender.sendMessage(ChatColor.RED + "Use /bot remove to remove a fakeplayer"); return; } @@ -93,4 +113,31 @@ public class BotCommand extends Command { bot.kill(); } + + private void onAction(CommandSender sender, String[] args) { + if (args.length < 3) { + sender.sendMessage(ChatColor.RED + "Use /bot action to make fakeplayer do action"); + return; + } + + int tickDelay = 20; + if (args.length > 3 && MathUtils.isNumeric(args[3])) { + tickDelay = Integer.parseInt(args[3]); + } + + Bot bot = Bot.getBot(args[1]); + BotAction action = Actions.getForName(args[2]); + + if (bot == null) { + sender.sendMessage(ChatColor.RED + "This fakeplayer is null"); + return; + } + if (action == null) { + sender.sendMessage(ChatColor.RED + "This action is null"); + return; + } + + bot.setBotAction(action.getNew(tickDelay, ((CraftPlayer) sender).getHandle())); + sender.sendMessage("Action set"); + } } diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/Actions.java b/src/main/java/top/leavesmc/leaves/bot/agent/Actions.java new file mode 100644 index 0000000000000000000000000000000000000000..c2a5e344745a0966d57cebce893d80c26dce0f83 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/Actions.java @@ -0,0 +1,43 @@ +package top.leavesmc.leaves.bot.agent; + +import top.leavesmc.leaves.bot.agent.action.AttackAction; +import top.leavesmc.leaves.bot.agent.action.DropAction; +import top.leavesmc.leaves.bot.agent.action.RotateAction; +import top.leavesmc.leaves.bot.agent.action.UseItemAction; + +import java.util.HashSet; +import java.util.Set; + +public class Actions { + + private static final Set actions = new HashSet<>(); + + public static void registerAll() { + register(new AttackAction()); + register(new DropAction()); + register(new RotateAction()); + register(new UseItemAction()); + } + + public static void register(BotAction action) { + for (BotAction a : actions) { + if (a.getName().equals(action.getName())) { + return; + } + } + actions.add(action); + } + + public static Set getAll() { + return actions; + } + + public static BotAction getForName(String name) { + for (BotAction a : actions) { + if (a.getName().equals(name)) { + return a; + } + } + return null; + } +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/BotAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/BotAction.java new file mode 100644 index 0000000000000000000000000000000000000000..78f04e28afa856c900f84af42f22666bec3ec830 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/BotAction.java @@ -0,0 +1,42 @@ +package top.leavesmc.leaves.bot.agent; + +import net.minecraft.server.level.ServerPlayer; +import top.leavesmc.leaves.bot.Bot; + +public abstract class BotAction { + + private final String name; + private boolean cancel; + private int tickDelay; + + public BotAction(String name) { + this.name = name; + this.cancel = false; + this.tickDelay = 20; + } + + public String getName() { + return name; + } + + public int getTickDelay() { + return tickDelay; + } + + public BotAction setTickDelay(int tickDelay) { + this.tickDelay = tickDelay; + return this; + } + + public boolean isCancel() { + return cancel; + } + + public void setCancel(boolean cancel) { + this.cancel = cancel; + } + + public abstract BotAction getNew(int tickDelay, ServerPlayer player); + + public abstract void tick(Bot bot); +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/action/AttackAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/action/AttackAction.java new file mode 100644 index 0000000000000000000000000000000000000000..78cf21fc321d3d3d13b2db315897acdf386c696f --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/action/AttackAction.java @@ -0,0 +1,34 @@ +package top.leavesmc.leaves.bot.agent.action; + +import net.minecraft.server.level.ServerPlayer; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; +import top.leavesmc.leaves.bot.Bot; +import top.leavesmc.leaves.bot.agent.BotAction; +import top.leavesmc.leaves.util.MathUtils; + +public class AttackAction extends BotAction { + + public AttackAction() { + super("attack"); + } + + @Override + public BotAction getNew(int tickDelay, ServerPlayer player) { + return new AttackAction().setTickDelay(tickDelay); + } + + @Override + public void tick(Bot bot) { + Vector vector = MathUtils.getDirection(bot.getYRot(), bot.getXRot()).normalize(); + Location loc = bot.getBukkitPlayer().getEyeLocation().add(vector); + + RayTraceResult result = loc.getWorld().rayTraceEntities(loc, vector, 5); + + if (result != null && result.getHitEntity() != null) { + bot.attack(((CraftEntity) result.getHitEntity()).getHandle()); + } + } +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/action/DropAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/action/DropAction.java new file mode 100644 index 0000000000000000000000000000000000000000..91da2f89b6937a78a39da2a6f2c346f0ad446001 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/action/DropAction.java @@ -0,0 +1,22 @@ +package top.leavesmc.leaves.bot.agent.action; + +import net.minecraft.server.level.ServerPlayer; +import top.leavesmc.leaves.bot.Bot; +import top.leavesmc.leaves.bot.agent.BotAction; + +public class DropAction extends BotAction { + public DropAction() { + super("drop"); + } + + @Override + public BotAction getNew(int tickDelay, ServerPlayer player) { + return new DropAction().setTickDelay(tickDelay); + } + + @Override + public void tick(Bot bot) { + bot.dropAll(); + this.setCancel(true); + } +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/action/RotateAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/action/RotateAction.java new file mode 100644 index 0000000000000000000000000000000000000000..8f7263a97f56144e98794eae3e137a3a73a6d909 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/action/RotateAction.java @@ -0,0 +1,29 @@ +package top.leavesmc.leaves.bot.agent.action; + +import net.minecraft.server.level.ServerPlayer; +import top.leavesmc.leaves.bot.Bot; +import top.leavesmc.leaves.bot.agent.BotAction; + +public class RotateAction extends BotAction { + public RotateAction() { + super("rotate"); + } + + private ServerPlayer player; + + public BotAction setPlayer(ServerPlayer player) { + this.player = player; + return this; + } + + @Override + public BotAction getNew(int tickDelay, ServerPlayer player) { + return new RotateAction().setPlayer(player).setTickDelay(tickDelay); + } + + @Override + public void tick(Bot bot) { + bot.faceLocation(player.getBukkitEntity().getLocation()); + this.setCancel(true); + } +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/action/UseItemAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/action/UseItemAction.java new file mode 100644 index 0000000000000000000000000000000000000000..8f39161ff8f84392ef57a1ecda3b098a791841e5 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/action/UseItemAction.java @@ -0,0 +1,24 @@ +package top.leavesmc.leaves.bot.agent.action; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import top.leavesmc.leaves.bot.Bot; +import top.leavesmc.leaves.bot.agent.BotAction; + +public class UseItemAction extends BotAction { + public UseItemAction() { + super("use"); + } + + @Override + public BotAction getNew(int tickDelay, ServerPlayer player) { + return new UseItemAction().setTickDelay(tickDelay); + } + + @Override + public void tick(Bot bot) { + bot.getInventory().getSelected().use(bot.getLevel(), bot, InteractionHand.MAIN_HAND); + bot.punch(); + bot.updateItemInMainHand(); + } +} diff --git a/src/main/java/top/leavesmc/leaves/util/MathUtils.java b/src/main/java/top/leavesmc/leaves/util/MathUtils.java index acdef051d6d4eb4e0d957bfbd7f205827c2f23a9..d6a809569455872d08aeab81b174024d2bc3b53a 100644 --- a/src/main/java/top/leavesmc/leaves/util/MathUtils.java +++ b/src/main/java/top/leavesmc/leaves/util/MathUtils.java @@ -3,6 +3,8 @@ package top.leavesmc.leaves.util; import org.bukkit.util.NumberConversions; import org.bukkit.util.Vector; +import java.util.regex.Pattern; + public class MathUtils { // Lag ? public static void clean(Vector vector) { @@ -10,4 +12,67 @@ public class MathUtils { if (!NumberConversions.isFinite(vector.getY())) vector.setY(0); if (!NumberConversions.isFinite(vector.getZ())) vector.setZ(0); } + + private static final Pattern numericPattern = Pattern.compile("[0-9]*"); + public static boolean isNumeric(String str){ + return numericPattern.matcher(str).matches(); + } + + public static float[] fetchYawPitch(Vector dir) { + double x = dir.getX(); + double z = dir.getZ(); + + float[] out = new float[2]; + + if (x == 0.0D && z == 0.0D) { + out[1] = (float) (dir.getY() > 0.0D ? -90 : 90); + } + + else { + double theta = Math.atan2(-x, z); + out[0] = (float) Math.toDegrees((theta + 6.283185307179586D) % 6.283185307179586D); + + double x2 = NumberConversions.square(x); + double z2 = NumberConversions.square(z); + double xz = Math.sqrt(x2 + z2); + out[1] = (float) Math.toDegrees(Math.atan(-dir.getY() / xz)); + } + + return out; + } + + public static float fetchPitch(Vector dir) { + double x = dir.getX(); + double z = dir.getZ(); + + float result; + + if (x == 0.0D && z == 0.0D) { + result = (float) (dir.getY() > 0.0D ? -90 : 90); + } + + else { + double x2 = NumberConversions.square(x); + double z2 = NumberConversions.square(z); + double xz = Math.sqrt(x2 + z2); + result = (float) Math.toDegrees(Math.atan(-dir.getY() / xz)); + } + + return result; + } + + public static Vector getDirection(double rotX, double rotY) { + Vector vector = new Vector(); + + rotX = Math.toRadians(rotX); + rotY = Math.toRadians(rotY); + + double xz = Math.abs(Math.cos(rotY)); + + vector.setX(-Math.sin(rotX) * xz); + vector.setZ(Math.cos(rotX) * xz); + vector.setY(-Math.sin(rotY)); + + return vector; + } }