mirror of
https://github.com/TotalFreedomMC/TF-LibsDisguises.git
synced 2024-05-28 23:31:19 +00:00
246 lines
10 KiB
Java
246 lines
10 KiB
Java
package me.libraryaddict.disguise.disguisetypes;
|
|
|
|
import com.comphenix.protocol.PacketType;
|
|
import com.comphenix.protocol.ProtocolLibrary;
|
|
import com.comphenix.protocol.events.PacketContainer;
|
|
import com.comphenix.protocol.reflect.StructureModifier;
|
|
import me.libraryaddict.disguise.DisguiseAPI;
|
|
import me.libraryaddict.disguise.DisguiseConfig;
|
|
import me.libraryaddict.disguise.disguisetypes.watchers.BatWatcher;
|
|
import me.libraryaddict.disguise.utilities.DisguiseUtilities;
|
|
import me.libraryaddict.disguise.utilities.reflection.ReflectionManager;
|
|
import me.libraryaddict.disguise.utilities.translations.LibsMsg;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.scheduler.BukkitRunnable;
|
|
import org.bukkit.util.Vector;
|
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
|
|
/**
|
|
* Created by libraryaddict on 20/05/2021.
|
|
*/
|
|
class DisguiseRunnable extends BukkitRunnable {
|
|
private int blockX, blockY, blockZ, facing;
|
|
private int deadTicks = 0;
|
|
private int actionBarTicks = -1;
|
|
private int refreshRate;
|
|
private long lastRefreshed = System.currentTimeMillis();
|
|
private Disguise disguise;
|
|
final Double vectorY;
|
|
final boolean alwaysSendVelocity;
|
|
|
|
public DisguiseRunnable(Disguise disguise) {
|
|
this.disguise = disguise;
|
|
|
|
switch (disguise.getType()) {
|
|
case FIREWORK:
|
|
case WITHER_SKULL:
|
|
case EXPERIENCE_ORB:
|
|
vectorY = 0.000001D;
|
|
alwaysSendVelocity = true;
|
|
break;
|
|
default:
|
|
vectorY = null;
|
|
alwaysSendVelocity = false;
|
|
break;
|
|
}
|
|
|
|
// Where refresh rate is in ticks, exp is in here due to a fire exploit + stop it glitching out so much
|
|
switch (disguise.getType()) {
|
|
case FIREWORK:
|
|
case EXPERIENCE_ORB:
|
|
refreshRate = 40; // 2 seconds
|
|
break;
|
|
case EVOKER_FANGS:
|
|
refreshRate = 23;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
refreshRate *= 50;
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
if (!disguise.isDisguiseInUse() || disguise.getEntity() == null || !Bukkit.getWorlds().contains(disguise.getEntity().getWorld())) {
|
|
disguise.stopDisguise();
|
|
|
|
// If still somehow not cancelled
|
|
if (!isCancelled()) {
|
|
cancel();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (++actionBarTicks % 15 == 0) {
|
|
actionBarTicks = 0;
|
|
|
|
disguise.doActionBar();
|
|
}
|
|
|
|
// If entity is no longer valid. Remove it.
|
|
if (disguise.getEntity() instanceof Player && !((Player) disguise.getEntity()).isOnline()) {
|
|
disguise.removeDisguise();
|
|
} else if (disguise.disguiseExpires > 0 && (DisguiseConfig.isDynamicExpiry() ? disguise.disguiseExpires-- == 1 :
|
|
disguise.disguiseExpires < System.currentTimeMillis())) { // If disguise expired
|
|
disguise.removeDisguise();
|
|
|
|
if (disguise.getEntity() instanceof Player) {
|
|
LibsMsg.EXPIRED_DISGUISE.send(disguise.getEntity());
|
|
}
|
|
|
|
return;
|
|
} else if (!disguise.getEntity().isValid()) {
|
|
// If it has been dead for 30+ ticks
|
|
// This is to ensure that this disguise isn't removed while clients think its the real entity
|
|
// The delay is because if it sends the destroy entity packets straight away, then it means no
|
|
// death animation
|
|
// This is probably still a problem for wither and enderdragon deaths.
|
|
if (deadTicks++ > (disguise.getType() == DisguiseType.ENDER_DRAGON ? 200 : 20)) {
|
|
if (disguise.isRemoveDisguiseOnDeath()) {
|
|
disguise.removeDisguise();
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
deadTicks = 0;
|
|
|
|
// If the disguise type is invisibable, we need to resend the entity packet else it will turn invisible
|
|
if (refreshRate > 0 && lastRefreshed + refreshRate < System.currentTimeMillis()) {
|
|
lastRefreshed = System.currentTimeMillis();
|
|
|
|
DisguiseUtilities.refreshTrackers((TargetedDisguise) disguise);
|
|
}
|
|
|
|
if (disguise.isModifyBoundingBox()) {
|
|
DisguiseUtilities.doBoundingBox((TargetedDisguise) disguise);
|
|
}
|
|
|
|
if (disguise.getType() == DisguiseType.BAT && !((BatWatcher) disguise.getWatcher()).isHanging()) {
|
|
return;
|
|
}
|
|
|
|
doVelocity(vectorY, alwaysSendVelocity);
|
|
|
|
if (disguise.getType() == DisguiseType.EXPERIENCE_ORB) {
|
|
PacketContainer packet = new PacketContainer(PacketType.Play.Server.REL_ENTITY_MOVE);
|
|
|
|
packet.getIntegers().write(0, disguise.getEntity().getEntityId());
|
|
|
|
try {
|
|
for (Player player : DisguiseUtilities.getPerverts(disguise)) {
|
|
if (disguise.getEntity() != player) {
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet, false);
|
|
continue;
|
|
} else if (!disguise.isSelfDisguiseVisible() || !(disguise.getEntity() instanceof Player)) {
|
|
continue;
|
|
}
|
|
|
|
PacketContainer selfPacket = packet.shallowClone();
|
|
|
|
selfPacket.getModifier().write(0, DisguiseAPI.getSelfDisguiseId());
|
|
|
|
try {
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket((Player) disguise.getEntity(), selfPacket, false);
|
|
} catch (InvocationTargetException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
} catch (InvocationTargetException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void doVelocity(Double vectorY, boolean alwaysSendVelocity) {
|
|
// If the vectorY isn't 0. Cos if it is. Then it doesn't want to send any vectors.
|
|
// If this disguise has velocity sending enabled and the entity is flying.
|
|
if (disguise.isVelocitySent() && vectorY != null && (alwaysSendVelocity || !disguise.getEntity().isOnGround())) {
|
|
Vector vector = disguise.getEntity().getVelocity();
|
|
|
|
// If the entity doesn't have velocity changes already - You know. I really can't wrap my
|
|
// head about the
|
|
// if statement.
|
|
// But it doesn't seem to do anything wrong..
|
|
if (vector.getY() != 0 && !(vector.getY() < 0 && alwaysSendVelocity && disguise.getEntity().isOnGround())) {
|
|
return;
|
|
}
|
|
|
|
// If disguise isn't a experience orb, or the entity isn't standing on the ground
|
|
if (disguise.getType() != DisguiseType.EXPERIENCE_ORB || !disguise.getEntity().isOnGround()) {
|
|
PacketContainer lookPacket = null;
|
|
|
|
if (disguise.getType() == DisguiseType.WITHER_SKULL && DisguiseConfig.isWitherSkullPacketsEnabled()) {
|
|
lookPacket = new PacketContainer(PacketType.Play.Server.ENTITY_LOOK);
|
|
|
|
StructureModifier<Object> mods = lookPacket.getModifier();
|
|
lookPacket.getIntegers().write(0, disguise.getEntity().getEntityId());
|
|
Location loc = disguise.getEntity().getLocation();
|
|
|
|
mods.write(4,
|
|
DisguiseUtilities.getYaw(disguise.getType(), disguise.getEntity().getType(), (byte) Math.floor(loc.getYaw() * 256.0F / 360.0F)));
|
|
mods.write(5,
|
|
DisguiseUtilities.getPitch(disguise.getType(), disguise.getEntity().getType(), (byte) Math.floor(loc.getPitch() * 256.0F / 360.0F)));
|
|
|
|
if (disguise.isSelfDisguiseVisible() && disguise.getEntity() instanceof Player) {
|
|
PacketContainer selfLookPacket = lookPacket.shallowClone();
|
|
|
|
selfLookPacket.getIntegers().write(0, DisguiseAPI.getSelfDisguiseId());
|
|
|
|
try {
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket((Player) disguise.getEntity(), selfLookPacket, false);
|
|
} catch (InvocationTargetException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|
|
try {
|
|
PacketContainer velocityPacket = new PacketContainer(PacketType.Play.Server.ENTITY_VELOCITY);
|
|
|
|
StructureModifier<Integer> mods = velocityPacket.getIntegers();
|
|
|
|
// Write entity ID
|
|
mods.write(0, disguise.getEntity().getEntityId());
|
|
mods.write(1, (int) (vector.getX() * 8000));
|
|
mods.write(3, (int) (vector.getZ() * 8000));
|
|
|
|
for (Player player : DisguiseUtilities.getPerverts(disguise)) {
|
|
PacketContainer tempVelocityPacket = velocityPacket.shallowClone();
|
|
mods = tempVelocityPacket.getIntegers();
|
|
|
|
// If the viewing player is the disguised player
|
|
if (disguise.getEntity() == player) {
|
|
// If not using self disguise, continue
|
|
if (!disguise.isSelfDisguiseVisible()) {
|
|
continue;
|
|
}
|
|
|
|
// Write self disguise ID
|
|
mods.write(0, DisguiseAPI.getSelfDisguiseId());
|
|
}
|
|
|
|
mods.write(2, (int) (8000D * (vectorY * ReflectionManager.getPing(player)) * 0.069D));
|
|
|
|
if (lookPacket != null && player != disguise.getEntity()) {
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, lookPacket, false);
|
|
}
|
|
|
|
ProtocolLibrary.getProtocolManager().sendServerPacket(player, tempVelocityPacket, false);
|
|
}
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
// If we need to send a packet to update the exp position as it likes to gravitate client
|
|
// sided to
|
|
// players.
|
|
}
|
|
}
|
|
}
|