Merge main: apply array-based chunk storage to World.java, resolve BlockUpdateHandler conflict

Co-authored-by: funkemunky <30784509+funkemunky@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-02-20 16:07:21 +00:00
parent 1b860c9bd5
commit 440fec9eaf
55 changed files with 1245 additions and 833 deletions
+5 -5
View File
@@ -19,6 +19,10 @@
</properties>
<repositories>
<repository>
<id>maven-central</id>
<url>https://nexus.funkemunky.cc/repository/maven-central/</url>
</repository>
<repository>
<id>viaversion-repo</id>
<url>https://repo.viaversion.com</url>
@@ -27,10 +31,6 @@
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>evokegames</id>
<url>https://maven.evokegames.gg/snapshots</url>
</repository>
<repository>
<id>aikar</id>
<url>https://repo.aikar.co/content/groups/aikar/</url>
@@ -267,7 +267,7 @@
<dependency>
<groupId>com.github.retrooper</groupId>
<artifactId>packetevents-spigot</artifactId>
<version>2.9.4</version>
<version>2.11.1</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -17,6 +17,8 @@ import dev.brighten.ac.handler.PacketHandler;
import dev.brighten.ac.handler.entity.FakeEntityTracker;
import dev.brighten.ac.handler.keepalive.KeepaliveProcessor;
import dev.brighten.ac.handler.keepalive.actions.ActionManager;
import dev.brighten.ac.handler.protocol.Protocol;
import dev.brighten.ac.handler.protocol.impl.NoAPI;
import dev.brighten.ac.logging.LoggerManager;
import dev.brighten.ac.utils.*;
import dev.brighten.ac.utils.annotation.ConfigSetting;
@@ -30,6 +32,7 @@ import dev.brighten.ac.utils.timer.impl.TickTimer;
import dev.brighten.ac.utils.world.WorldInfo;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.PackagePrivate;
import org.bukkit.Bukkit;
import org.bukkit.World;
@@ -116,6 +119,9 @@ public class Anticheat extends JavaPlugin {
private final RollingAverageDouble tps = new RollingAverageDouble(4, 20);
private final Map<UUID, WorldInfo> worldInfoMap = new HashMap<>();
@Setter
private Protocol protocol = new NoAPI();
private final List<BaseCommand> commands = new ArrayList<>();
public static boolean allowDebug = true;
@@ -252,7 +258,7 @@ public class Anticheat extends JavaPlugin {
} catch (IllegalStateException e) {
Anticheat.INSTANCE.getLogger().log(Level.SEVERE, "Check ID unregister failed", e);
}
commandManager.getScheduler().cancelLocaleTask();
commandPropertiesManager = null;
try {
@@ -23,5 +23,5 @@ public @interface CheckData {
int punishVl() default 10;
ClientVersion minVersion() default ClientVersion.V_1_8;
ClientVersion maxVersion() default ClientVersion.V_1_21_7;
ClientVersion maxVersion() default ClientVersion.V_1_21_11;
}
@@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.particle.type.ParticleTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import dev.brighten.ac.Anticheat;
@@ -19,7 +20,6 @@ import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.TickTimer;
import dev.brighten.ac.utils.world.EntityData;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
@@ -46,7 +46,7 @@ public class Hitbox extends Check {
if(packet.getAction() != WrapperPlayClientInteractEntity.InteractAction.ATTACK)
return;
Optional<TrackedEntity> entity = player.getEntityLocationHandler().getTrackedEntity(packet.getEntityId());
Optional<TrackedEntity> entity = player.getWorldTracker().getCurrentWorld().get().getTrackedEntity(packet.getEntityId());
if(entity.isEmpty() || !allowedEntityTypes.contains(entity.get().getEntityType())) return;
attacks.add(new Tuple<>(entity.get(),
@@ -118,7 +118,7 @@ public class Hitbox extends Check {
boolean didSneakOrElytra = player.getInfo().getLastSneak().isNotPassed(40)
|| player.getInfo().getLastElytra().isNotPassed(40);
List<Vector> directions = new ArrayList<>(Arrays.asList(MathUtils.getDirection(
List<Vector3d> directions = new ArrayList<>(Arrays.asList(MathUtils.getDirection(
player.getMovement().getTo().getLoc().getYaw(),
player.getMovement().getTo().getLoc().getPitch()),
MathUtils.getDirection(player.getMovement().getFrom().getLoc().getYaw(),
@@ -126,7 +126,7 @@ public class Hitbox extends Check {
if(!didSneakOrElytra) {
to.add(0, 1.62f, 0);
for (Vector direction : directions) {
for (Vector3d direction : directions) {
for (SimpleCollisionBox targetBox : boxes) {
final AxisAlignedBB vanillaBox = new AxisAlignedBB(targetBox);
@@ -143,7 +143,7 @@ public class Hitbox extends Check {
}
//Checking all possible eyeheights since client actions notoriously desync from the server side
} else {
for (Vector direction : directions) {
for (Vector3d direction : directions) {
for (double eyeHeight : player.getMovement().getEyeHeights()) {
for (SimpleCollisionBox targetBox : boxes) {
final AxisAlignedBB vanillaBox = new AxisAlignedBB(targetBox);
@@ -180,7 +180,7 @@ public class Hitbox extends Check {
debug("buffer: %.3f distance=%.2f hits=%s sneaking=%s", buffer, distance, hits,
player.getInfo().isSneaking());
} else if(player.getEntityLocationHandler().streak > 1) {
} else if(player.getEntityTrackHandler().streak > 1) {
if (++hbuffer > 5) {
flag("%.1f;%.1f;%.1f", entity.getNewEntityLocation().x, entity.getNewEntityLocation().y, entity.getNewEntityLocation().z);
}
@@ -1,6 +1,5 @@
package dev.brighten.ac.check.impl.combat.killaura;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientAnimation;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import dev.brighten.ac.api.check.CheckType;
@@ -29,10 +28,10 @@ public class KABot extends Check {
@Bind
WAction<WrapperPlayClientInteractEntity> packet = packet -> {
val optional = player.getEntityLocationHandler().getTrackedEntity(packet.getEntityId());
val optional = player.getWorldTracker().getCurrentWorld().get().getTrackedEntity(packet.getEntityId());
if(optional.isPresent()
&& (player.getEntityLocationHandler().clientHasEntity.get()
&& (player.getEntityTrackHandler().clientHasEntity.get()
|| !optional.get().getFakeMobs().isEmpty())) {
if(++buffer > 3) {
flag("Attacked player without attacking bot!");
@@ -1,6 +1,6 @@
package dev.brighten.ac.check.impl.combat.killaura;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.Check;
@@ -13,7 +13,6 @@ import dev.brighten.ac.utils.world.CollisionBox;
import dev.brighten.ac.utils.world.EntityData;
import dev.brighten.ac.utils.world.types.RayCollision;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
import org.bukkit.util.Vector;
/**
* @author funkemunky
@@ -43,14 +42,13 @@ public class KATrace extends Check {
return;
}
var trackedEntity = player.getEntityLocationHandler().getTrackedEntity(player.getInfo().getTarget().getEntityId());
var trackedEntity = player.getWorldTracker().getCurrentWorld().get().getTrackedEntity(player.getInfo().getTarget().getEntityId());
if(trackedEntity.isEmpty()) {
return;
}
// Getting the target's bounding box
SimpleCollisionBox targetBox = (SimpleCollisionBox) EntityData.getEntityBox(player.getInfo().getTarget()
.getLocation(), trackedEntity.get());
SimpleCollisionBox targetBox = (SimpleCollisionBox) EntityData.getEntityBox(player.getInfo().getTarget().getLocation(), trackedEntity.get());
if(targetBox == null) return;
@@ -59,12 +57,12 @@ public class KATrace extends Check {
// Setting the player's eye height based on their sneak status
origin.add(0, player.getEyeHeight(), 0);
final Vector originVec = origin.toVector();
final Vector3d originVec = origin.toVector();
// Setting a trace based on their view direction
RayCollision collision = new RayCollision(originVec, origin.getDirection());
Vector targetPoint = collision.collisionPoint(targetBox);
Vector3d targetPoint = collision.collisionPoint(targetBox);
//If the ray isn't collided, we might as well not run this check. Just a simple boxes on array check
if(targetPoint == null) return;
@@ -84,7 +82,7 @@ public class KATrace extends Check {
continue;
// We want to shrink the box slightly since there is a bit of a margin of error in the ray trace.
Vector point = collision.collisionPoint(box.copy().shrink(0.005f, 0.005f, 0.005f));
Vector3d point = collision.collisionPoint(box.copy().shrink(0.005f, 0.005f, 0.005f));
if (point != null && originVec.distanceSquared(point) < dist - 0.2) {
rayCollidedOnBlock = true;
@@ -31,7 +31,7 @@ public class KACalc extends KListener {
@Bind
WAction<WrapperPlayClientPlayerFlying> flying = packet -> {
if(player.getInfo().getTarget() == null || player.getInfo().lastAttack.isPassed(40)) return;
Optional<TrackedEntity> optional = player.getEntityLocationHandler()
Optional<TrackedEntity> optional = player.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(player.getInfo().getTarget().getEntityId());
if(optional.isEmpty()) return;
@@ -46,7 +46,7 @@ public class KACalc extends KListener {
KLocation originKLoc = player.getMovement().getTo().getLoc().clone()
.add(0, player.getInfo().isSneaking() ? 1.54f : 1.62f, 0);
double halfHeight = player.getInfo().getTarget().getEyeHeight() / 2;
double halfHeight = player.getInfo().getTarget().getPose().eyeHeight / 2;
KLocation targetLocation = new KLocation(current.getX(), current.getY(), current.getZ());
var rotations = MathUtils
.getRotation(originKLoc, targetLocation.clone().add(0, halfHeight, 0));
@@ -1,6 +1,7 @@
package dev.brighten.ac.check.impl.movement;
import com.github.retrooper.packetevents.protocol.teleport.RelativeFlag;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerPositionAndLook;
import dev.brighten.ac.Anticheat;
@@ -18,7 +19,6 @@ import dev.brighten.ac.utils.annotation.Bind;
import dev.brighten.ac.utils.objects.evicting.EvictingSet;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
import org.bukkit.Location;
import org.bukkit.util.Vector;
import java.util.List;
import java.util.Set;
@@ -31,7 +31,7 @@ public class Phase extends Check {
}
private int ticks;
private final Set<Vector> POSITIONS = new EvictingSet<>(10);
private final Set<Vector3d> POSITIONS = new EvictingSet<>(10);
private Location teleportLoc = null;
@Bind
@@ -1,6 +1,7 @@
package dev.brighten.ac.check.impl.movement.speed;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.Check;
@@ -36,11 +37,11 @@ public class Speed extends Check {
moveFactor+= (float) (moveFactor * 0.30000001192092896D);
if(player.getPotionHandler().hasPotionEffect(PotionEffectType.SPEED))
if(player.getPotionHandler().hasPotionEffect(PotionTypes.SPEED))
moveFactor += (float) ((PlayerUtils.getPotionEffectLevel(player.getBukkitPlayer(), PotionEffectType.SPEED)
* (0.200000000298023224D)) * moveFactor);
if(player.getPotionHandler().hasPotionEffect(PotionEffectType.SLOW))
if(player.getPotionHandler().hasPotionEffect(PotionTypes.SLOWNESS))
moveFactor += (float) ((PlayerUtils.getPotionEffectLevel(player.getBukkitPlayer(), PotionEffectType.SLOW)
* (-0.15000000596046448D)) * moveFactor);
@@ -1,6 +1,8 @@
package dev.brighten.ac.check.impl.movement.velocity;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.Check;
@@ -12,12 +14,10 @@ import dev.brighten.ac.utils.BlockUtils;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.MathUtils;
import dev.brighten.ac.utils.annotation.Bind;
import dev.brighten.ac.utils.math.IntVector;
import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.TickTimer;
import lombok.val;
import me.hydro.emulator.util.mcp.MathHelper;
import org.bukkit.potion.PotionEffectType;
import java.util.ArrayList;
import java.util.List;
@@ -61,8 +61,8 @@ public class VelocityB extends Check {
val underBlockLoc = previousFrom != null
? player.getMovement().getFrom().getLoc() : player.getMovement().getTo().getLoc();
WrappedBlock underMaterial = player.getBlockUpdateHandler()
.getBlock(new IntVector(MathHelper.floor_double(underBlockLoc.getX()),
WrappedBlock underMaterial = player.getWorldTracker()
.getBlock(new Vector3i(MathHelper.floor_double(underBlockLoc.getX()),
MathHelper.floor_double(underBlockLoc.getY() - 1),
MathHelper.floor_double(underBlockLoc.getZ())));
@@ -87,8 +87,8 @@ public class VelocityB extends Check {
double pmotionx = 0, pmotionz = 0;
boolean onGround = player.getMovement().getFrom().isOnGround();
val speed = player.getPotionHandler().getEffectByType(PotionEffectType.SPEED);
val slow = player.getPotionHandler().getEffectByType(PotionEffectType.SLOW);
val speed = player.getPotionHandler().getEffectByType(PotionTypes.SPEED);
val slow = player.getPotionHandler().getEffectByType(PotionTypes.SLOWNESS);
for (Iteration iteration : iterations) {
float forward = iteration.f, strafe = iteration.s;
@@ -138,9 +138,9 @@ public class VelocityB extends Check {
aiMoveSpeed += aiMoveSpeed * 0.30000001192092896D;
if (speed.isPresent())
aiMoveSpeed += (speed.get().getAmplifier() + 1) * 0.20000000298023224D * aiMoveSpeed;
aiMoveSpeed += (speed.get().properties().amplifier() + 1) * 0.20000000298023224D * aiMoveSpeed;
if (slow.isPresent())
aiMoveSpeed += (slow.get().getAmplifier() + 1) * -0.15000000596046448D * aiMoveSpeed;
aiMoveSpeed += (slow.get().properties().amplifier() + 1) * -0.15000000596046448D * aiMoveSpeed;
float f5;
if (onGround) {
@@ -1,6 +1,7 @@
package dev.brighten.ac.check.impl.world;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerBlockPlacement;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import dev.brighten.ac.api.check.CheckType;
@@ -35,7 +36,7 @@ public class BlockA extends Check {
WAction<WrapperPlayClientPlayerBlockPlacement> blockPlace = packet -> {
Vector3d loc = packet.getBlockPosition().toVector3d();
WrappedBlock block = player.getBlockUpdateHandler().getBlock(loc);
WrappedBlock block = player.getWorldTracker().getBlock(new Vector3i(MathUtils.floor(loc.getX()), MathUtils.floor(loc.getY()), MathUtils.floor(loc.getZ())));
CollisionBox box = BlockData.getData(block.getType()).getBox(player, block, player.getPlayerVersion());
@@ -14,12 +14,12 @@ import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.block.WrappedBlock;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.annotation.Bind;
import dev.brighten.ac.utils.math.IntVector;
import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.TickTimer;
import dev.brighten.ac.utils.world.BlockData;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
@CheckData(name = "Block (D)", checkId = "blockc", type = CheckType.INTERACT)
public class BlockD extends Check {
@@ -45,7 +45,7 @@ public class BlockD extends Check {
packet.getFace().getModY(),
packet.getFace().getModZ());
WrappedBlock block = new WrappedBlock(new IntVector(packet.getBlockPosition()),
WrappedBlock block = new WrappedBlock(packet.getBlockPosition(),
placedType,
WrappedBlockState.getDefaultState(placedType));
blockPlaceLocations.put(blockpos, block);
@@ -7,11 +7,12 @@ import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.api.spigot.impl.LegacyPlayer;
import dev.brighten.ac.api.spigot.impl.ModernPlayer;
@@ -22,17 +23,20 @@ import dev.brighten.ac.data.info.GeneralInformation;
import dev.brighten.ac.data.info.LagInformation;
import dev.brighten.ac.data.obj.InstantAction;
import dev.brighten.ac.data.obj.NormalAction;
import dev.brighten.ac.handler.EntityLocationHandler;
import dev.brighten.ac.handler.EntityTrackHandler;
import dev.brighten.ac.handler.MovementHandler;
import dev.brighten.ac.handler.PotionHandler;
import dev.brighten.ac.handler.VelocityHandler;
import dev.brighten.ac.handler.block.BlockUpdateHandler;
import dev.brighten.ac.handler.block.World;
import dev.brighten.ac.handler.entity.FakeMob;
import dev.brighten.ac.handler.keepalive.KeepAlive;
import dev.brighten.ac.handler.protocol.Protocol;
import dev.brighten.ac.messages.Messages;
import dev.brighten.ac.packet.TransactionServerWrapper;
import dev.brighten.ac.utils.*;
import dev.brighten.ac.utils.Helper;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.Tuple;
import dev.brighten.ac.utils.XMaterial;
import dev.brighten.ac.utils.objects.evicting.EvictingList;
import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.MillisTimer;
@@ -49,7 +53,6 @@ import me.hydro.emulator.object.input.DataSupplier;
import me.hydro.emulator.util.mcp.AxisAlignedBB;
import me.hydro.emulator.util.mcp.BlockPos;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -72,10 +75,10 @@ public class APlayer {
private VelocityHandler velocityHandler;
@Getter
private EntityLocationHandler entityLocationHandler;
private EntityTrackHandler entityTrackHandler;
@Getter
private BlockUpdateHandler blockUpdateHandler;
private BlockUpdateHandler worldTracker;
@Getter
private CheckHandler checkHandler;
@@ -138,87 +141,103 @@ public class APlayer {
this.movement = new MovementHandler(this);
this.potionHandler = new PotionHandler(this);
this.velocityHandler = new VelocityHandler(this);
this.entityLocationHandler = new EntityLocationHandler(this);
this.blockUpdateHandler = new BlockUpdateHandler(this);
this.entityTrackHandler = new EntityTrackHandler(this);
this.worldTracker = new BlockUpdateHandler(this);
this.checkHandler = new CheckHandler(this);
this.info = new GeneralInformation();
this.lagInfo = new LagInformation();
this.blockInfo = new BlockInformation(this);
worldTracker.getCurrentWorld().set(new World(bukkitPlayer.getWorld().getName()));
creation.reset();
playerVersion = ClientVersion.getById(Anticheat.INSTANCE.getProtocol().getPlayerVersion(this));
Anticheat.INSTANCE.getScheduler().schedule(() -> {
// Grabbing the protocol version of the player.
Anticheat.INSTANCE.getLogger().info("Attempting Getting player version for " + getBukkitPlayer().getName());
ClientVersion version = ClientVersion.getById(Protocol.getProtocol().getPlayerVersion(getBukkitPlayer()));
ClientVersion version = ClientVersion.getById(Anticheat.INSTANCE.getProtocol().getPlayerVersion(this));
this.playerVersion = version;
Anticheat.INSTANCE.getLogger().info("Got player version " + version.name() + " for " + getBukkitPlayer().getName());
if(PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9)) {
this.wrappedPlayer = new LegacyPlayer(getBukkitPlayer());
} else this.wrappedPlayer = new ModernPlayer(getBukkitPlayer());
EMULATOR = new Emulator(new DataSupplier() {
@Override
public List<AxisAlignedBB> getCollidingBoxes(AxisAlignedBB bb) {
SimpleCollisionBox sbc = new SimpleCollisionBox(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ);
// Greater than 20? We want to truncate to prevent huge processing cost
if(sbc.min().distanceSquared(sbc.max()) > 400) {
sbc.maxX = sbc.minX + Math.min(sbc.maxX - sbc.minX, 20);
sbc.maxY = sbc.minY + Math.max(sbc.maxY - sbc.minY, 20);
sbc.maxZ = sbc.minZ + Math.max(sbc.maxZ - sbc.minZ, 20);
}
List<AxisAlignedBB> axisAlignedBBs = new ArrayList<>();
for (SimpleCollisionBox bb2 : Helper.getCollisions(APlayer.this,
sbc)) {
axisAlignedBBs
.add(new AxisAlignedBB(bb2.minX, bb2.minY, bb2.minZ, bb2.maxX, bb2.maxY, bb2.maxZ));
}
return axisAlignedBBs;
}
@Override
public Block getBlockAt(BlockPos blockPos) {
//Optional<org.bukkit.block.Block>
var block = APlayer.this.getBlockUpdateHandler()
.getBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ());
StateType type = block.getType();
if(type == StateTypes.SLIME_BLOCK) {
return new BlockSlime();
} else if(type == StateTypes.SOUL_SAND) {
return new BlockSoulSand();
} else if(type == StateTypes.COBWEB) {
return new BlockWeb();
} else if(type == StateTypes.ICE || type == StateTypes.PACKED_ICE || type == StateTypes.FROSTED_ICE) {
return new BlockIce();
} else if(type == StateTypes.BLUE_ICE) {
return new BlockBlueIce();
}
return new Block();
}
}, getPlayerVersion().getProtocolVersion());
generateEntities();
// Enabling alerts for players on join if they have the permissions to
if(getBukkitPlayer().hasPermission("anticheat.command.alerts")
|| getBukkitPlayer().hasPermission("anticheat.alerts")) {
Check.alertsEnabled.add(getUuid());
getBukkitPlayer().spigot().sendMessage(Messages.ALERTS_ON);
}
initialized = true;
Anticheat.INSTANCE.getRunUtils().task(() -> checkHandler.initChecks());
}, 100, TimeUnit.MILLISECONDS);
if(PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9)) {
this.wrappedPlayer = new LegacyPlayer(getBukkitPlayer());
} else this.wrappedPlayer = new ModernPlayer(getBukkitPlayer());
Cache<AxisAlignedBB, List<AxisAlignedBB>> collisionCache = CacheBuilder.newBuilder()
.maximumSize(200)
.expireAfterWrite(100, TimeUnit.MILLISECONDS)
.build();
EMULATOR = new Emulator(new DataSupplier() {
@Override
public List<AxisAlignedBB> getCollidingBoxes(AxisAlignedBB bb) {
var cacheIfPresent = collisionCache.getIfPresent(bb);
if(cacheIfPresent != null) return cacheIfPresent;
SimpleCollisionBox sbc = new SimpleCollisionBox(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ);
// Greater than 20? We want to truncate to prevent huge processing cost
if(sbc.min().distanceSquared(sbc.max()) > 400) {
sbc.maxX = sbc.minX + Math.min(sbc.maxX - sbc.minX, 20);
sbc.maxY = sbc.minY + Math.max(sbc.maxY - sbc.minY, 20);
sbc.maxZ = sbc.minZ + Math.max(sbc.maxZ - sbc.minZ, 20);
}
List<AxisAlignedBB> axisAlignedBBs = new ArrayList<>();
for (SimpleCollisionBox bb2 : Helper.getCollisions(APlayer.this,
sbc)) {
axisAlignedBBs
.add(new AxisAlignedBB(bb2.minX, bb2.minY, bb2.minZ, bb2.maxX, bb2.maxY, bb2.maxZ));
}
collisionCache.put(bb, axisAlignedBBs);
return axisAlignedBBs;
}
@Override
public Block getBlockAt(BlockPos blockPos) {
//Optional<org.bukkit.block.Block>
var block = APlayer.this.getWorldTracker()
.getBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ());
StateType type = block.getType();
if(type == StateTypes.SLIME_BLOCK) {
return new BlockSlime();
} else if(type == StateTypes.SOUL_SAND) {
return new BlockSoulSand();
} else if(type == StateTypes.COBWEB) {
return new BlockWeb();
} else if(type == StateTypes.ICE || type == StateTypes.PACKED_ICE || type == StateTypes.FROSTED_ICE) {
return new BlockIce();
} else if(type == StateTypes.BLUE_ICE) {
return new BlockBlueIce();
}
return new Block();
}
}, getPlayerVersion().getProtocolVersion());
generateEntities();
// Enabling alerts for players on join if they have the permissions to
if(getBukkitPlayer().hasPermission("anticheat.command.alerts")
|| getBukkitPlayer().hasPermission("anticheat.alerts")) {
Check.alertsEnabled.add(getUuid());
getBukkitPlayer().spigot().sendMessage(Messages.ALERTS_ON);
}
initialized = true;
Anticheat.INSTANCE.getRunUtils().task(() -> checkHandler.initChecks());
}
private void generateEntities() {
@@ -228,7 +247,7 @@ public class APlayer {
RayCollision coll = new RayCollision(origin.toVector(), origin.getDirection().multiply(-1));
Vector loc1 = coll.collisionPoint(2);
Vector3d loc1 = coll.collisionPoint(2);
List<EntityData<?>> dataList = new ArrayList<>();
@@ -330,10 +349,6 @@ public class APlayer {
user.writePacketSilently(packet);
}
public DimensionType getDimensionType() {
return user.getDimensionType();
}
public void sendPacket(PacketWrapper<?> packet) {
user.sendPacket(packet);
}
@@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.protocol.particle.type.ParticleTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.entity.TrackedEntity;
@@ -132,11 +133,11 @@ public class BlockInformation {
}
final StateType type =
player.getBlockUpdateHandler().getBlock(new IntVector(x, y, z)).getType();
player.getWorldTracker().getBlock(new Vector3i(x, y, z)).getType();
if (type != StateTypes.AIR) {
IntVector vec = new IntVector(x, y, z);
Vector3i vec = new Vector3i(x, y, z);
CollisionBox blockBox = BlockData.getData(type)
.getBox(player, vec, player.getPlayerVersion());
@@ -1,10 +1,12 @@
package dev.brighten.ac.data.info;
import com.github.retrooper.packetevents.util.Vector3d;
import dev.brighten.ac.data.obj.Pose;
import dev.brighten.ac.handler.block.WrappedBlock;
import dev.brighten.ac.handler.entity.TrackedEntity;
import dev.brighten.ac.packet.PlayerCapabilities;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.KPotionEffect;
import dev.brighten.ac.utils.PastLocation;
import dev.brighten.ac.utils.math.RollingAverage;
import dev.brighten.ac.utils.objects.evicting.EvictingList;
@@ -12,8 +14,6 @@ import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.TickTimer;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.entity.LivingEntity;
import org.bukkit.potion.PotionEffect;
import java.util.ArrayList;
import java.util.Collections;
@@ -33,8 +33,8 @@ public class GeneralInformation {
lastBlockUpdate = new TickTimer(), lastMiscNear = new TickTimer(), lastHalfBlock = new TickTimer(),
lastFence = new TickTimer(), lastFakeBotHit = new TickTimer(), lastInventoryOpen = new TickTimer(),
botAttack = new TickTimer(), lastAttack = new TickTimer(), lastCanceledFlying = new TickTimer();
public LivingEntity target;
public Optional<PotionEffect> groundJumpBoost;
public TrackedEntity target;
public Optional<KPotionEffect> groundJumpBoost = Optional.empty();
public boolean serverGround, lastServerGround, canFly, nearGround, worldLoaded, generalCancel, inVehicle, creative,
sneaking, lsneaking, sprinting, gliding, riptiding, wasOnSlime, onLadder, doingVelocity, breakingBlock,
inventoryOpen, swimming;
@@ -46,4 +46,7 @@ public class GeneralInformation {
public List<Vector3d> velocityHistory = Collections.synchronizedList(new EvictingList<>(5));
public List<PlayerCapabilities> possibleCapabilities = new ArrayList<>();
private int clientGroundTicks, clientAirTicks;
private double walkSpeed, flySpeed;
private PlayerInput playerInput = PlayerInput.NONE;
private Pose pose;
}
@@ -0,0 +1,14 @@
package dev.brighten.ac.data.info;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerInput;
public record PlayerInput(boolean forward, boolean backward, boolean left, boolean right, boolean jump, boolean sprint, boolean shift) {
public static PlayerInput getFromPacket(WrapperPlayClientPlayerInput packet) {
return new PlayerInput(packet.isForward(), packet.isBackward(), packet.isLeft(),
packet.isRight(), packet.isJump(), packet.isSprint(), packet.isShift());
}
public static final PlayerInput NONE = new PlayerInput(false, false, false,
false, false, false, false);
}
@@ -1,10 +1,10 @@
package dev.brighten.ac.data.obj;
import dev.brighten.ac.handler.block.World;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.World;
@Getter
@Setter
@@ -0,0 +1,25 @@
package dev.brighten.ac.data.obj;
public enum Pose {
STANDING(0.6f, 1.8f, 1.62f),
FALL_FLYING(0.6f, 0.6f, 0.4f),
SLEEPING(0.2f, 0.2f, 0.2f),
SWIMMING(0.6f, 0.6f, 0.4f),
SPIN_ATTACK(0.6f, 0.6f, 0.4f),
CROUCHING(0.6f, 1.5f, 1.27f),
DYING(0.2f, 0.2f, 0.2f),
// Non-player poses
NINE_CROUCHING(0.6f, 1.65f, 1.54f), // 1.9-1.13 clients have a slightly different crouching hitbox
LONG_JUMPING(0.6f, 1.8f, 1.54f); // DUMMY (players can't have this pose)
public final float width;
public final float height;
public final float eyeHeight;
Pose(float width, float height, float eyeHeight) {
this.width = width;
this.height = height;
this.eyeHeight = eyeHeight;
}
}
@@ -1,13 +1,13 @@
package dev.brighten.ac.handler;
import com.github.retrooper.packetevents.protocol.particle.type.ParticleTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.block.WrappedBlock;
import dev.brighten.ac.utils.ItemBuilder;
import dev.brighten.ac.utils.Materials;
import dev.brighten.ac.utils.annotation.Init;
import dev.brighten.ac.utils.math.IntVector;
import dev.brighten.ac.utils.world.BlockData;
import dev.brighten.ac.utils.world.EntityData;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
@@ -31,7 +31,7 @@ import java.util.stream.Collectors;
@Init
public class BBRevealHandler implements Listener {
private final Map<UUID, Set<IntVector>> blocksToShow = new HashMap<>();
private final Map<UUID, Set<Vector3i>> blocksToShow = new HashMap<>();
private final Set<Entity> entitiesToShow = new HashSet<>();
public static BBRevealHandler INSTANCE;
@@ -52,9 +52,9 @@ public class BBRevealHandler implements Listener {
if(player == null || !player.getWrappedPlayer().getItemInHand().isSimilar(wand)) return;
if(event.getAction() == Action.RIGHT_CLICK_BLOCK) {
IntVector blockLoc = new IntVector(event.getClickedBlock().getX(),
Vector3i blockLoc = new Vector3i(event.getClickedBlock().getX(),
event.getClickedBlock().getY(), event.getClickedBlock().getZ());
Set<IntVector> blocksToShow = this.blocksToShow
Set<Vector3i> blocksToShow = this.blocksToShow
.computeIfAbsent(event.getPlayer().getUniqueId(), k -> new HashSet<>());
if(blocksToShow.contains(blockLoc)) {
blocksToShow.remove(blockLoc);
@@ -63,11 +63,11 @@ public class BBRevealHandler implements Listener {
.create());
} else {
blocksToShow.add(blockLoc);
WrappedBlock block = player.getBlockUpdateHandler().getBlock(blockLoc);
WrappedBlock block = player.getWorldTracker().getCurrentWorld().get().getBlock(blockLoc);
event.getPlayer().spigot().sendMessage(new ComponentBuilder("Now showing block: ")
.color(ChatColor.GREEN).color(ChatColor.WHITE).append(event.getClickedBlock().getType().name())
.color(ChatColor.GRAY)
.append(" flags: " + block.getBlockState().getType() + " | " + Materials.checkFlag(block.getType(), Materials.COLLIDABLE) + "," +
.append(" flags: " + block.getType() + " | " + block.getType().isSolid() + "," +
Materials.checkFlag(block.getType(), Materials.SOLID) + "," + Materials.checkFlag(block.getType(), Materials.LIQUID))
.color(ChatColor.RED)
.append(" | box=" + BlockData.getData(block.getType()).getBox(player, blockLoc, player.getPlayerVersion()).downCast().stream().map(SimpleCollisionBox::toString).collect(Collectors.joining(", ")))
@@ -107,7 +107,7 @@ public class BBRevealHandler implements Listener {
if(player.isEmpty()) return;
blocks.forEach(blockLoc -> {
var block = player.get().getBlockUpdateHandler().getBlock(blockLoc);
var block = player.get().getWorldTracker().getCurrentWorld().get().getBlock(blockLoc);
var blockBox = BlockData.getData(block.getType())
.getBox(player.get(), blockLoc, player.get().getPlayerVersion());
@@ -1,14 +1,17 @@
package dev.brighten.ac.handler;
import com.github.retrooper.packetevents.protocol.attribute.Attribute;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityPositionSync;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport;
import dev.brighten.ac.Anticheat;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.entity.FakeMob;
import dev.brighten.ac.handler.entity.TrackedEntity;
@@ -18,20 +21,15 @@ import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.MillisTimer;
import dev.brighten.ac.utils.world.types.RayCollision;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
@RequiredArgsConstructor
public class EntityLocationHandler {
public class EntityTrackHandler {
private final APlayer data;
@Getter
private Map<Integer, TrackedEntity> trackedEntities = new Int2ObjectArrayMap<>();
private final Timer lastFlying = new MillisTimer();
public Set<Integer> canCreateMob = new HashSet<>();
@@ -43,7 +41,8 @@ public class EntityLocationHandler {
EntityTypes.WITCH, EntityTypes.COW, EntityTypes.CREEPER);
public Optional<Integer> getTargetOfFakeMob(int fakeMobId) {
for (TrackedEntity value : trackedEntities.values()) {
for (TrackedEntity value : data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntities().values()) {
if(value.getFakeMobs().stream().anyMatch(mob -> mob.getEntityId() == fakeMobId)) {
return Optional.of(value.getEntityId());
}
@@ -51,23 +50,6 @@ public class EntityLocationHandler {
return Optional.empty();
}
public Optional<TrackedEntity> getTrackedEntity(int entityId) {
TrackedEntity trackedEntity = trackedEntities.get(entityId);
if(trackedEntity == null) {
var entity = Anticheat.INSTANCE.getWorldInfo(data.getBukkitPlayer().getWorld()).getEntity(entityId);
if(entity.isEmpty()) {
return Optional.empty();
}
KLocation loc = new KLocation(entity.get().getLocation());
trackedEntity = new TrackedEntity(entityId, EntityTypes.PLAYER, loc);
trackedEntities.put(entityId, trackedEntity);
}
return Optional.of(trackedEntity);
}
/**
*
* We are processing PacketPlayInFlying to iterate the tracked entity locations
@@ -81,7 +63,7 @@ public class EntityLocationHandler {
processZombie();
trackedEntities.values().forEach(entity -> {
data.getWorldTracker().getCurrentWorld().get().getTrackedEntities().values().forEach(entity -> {
var oldLoc = entity.getOldEntityLocation();
var newLoc = entity.getNewEntityLocation();
@@ -109,7 +91,8 @@ public class EntityLocationHandler {
* @param packet WrappedOutRelativePosition
*/
void onRelPosition(WPacketPlayOutEntity packet) {
Optional<TrackedEntity> entity = getTrackedEntity(packet.getId());
Optional<TrackedEntity> entity = data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(packet.getId());
if(entity.isEmpty() || !allowedEntityTypes.contains(entity.get().getEntityType())) return;
@@ -132,7 +115,8 @@ public class EntityLocationHandler {
}
void onPositionSync(WrapperPlayServerEntityPositionSync packet) {
Optional<TrackedEntity> entity = getTrackedEntity(packet.getId());
Optional<TrackedEntity> entity = data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(packet.getId());
if(entity.isEmpty() || !allowedEntityTypes.contains(entity.get().getEntityType())) return;
@@ -161,7 +145,8 @@ public class EntityLocationHandler {
* @param packet WrappedOutEntityTeleportPacket
*/
void onTeleportSent(WrapperPlayServerEntityTeleport packet) {
Optional<TrackedEntity> entity = getTrackedEntity(packet.getEntityId());
Optional<TrackedEntity> entity = data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(packet.getEntityId());
if(entity.isEmpty() || !allowedEntityTypes.contains(entity.get().getEntityType())) return;
@@ -205,6 +190,28 @@ public class EntityLocationHandler {
});
}
void updateAttributes(WrapperPlayServerUpdateAttributes attributes) {
data.runKeepaliveAction(ka -> {
TrackedEntity tracked = data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(attributes.getEntityId()).orElse(null);
if(tracked == null) return;
for (WrapperPlayServerUpdateAttributes.Property property : attributes.getProperties()) {
Attribute attribute = property.getAttribute();
if(attributes.getEntityId() == data.getBukkitPlayer().getEntityId() && attribute == Attributes.MOVEMENT_SPEED) {
ValuedAttribute value = tracked.getAttribute(attribute);
value.updateAttribute(property);
data.getInfo().setWalkSpeed(value.getValue());
}
tracked.updateAttribute(property);
}
});
}
/**
*
* We are running an action when a transaction is received. If the Entity provided is currently a target,
@@ -239,8 +246,10 @@ public class EntityLocationHandler {
}
public void removeFakeMob(int id) {
if(trackedEntities.containsKey(id)) {
List<FakeMob> mobs = getTrackedEntity(id).map(TrackedEntity::getFakeMobs).orElse(new ArrayList<>());
if(data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntities().containsKey(id)) {
List<FakeMob> mobs = data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(id).map(TrackedEntity::getFakeMobs).orElse(new ArrayList<>());
for (FakeMob mob : mobs) {
mob.despawn();
@@ -256,9 +265,11 @@ public class EntityLocationHandler {
private void createFakeMob(int entityId, KLocation location) {
if (!canCreateMob.contains(entityId)) return;
Optional<TrackedEntity> trackedEntity = getTrackedEntity(entityId);
Optional<TrackedEntity> trackedEntity = data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(entityId);
Optional<TrackedEntity> playerEntity = getTrackedEntity(data.getBukkitPlayer().getEntityId());
Optional<TrackedEntity> playerEntity = data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(data.getBukkitPlayer().getEntityId());
if(trackedEntity.isEmpty() || playerEntity.isEmpty()) return;
@@ -281,7 +292,7 @@ public class EntityLocationHandler {
RayCollision collision = new RayCollision(eyeLoc.toVector(), eyeLoc.getDirection());
Vector point = collision.collisionPoint(0.4);
Vector3d point = collision.collisionPoint(0.4);
FakeMob mob = new FakeMob(EntityTypes.SLIME);
List<EntityData<?>> types = new ArrayList<>();
@@ -298,7 +309,8 @@ public class EntityLocationHandler {
}
public void processZombie() {
List<FakeMob> fakeMobs = getTrackedEntity(data.getBukkitPlayer().getEntityId())
List<FakeMob> fakeMobs = data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(data.getBukkitPlayer().getEntityId())
.map(TrackedEntity::getFakeMobs)
.orElse(new ArrayList<>());
@@ -312,7 +324,7 @@ public class EntityLocationHandler {
RayCollision collision = new RayCollision(eyeLoc.toVector(), eyeLoc.getDirection());
Vector point = collision.collisionPoint(0.4);
Vector3d point = collision.collisionPoint(0.4);
fakeMob.teleport(point.getX(), point.getY(), point.getZ(), 0 ,0);
break;
@@ -321,7 +333,8 @@ public class EntityLocationHandler {
}
public void processFakeMobs(int entityId, boolean rel, double x, double y, double z) {
List<FakeMob> fakeMobs = getTrackedEntity(entityId).map(TrackedEntity::getFakeMobs).orElse(new ArrayList<>());
List<FakeMob> fakeMobs = data.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(entityId).map(TrackedEntity::getFakeMobs).orElse(new ArrayList<>());
if(fakeMobs.isEmpty()) {
if(!rel) {
@@ -3,6 +3,7 @@ package dev.brighten.ac.handler;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import com.github.retrooper.packetevents.protocol.teleport.RelativeFlag;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@@ -12,13 +13,13 @@ import dev.brighten.ac.compat.CompatHandler;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.data.obj.CMove;
import dev.brighten.ac.utils.*;
import dev.brighten.ac.utils.math.IntVector;
import dev.brighten.ac.utils.objects.evicting.EvictingList;
import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.TickTimer;
import dev.brighten.ac.utils.world.CollisionBox;
import dev.brighten.ac.utils.world.types.RayCollision;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.val;
@@ -30,9 +31,6 @@ import me.hydro.emulator.util.Vector;
import me.hydro.emulator.util.mcp.MathHelper;
import me.hydro.emulator.util.mcp.MathHelper.FastMathType;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
import java.util.*;
@@ -87,21 +85,14 @@ public class MovementHandler {
private final Timer lastCinematic = new TickTimer(2);
private final Timer lastReset = new TickTimer(2);
private final EvictingList<Integer> sensitivitySamples = new EvictingList<>(50);
private boolean modernMovement;
private final boolean modernMovement;
public MovementHandler(APlayer player) {
this.player = player;
Player bplayer = player.getBukkitPlayer();
// Initializing player location
to.setWorld(bplayer.getWorld());
to.getLoc().setX(bplayer.getLocation().getX());
to.getLoc().setY(bplayer.getLocation().getY());
to.getLoc().setZ(bplayer.getLocation().getZ());
to.getLoc().setYaw(bplayer.getLocation().getYaw());
to.getLoc().setPitch(bplayer.getLocation().getPitch());
to.setBox(new SimpleCollisionBox(to.getLoc(), 0.6, 1.8));
to.setOnGround(bplayer.isOnGround());
to.setOnGround(false);
// Setting from as same location as to
from.setLoc(to);
@@ -123,31 +114,32 @@ public class MovementHandler {
*/
final PotionEffect[] EFFECTS = new PotionEffect[3];
for (org.bukkit.potion.PotionEffect potionEffect : player.getPotionHandler().potionEffects) {
if (potionEffect.getType().equals(PotionEffectType.SPEED)) {
for (KPotionEffect potionEffect : player.getPotionHandler().getPotionEffects()) {
if (potionEffect.potionType().equals(PotionTypes.SPEED)) {
EFFECTS[0] = PotionEffect.builder()
.amplifier(potionEffect.getAmplifier())
.amplifier(potionEffect.properties().amplifier())
.type(me.hydro.emulator.util.PotionEffectType.SPEED)
.build();
} else if (potionEffect.getType().equals(PotionEffectType.SLOW)) {
} else if (potionEffect.potionType().equals(PotionTypes.SLOWNESS)) {
EFFECTS[1] = PotionEffect.builder()
.amplifier(potionEffect.getAmplifier())
.amplifier(potionEffect.properties().amplifier())
.type(me.hydro.emulator.util.PotionEffectType.SLOW)
.build();
} else if (potionEffect.getType().equals(PotionEffectType.JUMP)) {
} else if (potionEffect.potionType().equals(PotionTypes.JUMP_BOOST)) {
EFFECTS[2] = PotionEffect.builder()
.amplifier(potionEffect.getAmplifier())
.amplifier(potionEffect.properties().amplifier())
.type(me.hydro.emulator.util.PotionEffectType.JUMP)
.build();
}
}
if(player.EMULATOR.getTags().contains("003") && !isZeroThree) {
if (player.EMULATOR.getTags().contains("003") && !isZeroThree) {
runEmulation(to, true);
}
IterationResult minimum = null;
iteration: {
iteration:
{
for (KLocation posLoc : new ArrayList<>(posLocs)) {
// Resetting to prevent lag issues.
@@ -157,7 +149,7 @@ public class MovementHandler {
if (minimum == null || minimum.getOffset() > result.getOffset()) {
minimum = result;
if(minimum.getOffset() < 1E-26) {
if (minimum.getOffset() < 1E-26) {
// The player teleported, therefore we don't need to continue with predictions.
break iteration;
}
@@ -171,96 +163,95 @@ public class MovementHandler {
Motion previousMotion = player.EMULATOR.getMotion().clone();
for (int forward : isZeroThree ? new int[] {0} : FULL_RANGE) {
for (int strafe : isZeroThree ? new int[] {0} : FULL_RANGE) {
for (int forward : isZeroThree ? new int[]{0} : FULL_RANGE) {
for (int strafe : isZeroThree ? new int[]{0} : FULL_RANGE) {
for (boolean jumping : getJumpingIterations()) {
for (boolean sprinting : getSprintingIterations(forward)) {
for (boolean usingItem : getUsingItemIterations(forward, strafe)) {
for (boolean hitSlow : getHitSlowIterations()) {
for (FastMathType fastMath : getFastMathIterations(forward, strafe)) {
for(Vector3d possibleVector : possibleVelocity) {
IterationInput input = IterationInput.builder()
.jumping(jumping)
.forward(forward)
.strafing(strafe)
.sprinting(sprinting)
.usingItem(usingItem)
.modernMovement(modernMovement)
.hitSlowdown(hitSlow)
.aiMoveSpeed(player.getBukkitPlayer().getWalkSpeed() / 2)
.fastMathType(fastMath)
.sneaking(player.getInfo().isSneaking())
.ground(from.isOnGround())
.to(new Vector(to.getX(), to.getY(), to.getZ()))
.yaw(to.getYaw())
.lastReportedBoundingBox(from.getBox().toNeo())
.effectSpeed(EFFECTS[0])
.effectSlow(EFFECTS[1])
.waitingForTeleport(!posLocs.isEmpty())
.effectJump(EFFECTS[2]).build();
for (boolean usingItem : getUsingItemIterations(forward, strafe)) {
for (boolean hitSlow : getHitSlowIterations()) {
for (FastMathType fastMath : getFastMathIterations(forward, strafe)) {
for (Vector3d possibleVector : possibleVelocity) {
IterationInput input = IterationInput.builder()
.jumping(jumping)
.forward(forward)
.strafing(strafe)
.sprinting(sprinting)
.usingItem(usingItem)
.modernMovement(modernMovement)
.hitSlowdown(hitSlow)
.aiMoveSpeed(player.getBukkitPlayer().getWalkSpeed() / 2)
.fastMathType(fastMath)
.sneaking(player.getInfo().sneaking)
.ground(from.isOnGround())
.to(new Vector(to.getX(), to.getY(), to.getZ()))
.yaw(to.getYaw())
.lastReportedBoundingBox(from.getBox().toNeo())
.effectSpeed(EFFECTS[0])
.effectSlow(EFFECTS[1])
.waitingForTeleport(!posLocs.isEmpty())
.effectJump(EFFECTS[2]).build();
boolean isVelocity = false;
if(possibleVector != null) {
// Setting the motion to the possible velocity vector.
player.EMULATOR.getMotion().setMotionX(possibleVector.getX());
player.EMULATOR.getMotion().setMotionY(possibleVector.getY());
player.EMULATOR.getMotion().setMotionZ(possibleVector.getZ());
// Has to be this way because order of operations in the emulator.
isVelocity = true;
} else {
// Resetting the motion to the previous motion.
player.EMULATOR.getMotion().setMotionX(previousMotion.getMotionX());
player.EMULATOR.getMotion().setMotionY(previousMotion.getMotionY());
player.EMULATOR.getMotion().setMotionZ(previousMotion.getMotionZ());
}
boolean isVelocity = false;
if (possibleVector != null) {
// Setting the motion to the possible velocity vector.
player.EMULATOR.getMotion().setMotionX(possibleVector.getX());
player.EMULATOR.getMotion().setMotionY(possibleVector.getY());
player.EMULATOR.getMotion().setMotionZ(possibleVector.getZ());
// Has to be this way because order of operations in the emulator.
isVelocity = true;
} else {
// Resetting the motion to the previous motion.
player.EMULATOR.getMotion().setMotionX(previousMotion.getMotionX());
player.EMULATOR.getMotion().setMotionY(previousMotion.getMotionY());
player.EMULATOR.getMotion().setMotionZ(previousMotion.getMotionZ());
}
IterationResult result = player.EMULATOR.runIteration(input);
IterationResult result = player.EMULATOR.runIteration(input);
if(isVelocity) {
result.getTags().add("velocity");
}
if (isVelocity) {
result.getTags().add("velocity");
}
if(fastMath == FastMathType.FAST_LEGACY) {
result.getTags().add("fast_legacy");
} else if(fastMath == FastMathType.VANILLA) {
result.getTags().add("vanilla");
} else if(fastMath == FastMathType.FAST_NEW) {
result.getTags().add("fast_new");
} else if(fastMath == FastMathType.MODERN_VANILLA) {
result.getTags().add("modern_vanilla");
}
if (fastMath == FastMathType.FAST_LEGACY) {
result.getTags().add("fast_legacy");
} else if (fastMath == FastMathType.VANILLA) {
result.getTags().add("vanilla");
} else if (fastMath == FastMathType.FAST_NEW) {
result.getTags().add("fast_new");
} else if (fastMath == FastMathType.MODERN_VANILLA) {
result.getTags().add("modern_vanilla");
}
if(forward > 0) {
result.getTags().add("w-key");
} else if(forward < 0) {
result.getTags().add("s-key");
}
if (forward > 0) {
result.getTags().add("w-key");
} else if (forward < 0) {
result.getTags().add("s-key");
}
if(strafe > 0) {
result.getTags().add("d-key");
} else if(strafe < 0) {
result.getTags().add("a-key");
}
if (strafe > 0) {
result.getTags().add("d-key");
} else if (strafe < 0) {
result.getTags().add("a-key");
}
if (minimum == null || minimum.getOffset() > result.getOffset()) {
minimum = result;
if (minimum == null || minimum.getOffset() > result.getOffset()) {
minimum = result;
if (minimum.getOffset() < 1E-26) {
break iteration;
if (minimum.getOffset() < 1E-26) {
break iteration;
}
}
}
}
}
}
}
}
}
}
}
}
if(minimum != null) {
if (minimum != null) {
predicted = minimum.getPredicted();
double mx = player.EMULATOR.getMotion().getMotionX();
@@ -269,7 +260,7 @@ public class MovementHandler {
double total = mx * mx + my * my + mz * mz;
if(total < 9E-4) {
if (total < 9E-4) {
player.getInfo().lastCanceledFlying.reset();
minimum.getTags().add("003");
}
@@ -282,11 +273,11 @@ public class MovementHandler {
}
player.EMULATOR.confirm(minimum.getIteration());
if(minimum.getTags().contains("003")) {
if (minimum.getTags().contains("003")) {
player.EMULATOR.getTags().add("003");
}
if(minimum.getTags().contains("bad_offset")) {
if (minimum.getTags().contains("bad_offset")) {
player.EMULATOR.setLastReportedBoundingBox(getTo().getBox().toNeo());
}
}
@@ -294,7 +285,7 @@ public class MovementHandler {
private FastMathType[] getFastMathIterations(int strafe, int forward) {
// Because no movement is being applied, there is no angle calculation being done
if(strafe == 0 && forward == 0) {
if (strafe == 0 && forward == 0) {
return new FastMathType[]{FastMathType.FAST_LEGACY};
}
@@ -317,7 +308,9 @@ public class MovementHandler {
private boolean[] getUsingItemIterations(int forward, int strafe) {
return (forward == 0 && strafe == 0 ||
!BlockUtils.isUsable(player.getBukkitPlayer().getItemInHand().getType())) ? ALWAYS_FALSE : IS_OR_NOT;
!BlockUtils.isUsable(player.getPlayerVersion(),
SpigotConversionUtil.fromBukkitItemMaterial(player.getBukkitPlayer().getInventory().getItemInHand().getType())))
? ALWAYS_FALSE : IS_OR_NOT;
}
private boolean[] getJumpingIterations() {
@@ -336,13 +329,13 @@ public class MovementHandler {
&& player.getPlayerVersion().isNewerThanOrEquals(ClientVersion.V_1_17);
checkMovement = teleportsToConfirm == 0 && posLocs.isEmpty();
if (checkMovement) {
moveTicks++;
if (!packet.hasPositionChanged()) moveTicks = 1;
} else moveTicks = 0;
if(excuseNextFlying) {
if (excuseNextFlying) {
return;
}
@@ -359,10 +352,10 @@ public class MovementHandler {
if (moveTicks > 0) {
// Updating block locations
player.getInfo().setBlockOnTo(Optional.of(player.getBlockUpdateHandler()
.getBlock(new IntVector(to.getLoc()))));
player.getInfo().setBlockBelow(Optional.of(player.getBlockUpdateHandler()
.getBlock(new IntVector(to.getLoc().clone().subtract(0, 1, 0)))));
player.getInfo().setBlockOnTo(Optional.of(player.getWorldTracker()
.getBlock(to.getLoc().toVector3i())));
player.getInfo().setBlockBelow(Optional.of(player.getWorldTracker()
.getBlock(to.getLoc().clone().subtract(0, 1, 0).clone().toVector3i())));
if (packet.hasPositionChanged()) {
// Updating player bounding box
@@ -486,7 +479,7 @@ public class MovementHandler {
player.getInfo().setWasOnSlime(player.getBlockInfo().onSlime);
groundTicks++;
airTicks = 0;
player.getInfo().groundJumpBoost = player.getPotionHandler().getEffectByType(PotionEffectType.JUMP);
player.getInfo().groundJumpBoost = player.getPotionHandler().getEffectByType(PotionTypes.JUMP_BOOST);
} else {
player.getInfo().groundJumpBoost = Optional.empty();
airTicks++;
@@ -503,7 +496,7 @@ public class MovementHandler {
.anyMatch(capability -> capability.canFly));
boolean hasLevitation = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)
&& player.getPotionHandler().hasPotionEffect(XPotion.LEVITATION.getPotionEffectType());
&& player.getPotionHandler().hasPotionEffect(PotionTypes.LEVITATION);
player.getInfo().setRiptiding(CompatHandler.getINSTANCE().isRiptiding(player.getBukkitPlayer()));
player.getInfo().setGliding(CompatHandler.getINSTANCE().isGliding(player.getBukkitPlayer()));
@@ -570,7 +563,7 @@ it
// generate a method that processes velocityHistory and compares to current deltaY.
private void processVelocity() {
//Iterate through player.getInfo().getVelocityHistory() and compare to current deltaY.
if(player.getInfo().isDoingVelocity()) {
if (player.getInfo().isDoingVelocity()) {
player.getInfo().getVelocity().reset();
}
synchronized (player.getInfo().getVelocityHistory()) {
@@ -590,22 +583,22 @@ it
}
private void processBotMove(WrapperPlayClientPlayerFlying packet) {
if(player.getMob() == null) return;
if (player.getMob() == null) return;
if (packet.hasPositionChanged() || packet.hasRotationChanged()) {
KLocation origin = to.getLoc().clone().add(0, 1.7, 0);
final double MULTIPLIER = Math.max(-0.5, Math.min(-1, -1 / (Math.abs(deltaYaw) * 0.25)));
RayCollision coll = new RayCollision(origin.toVector(), origin.getDirection()
.multiply(MULTIPLIER).setY(0));
.multiply(MULTIPLIER).withY(0));
Location loc1 = coll.collisionPoint(1.5).toLocation(player.getBukkitPlayer().getWorld());
KLocation loc1 = new KLocation(coll.collisionPoint(1.5));
if (player.getInfo().botAttack.isNotPassed(7)) {
loc1.setY(Math.max(origin.getY() + 2, loc1.getY()));
player.getMob().teleport(loc1.getX(), loc1.getY(), loc1.getZ(), loc1.getYaw(), loc1.getPitch());
} else {
loc1.setY(Math.max(origin.getY() + 0.6, loc1.getY()));
if(Math.random() > 0.2)
if (Math.random() > 0.2)
Anticheat.INSTANCE.getRunUtils().taskLaterAsync(() -> player.getMob()
.teleport(loc1.getX(), loc1.getY(), loc1.getZ(), loc1.getYaw(), loc1.getPitch()), 5);
}
@@ -661,7 +654,7 @@ it
public void runPositionHackFix() {
if (sentPositionUpdate) return;
player.sendPacket(new WrapperPlayServerPlayerPositionAndLook(0, Vector3d.zero(), new Vector3d(0,0,0), 0, 0,
player.sendPacket(new WrapperPlayServerPlayerPositionAndLook(0, Vector3d.zero(), new Vector3d(0, 0, 0), 0, 0,
relFlags));
player.getBukkitPlayer().sendMessage("§c[Anticheat] §7Position update sent to fix movement issues.");
@@ -725,10 +718,10 @@ it
packet.getYaw(), packet.getPitch());
if (packet.getRelativeFlags().has(RelativeFlag.X)) {
loc.add(player.getMovement().getTo().getLoc().getX(), 0 ,0);
loc.add(player.getMovement().getTo().getLoc().getX(), 0, 0);
}
if (packet.getRelativeFlags().has(RelativeFlag.Y)) {
loc.add(0, player.getMovement().getTo().getLoc().getY() ,0);
loc.add(0, player.getMovement().getTo().getLoc().getY(), 0);
}
if (packet.getRelativeFlags().has(RelativeFlag.Z)) {
loc.add(0, 0, player.getMovement().getTo().getLoc().getZ());
@@ -743,7 +736,6 @@ it
teleportsToConfirm++;
loc.setTimeStamp(System.currentTimeMillis());
player.runKeepaliveAction(ka -> {
teleportsToConfirm--;
@@ -762,7 +754,7 @@ it
*
* @param location Location
*/
public void moveTo(Location location) {
public void moveTo(KLocation location) {
KLocation newLoc = new KLocation(location);
to.getLoc().setLocation(newLoc);
to.getLoc().setLocation(newLoc);
@@ -814,7 +806,7 @@ it
* @param packet WrapperPlayClientPlayerFlyingh
*/
private void setTo(WrapperPlayClientPlayerFlying packet) {
to.setWorld(player.getBukkitPlayer().getWorld());
to.setWorld(player.getWorldTracker().getCurrentWorld().get());
if (packet.hasPositionChanged()) {
to.getLoc().setX(packet.getLocation().getX());
to.getLoc().setY(packet.getLocation().getY());
@@ -18,6 +18,8 @@ import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.data.info.PlayerInput;
import dev.brighten.ac.data.obj.Pose;
import dev.brighten.ac.handler.entity.FakeMob;
import dev.brighten.ac.handler.entity.TrackedEntity;
import dev.brighten.ac.packet.PlayerCapabilities;
@@ -26,10 +28,7 @@ import dev.brighten.ac.packet.WPacketPlayOutEntity;
import dev.brighten.ac.utils.BlockUtils;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.MovementUtils;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import lombok.val;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import java.util.Optional;
@@ -38,13 +37,14 @@ public class PacketHandler {
public boolean processReceive(APlayer player, PacketReceiveEvent event) {
long timestamp = System.currentTimeMillis();
Object wrapped;
if (event.getPacketType().equals(PacketType.Play.Client.PONG)
|| event.getPacketType().equals(PacketType.Play.Client.WINDOW_CONFIRMATION)) {
boolean cancel = false;
if (event.getPacketType().equals(PacketType.Play.Client.PONG) || event.getPacketType().equals(PacketType.Play.Client.WINDOW_CONFIRMATION)) {
TransactionClientWrapper packet = new TransactionClientWrapper(event);
wrapped = packet;
if(packet.getId() == 0) {
if (packet.getId() == 0) {
if (Anticheat.INSTANCE.getKeepaliveProcessor().keepAlives.get(packet.getAction()) != null) {
Anticheat.INSTANCE.getKeepaliveProcessor().addResponse(player, packet.getAction());
@@ -68,7 +68,7 @@ public class PacketHandler {
synchronized (player.instantTransaction) {
var iterator = player.instantTransaction.keySet().iterator();
while(iterator.hasNext()) {
while (iterator.hasNext()) {
Short key = iterator.next();
if (key > ka.id) {
@@ -96,7 +96,7 @@ public class PacketHandler {
synchronized (player.keepAliveLock) {
player.keepAliveStamps.removeIf(action -> {
if(action.stamp > ka.id) {
if (action.stamp > ka.id) {
return false;
}
@@ -110,10 +110,17 @@ public class PacketHandler {
Optional.ofNullable(player.instantTransaction.remove(packet.getAction()))
.ifPresent(t -> t.two.accept(t.one));
}
} else if(event.getPacketType().equals(PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION)
|| event.getPacketType().equals(PacketType.Play.Client.PLAYER_POSITION)
|| event.getPacketType().equals(PacketType.Play.Client.PLAYER_ROTATION)
|| event.getPacketType().equals(PacketType.Play.Client.PLAYER_FLYING)) {
} else if (event.getPacketType().equals(PacketType.Play.Client.PLAYER_INPUT)) {
WrapperPlayClientPlayerInput packet = new WrapperPlayClientPlayerInput(event);
wrapped = packet;
player.getInfo().setSprinting(packet.isSprint());
player.getInfo().setSneaking(packet.isShift());
player.getInfo().setPlayerInput(PlayerInput.getFromPacket(packet));
player.getBukkitPlayer().sendMessage("packet: " + packet.isForward());
} else if (event.getPacketType().equals(PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION) || event.getPacketType().equals(PacketType.Play.Client.PLAYER_POSITION) || event.getPacketType().equals(PacketType.Play.Client.PLAYER_ROTATION) || event.getPacketType().equals(PacketType.Play.Client.PLAYER_FLYING)) {
WrapperPlayClientPlayerFlying packet = new WrapperPlayClientPlayerFlying(event);
wrapped = packet;
if (player.getMovement().isExcuseNextFlying()) {
@@ -127,7 +134,7 @@ public class PacketHandler {
player.getLagInfo().setLastFlying(timestamp);
player.getEntityLocationHandler().onFlying();
player.getEntityTrackHandler().onFlying();
if (player.getPlayerVersion().isNewerThanOrEquals(ClientVersion.V_1_17)
&& packet.hasPositionChanged() && packet.hasRotationChanged()
@@ -145,17 +152,17 @@ public class PacketHandler {
player.getVelocityHandler().onFlyingPost(packet);
return result;
} else if(event.getPacketType().equals(PacketType.Play.Client.STEER_VEHICLE)) {
} else if (event.getPacketType().equals(PacketType.Play.Client.STEER_VEHICLE)) {
WrapperPlayClientSteerVehicle packet = new WrapperPlayClientSteerVehicle(event);
wrapped = packet;
// Check for isUnmount()
if (player.getBukkitPlayer().isInsideVehicle() && packet.isUnmount()) {
if (player.getInfo().isInVehicle() && packet.isUnmount()) {
player.getInfo().getVehicleSwitch().reset();
player.getInfo().setInVehicle(false);
}
} else if(event.getPacketType().equals(PacketType.Play.Client.ENTITY_ACTION)) {
} else if (event.getPacketType().equals(PacketType.Play.Client.ENTITY_ACTION)) {
WrapperPlayClientEntityAction packet = new WrapperPlayClientEntityAction(event);
wrapped = packet;
@@ -178,13 +185,13 @@ public class PacketHandler {
break;
}
case START_FLYING_WITH_ELYTRA: {
if(player.isGlidePossible()) {
if (player.isGlidePossible()) {
player.getInfo().setGliding(true);
}
break;
}
}
} else if(event.getPacketType().equals(PacketType.Play.Client.INTERACT_ENTITY)) {
} else if (event.getPacketType().equals(PacketType.Play.Client.INTERACT_ENTITY)) {
WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
wrapped = packet;
@@ -192,39 +199,44 @@ public class PacketHandler {
FakeMob mob = Anticheat.INSTANCE.getFakeTracker().getEntityById(packet.getEntityId());
if (packet.getAction() == WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
if (player.hitsToCancel > 0) {
player.hitsToCancel--;
cancel = true;
}
if (mob != null) {
player.getEntityLocationHandler().getTargetOfFakeMob(mob.getEntityId())
player.getEntityTrackHandler().getTargetOfFakeMob(mob.getEntityId())
.ifPresent(targetId -> {
player.getEntityLocationHandler().removeFakeMob(targetId);
player.getEntityTrackHandler().removeFakeMob(targetId);
player.getInfo().lastFakeBotHit.reset();
});
if (player.getMob().getEntityId() == packet.getEntityId()) {
player.getInfo().botAttack.reset();
}
} else {
Optional<Entity> target = Anticheat.INSTANCE.getWorldInfo(player.getBukkitPlayer().getWorld()).getEntity(packet.getEntityId());
Optional<TrackedEntity> target = player.getWorldTracker().getCurrentWorld().get()
.getTrackedEntity(packet.getEntityId());
if(target.isPresent() && target.get() instanceof LivingEntity entity) {
if (target.isPresent() && target.get().getEntityType().isInstanceOf(EntityTypes.LIVINGENTITY)) {
if (player.getInfo().lastFakeBotHit.isPassed(400) && Math.random() > 0.9) {
player.getEntityLocationHandler().canCreateMob.add(entity.getEntityId());
player.getEntityTrackHandler().canCreateMob.add(target.get().getEntityId());
}
player.getInfo().setTarget(entity);
player.getInfo().setTarget(target.get());
}
}
player.getInfo().lastAttack.reset();
}
} else if(event.getPacketType().equals(PacketType.Play.Client.ANIMATION)) {
} else if (event.getPacketType().equals(PacketType.Play.Client.ANIMATION)) {
WrapperPlayClientAnimation packet = new WrapperPlayClientAnimation(event);
wrapped = packet;
if(packet.getHand() == InteractionHand.MAIN_HAND) {
if (packet.getHand() == InteractionHand.MAIN_HAND) {
long delta = timestamp - player.getInfo().lastArmSwing;
player.getInfo().cps.add(1000D / delta, timestamp);
player.getInfo().lastArmSwing = timestamp;
}
} else if(event.getPacketType().equals(PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT)) {
} else if (event.getPacketType().equals(PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT)) {
WrapperPlayClientPlayerBlockPlacement packet = new WrapperPlayClientPlayerBlockPlacement(event);
wrapped = packet;
@@ -236,19 +248,19 @@ public class PacketHandler {
// Used item
if (pos.getX() == -1 && (pos.getY() == 255 | pos.getY() == -1) && pos.getZ() == -1
&& stack.isPresent()
&& BlockUtils.isUsable(SpigotConversionUtil.toBukkitItemMaterial(stack.get().getType()))) {
&& BlockUtils.isUsable(player.getPlayerVersion(), stack.get().getType())) {
player.getInfo().getLastUseItem().reset();
}
player.getBlockUpdateHandler().onPlace(packet);
} else if(event.getPacketType().equals(PacketType.Play.Client.PLAYER_DIGGING)) {
player.getWorldTracker().onPlace(packet);
} else if (event.getPacketType().equals(PacketType.Play.Client.PLAYER_DIGGING)) {
WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
wrapped = packet;
player.getInfo().getLastBlockDig().reset();
player.getBlockUpdateHandler().onDig(packet);
} else if(event.getPacketType().equals(PacketType.Play.Client.CLIENT_STATUS)) {
player.getWorldTracker().onDig(packet);
} else if (event.getPacketType().equals(PacketType.Play.Client.CLIENT_STATUS)) {
WrapperPlayClientClientStatus packet = new WrapperPlayClientClientStatus(event);
wrapped = packet;
@@ -258,10 +270,10 @@ public class PacketHandler {
player.getInfo().lastInventoryOpen.reset();
return false;
}
} else if(event.getPacketType().equals(PacketType.Play.Client.CLOSE_WINDOW)) {
} else if (event.getPacketType().equals(PacketType.Play.Client.CLOSE_WINDOW)) {
wrapped = new WrapperPlayClientCloseWindow(event);
player.getInfo().setInventoryOpen(false);
} else if(event.getPacketType() == PacketType.Play.Client.PLUGIN_MESSAGE) {
} else if (event.getPacketType().equals(PacketType.Play.Client.PLUGIN_MESSAGE)) {
WrapperPlayClientPluginMessage packet = new WrapperPlayClientPluginMessage(event);
wrapped = packet;
@@ -286,7 +298,7 @@ public class PacketHandler {
+ ": " + wrapped);
}
return player.getCheckHandler().callSyncPacket(wrapped, timestamp);
return cancel || player.getCheckHandler().callSyncPacket(wrapped, timestamp);
}
public boolean processSend(APlayer player, PacketSendEvent event) {
@@ -309,30 +321,36 @@ public class PacketHandler {
player.getInfo().getPossibleCapabilities().clear();
}
}, true);
} else if(event.getPacketType() == PacketType.Play.Server.UPDATE_ATTRIBUTES) {
WrapperPlayServerUpdateAttributes packet = new WrapperPlayServerUpdateAttributes(event);
wrapped = packet;
player.getEntityTrackHandler().updateAttributes(packet);
} else if(event.getPacketType() == PacketType.Play.Server.BLOCK_CHANGE) {
WrapperPlayServerBlockChange packet = new WrapperPlayServerBlockChange(event);
wrapped = packet;
player.getBlockUpdateHandler().runUpdate(packet);
player.getWorldTracker().runUpdate(packet);
} else if(event.getPacketType() == PacketType.Play.Server.MULTI_BLOCK_CHANGE) {
WrapperPlayServerMultiBlockChange packet = new WrapperPlayServerMultiBlockChange(event);
wrapped = packet;
player.getBlockUpdateHandler().runUpdate(packet);
player.getWorldTracker().runUpdate(packet);
} else if(event.getPacketType() == PacketType.Play.Server.CHUNK_DATA) {
WrapperPlayServerChunkData packet = new WrapperPlayServerChunkData(event);
wrapped = packet;
player.getBlockUpdateHandler().runUpdate(packet);
player.getWorldTracker().runUpdate(packet);
} else if(event.getPacketType() == PacketType.Play.Server.MAP_CHUNK_BULK) {
WrapperPlayServerChunkDataBulk packet = new WrapperPlayServerChunkDataBulk(event);
wrapped = packet;
player.getBlockUpdateHandler().runUpdate(packet);
player.getWorldTracker().runUpdate(packet);
} else if(event.getPacketType() == PacketType.Play.Server.ENTITY_EFFECT) {
WrapperPlayServerEntityEffect packet = new WrapperPlayServerEntityEffect(event);
@@ -394,18 +412,19 @@ public class PacketHandler {
} else if(event.getPacketType() == PacketType.Play.Server.RESPAWN) {
wrapped = new WrapperPlayServerRespawn(event);
if(player.getPlayerVersion().isOlderThan(ClientVersion.V_1_14)) {
player.runKeepaliveAction(k -> player.getBukkitPlayer().setSprinting(false), 1);
player.runKeepaliveAction(k -> player.getInfo().setSprinting(false), 1);
}
player.runKeepaliveAction(ka -> player.getInfo().lastRespawn.reset());
player.runKeepaliveAction(ka -> player.getBlockUpdateHandler()
.setMinHeight(player.getDimensionType()));
player.runKeepaliveAction(ka -> {
player.getInfo().lastRespawn.reset();
player.getInfo().setPose(Pose.STANDING);
});
player.runKeepaliveAction(ka -> player.getWorldTracker()
.onRespawn((WrapperPlayServerRespawn) wrapped));
} else if(event.getPacketType() == PacketType.Play.Server.PLAYER_POSITION_AND_LOOK) {
WrapperPlayServerPlayerPositionAndLook packet = new WrapperPlayServerPlayerPositionAndLook(event);
wrapped = packet;
player.runKeepaliveAction(ka ->
player.getBlockUpdateHandler().setMinHeight(player.getDimensionType()));
player.getMovement().addPosition(packet);
} else if(event.getPacketType() == PacketType.Play.Server.ATTACH_ENTITY) {
WrapperPlayServerAttachEntity packet = new WrapperPlayServerAttachEntity(event);
@@ -423,37 +442,37 @@ public class PacketHandler {
wrapped = packet;
player.getEntityLocationHandler().onEntityDestroy(packet);
player.getEntityTrackHandler().onEntityDestroy(packet);
} else if(event.getPacketType() == PacketType.Play.Server.ENTITY_TELEPORT) {
WrapperPlayServerEntityTeleport packet = new WrapperPlayServerEntityTeleport(event);
wrapped = packet;
player.getEntityLocationHandler().onTeleportSent(packet);
player.getEntityTrackHandler().onTeleportSent(packet);
} else if(event.getPacketType() == PacketType.Play.Server.ENTITY_MOVEMENT) {
WrapperPlayServerEntityMovement packet = new WrapperPlayServerEntityMovement(event);
wrapped = packet;
player.getEntityLocationHandler().onRelPosition(new WPacketPlayOutEntity(packet));
player.getEntityTrackHandler().onRelPosition(new WPacketPlayOutEntity(packet));
} else if(event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE) {
WrapperPlayServerEntityRelativeMove packet = new WrapperPlayServerEntityRelativeMove(event);
wrapped = packet;
player.getEntityLocationHandler().onRelPosition(new WPacketPlayOutEntity(packet));
player.getEntityTrackHandler().onRelPosition(new WPacketPlayOutEntity(packet));
} else if(event.getPacketType() == PacketType.Play.Server.ENTITY_ROTATION) {
WrapperPlayServerEntityRotation packet = new WrapperPlayServerEntityRotation(event);
wrapped = packet;
player.getEntityLocationHandler().onRelPosition(new WPacketPlayOutEntity(packet));
player.getEntityTrackHandler().onRelPosition(new WPacketPlayOutEntity(packet));
} else if(event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE_AND_ROTATION) {
WrapperPlayServerEntityRelativeMoveAndRotation packet = new WrapperPlayServerEntityRelativeMoveAndRotation(event);
wrapped = packet;
player.getEntityLocationHandler().onRelPosition(new WPacketPlayOutEntity(packet));
player.getEntityTrackHandler().onRelPosition(new WPacketPlayOutEntity(packet));
} else if(event.getPacketType() == PacketType.Play.Server.SPAWN_ENTITY) {
WrapperPlayServerSpawnEntity packet = new WrapperPlayServerSpawnEntity(event);
wrapped = packet;
@@ -462,7 +481,7 @@ public class PacketHandler {
double y = packet.getPosition().getY();
double z = packet.getPosition().getZ();
player.getEntityLocationHandler().getTrackedEntities().put(packet.getEntityId(),
player.getWorldTracker().getCurrentWorld().get().getTrackedEntities().put(packet.getEntityId(),
new TrackedEntity(packet.getEntityId(), packet.getEntityType(),
new KLocation(x, y, z, packet.getYaw(), packet.getPitch())));
} else if(event.getPacketType() == PacketType.Play.Server.SPAWN_LIVING_ENTITY) {
@@ -474,7 +493,7 @@ public class PacketHandler {
double y = packet.getPosition().getY();
double z = packet.getPosition().getZ();
player.getEntityLocationHandler().getTrackedEntities().put(packet.getEntityId(),
player.getWorldTracker().getCurrentWorld().get().getTrackedEntities().put(packet.getEntityId(),
new TrackedEntity(packet.getEntityId(), packet.getEntityType(),
new KLocation(x, y, z, packet.getYaw(), packet.getPitch())));
} else if(event.getPacketType() == PacketType.Play.Server.SPAWN_PLAYER) {
@@ -487,7 +506,7 @@ public class PacketHandler {
double z = packet.getPosition().getZ();
player.getEntityLocationHandler().getTrackedEntities().put(packet.getEntityId(),
player.getWorldTracker().getCurrentWorld().get().getTrackedEntities().put(packet.getEntityId(),
new TrackedEntity(packet.getEntityId(), EntityTypes.PLAYER,
new KLocation(x, y, z, packet.getYaw(),packet.getPitch())));
} else if(event.getPacketType() == PacketType.Play.Server.SPAWN_PAINTING) {
@@ -499,14 +518,14 @@ public class PacketHandler {
int y = packet.getPosition().getY();
int z = packet.getPosition().getZ();
player.getEntityLocationHandler().getTrackedEntities().put(packet.getEntityId(),
player.getWorldTracker().getCurrentWorld().get().getTrackedEntities().put(packet.getEntityId(),
new TrackedEntity(packet.getEntityId(), EntityTypes.PAINTING, new KLocation(x, y, z)));
} else if(event.getPacketType() == PacketType.Play.Server.ENTITY_POSITION_SYNC) {
WrapperPlayServerEntityPositionSync packet = new WrapperPlayServerEntityPositionSync(event);
wrapped = packet;
player.getEntityLocationHandler().onPositionSync(packet);
player.getEntityTrackHandler().onPositionSync(packet);
} else if(event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
wrapped = new WrapperPlayServerEntityMetadata(event);
}else if(event.getPacketType() == PacketType.Play.Server.DESTROY_ENTITIES) {
@@ -514,7 +533,7 @@ public class PacketHandler {
wrapped = packet;
player.getEntityLocationHandler().onEntityDestroy(packet);
player.getEntityTrackHandler().onEntityDestroy(packet);
} else if(event.getPacketType() == PacketType.Play.Server.CLOSE_WINDOW) {
wrapped = new WrapperPlayServerCloseWindow(event);
player.runKeepaliveAction(ka -> player.getInfo().setInventoryOpen(false));
@@ -1,59 +1,118 @@
package dev.brighten.ac.handler;
import com.github.retrooper.packetevents.protocol.potion.PotionType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEffect;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.utils.KPotionEffect;
import dev.brighten.ac.utils.KProperties;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class PotionHandler {
private final APlayer data;
public List<PotionEffect> potionEffects = new CopyOnWriteArrayList<>();
private final List<KPotionEffect> potionEffects = new ArrayList<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public PotionHandler(APlayer data) {
public PotionHandler(APlayer data) {
this.data = data;
potionEffects.addAll(data.getBukkitPlayer().getActivePotionEffects());
lock.writeLock().lock();
try {
data.getBukkitPlayer().getActivePotionEffects().stream()
.map(pe ->
new KPotionEffect(
SpigotConversionUtil.fromBukkitPotionEffectType(pe.getType()),
KProperties.fromBukkit(pe)
))
.forEach(potionEffects::add);
} finally {
lock.writeLock().unlock();
}
}
public void onFlying(WrapperPlayClientPlayerFlying packet) {
for (PotionEffect effect : potionEffects) {
if(data.getBukkitPlayer().hasPotionEffect(effect.getType())) continue;
lock.readLock().lock();
try {
for (KPotionEffect effect : potionEffects) {
lock.readLock().lock();
data.runKeepaliveAction(d -> data.getPotionHandler().potionEffects.remove(effect));
try {
if (data.getBukkitPlayer().hasPotionEffect(SpigotConversionUtil.toBukkitPotionEffectType(effect.potionType()))) continue;
data.runKeepaliveAction(d -> {
lock.writeLock().lock();
try {
data.getPotionHandler().potionEffects.remove(effect);
} finally {
lock.writeLock().unlock();
}
});
} finally {
lock.readLock().unlock();
}
}
} finally {
lock.readLock().unlock();
}
}
public void onPotionEffect(WrapperPlayServerEntityEffect packet) {
data.runKeepaliveAction(d -> {
var type = SpigotConversionUtil.toBukkitPotionEffectType(packet.getPotionType());
data.getPotionHandler().potionEffects.stream().filter(pe -> pe.getType().equals(type))
.forEach(data.getPotionHandler().potionEffects::remove);
data.getPotionHandler().potionEffects
.add(new PotionEffect(type, packet.getEffectDurationTicks(), packet.getEffectAmplifier(),
packet.isAmbient()));
var type = packet.getPotionType();
lock.writeLock().lock();
try {
data.getPotionHandler().potionEffects.removeIf(pe -> pe.potionType().equals(type));
data.getPotionHandler().potionEffects
.add(new KPotionEffect(type, new KProperties(packet.getEffectAmplifier()
, packet.getEffectDurationTicks(),
packet.isAmbient(), packet.isVisible(), packet.isShowIcon(), null)));
} finally {
lock.readLock().unlock();
}
});
}
public boolean hasPotionEffect(PotionEffectType type) {
for (PotionEffect potionEffect : potionEffects) {
if(potionEffect.getType().equals(type))
return true;
public boolean hasPotionEffect(PotionType type) {
lock.readLock().lock();
try {
for (KPotionEffect potionEffect : potionEffects) {
if (potionEffect.potionType().equals(type))
return true;
}
return false;
} finally {
lock.readLock().unlock();
}
return false;
}
public Optional<PotionEffect> getEffectByType(PotionEffectType type) {
for (PotionEffect potionEffect : potionEffects) {
if(potionEffect.getType().equals(type))
return Optional.of(potionEffect);
public Optional<KPotionEffect> getEffectByType(PotionType type) {
lock.readLock().lock();
try {
for (KPotionEffect potionEffect : potionEffects) {
if (potionEffect.potionType().equals(type))
return Optional.of(potionEffect);
}
return Optional.empty();
} finally {
lock.readLock().unlock();
}
return Optional.empty();
}
}
public List<KPotionEffect> getPotionEffects() {
lock.readLock().lock();
try {
return new ArrayList<>(potionEffects);
} finally {
lock.readLock().unlock();
}
}
}
@@ -0,0 +1,49 @@
package dev.brighten.ac.handler;
import com.github.retrooper.packetevents.protocol.attribute.Attribute;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import lombok.Getter;
import lombok.Setter;
import me.hydro.emulator.util.mcp.MathHelper;
import java.util.Objects;
@Getter
public class ValuedAttribute {
private final Attribute attribute;
@Setter
private WrapperPlayServerUpdateAttributes.Property property;
private double value;
public ValuedAttribute(Attribute attribute) {
this.attribute = attribute;
this.value = attribute.getDefaultValue();
}
public void updateAttribute(WrapperPlayServerUpdateAttributes.Property property) {
this.property = property;
double multiplier = 1, additional = 0, base = 0;
for (WrapperPlayServerUpdateAttributes.PropertyModifier modifier : property.getModifiers()) {
switch (modifier.getOperation()) {
case ADDITION -> additional += modifier.getAmount();
case MULTIPLY_BASE -> base += modifier.getAmount();
case MULTIPLY_TOTAL -> multiplier*= (1 + modifier.getAmount());
}
}
this.value = MathHelper.clamp_double((property.getValue() + additional) * (1 - base) * multiplier,
attribute.getMinValue(), attribute.getMaxValue());
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ValuedAttribute that)) return false;
return Objects.equals(attribute, that.attribute);
}
@Override
public int hashCode() {
return Objects.hash(attribute);
}
}
@@ -1,67 +1,68 @@
package dev.brighten.ac.handler.block;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk;
import com.github.retrooper.packetevents.protocol.world.chunk.Column;
import com.github.retrooper.packetevents.protocol.world.chunk.TileEntity;
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_16.Chunk_v1_9;
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_7.Chunk_v1_7;
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_8.Chunk_v1_8;
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v_1_18.Chunk_v1_18;
import com.github.retrooper.packetevents.protocol.world.chunk.palette.PaletteType;
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerBlockPlacement;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerBlockChange;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChunkData;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChunkDataBulk;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerMultiBlockChange;
import dev.brighten.ac.Anticheat;
import com.github.retrooper.packetevents.wrapper.play.server.*;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.utils.BlockUtils;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.Materials;
import dev.brighten.ac.utils.XMaterial;
import dev.brighten.ac.utils.math.IntVector;
import dev.brighten.ac.utils.world.types.RayCollision;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.hydro.emulator.util.mcp.MathHelper;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
@Slf4j
@SuppressWarnings("unused")
@RequiredArgsConstructor
public class BlockUpdateHandler {
// Array dimensions: 64×64 covers a render distance of up to 32 chunks without
// collision. Index = (chunkX & MASK) * SIZE + (chunkZ & MASK); stored KColumn
// x/z are chunk coordinates and are validated on every lookup.
private static final int CHUNK_ARRAY_BITS = 6; // 2^6 = 64 per axis
private static final int CHUNK_ARRAY_SIZE = 1 << CHUNK_ARRAY_BITS; // 64
private static final int CHUNK_ARRAY_MASK = CHUNK_ARRAY_SIZE - 1; // 63
private final KColumn[] chunks = new KColumn[CHUNK_ARRAY_SIZE * CHUNK_ARRAY_SIZE];
private final APlayer player;
private final Map<String, World> worlds = new HashMap<>();
@Getter
private AtomicReference<World> currentWorld = new AtomicReference<>();
/**
* Clear all chunks when the player changes worlds
*/
public void onWorldChange() {
synchronized (chunks) {
java.util.Arrays.fill(chunks, null);
}
public void onRespawn(WrapperPlayServerRespawn respawn) {
respawn.getWorldName()
.filter(name -> !name.equals(currentWorld.get().getName()))
.ifPresent(worldName -> {
currentWorld.set(getWorldByName(worldName));
player.getMob().despawn();
setMinHeight(player.getDimensionType());
player.runKeepaliveAction(ka -> {
KLocation origin = player.getMovement().getTo().getLoc().add(0, 1.7, 0);
RayCollision coll = new RayCollision(origin.toVector(), origin.getDirection().multiply(-1));
Vector3d loc1 = coll.collisionPoint(1.2);
player.getMob().spawn(true, new KLocation(loc1), new ArrayList<>(), player);
}, 1);
});
}
private World getWorldByName(String name) {
return worlds.values().stream()
.filter(world -> world.getName().equals(name))
.findFirst()
.orElse(worlds.put(name, new World(name)));
}
/**
@@ -72,25 +73,30 @@ public class BlockUpdateHandler {
public void onPlace(WrapperPlayClientPlayerBlockPlacement place) {
player.getInfo().lastBlockUpdate.reset();
// Could not possibly be a block placement as it's not a block a player is holding.
IntVector pos = new IntVector(place.getBlockPosition());
Vector3i pos = place.getBlockPosition();
// Some dumbass shit I have to do because Minecraft with Lilypads
if (place.getItemStack().isPresent()
&& BlockUtils.getXMaterial(place.getItemStack().get().getType()).equals(XMaterial.LILY_PAD)) {
RayCollision rayCollision = new RayCollision(player.getBukkitPlayer().getEyeLocation().toVector(),
player.getBukkitPlayer().getLocation().getDirection());
&& place.getItemStack().get().getType().equals(ItemTypes.LILY_PAD)) {
RayCollision rayCollision = new RayCollision(player.getMovement().getTo().getLoc()
.add(0, player.getEyeHeight(), 0).toVector(),
player.getMovement().getTo().getLoc().getDirection());
//TODO Refactor this system to use just packetevents instead of this class
WrappedBlock block = rayCollision.getClosestBlockOfType(player, Materials.LIQUID, 5);
if (block != null) {
pos = new IntVector(block.getLocation().getX(), block.getLocation().getY() + 1, block.getLocation().getZ());
pos = new Vector3i(
block.getLocation().getX(),
block.getLocation().getY() + 1,
block.getLocation().getZ());
} else return;
} // Not an actual block place, just an interact
else if (pos.getX() == -1 && (pos.getY() == 255 || pos.getY() == -1) && pos.getZ() == -1) {
return;
} else {
pos.setX(pos.getX() + place.getFace().getModX());
pos.setY(pos.getY() + place.getFace().getModY());
pos.setZ(pos.getZ() + place.getFace().getModZ());
pos = pos.with(pos.getX() + place.getFace().getModX(),
pos.getY() + place.getFace().getModY(),
pos.getZ() + place.getFace().getModZ());
}
player.getInfo().getLastPlace().reset();
@@ -100,220 +106,16 @@ public class BlockUpdateHandler {
int y = pos.getY();
int z = pos.getZ();
var placedType = place.getItemStack().get().getType().getPlacedType();
if(place.getItemStack().isEmpty() || placedType == null) {
if(place.getItemStack().isEmpty() || place.getItemStack().get().getType().getPlacedType() == null) {
return;
}
updateBlock(x, y, z, WrappedBlockState.getDefaultState(placedType));
currentWorld.get().updateBlock(x, y, z,
WrappedBlockState.getDefaultState(place.getItemStack().get().getType().getPlacedType()));
}
/**
* Keep track of block diggings since the Bukkit API will be a bit behind
* @param x x coordinate
* @param z z coordinate
* @return the chunk at the specified coordinates
*/
public KColumn getChunk(int x, int z) {
int chunkX = x >> 4;
int chunkZ = z >> 4;
synchronized (chunks) {
int index = chunkIndex(chunkX, chunkZ);
KColumn chunk = chunks[index];
// Validate that the stored entry belongs to this chunk position
if (chunk == null || chunk.x() != chunkX || chunk.z() != chunkZ) {
chunk = getBukkitColumn(player.getBukkitPlayer().getWorld(), x, z);
if (chunk == null) {
return new KColumn(chunkX, chunkZ, new BaseChunk[maxHeight / 16]);
}
chunks[index] = chunk;
}
return chunk;
}
}
private static int chunkIndex(int chunkX, int chunkZ) {
return (chunkX & CHUNK_ARRAY_MASK) * CHUNK_ARRAY_SIZE + (chunkZ & CHUNK_ARRAY_MASK);
}
private KColumn getBukkitColumn(World world, int x, int z) {
int chunkX = x >> 4;
int chunkZ = z >> 4;
Chunk chunk = BlockUtils.getChunkAsync(world, chunkX, chunkZ).orElse(null);
if(chunk == null) {
// Handle loading on main thread
Anticheat.INSTANCE.getRunUtils().task(() -> {
int index = chunkIndex(chunkX, chunkZ);
synchronized (chunks) {
KColumn existing = chunks[index];
if (existing == null || existing.x() != chunkX || existing.z() != chunkZ) {
KColumn loaded = getBukkitColumn(world, x, z);
if (loaded != null) {
chunks[index] = loaded;
}
}
}
});
return null;
}
BaseChunk[] levels = new BaseChunk[world.getMaxHeight() / 16];
for(int i = 0; i < levels.length; i++) {
levels[i] = create();
}
int chunkBlockX = chunk.getX() * 16;
int chunkBlockZ = chunk.getZ() * 16;
for(int blockX = chunkBlockX; blockX < chunkBlockX + 16 ; blockX++) {
for(int blockZ = chunkBlockZ; blockZ < chunkBlockZ + 16 ; blockZ++) {
for(int blockY = minHeight ; blockY < world.getMaxHeight() ; blockY++) {
Block block = chunk.getBlock(blockX, blockY, blockZ);
if(block.getType() == null || block.getType().equals(Material.AIR)) {
continue; // Air
}
BaseChunk baseChunk = levels[blockY >> 4];
WrappedBlockState state = SpigotConversionUtil.fromBukkitMaterialData(block.getState().getData());
baseChunk.set(blockX & 15, blockY & 15, blockZ & 15, state);
}
}
}
return new KColumn(chunkX, chunkZ, levels);
}
private void updateChunk(Column chunk) {
synchronized (chunks) {
int index = chunkIndex(chunk.getX(), chunk.getZ());
chunks[index] = new KColumn(chunk.getX(), chunk.getZ(), chunk.getChunks());
}
}
private static BaseChunk create() {
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_18)) {
return new Chunk_v1_18();
} else if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
return new Chunk_v1_9(0, PaletteType.BIOME.create().paletteType.create());
} else if(PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_8)) {
return new Chunk_v1_8(false);
}
return new Chunk_v1_7(false, false);
}
/**
* Get a block at the specified coordinates
* @param location the location of the block
* @return the block at the specified coordinates
*/
public WrappedBlock getBlock(Location location) {
return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
private int minHeight = 0, maxHeight = 256;
public void setMinHeight(DimensionType type) {
minHeight = type.getMinY();
maxHeight = minHeight + type.getHeight();
}
private static final WrappedBlockState airBlockState = WrappedBlockState.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), 0);
/**
* Get a block at the specified coordinates
* @param x x coordinate
* @param y y coordinate
* @param z z coordinate
* @return the block at the specified coordinates
*/
public WrappedBlock getBlock(int x, int y, int z) {
KColumn col = getChunk(x, z);
y -= minHeight;
final int worldY = y;
// Fast bounds check for absurd/invalid Y before chunk indexing
if (y < 0 || y >= (maxHeight - minHeight)) {
return new WrappedBlock(new IntVector(x, worldY, z),
StateTypes.AIR,
airBlockState);
}
// Also ensure the section index is within the cached column bounds
final int sectionIndex = y >> 4;
if (sectionIndex >= col.chunks().length) {
return new WrappedBlock(new IntVector(x, worldY, z),
StateTypes.AIR,
airBlockState);
}
BaseChunk chunk = col.chunks()[sectionIndex];
if(chunk == null) {
//Get Bukkit Block
Block block = BlockUtils.getBlockAsync(new Location(player.getBukkitPlayer().getWorld(), x, y, z))
.orElse(null);
if(block != null) {
WrappedBlockState state = SpigotConversionUtil.fromBukkitMaterialData(block.getState().getData());
if (state.getType() == StateTypes.AIR) {
return new WrappedBlock(new IntVector(x, y + minHeight, z),
StateTypes.AIR,
airBlockState);
} else {
chunk = create();
col.chunks()[y >> 4] = chunk;
chunk.set(x & 15, y & 15, z & 15, state);
}
} else return new WrappedBlock(new IntVector(x, y, z),
StateTypes.AIR,
airBlockState);
}
WrappedBlockState state = chunk.get(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(),x & 15, y & 15, z & 15);
return new WrappedBlock(new IntVector(x, y, z),
state.getType(),
state);
}
/**
* Get a block at the specified coordinates
* @param vec the coordinates
* @return the block at the specified coordinates
*/
public WrappedBlock getBlock(IntVector vec) {
return getBlock(vec.getX(), vec.getY(), vec.getZ());
}
public WrappedBlock getBlock(Vector3d vec) {
return getBlock(
MathHelper.floor_double(vec.getX()),
MathHelper.floor_double(vec.getY()),
MathHelper.floor_double(vec.getZ())
);
}
/**
* Get a block at the specified coordinates
* @param block Grabs coordinates from @link{org.bukkit.block.Block}
* @return the block at the specified coordinates
*/
public WrappedBlock getBlock(Block block) {
return getBlock(block.getX(), block.getY(), block.getZ());
}
static final WrappedBlockState airBlockState = WrappedBlockState
.getByGlobalId(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), 0);
/**
* Keep track of block breaking since the Bukkit API will be a bit behind.
@@ -324,13 +126,13 @@ public class BlockUpdateHandler {
player.getInfo().lastBlockUpdate.reset();
if (dig.getAction() == DiggingAction.FINISHED_DIGGING) {
IntVector pos = new IntVector(dig.getBlockPosition());
Vector3i pos = dig.getBlockPosition();
if (pos.getX() == -1 && (pos.getY() == 255 || pos.getY() == -1) && pos.getZ() == -1) {
return;
}
updateBlock(pos.getX(), pos.getY(), pos.getZ(), airBlockState);
currentWorld.get().updateBlock(pos.getX(), pos.getY(), pos.getZ(), airBlockState);
}
}
@@ -343,9 +145,9 @@ public class BlockUpdateHandler {
// Updating block information
player.runKeepaliveAction(k -> {
IntVector pos = new IntVector(packet.getBlockPosition());
Vector3i pos = packet.getBlockPosition();
updateBlock(pos.getX(), pos.getY(), pos.getZ(), packet.getBlockState());
currentWorld.get().updateBlock(pos.getX(), pos.getY(), pos.getZ(), packet.getBlockState());
});
}
@@ -358,41 +160,20 @@ public class BlockUpdateHandler {
player.runKeepaliveAction(k -> {
for (WrapperPlayServerMultiBlockChange.EncodedBlock info : packet.getBlocks()) {
WrappedBlockState blockState = info.getBlockState(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
WrappedBlockState blockState = info
.getBlockState(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
updateBlock(info.getX(), info.getY(), info.getZ(), blockState);
currentWorld.get().updateBlock(info.getX(), info.getY(), info.getZ(), blockState);
}
});
}
private void updateBlock(int x, int y, int z, WrappedBlockState blockState) {
KColumn col = getChunk(x, z);
int offset = y - minHeight;
if(offset < 0 || (offset >> 4) > col.chunks().length) {
return;
}
BaseChunk chunk = col.chunks()[offset >> 4];
if(chunk == null) {
chunk = create();
col.chunks()[offset >> 4] = chunk;
chunk.set(player.getPlayerVersion(), 0, 0, 0, 0);
}
chunk.set(x & 15, offset & 15, z & 15,
blockState);
}
/**
* Keep track of block updates since the Bukkit API will be a bit behind.
* @param chunkUpdate Wrapped PacketPlayOutMapChunk
*/
public void runUpdate(WrapperPlayServerChunkData chunkUpdate) {
player.runKeepaliveAction(k -> updateChunk(chunkUpdate.getColumn()));
player.runKeepaliveAction(k -> currentWorld.get().updateChunk(chunkUpdate.getColumn()));
}
public void runUpdate(WrapperPlayServerChunkDataBulk chunkBulk) {
@@ -403,9 +184,10 @@ public class BlockUpdateHandler {
int x = chunkBulk.getX()[index];
int z = chunkBulk.getZ()[index];
Column column = new Column(x, z, true, chunks, new TileEntity[0], chunkBulk.getBiomeData()[index]);
Column column = new Column(x, z, true, chunks, new TileEntity[0],
chunkBulk.getBiomeData()[index]);
updateChunk(column);
currentWorld.get().updateChunk(column);
}
});
}
@@ -418,8 +200,8 @@ public class BlockUpdateHandler {
* @param modZ the z modifier
* @return the block relative to the specified location
*/
public WrappedBlock getRelative(IntVector location, int modX, int modY, int modZ) {
return getBlock(location.clone().add(modX, modY, modZ));
public WrappedBlock getRelative(Vector3i location, int modX, int modY, int modZ) {
return currentWorld.get().getBlock(location.add(modX, modY, modZ));
}
/**
@@ -429,7 +211,7 @@ public class BlockUpdateHandler {
* @param distance the distance
* @return the block relative to the specified location
*/
public WrappedBlock getRelative(IntVector location, BlockFace face, int distance) {
public WrappedBlock getRelative(Vector3i location, BlockFace face, int distance) {
return getRelative(location,
face.getModX() * distance, face.getModY() * distance, face.getModZ() * distance);
}
@@ -440,8 +222,20 @@ public class BlockUpdateHandler {
* @param face the face
* @return the block relative to the specified location
*/
public WrappedBlock getRelative(IntVector location, BlockFace face) {
return getBlock(location.clone().add(face.getModX(), face.getModY(), face.getModZ()));
public WrappedBlock getRelative(Vector3i location, BlockFace face) {
return currentWorld.get().getBlock(location.add(face.getModX(), face.getModY(), face.getModZ()));
}
public WrappedBlock getBlock(int x, int y, int z) {
return currentWorld.get().getBlock(x, y, z);
}
public WrappedBlock getBlock(KLocation location) {
return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
public WrappedBlock getBlock(Vector3i location) {
return getBlock(location.getX(), location.getY(), location.getZ());
}
public record KColumn(int x, int z, BaseChunk[] chunks) {}
@@ -1,9 +1,11 @@
package dev.brighten.ac.handler.block;
import dev.brighten.ac.utils.math.IntVector;
import com.github.retrooper.packetevents.util.Vector3i;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
@RequiredArgsConstructor
@@ -17,7 +19,7 @@ public class Chunk {
* @param location - Location of the block
* @return Optional of the block at the specified location
*/
public Optional<WrappedBlock> getBlockAt(IntVector location) {
public Optional<WrappedBlock> getBlockAt(Vector3i location) {
return getBlockAt(location.getX(), location.getY(), location.getZ());
}
@@ -64,7 +66,18 @@ public class Chunk {
* @param location - Location of the block
* @param block - Block to update to
*/
public void updateBlock(IntVector location, WrappedBlock block) {
public void updateBlock(Vector3i location, WrappedBlock block) {
updateBlock(location.getX(), location.getY(), location.getZ(), block);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Chunk chunk)) return false;
return x == chunk.x && z == chunk.z && Objects.deepEquals(blocks, chunk.blocks);
}
@Override
public int hashCode() {
return Objects.hash(x, z, Arrays.deepHashCode(blocks));
}
}
@@ -0,0 +1,186 @@
package dev.brighten.ac.handler.block;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk;
import com.github.retrooper.packetevents.protocol.world.chunk.Column;
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_16.Chunk_v1_9;
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_7.Chunk_v1_7;
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v1_8.Chunk_v1_8;
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v_1_18.Chunk_v1_18;
import com.github.retrooper.packetevents.protocol.world.chunk.palette.PaletteType;
import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import dev.brighten.ac.handler.entity.TrackedEntity;
import dev.brighten.ac.utils.KLocation;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
import me.hydro.emulator.util.mcp.MathHelper;
import java.util.Map;
import java.util.Optional;
@Getter
public class World {
private final String name;
// Array dimensions: 64×64 covers a render distance of up to 32 chunks without
// collision. Index = (chunkX & MASK) * SIZE + (chunkZ & MASK); stored KColumn
// x/z are chunk coordinates and are validated on every lookup.
private static final int CHUNK_ARRAY_BITS = 6; // 2^6 = 64 per axis
private static final int CHUNK_ARRAY_SIZE = 1 << CHUNK_ARRAY_BITS; // 64
private static final int CHUNK_ARRAY_MASK = CHUNK_ARRAY_SIZE - 1; // 63
private final BlockUpdateHandler.KColumn[] chunks = new BlockUpdateHandler.KColumn[CHUNK_ARRAY_SIZE * CHUNK_ARRAY_SIZE];
private final Map<Integer, TrackedEntity> trackedEntities = new Int2ObjectOpenHashMap<>();
public World(String name) {
this.name = name;
}
private int minHeight = 0, maxHeight = 256;
public void setMinHeight(DimensionType type) {
minHeight = type.getMinY();
maxHeight = minHeight + type.getHeight();
}
/**
* Keep track of block diggings since the Bukkit API will be a bit behind
* @param x x coordinate
* @param z z coordinate
* @return the chunk at the specified coordinates
*/
public BlockUpdateHandler.KColumn getChunk(int x, int z) {
int chunkX = x >> 4;
int chunkZ = z >> 4;
synchronized (chunks) {
int index = chunkIndex(chunkX, chunkZ);
BlockUpdateHandler.KColumn chunk = chunks[index];
// Validate that the stored entry belongs to this chunk position
if (chunk == null || chunk.x() != chunkX || chunk.z() != chunkZ) {
chunk = new BlockUpdateHandler.KColumn(chunkX, chunkZ, new BaseChunk[maxHeight / 16]);
chunks[index] = chunk;
}
return chunk;
}
}
private static int chunkIndex(int chunkX, int chunkZ) {
return ((chunkX & CHUNK_ARRAY_MASK) << CHUNK_ARRAY_BITS) | (chunkZ & CHUNK_ARRAY_MASK);
}
void updateChunk(Column chunk) {
synchronized (chunks) {
int index = chunkIndex(chunk.getX(), chunk.getZ());
chunks[index] = new BlockUpdateHandler.KColumn(chunk.getX(), chunk.getZ(), chunk.getChunks());
}
}
private static BaseChunk create() {
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_18)) {
return new Chunk_v1_18();
} else if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
return new Chunk_v1_9(0, PaletteType.BIOME.create().paletteType.create());
} else if(PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_8)) {
return new Chunk_v1_8(false);
}
return new Chunk_v1_7(false, false);
}
/**
* Get a block at the specified coordinates
* @param location the location of the block
* @return the block at the specified coordinates
*/
public WrappedBlock getBlock(KLocation location) {
return getBlock(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
/**
* Get a block at the specified coordinates
* @param x x coordinate
* @param y y coordinate
* @param z z coordinate
* @return the block at the specified coordinates
*/
public WrappedBlock getBlock(int x, int y, int z) {
BlockUpdateHandler.KColumn col = getChunk(x, z);
y -= minHeight;
if(col == null) {
return new WrappedBlock(new Vector3i(x, y, z),
StateTypes.AIR,
BlockUpdateHandler.airBlockState);
}
BaseChunk chunk = col.chunks().length - 1 < (y >> 4) ? null : col.chunks()[Math.max(0, (y >> 4))];
if(chunk == null) {
//Get Bukkit Block
return new WrappedBlock(new Vector3i(x, y, z),
StateTypes.AIR,
BlockUpdateHandler.airBlockState);
}
WrappedBlockState state = chunk.get(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(),x & 15, y & 15, z & 15);
return new WrappedBlock(new Vector3i(x, y, z),
state.getType(),
state);
}
void updateBlock(int x, int y, int z, WrappedBlockState blockState) {
BlockUpdateHandler.KColumn col = getChunk(x, z);
int offset = y - minHeight;
if(offset < 0 || (offset >> 4) > col.chunks().length) {
return;
}
BaseChunk chunk = col.chunks()[offset >> 4];
if(chunk == null) {
chunk = create();
col.chunks()[offset >> 4] = chunk;
chunk.set(null, 0, 0, 0, 0);
}
chunk.set(x & 15, offset & 15, z & 15,
blockState);
}
/**
* Get a block at the specified coordinates
* @param vec the coordinates
* @return the block at the specified coordinates
*/
public WrappedBlock getBlock(Vector3i vec) {
return getBlock(vec.getX(), vec.getY(), vec.getZ());
}
public WrappedBlock getBlock(Vector3d vec) {
return getBlock(
MathHelper.floor_double(vec.getX()),
MathHelper.floor_double(vec.getY()),
MathHelper.floor_double(vec.getZ())
);
}
public Optional<TrackedEntity> getTrackedEntity(int entityId) {
TrackedEntity trackedEntity = trackedEntities.get(entityId);
if(trackedEntity == null) {
return Optional.empty();
}
return Optional.of(trackedEntity);
}
}
@@ -2,14 +2,14 @@ package dev.brighten.ac.handler.block;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import dev.brighten.ac.utils.math.IntVector;
import com.github.retrooper.packetevents.util.Vector3i;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class WrappedBlock {
private IntVector location;
private Vector3i location;
private StateType type;
private WrappedBlockState blockState;
}
@@ -1,13 +1,19 @@
package dev.brighten.ac.handler.entity;
import com.github.retrooper.packetevents.protocol.attribute.Attribute;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import dev.brighten.ac.data.obj.Pose;
import dev.brighten.ac.handler.ValuedAttribute;
import dev.brighten.ac.utils.EntityLocation;
import dev.brighten.ac.utils.KLocation;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Getter
@Setter
@@ -17,6 +23,8 @@ public class TrackedEntity {
private KLocation location;
private EntityLocation oldEntityLocation, newEntityLocation;
private List<FakeMob> fakeMobs = new ArrayList<>();
private Set<ValuedAttribute> attributes = new HashSet<>();
private Pose pose = Pose.STANDING;
public TrackedEntity(int entityId, EntityType entityType, KLocation location) {
this.entityId = entityId;
@@ -31,4 +39,30 @@ public class TrackedEntity {
newEntityLocation.yaw = location.getYaw();
newEntityLocation.pitch = location.getPitch();
}
public KLocation getEyeLocation() {
return new KLocation(location.getX(), location.getY() + pose.eyeHeight, location.getZ(),
location.getYaw(), location.getPitch());
}
public ValuedAttribute getAttribute(Attribute type) {
for(ValuedAttribute attribute : attributes) {
if(attribute.getAttribute().equals(type)) {
return attribute;
}
}
return null;
}
public void updateAttribute(WrapperPlayServerUpdateAttributes.Property property) {
ValuedAttribute attribute = getAttribute(property.getAttribute());
if(attribute == null) {
attribute = new ValuedAttribute(property.getAttribute());
}
attribute.updateAttribute(property);
attributes.add(attribute);
}
}
@@ -49,7 +49,7 @@ public class KeepaliveProcessor {
double dh = Math.min(value.getMovement().getDeltaXZ(), 1),
dy = Math.min(1, Math.abs(value.getMovement().getDeltaY()));
value.getInfo().nearbyEntities = value.getEntityLocationHandler().getTrackedEntities().values()
value.getInfo().nearbyEntities = value.getWorldTracker().getCurrentWorld().get().getTrackedEntities().values()
.stream()
.filter(te ->
te.getLocation().distance(value.getMovement().getTo().getLoc()) < (2 + (dh + dy) / 2))
@@ -1,25 +1,8 @@
package dev.brighten.ac.handler.protocol;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.handler.protocol.impl.NoAPI;
import dev.brighten.ac.handler.protocol.impl.ProtocolSupport;
import dev.brighten.ac.handler.protocol.impl.ViaVersionAPI;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import dev.brighten.ac.data.APlayer;
public interface Protocol {
int getPlayerVersion(Player player);
static Protocol getProtocol() {
if(Bukkit.getPluginManager().isPluginEnabled("ViaVersion")) {
Anticheat.INSTANCE.alog("Using ViaVersion for ProtocolAPI");
return new ViaVersionAPI();
} else if(Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport")) {
Anticheat.INSTANCE.alog("Using ProtocolSupport for ProtocolAPI");
return new ProtocolSupport();
} else {
Anticheat.INSTANCE.alog("Using Vanilla API for ProtocolAPI");
return new NoAPI();
}
}
int getPlayerVersion(APlayer player);
}
@@ -1,13 +1,13 @@
package dev.brighten.ac.handler.protocol.impl;
import com.github.retrooper.packetevents.PacketEvents;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.protocol.Protocol;
import org.bukkit.entity.Player;
public class NoAPI implements Protocol {
@Override
public int getPlayerVersion(Player player) {
return PacketEvents.getAPI().getPlayerManager().getClientVersion(player).getProtocolVersion();
public int getPlayerVersion(APlayer player) {
return PacketEvents.getAPI().getPlayerManager().getClientVersion(player.getBukkitPlayer()).getProtocolVersion();
}
}
@@ -1,13 +0,0 @@
package dev.brighten.ac.handler.protocol.impl;
import dev.brighten.ac.handler.protocol.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();
}
}
@@ -2,16 +2,16 @@ package dev.brighten.ac.handler.protocol.impl;
import com.viaversion.viaversion.api.Via;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.protocol.Protocol;
import org.bukkit.entity.Player;
public class ViaVersionAPI implements Protocol {
@Override
public int getPlayerVersion(Player player) {
Anticheat.INSTANCE.alog("Getting player version for " + player.getName());
var toReturn = Via.getAPI().getPlayerVersion(player.getUniqueId());
Anticheat.INSTANCE.alog("Player version for " + player.getName() + " is " + toReturn);
public int getPlayerVersion(APlayer player) {
Anticheat.INSTANCE.alog("Getting player version for " + player.getBukkitPlayer().getName());
var toReturn = Via.getAPI().getPlayerVersion(player.getBukkitPlayer().getUniqueId());
Anticheat.INSTANCE.alog("Player version for " + player.getBukkitPlayer().getName() + " is " + toReturn);
return toReturn;
}
@@ -1,5 +1,6 @@
package dev.brighten.ac.listener;
import com.github.retrooper.packetevents.util.Vector3d;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.utils.KLocation;
@@ -68,14 +69,15 @@ public class GeneralListener implements Listener {
Anticheat.INSTANCE.getPlayerRegistry().getPlayer(event.getPlayer().getUniqueId())
.ifPresent(player -> {
player.getBlockUpdateHandler().onWorldChange();
// Updating bot loc when changing worlds
Location origin = event.getTo().clone().add(0, 1.7, 0);
Vector mult = origin.getDirection().multiply(-1);
RayCollision coll = new RayCollision(origin.toVector(), origin.getDirection().multiply(-1));
RayCollision coll = new RayCollision(new Vector3d(origin.getX(), origin.getY(), origin.getZ()),
new Vector3d(mult.getX(), mult.getY(), mult.getZ()));
Vector loc1 = coll.collisionPoint(1.2);
Vector3d loc1 = coll.collisionPoint(1.2);
Anticheat.INSTANCE.getRunUtils().taskLater(() -> {
player.getMob().despawn();
@@ -1,6 +1,7 @@
package dev.brighten.ac.utils;
import com.github.retrooper.packetevents.protocol.world.Direction;
import com.github.retrooper.packetevents.util.Vector3d;
import dev.brighten.ac.utils.world.types.RayCollision;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
import org.bukkit.Location;
@@ -211,6 +212,14 @@ public class AxisAlignedBB {
return rayTrace(origin, dir);
}
public Vec3D rayTrace(Vector3d vorigin, Vector3d vdirection, double distance) {
Vec3D origin = new Vec3D(vorigin.getX(), vorigin.getY(), vorigin.getZ());
Vector3d direction = vdirection.multiply(distance);
Vec3D dir = origin.clone().add(direction.getX(), direction.getY(), direction.getZ());
return rayTrace(origin, dir);
}
public Vec3D rayTrace(Vec3D vec3d, Vec3D vec3d1) {
Vec3D vec3d2 = vec3d.a(vec3d1, this.minX);
Vec3D vec3d3 = vec3d.a(vec3d1, this.maxX);
@@ -2,19 +2,18 @@ package dev.brighten.ac.utils;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.block.WrappedBlock;
import dev.brighten.ac.handler.entity.TrackedEntity;
import dev.brighten.ac.utils.math.IntVector;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Vehicle;
import java.util.EnumMap;
import java.util.EnumSet;
@@ -84,20 +83,20 @@ public class BlockUtils {
return Optional.empty();
}
public static Optional<WrappedBlock> getRelative(APlayer player, IntVector location, int modX, int modY, int modZ) {
return Optional.of(player.getBlockUpdateHandler()
.getRelative(new IntVector(location.getX(), location.getY(), location.getZ()),
public static Optional<WrappedBlock> getRelative(APlayer player, Vector3i location, int modX, int modY, int modZ) {
return Optional.of(player.getWorldTracker()
.getRelative(new Vector3i(location.getX(), location.getY(), location.getZ()),
modX, modY, modZ));
}
public static Optional<WrappedBlock> getRelative(APlayer player, IntVector location,
public static Optional<WrappedBlock> getRelative(APlayer player, Vector3i location,
com.github.retrooper.packetevents.protocol.world
.BlockFace face, int distance) {
return getRelative(player, location,
face.getModX() * distance, face.getModY() * distance, face.getModZ() * distance);
}
public static Optional<WrappedBlock> getRelative(APlayer player, IntVector vector, BlockFace face) {
public static Optional<WrappedBlock> getRelative(APlayer player, Vector3i vector, BlockFace face) {
return getRelative(player, vector,
face.getModX(), face.getModY(), face.getModZ());
}
@@ -134,6 +133,12 @@ public class BlockUtils {
return isUsable(getXMaterial(material));
}
public static boolean isUsable(ClientVersion version, ItemType type) {
return type.hasAttribute(ItemTypes.ItemAttribute.EDIBLE)
|| (version.isOlderThan(ClientVersion.V_1_9) && type.hasAttribute(ItemTypes.ItemAttribute.SWORD))
|| type.equals(ItemTypes.SHIELD);
}
public static boolean isUsable(XMaterial xmaterial) {
if(XEDIBLE.contains(xmaterial)) return true;
return switch (xmaterial) {
@@ -1,16 +1,15 @@
package dev.brighten.ac.utils;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.particle.Particle;
import com.github.retrooper.packetevents.protocol.particle.type.ParticleType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerParticle;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.entity.TrackedEntity;
import dev.brighten.ac.utils.math.IntVector;
import dev.brighten.ac.utils.world.BlockData;
import dev.brighten.ac.utils.world.CollisionBox;
import dev.brighten.ac.utils.world.EntityData;
@@ -137,8 +136,8 @@ public class Helper {
for (int x = x1; x < x2; ++x)
for (int y = y1 - 1; y < y2; ++y)
for (int z = z1; z < z2; ++z) {
IntVector vec = new IntVector(x, y, z);
StateType type = player.getBlockUpdateHandler().getBlock(vec).getType();
Vector3i vec = new Vector3i(x, y, z);
StateType type = player.getWorldTracker().getBlock(vec).getType();
if (type != StateTypes.AIR && (mask == -100 || Materials.checkFlag(type, mask))) {
CollisionBox box = BlockData.getData(type)
@@ -0,0 +1,7 @@
package dev.brighten.ac.utils;
import com.github.retrooper.packetevents.protocol.potion.PotionType;
public record KPotionEffect(PotionType potionType, KProperties properties) {
}
@@ -0,0 +1,18 @@
package dev.brighten.ac.utils;
import com.github.retrooper.packetevents.protocol.potion.PotionEffect;
import org.jetbrains.annotations.Nullable;
public record KProperties(int amplifier, int duration, boolean ambient, boolean showParticles, boolean showIcon,
@Nullable KProperties hiddenEffect) {
public PotionEffect.Properties toProperties() {
return new PotionEffect.Properties(amplifier, duration, ambient, showParticles, showIcon,
hiddenEffect == null ? null : hiddenEffect.toProperties());
}
public static KProperties fromBukkit(org.bukkit.potion.PotionEffect potionEffect) {
return new KProperties(potionEffect.getAmplifier(), potionEffect.getDuration(), potionEffect.isAmbient(),
potionEffect.hasParticles(), false, null);
}
}
@@ -9,6 +9,7 @@ import org.bukkit.Material;
import java.util.HashMap;
import java.util.Map;
//TODO Refactor this system to use just packetevents instead of this class
public class Materials {
private static final Map<StateType, Integer> MATERIAL_FLAGS = new HashMap<>();
@@ -31,11 +32,11 @@ public class Materials {
int flag = MATERIAL_FLAGS.getOrDefault(mat, 0);
//We use the one in BlockUtils also since we can't trust Material to include everything.
if (mat.isSolid() || mat.getName().contains("COMPARATOR") || mat.getName().contains("DIODE")) {
if (mat.isSolid() || mat.getName().contains("COMPARATOR") || mat.getName().contains("DIODE") || mat.isBlocking()) {
flag |= SOLID;
}
if(!(BlockData.getData(mat).getDefaultBox() instanceof NoCollisionBox)) {
if(!(BlockData.getData(mat).getDefaultBox() instanceof NoCollisionBox) || mat.isBlocking()) {
flag |= COLLIDABLE;
}
@@ -58,7 +58,7 @@ public class MiscUtils {
for(int x = startX ; x < endX ; x++) {
for(int y = startY ; y < endY ; y++) {
for(int z = startZ ; z < endZ ; z++) {
StateType type = player.getBlockUpdateHandler().getBlock(x, y, z).getType();
StateType type = player.getWorldTracker().getBlock(x, y, z).getType();
if(Materials.checkFlag(type, bitmask))
return true;
@@ -19,7 +19,7 @@ public class MovementUtils {
public static double getJumpHeight(APlayer data) {
float baseHeight = 0.42f;
baseHeight+= data.getInfo().groundJumpBoost.map(ef -> ef.getAmplifier() + 1)
baseHeight+= data.getInfo().groundJumpBoost.map(ef -> ef.properties().amplifier() + 1)
.orElse(0) * 0.1f;
return baseHeight;
@@ -38,7 +38,7 @@ public class MovementUtils {
int i = MathHelper.floor_double(data.getMovement().getTo().getLoc().getX());
int j = MathHelper.floor_double(data.getMovement().getTo().getBox().minY);
int k = MathHelper.floor_double(data.getMovement().getTo().getLoc().getZ());
WrappedBlock block = data.getBlockUpdateHandler().getBlock(i, j, k);
WrappedBlock block = data.getWorldTracker().getBlock(i, j, k);
return Materials.checkFlag(block.getType(), Materials.LADDER);
@@ -54,6 +54,10 @@ public class IntVector implements Cloneable {
return new Vector(x, y, z);
}
public Vector3i toVector3i() {
return new Vector3i(x, y, z);
}
@Override
public String toString() {
return "[" + x + ", " + y + ", " + z + "]";
@@ -2,11 +2,14 @@ package dev.brighten.ac.utils.math;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.util.Vector3d;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.MathUtils;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
@@ -15,15 +18,15 @@ public class RayTrace {
//origin = start position
//direction = direction in which the raytrace will go
Vector origin, direction;
Vector3d origin, direction;
public RayTrace(Vector origin, Vector direction) {
public RayTrace(Vector3d origin, Vector3d direction) {
this.origin = origin;
this.direction = direction;
}
//general intersection detection
public static boolean intersects(Vector position, Vector min, Vector max) {
public static boolean intersects(Vector3d position, Vector3d min, Vector3d max) {
if (position.getX() < min.getX() || position.getX() > max.getX()) {
return false;
} else if (position.getY() < min.getY() || position.getY() > max.getY()) {
@@ -32,27 +35,27 @@ public class RayTrace {
}
//get a point on the raytrace at X blocks away
public Vector getPostion(double blocksAway) {
return origin.clone().add(direction.clone().multiply(blocksAway));
public Vector3d getPostion(double blocksAway) {
return origin.add(direction.multiply(blocksAway));
}
//checks if a position is on contained within the position
public boolean isOnLine(Vector position) {
public boolean isOnLine(Vector3d position) {
double t = (position.getX() - origin.getX()) / direction.getX();
return position.getBlockY() == origin.getY() + (t * direction.getY()) && position.getBlockZ() == origin.getZ() + (t * direction.getZ());
return MathUtils.floor(position.getY()) == origin.getY() + (t * direction.getY()) && MathUtils.floor(position.getZ()) == origin.getZ() + (t * direction.getZ());
}
//get all postions on a raytrace
public List<Vector> traverse(double blocksAway, double accuracy) {
List<Vector> positions = new ArrayList<>();
public List<Vector3d> traverse(double blocksAway, double accuracy) {
List<Vector3d> positions = new ArrayList<>();
for (double d = 0; d <= blocksAway; d += accuracy) {
positions.add(getPostion(d));
}
return positions;
}
public List<Vector> traverse(double skip, double blocksAway, double accuracy) {
List<Vector> positions = new ArrayList<>();
public List<Vector3d> traverse(double skip, double blocksAway, double accuracy) {
List<Vector3d> positions = new ArrayList<>();
for (double d = skip; d <= blocksAway; d += accuracy) {
positions.add(getPostion(d));
}
@@ -62,14 +65,17 @@ public class RayTrace {
public List<Block> getBlocks(World world, double blocksAway, double accuracy) {
List<Block> blocks = new ArrayList<>();
traverse(blocksAway, accuracy).stream().filter(vector -> vector.toLocation(world).getBlock().getType().isSolid()).forEach(vector -> blocks.add(vector.toLocation(world).getBlock()));
traverse(blocksAway, accuracy).stream()
.map(KLocation::new)
.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<Vector> positions = traverse(blocksAway, accuracy);
for (Vector position : positions) {
public Vector3d positionOfIntersection(Vector3d min, Vector3d max, double blocksAway, double accuracy) {
List<Vector3d> positions = traverse(blocksAway, accuracy);
for (Vector3d position : positions) {
if (intersects(position, min, max)) {
return position;
}
@@ -78,9 +84,9 @@ public class RayTrace {
}
//intersection detection for current raytrace
public boolean intersects(Vector min, Vector max, double blocksAway, double accuracy) {
List<Vector> positions = traverse(blocksAway, accuracy);
for (Vector position : positions) {
public boolean intersects(Vector3d min, Vector3d max, double blocksAway, double accuracy) {
List<Vector3d> positions = traverse(blocksAway, accuracy);
for (Vector3d position : positions) {
if (intersects(position, min, max)) {
return true;
}
@@ -89,9 +95,9 @@ public class RayTrace {
}
//bounding blockbox instead of vector
public Vector positionOfIntersection(SimpleCollisionBox collisionBox, double blocksAway, double accuracy) {
List<Vector> positions = traverse(blocksAway, accuracy);
for (Vector position : positions) {
public Vector3d positionOfIntersection(SimpleCollisionBox collisionBox, double blocksAway, double accuracy) {
List<Vector3d> positions = traverse(blocksAway, accuracy);
for (Vector3d position : positions) {
if (intersects(position, collisionBox.min(), collisionBox.max())) {
return position;
}
@@ -99,9 +105,9 @@ public class RayTrace {
return null;
}
public Vector positionOfIntersection(SimpleCollisionBox collisionBox, double skip, double blocksAway, double accuracy) {
List<Vector> positions = traverse(skip, blocksAway, accuracy);
for (Vector position : positions) {
public Vector3d positionOfIntersection(SimpleCollisionBox collisionBox, double skip, double blocksAway, double accuracy) {
List<Vector3d> positions = traverse(skip, blocksAway, accuracy);
for (Vector3d position : positions) {
if (intersects(position, collisionBox.min(), collisionBox.max())) {
return position;
}
@@ -111,8 +117,8 @@ public class RayTrace {
//bounding blockbox instead of vector
public boolean intersects(SimpleCollisionBox collisionBox, double blocksAway, double accuracy) {
List<Vector> positions = traverse(blocksAway, accuracy);
for (Vector position : positions) {
List<Vector3d> positions = traverse(blocksAway, accuracy);
for (Vector3d position : positions) {
if (intersects(position, collisionBox.min(), collisionBox.max())) {
return true;
}
@@ -121,8 +127,8 @@ public class RayTrace {
}
public boolean intersects(SimpleCollisionBox collisionBox, double skip, double blocksAway, double accuracy) {
List<Vector> positions = traverse(blocksAway, accuracy);
for (Vector position : positions) {
List<Vector3d> positions = traverse(blocksAway, accuracy);
for (Vector3d position : positions) {
if (intersects(position, collisionBox.min(), collisionBox.max())) {
return true;
}
@@ -132,8 +138,8 @@ public class RayTrace {
//debug / effects
public void highlight(World world, double blocksAway, double accuracy) {
for (Vector position : traverse(blocksAway, accuracy)) {
world.playEffect(position.toLocation(world), (PacketEvents.getAPI().getServerManager().getVersion()
for (Vector3d position : traverse(blocksAway, accuracy)) {
world.playEffect(new Location(world, position.x, position.y, position.z), (PacketEvents.getAPI().getServerManager().getVersion()
.isNewerThanOrEquals(ServerVersion.V_1_13) ? Effect.SMOKE : Effect.valueOf("COLOURED_DUST")), 0);
}
}
@@ -8,10 +8,10 @@ import com.github.retrooper.packetevents.protocol.world.states.defaulttags.Block
import com.github.retrooper.packetevents.protocol.world.states.enums.*;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.block.WrappedBlock;
import dev.brighten.ac.utils.BlockUtils;
import dev.brighten.ac.utils.math.IntVector;
import dev.brighten.ac.utils.world.blocks.*;
import dev.brighten.ac.utils.world.types.*;
@@ -110,12 +110,58 @@ public enum BlockData {
_DOOR(new DoorHandler(), BlockTags.DOORS.getStates().toArray(new StateType[0])),
_HOPPER(new HopperBounding(), StateTypes.HOPPER),
_HOPPER((version, player, block) -> {
if(version.isOlderThan(ClientVersion.V_1_13)) {
double thickness = 0.125;
return new ComplexCollisionBox(
new SimpleCollisionBox(0,0,0,1, 0.125*5,1),
new SimpleCollisionBox(0, 0.125*5, 0, thickness, 1, 1),
new SimpleCollisionBox(1-thickness, 0.125*5, 0, 1, 1, 1),
new SimpleCollisionBox(0, 0.125*5, 0, 1, 1, thickness),
new SimpleCollisionBox(0, 0.125*5, 1-thickness, 1, 1, 1)
);
} else {
ComplexCollisionBox hopperBox = new ComplexCollisionBox();
switch (block.getBlockState().getFacing()) {
case DOWN:
hopperBox.add(new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 4.0D, 10.0D));
break;
case EAST:
hopperBox.add(new HexCollisionBox(12.0D, 4.0D, 6.0D, 16.0D, 8.0D, 10.0D));
break;
case NORTH:
hopperBox.add(new HexCollisionBox(6.0D, 4.0D, 0.0D, 10.0D, 8.0D, 4.0D));
break;
case SOUTH:
hopperBox.add(new HexCollisionBox(6.0D, 4.0D, 12.0D, 10.0D, 8.0D, 16.0D));
break;
case WEST:
hopperBox.add(new HexCollisionBox(0.0D, 4.0D, 6.0D, 4.0D, 8.0D, 10.0D));
break;
}
hopperBox.add(new SimpleCollisionBox(0, 0.625, 0, 1.0, 0.6875, 1.0));
hopperBox.add(new SimpleCollisionBox(0, 0.6875, 0, 0.125, 1, 1));
hopperBox.add(new SimpleCollisionBox(0.125, 0.6875, 0, 1, 1, 0.125));
hopperBox.add(new SimpleCollisionBox(0.125, 0.6875, 0.875, 1, 1, 1));
hopperBox.add(new SimpleCollisionBox(0.25, 0.25, 0.25, 0.75, 0.625, 0.75));
hopperBox.add(new SimpleCollisionBox(0.875, 0.6875, 0.125, 1, 1, 0.875));
return hopperBox;
}
}, StateTypes.HOPPER),
_CAKE((protocol, player, block) -> {
double f1 = (1 + block.getBlockState().getBites() * 2) / 16D;
return new SimpleCollisionBox(f1, 0, 0.0625, 1 - 0.0625, 0.5, 1 - 0.0625);
}, StateTypes.CAKE),
STONE_CUTTER((version, player, block) -> {
if (version.isOlderThanOrEquals(ClientVersion.V_1_13_2))
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1);
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 9.0D, 16.0D);
}, StateTypes.STONECUTTER),
_COCOA_BEAN((protocol, player, block) -> {
int age = block.getBlockState().getAge();
if (protocol.isNewerThanOrEquals(ClientVersion.V_1_9_1) && protocol.isOlderThan(ClientVersion.V_1_11))
@@ -282,7 +328,34 @@ public enum BlockData {
StateTypes.STRUCTURE_VOID),
_END_ROD(new DynamicRod(), StateTypes.END_ROD),
_CAULDRON(new CouldronBounding(), StateTypes.CAULDRON),
_CAULDRON((version, player, block) -> {
if(version.isOlderThanOrEquals(ClientVersion.V_1_13_2)) {
double thickness = 0.125;
return new ComplexCollisionBox(new SimpleCollisionBox(0,0,0,1, 0.3125,1),
new SimpleCollisionBox(0, 0.3125, 0, thickness, 1, 1),
new SimpleCollisionBox(1-thickness, 0.3125, 0, 1, 1, 1),
new SimpleCollisionBox(0, 0.3125, 0, 1, 1, thickness),
new SimpleCollisionBox(0, 0.3125, 1-thickness, 1, 1, 1));
} else {
return new ComplexCollisionBox(new SimpleCollisionBox(0.0, 0.0, 0.0, 0.125, 1.0, 0.25),
new SimpleCollisionBox(0.0, 0.0, 0.75, 0.125, 1.0, 1.0),
new SimpleCollisionBox(0.125, 0.0, 0.0, 0.25, 1.0, 0.125),
new SimpleCollisionBox(0.125, 0.0, 0.875, 0.25, 1.0, 1.0),
new SimpleCollisionBox(0.75, 0.0, 0.0, 1.0, 1.0, 0.125),
new SimpleCollisionBox(0.75, 0.0, 0.875, 1.0, 1.0, 1.0),
new SimpleCollisionBox(0.875, 0.0, 0.125, 1.0, 1.0, 0.25),
new SimpleCollisionBox(0.875, 0.0, 0.75, 1.0, 1.0, 0.875),
new SimpleCollisionBox(0.0, 0.1875, 0.25, 1.0, 0.25, 0.75),
new SimpleCollisionBox(0.125, 0.1875, 0.125, 0.875, 0.25, 0.25),
new SimpleCollisionBox(0.125, 0.1875, 0.75, 0.875, 0.25, 0.875),
new SimpleCollisionBox(0.25, 0.1875, 0.0, 0.75, 1.0, 0.125),
new SimpleCollisionBox(0.25, 0.1875, 0.875, 0.75, 1.0, 1.0),
new SimpleCollisionBox(0.0, 0.25, 0.25, 0.125, 1.0, 0.75),
new SimpleCollisionBox(0.875, 0.25, 0.25, 1.0, 1.0, 0.75)
);
}
}, StateTypes.CAULDRON),
_CACTUS(new SimpleCollisionBox(0.0625, 0, 0.0625,
1 - 0.0625, 1 - 0.0625, 1 - 0.0625), StateTypes.CACTUS),
_PISTON_BASE(new PistonBaseCollision(), StateTypes.PISTON, StateTypes.STICKY_PISTON),
@@ -304,6 +377,67 @@ public enum BlockData {
}, StateTypes.LECTERN),
_POT(new SimpleCollisionBox(0.3125, 0.0, 0.3125, 0.6875, 0.375, 0.6875),
StateTypes.FLOWER_POT),
KELP(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 9.0D, 16.0D), StateTypes.KELP),
// Kelp block is a full block, so it by default is correct
BELL((version, player, block) -> {
if (version.isOlderThanOrEquals(ClientVersion.V_1_13_2))
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1);
BlockFace direction = block.getBlockState().getFacing();
if (block.getBlockState().getAttachment() == Attachment.FLOOR) {
return direction != BlockFace.NORTH && direction != BlockFace.SOUTH ?
new HexCollisionBox(4.0D, 0.0D, 0.0D, 12.0D, 16.0D, 16.0D) :
new HexCollisionBox(0.0D, 0.0D, 4.0D, 16.0D, 16.0D, 12.0D);
}
ComplexCollisionBox complex = new ComplexCollisionBox(
new HexCollisionBox(5.0D, 6.0D, 5.0D, 11.0D, 13.0D, 11.0D),
new HexCollisionBox(4.0D, 4.0D, 4.0D, 12.0D, 6.0D, 12.0D));
if (block.getBlockState().getAttachment() == Attachment.CEILING) {
complex.add(new HexCollisionBox(7.0D, 13.0D, 7.0D, 9.0D, 16.0D, 9.0D));
} else if (block.getBlockState().getAttachment() == Attachment.DOUBLE_WALL) {
if (direction != BlockFace.NORTH && direction != BlockFace.SOUTH) {
complex.add(new HexCollisionBox(0.0D, 13.0D, 7.0D, 16.0D, 15.0D, 9.0D));
} else {
complex.add(new HexCollisionBox(7.0D, 13.0D, 0.0D, 9.0D, 15.0D, 16.0D));
}
} else if (direction == BlockFace.NORTH) {
complex.add(new HexCollisionBox(7.0D, 13.0D, 0.0D, 9.0D, 15.0D, 13.0D));
} else if (direction == BlockFace.SOUTH) {
complex.add(new HexCollisionBox(7.0D, 13.0D, 3.0D, 9.0D, 15.0D, 16.0D));
} else {
if (direction == BlockFace.EAST) {
complex.add(new HexCollisionBox(3.0D, 13.0D, 7.0D, 16.0D, 15.0D, 9.0D));
} else {
complex.add(new HexCollisionBox(0.0D, 13.0D, 7.0D, 13.0D, 15.0D, 9.0D));
}
}
return complex;
}, StateTypes.BELL),
SCAFFOLDING((version, player, block) -> {
// ViaVersion replacement block - hay block
if (version.isOlderThanOrEquals(ClientVersion.V_1_13_2))
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1);
if (player.getMovement().getFrom().getY() > player.getMovement().getTo().getY() + 1 - 1e-5 && !player.getInfo().sneaking) {
return new ComplexCollisionBox(new HexCollisionBox(0.0D, 14.0D, 0.0D, 16.0D, 16.0D, 16.0D),
new HexCollisionBox(0.0D, 0.0D, 0.0D, 2.0D, 16.0D, 2.0D),
new HexCollisionBox(14.0D, 0.0D, 0.0D, 16.0D, 16.0D, 2.0D),
new HexCollisionBox(0.0D, 0.0D, 14.0D, 2.0D, 16.0D, 16.0),
new HexCollisionBox(14.0D, 0.0D, 14.0D, 16.0D, 16.0D, 16.0D));
}
return block.getBlockState().getDistance() != 0 && block.getBlockState().isBottom() && player.getMovement().getFrom().getY() > player.getMovement().getTo().getY() - 1e-5 ?
new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D) :
NoCollisionBox.INSTANCE;
}, StateTypes.SCAFFOLDING),
_NONE(NoCollisionBox.INSTANCE, Stream.of(StateTypes.TORCH, StateTypes.REDSTONE_TORCH,
StateTypes.REDSTONE_WIRE, StateTypes.REDSTONE_WALL_TORCH, StateTypes.POWERED_RAIL, StateTypes.WALL_TORCH,
@@ -361,10 +495,10 @@ public enum BlockData {
return getBox(player, block.getLocation(), version);
}
public CollisionBox getBox(APlayer player, IntVector block, ClientVersion version) {
public CollisionBox getBox(APlayer player, Vector3i block, ClientVersion version) {
if (this.box != null)
return this.box.copy().offset(block.getX(), block.getY(), block.getZ());
return new DynamicCollisionBox(dynamic, player, player.getBlockUpdateHandler().getBlock(block), version)
return new DynamicCollisionBox(dynamic, player, player.getWorldTracker().getBlock(block), version)
.offset(block.getX(), block.getY(), block.getZ());
}
@@ -3,6 +3,7 @@ package dev.brighten.ac.utils.world;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import dev.brighten.ac.handler.entity.TrackedEntity;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.world.types.NoCollisionBox;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
import org.bukkit.Location;
@@ -23,6 +24,10 @@ public class EntityData {
return bounds(entity.getEntityType()).offset(location.getX(), location.getY(), location.getZ());
}
public static CollisionBox getEntityBox(KLocation location, TrackedEntity entity) {
return bounds(entity.getEntityType()).offset(location.getX(), location.getY(), location.getZ());
}
public static CollisionBox getEntityBox(Location location, EntityType entity) {
return bounds(entity).offset(location.getX(), location.getY(), location.getZ());
}
@@ -7,9 +7,9 @@ import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.enums.Half;
import com.github.retrooper.packetevents.protocol.world.states.enums.Hinge;
import com.github.retrooper.packetevents.util.Vector3i;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.block.WrappedBlock;
import dev.brighten.ac.utils.math.IntVector;
import dev.brighten.ac.utils.world.CollisionBox;
import dev.brighten.ac.utils.world.types.CollisionFactory;
import dev.brighten.ac.utils.world.types.HexCollisionBox;
@@ -50,10 +50,10 @@ public class DoorHandler implements CollisionFactory {
if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_12_2)
|| version.isOlderThanOrEquals(ClientVersion.V_1_12_2)) {
if (door.getBlockState().getHalf() == Half.LOWER) {
IntVector aboveVec = door.getLocation().clone();
Vector3i aboveVec = door.getLocation();
aboveVec.setY(aboveVec.getY() + 1);
WrappedBlockState above = player.getBlockUpdateHandler().getBlock(aboveVec).getBlockState();
aboveVec = aboveVec.add(0, aboveVec.getY() + 1, 0);
WrappedBlockState above = player.getWorldTracker().getBlock(aboveVec).getBlockState();
facingDirection = door.getBlockState().getFacing();
isClosed = !door.getBlockState().isOpen();
@@ -67,10 +67,10 @@ public class DoorHandler implements CollisionFactory {
isRightHinge = false;
}
} else {
IntVector belowVec = door.getLocation().clone();
Vector3i belowVec = door.getLocation();
belowVec.setY(belowVec.getY() - 1);
WrappedBlockState below = player.getBlockUpdateHandler().getBlock(belowVec).getBlockState();
belowVec = belowVec.add(0, belowVec.getY() - 1, 0);
WrappedBlockState below = player.getWorldTracker().getBlock(belowVec).getBlockState();
if (below.getType() == door.getBlockState().getType() && below.getHalf() == Half.LOWER) {
isClosed = !below.isOpen();
@@ -44,7 +44,7 @@ public class DynamicStair implements CollisionFactory {
z = originalStairs.getLocation().getZ();
WrappedBlock offsetOne = player == null
? null
: player.getBlockUpdateHandler().getBlock(
: player.getWorldTracker().getBlock(
x + facing.getModX(),
y + facing.getModY(),
z + facing.getModZ());
@@ -64,7 +64,7 @@ public class DynamicStair implements CollisionFactory {
}
}
WrappedBlock offsetTwo = player.getBlockUpdateHandler()
WrappedBlock offsetTwo = player.getWorldTracker()
.getBlock(x + facing.getOppositeFace().getModX(),
y + facing.getOppositeFace().getModY(), z
+ facing.getOppositeFace().getModZ());
@@ -4,18 +4,18 @@ import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.particle.type.ParticleType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.util.Vector3d;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.block.WrappedBlock;
import dev.brighten.ac.handler.entity.TrackedEntity;
import dev.brighten.ac.utils.Helper;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.Materials;
import dev.brighten.ac.utils.Tuple;
import dev.brighten.ac.utils.math.RayTrace;
import dev.brighten.ac.utils.world.BlockData;
import dev.brighten.ac.utils.world.CollisionBox;
import me.hydro.emulator.util.mcp.MathHelper;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.Arrays;
@@ -58,15 +58,15 @@ public class RayCollision implements CollisionBox {
directionZ = 0;
}
public RayCollision(LivingEntity e) {
public RayCollision(TrackedEntity e) {
this(e.getEyeLocation());
}
public RayCollision(Location l) {
public RayCollision(KLocation l) {
this(l.toVector(),l.getDirection());
}
public RayCollision(Vector position, Vector direction) {
public RayCollision(Vector3d position, Vector3d direction) {
this.originX = position.getX();
this.originY = position.getY();
this.originZ = position.getZ();
@@ -75,17 +75,17 @@ public class RayCollision implements CollisionBox {
this.directionZ = direction.getZ();
}
public Vector getOrigin() {
return new Vector(originX, originY, originZ);
public Vector3d getOrigin() {
return new Vector3d(originX, originY, originZ);
}
public Vector getDirection() {
return new Vector(directionX, directionY, directionZ);
public Vector3d getDirection() {
return new Vector3d(directionX, directionY, directionZ);
}
@Override
public boolean isCollided(CollisionBox other) {
if (other instanceof RayCollision) {
if (other instanceof RayCollision) {
return false; // lol no support
} else {
List<SimpleCollisionBox> boxes = new ArrayList<>();
@@ -141,7 +141,7 @@ public class RayCollision implements CollisionBox {
public List<CollisionBox> boxesOnRay(APlayer player, double distance) {
int amount = Math.round((float) (distance / 0.5));
Location[] locs = new Location[Math.max(2, amount)]; //We do a max to prevent NegativeArraySizeException.
KLocation[] locs = new KLocation[Math.max(2, amount)]; //We do a max to prevent NegativeArraySizeException.
List<CollisionBox> boxes = new ArrayList<>();
ClientVersion version = PacketEvents.getAPI().getServerManager().getVersion().toClientVersion();
@@ -152,7 +152,7 @@ public class RayCollision implements CollisionBox {
int fy = MathHelper.floor_double(originY + (directionY * ix));
int fz = MathHelper.floor_double(originZ + (directionZ * ix));
WrappedBlock block = player.getBlockUpdateHandler().getBlock(fx, fy, fz);
WrappedBlock block = player.getWorldTracker().getBlock(fx, fy, fz);
if (block == null) continue;
@@ -173,7 +173,7 @@ public class RayCollision implements CollisionBox {
public WrappedBlock getClosestBlockOfType(APlayer player, int bitmask, double distance) {
int amount = Math.round((float) (distance / 0.5));
Location[] locs = new Location[Math.max(2, amount)]; //We do a max
KLocation[] locs = new KLocation[Math.max(2, amount)]; //We do a max
ClientVersion version = PacketEvents.getAPI().getServerManager().getVersion().toClientVersion();
for (int i = 0; i < locs.length; i++) {
@@ -183,7 +183,7 @@ public class RayCollision implements CollisionBox {
int fy = MathHelper.floor_double(originY + (directionY * ix));
int fz = MathHelper.floor_double(originZ + (directionZ * ix));
WrappedBlock block = player.getBlockUpdateHandler().getBlock(fx, fy, fz);
WrappedBlock block = player.getWorldTracker().getBlock(fx, fy, fz);
if(block == null || !Materials.checkFlag(block.getType(), bitmask)) continue;
@@ -228,7 +228,7 @@ public class RayCollision implements CollisionBox {
RayTrace trace = new RayTrace(ray.getOrigin(), ray.getDirection());
Vector point = trace.positionOfIntersection(box, Math.max(0, dist - range), 0.01);
Vector3d point = trace.positionOfIntersection(box, Math.max(0, dist - range), 0.01);
return ray.getOrigin().distance(point);
}
@@ -347,23 +347,23 @@ public class RayCollision implements CollisionBox {
}
}
public Vector collisionPoint(SimpleCollisionBox box) {
public Vector3d collisionPoint(SimpleCollisionBox box) {
Tuple<Double, Double> p = new Tuple<>();
if (box==null||!intersect(this,box,p))
return null;
Vector vector = new Vector(directionX,directionY,directionZ);
Vector3d vector = new Vector3d(directionX,directionY,directionZ);
vector.normalize();
vector.multiply(p.one);
vector.add(new Vector(originX,originY,originZ));
vector.add(new Vector3d(originX,originY,originZ));
return vector;
}
public Vector collisionPoint(double dist) {
Vector vector = new Vector(directionX,directionY,directionZ);
public Vector3d collisionPoint(double dist) {
Vector3d vector = new Vector3d(directionX,directionY,directionZ);
vector.normalize();
vector.multiply(dist);
vector.add(new Vector(originX,originY,originZ));
vector.add(new Vector3d(originX,originY,originZ));
return vector;
}
}
@@ -1,6 +1,7 @@
package dev.brighten.ac.utils.world.types;
import com.github.retrooper.packetevents.protocol.particle.type.ParticleType;
import com.github.retrooper.packetevents.util.Vector3d;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.utils.Helper;
import dev.brighten.ac.utils.KLocation;
@@ -54,7 +55,7 @@ public class SimpleCollisionBox implements CollisionBox {
maxZ = width / 2;
}
public SimpleCollisionBox(Vector min, Vector max) {
public SimpleCollisionBox(Vector3d min, Vector3d max) {
this(min.getX(), min.getY(), min.getZ(), max.getX(), max.getY(), max.getZ());
}
@@ -76,6 +77,13 @@ public class SimpleCollisionBox implements CollisionBox {
maxY += height;
}
public SimpleCollisionBox(Vector3d vec, double width, double height) {
this(vec.getX(), vec.getY(), vec.getZ(), vec.getX(), vec.getY(), vec.getZ());
expand(width / 2, 0, width / 2);
maxY += height;
}
public void sort() {
double temp;
if (minX >= maxX) {
@@ -196,26 +204,26 @@ public class SimpleCollisionBox implements CollisionBox {
return this;
}
public Vector[] corners() {
public Vector3d[] corners() {
sort();
Vector[] vectors = new Vector[8];
vectors[0] = new Vector(minX, minY, minZ);
vectors[1] = new Vector(minX, minY, maxZ);
vectors[2] = new Vector(maxX, minY, minZ);
vectors[3] = new Vector(maxX, minY, maxZ);
vectors[4] = new Vector(minX, maxY, minZ);
vectors[5] = new Vector(minX, maxY, maxZ);
vectors[6] = new Vector(maxX, maxY, minZ);
vectors[7] = new Vector(maxX, maxY, maxZ);
Vector3d[] vectors = new Vector3d[8];
vectors[0] = new Vector3d(minX, minY, minZ);
vectors[1] = new Vector3d(minX, minY, maxZ);
vectors[2] = new Vector3d(maxX, minY, minZ);
vectors[3] = new Vector3d(maxX, minY, maxZ);
vectors[4] = new Vector3d(minX, maxY, minZ);
vectors[5] = new Vector3d(minX, maxY, maxZ);
vectors[6] = new Vector3d(maxX, maxY, minZ);
vectors[7] = new Vector3d(maxX, maxY, maxZ);
return vectors;
}
public Vector min() {
return new Vector(minX, minY, minZ);
public Vector3d min() {
return new Vector3d(minX, minY, minZ);
}
public Vector max() {
return new Vector(maxX, maxY, maxZ);
public Vector3d max() {
return new Vector3d(maxX, maxY, maxZ);
}
@Override
@@ -1,11 +1,11 @@
package dev.brighten.ac.utils;
import com.github.retrooper.packetevents.util.MathUtil;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import lombok.Data;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.util.Vector;
import org.joml.Vector2d;
import java.util.Objects;
@@ -41,14 +41,18 @@ public class KLocation implements Cloneable {
this.timeStamp = System.currentTimeMillis();
}
public KLocation(Vector vector) {
public KLocation(Location location) {
this(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
}
public KLocation(Vector3d vector) {
this.x = vector.getX();
this.y = vector.getY();
this.z = vector.getZ();
this.timeStamp = System.currentTimeMillis();
}
public KLocation(Location location) {
public KLocation(KLocation location) {
this.x = location.getX();
this.y = location.getY();
this.z = location.getZ();
@@ -57,12 +61,12 @@ public class KLocation implements Cloneable {
this.timeStamp = System.currentTimeMillis();
}
public Vector toVector() {
return new Vector(x, y, z);
public Vector3d toVector() {
return new Vector3d(x, y, z);
}
public Vector3d toVector3d() {
return new Vector3d(x, y, z);
public Vector3i toVector3i() {
return new Vector3i((int) x, (int) y, (int) z);
}
public Location toLocation(World world) {
@@ -112,8 +116,27 @@ public class KLocation implements Cloneable {
return this;
}
public Vector getDirection() {
return MathUtils.getDirection(this);
public Vector3d getDirection() {
double rotX = this.getYaw();
double rotY = this.getPitch();
double x, y, z;
y = -Math.sin(Math.toRadians(rotY));
double xz = Math.cos(Math.toRadians(rotY));
x = -xz * Math.sin(Math.toRadians(rotX));
z = xz * Math.cos(Math.toRadians(rotX));
return new Vector3d(x, y, z);
}
public int getBlockX() {
return MathUtil.floor(x);
}
public int getBlockY() {
return MathUtil.floor(y);
}
public int getBlockZ() {
return MathUtil.floor(z);
}
@Override
@@ -1,5 +1,6 @@
package dev.brighten.ac.utils;
import com.github.retrooper.packetevents.util.Vector3d;
import lombok.val;
import me.hydro.emulator.util.mcp.MathHelper;
import org.bukkit.Location;
@@ -196,10 +197,6 @@ public class MathUtils {
return MathUtils.yawTo180D(playerRotation.getX() - expectedRotation.getX());
}
public static double getAngle(KLocation loc1, KLocation loc2) {
return getAngle(loc1.toLocation(null), loc2.toLocation(null));
}
public static float distanceBetweenAngles(float a, float b) {
final float first = a % 360;
final float second = b % 360;
@@ -544,16 +541,14 @@ public class MathUtils {
return (short) num;
}
/* Stolen from Bukkit */
public static Vector getDirection(KLocation loc) {
Vector vector = new Vector();
public static Vector3d getDirection(KLocation loc) {
Vector3d vector = new Vector3d();
double rotX = loc.getYaw();
double rotY = loc.getPitch();
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;
return new Vector3d(-xz * Math.sin(Math.toRadians(rotX)),
-Math.sin(Math.toRadians(rotY)),
xz * Math.cos(Math.toRadians(rotX)));
}
@@ -704,12 +699,12 @@ public class MathUtils {
return squareRoot;
}
public static Vector getDirection(float yaw, float pitch) {
public static Vector3d getDirection(float yaw, float pitch) {
float f = MathHelper.cos(MathHelper.FastMathType.VANILLA, -yaw * 0.017453292F - (float)Math.PI);
float f1 = MathHelper.sin(MathHelper.FastMathType.VANILLA, -yaw * 0.017453292F - (float)Math.PI);
float f2 = -MathHelper.cos(MathHelper.FastMathType.VANILLA, -pitch * 0.017453292F);
float f3 = MathHelper.sin(MathHelper.FastMathType.VANILLA, -pitch * 0.017453292F);
return new Vector(f1 * f2, f3, f * f2);
return new Vector3d(f1 * f2, f3, f * f2);
}
public static float sqrt(float number) {
+1 -1
Submodule Neo updated: b45b76d09d...feb79131a2
+4
View File
@@ -30,6 +30,10 @@
</build>
<repositories>
<repository>
<id>maven-central</id>
<url>https://nexus.funkemunky.cc/repository/maven-central/</url>
</repository>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>