Compare commits

...
8 Commits
58 changed files with 1064 additions and 451 deletions

No files matched your search

+41 -3
View File
@@ -28,12 +28,13 @@ spotless {
group = "ac.grim.grimac"
version = "2.3.69"
description = "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0."
java.sourceCompatibility = JavaVersion.VERSION_1_8
java.targetCompatibility = JavaVersion.VERSION_1_8
// Set to false for debug builds
// You cannot live reload classes if the jar relocates dependencies
var relocate = true;
// Checks Project properties -> environment variable -> defaults true
val relocate: Boolean = project.findProperty("relocate")?.toString()?.toBoolean()
?: System.getenv("RELOCATE_JAR")?.toBoolean()
?: true
repositories {
mavenLocal()
@@ -154,6 +155,43 @@ publishing.publications.create<MavenPublication>("maven") {
artifact(tasks["shadowJar"])
}
java {
sourceSets {
create("java18") {
java {
srcDirs("src/main/java18")
}
compileClasspath += main.get().output
runtimeClasspath += main.get().output
}
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
tasks.withType<JavaCompile> {
if (name == "compileJava18Java") {
options.compilerArgs.addAll(listOf("--add-modules", "jdk.incubator.vector", "-Xlint:unchecked"))
sourceCompatibility = "18"
targetCompatibility = "18"
}
}
tasks.withType<Jar> {
manifest {
attributes("Multi-Release" to "true")
}
duplicatesStrategy = DuplicatesStrategy.INCLUDE // Important for multi-release JARs
from(sourceSets.main.get().output)
from(sourceSets.getByName("java18").output) {
into("META-INF/versions/18")
}
}
tasks.shadowJar {
minimize()
archiveFileName.set("${project.name}-${project.version}.jar")
@@ -0,0 +1,149 @@
package ac.grim.grimac.utils.vector;
import jdk.incubator.vector.*;
public final class SIMDVector3D implements Vector3D {
private static final VectorSpecies<Double> SPECIES = DoubleVector.SPECIES_PREFERRED;
private static final VectorMask<Double> LENGTH_3_ARRAY_MASK = SPECIES.indexInRange(0, 3);
private static final VectorShuffle<Double> CROSS_PRODUCT_SHUFFLE1 = VectorShuffle.fromArray(SPECIES, new int[]{1, 2, 0, 3}, 0);
private static final VectorShuffle<Double> CROSS_PRODUCT_SHUFFLE2 = VectorShuffle.fromArray(SPECIES, new int[]{2, 0, 1, 3}, 0);
private static final DoubleVector FOURTH_COMPONENT_ZERO = DoubleVector.zero(SPECIES).withLane(3, 1.0);
private DoubleVector vector;
public SIMDVector3D(double x, double y, double z) {
this.vector = DoubleVector.fromArray(SPECIES, new double[]{x, y, z, 0}, 0);
}
@Override
public double getX() {
return this.vector.lane(0);
}
@Override
public double getY() {
return this.vector.lane(1);
}
@Override
public double getZ() {
return this.vector.lane(2);
}
@Override
public Vector3D setX(double x) {
this.vector = this.vector.withLane(0, x);
return this;
}
@Override
public Vector3D setY(double y) {
this.vector = this.vector.withLane(1, y);
return this;
}
@Override
public Vector3D setZ(double z) {
this.vector = this.vector.withLane(2, z);
return this;
}
@Override
public double length() {
return Math.sqrt(lengthSquared());
}
@Override
public double lengthSquared() {
return this.vector.mul(this.vector).reduceLanes(VectorOperators.ADD);
}
@Override
public Vector3D multiply(double m) {
this.vector = this.vector.mul(m);
return this;
}
@Override
public Vector3D normalize() {
// DoubleVector squared = this.vector.mul(this.vector);
// double sum = squared.reduceLanes(VectorOperators.ADD);
// double length = Math.sqrt(sum);
// this.vector = this.vector.div(length);
// return this;
double length = length();
this.vector = this.vector.div(length).blend(FOURTH_COMPONENT_ZERO, LENGTH_3_ARRAY_MASK.not());
return this;
}
@Override
public Vector3D crossProduct(Vector3D other) {
SIMDVector3D o = (SIMDVector3D) other;
DoubleVector tmp0 = this.vector.rearrange(CROSS_PRODUCT_SHUFFLE1);
DoubleVector tmp1 = o.vector.rearrange(CROSS_PRODUCT_SHUFFLE2);
DoubleVector tmp2 = tmp0.mul(o.vector);
DoubleVector tmp3 = tmp0.mul(tmp1);
DoubleVector tmp4 = tmp2.rearrange(CROSS_PRODUCT_SHUFFLE1);
this.vector = tmp3.sub(tmp4).blend(FOURTH_COMPONENT_ZERO, LENGTH_3_ARRAY_MASK.not());
return this;
}
@Override
public Vector3D add(Vector3D o) {
this.vector = this.vector.add(((SIMDVector3D) o).vector);
return this;
}
@Override
public Vector3D subtract(Vector3D o) {
this.vector = this.vector.sub(((SIMDVector3D) o).vector);
return this;
}
@Override
public Vector3D multiply(Vector3D o) {
this.vector = this.vector.mul(((SIMDVector3D) o).vector);
return this;
}
@Override
public double distance(Vector3D o) {
return Math.sqrt(distanceSquared(o));
}
@Override
public double distanceSquared(Vector3D o) {
DoubleVector diff = this.vector.sub(((SIMDVector3D) o).vector);
return diff.mul(diff).reduceLanes(VectorOperators.ADD);
}
@Override
public double dot(Vector3D o) {
return this.vector.mul(((SIMDVector3D) o).vector).reduceLanes(VectorOperators.ADD);
}
@Override
public Vector3D clone() {
// I think this makes a shallow clone if I do it like this?
// try {
// return (Vector3D) super.clone();
// } catch (CloneNotSupportedException e) {
// throw new Error(e);
// }
try {
SIMDVector3D cloned = (SIMDVector3D) super.clone();
// Create a new DoubleVector with the same values
cloned.vector = DoubleVector.fromArray(SPECIES,
new double[]{this.getX(), this.getY(), this.getZ(), 0}, 0);
return cloned;
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
}
@@ -0,0 +1,13 @@
package ac.grim.grimac.utils.vector;
import jdk.incubator.vector.VectorMask;
import jdk.incubator.vector.VectorSpecies;
import jdk.incubator.vector.DoubleVector;
public class VectorOperationsJava18 implements VectorOperations {
@Override
public Vector3D newVector(double x, double y, double z) {
return new SIMDVector3D(x, y, z);
}
}
@@ -27,6 +27,7 @@ import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.nmsutil.BlockRayTrace;
import ac.grim.grimac.utils.data.packetentity.dragon.PacketEntityEnderDragonPart;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
@@ -41,7 +42,7 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientIn
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -51,6 +52,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
// You may not copy the check unless you are licensed under GPL
@CheckData(name = "Reach", configName = "Reach", setback = 10)
public class Reach extends Check implements PacketCheck {
@@ -208,7 +211,7 @@ public class Reach extends Check implements PacketCheck {
double minDistance = Double.MAX_VALUE;
// https://bugs.mojang.com/browse/MC-67665
List<Vector> possibleLookDirs = new ArrayList<>(Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot)));
List<Vector3D> possibleLookDirs = new ArrayList<>(Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot)));
// If we are a tick behind, we don't know their next look so don't bother doing this
if (!isPrediction) {
@@ -228,12 +231,12 @@ public class Reach extends Check implements PacketCheck {
// +3 would be 3 + 3 = 6, which is the pre-1.20.5 behaviour, preventing "Missed Hitbox"
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE) + 3;
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (Vector lookVec : possibleLookDirs) {
for (Vector3D lookVec : possibleLookDirs) {
for (double eye : possibleEyeHeights) {
Vector eyePos = new Vector(from.getX(), from.getY() + eye, from.getZ());
Vector endReachPos = eyePos.clone().add(new Vector(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
ac.grim.grimac.utils.vector.Vector3D eyePos = newVector3D(from.getX(), from.getY() + eye, from.getZ());
ac.grim.grimac.utils.vector.Vector3D endReachPos = eyePos.clone().add(newVector3D(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
Vector intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).getFirst();
Vector3D intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).getFirst();
if (ReachUtils.isVecInside(targetBox, eyePos)) {
minDistance = 0;
@@ -281,7 +284,7 @@ public class Reach extends Check implements PacketCheck {
public void handleBlockChange(Vector3i vector3i, WrappedBlockState state) {
if (blocksChangedThisTick.size() >= 40) return; // Don't let players freeze movement packets to grow this
// Only do this for nearby blocks
if (new Vector(vector3i.x, vector3i.y, vector3i.z).distanceSquared(new Vector(player.x, player.y, player.z)) > 6) return;
if (newVector3D(vector3i.x, vector3i.y, vector3i.z).distanceSquared(newVector3D(player.x, player.y, player.z)) > 6) return;
// Only do this if the state really had any world impact
if (state.equals(player.compensatedWorld.getWrappedBlockStateAt(vector3i))) return;
blocksChangedThisTick.add(vector3i);
@@ -289,14 +292,14 @@ public class Reach extends Check implements PacketCheck {
// Returns a pair so we can check the block type in the flag
@Nullable
private Pair<Double, HitData> getTargetBlock(GrimPlayer player, List<Vector> possibleLookDirs, Vector3d from, double minDistance) {
private Pair<Double, HitData> getTargetBlock(GrimPlayer player, List<Vector3D> possibleLookDirs, Vector3d from, double minDistance) {
// Check every possible look direction and every possible eye height
// IF *NONE* of them allow the player to hit the entity, this is an invalid hit
HitData bestHitData = null;
double min = Double.MAX_VALUE;
for (Vector lookVec : possibleLookDirs) {
for (Vector3D lookVec : possibleLookDirs) {
for (double eye : player.getPossibleEyeHeights()) {
Vector eyes = new Vector(from.getX(), from.getY() + eye, from.getZ());
Vector3D eyes = newVector3D(from.getX(), from.getY() + eye, from.getZ());
final double reach = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
final HitData hitResult = BlockRayTrace.getNearestReachHitResult(player, eyes, lookVec, minDistance, reach);
if (hitResult == null) {
@@ -9,7 +9,7 @@ import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import ac.grim.grimac.utils.lists.EvictingQueue;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.HashSet;
import java.util.Set;
@@ -45,8 +45,8 @@ public class DebugHandler extends Check implements PostPredictionCheck {
ChatColor color = pickColor(offset, offset);
Vector predicted = player.predictedVelocity.vector;
Vector actually = player.actualMovement;
Vector3D predicted = player.predictedVelocity.vector;
Vector3D actually = player.actualMovement;
ChatColor xColor = pickColor(Math.abs(predicted.getX() - actually.getX()), offset);
ChatColor yColor = pickColor(Math.abs(predicted.getY() - actually.getY()), offset);
@@ -9,7 +9,9 @@ import ac.grim.grimac.utils.math.VectorUtils;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
@CheckData(name = "FarPlace")
public class FarPlace extends BlockPlaceCheck {
@@ -27,8 +29,8 @@ public class FarPlace extends BlockPlaceCheck {
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (double d : possibleEyeHeights) {
SimpleCollisionBox box = new SimpleCollisionBox(blockPos);
Vector eyes = new Vector(player.x, player.y + d, player.z);
Vector best = VectorUtils.cutBoxToVector(eyes, box);
Vector3D eyes = newVector3D(player.x, player.y + d, player.z);
Vector3D best = VectorUtils.cutBoxToVector(eyes, box);
min = Math.min(min, eyes.distanceSquared(best));
}
@@ -19,12 +19,14 @@ import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerExplosion;
import lombok.Getter;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import org.jetbrains.annotations.Nullable;
import java.util.Deque;
import java.util.LinkedList;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
@CheckData(name = "AntiExplosion", configName = "Explosion", setback = 10)
public class ExplosionHandler extends Check implements PostPredictionCheck {
Deque<VelocityData> firstBreadMap = new LinkedList<>();
@@ -121,7 +123,7 @@ public class ExplosionHandler extends Check implements PostPredictionCheck {
}
public void addPlayerExplosion(int breadOne, Vector3f explosion) {
firstBreadMap.add(new VelocityData(-1, breadOne, player.getSetbackTeleportUtil().isSendingSetback, new Vector(explosion.getX(), explosion.getY(), explosion.getZ())));
firstBreadMap.add(new VelocityData(-1, breadOne, player.getSetbackTeleportUtil().isSendingSetback, newVector3D(explosion.getX(), explosion.getY(), explosion.getZ())));
}
public void setPointThree(boolean isPointThree) {
@@ -15,12 +15,14 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityVelocity;
import lombok.Getter;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import org.jetbrains.annotations.NotNull;
import java.util.Deque;
import java.util.LinkedList;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
// We are making a velocity sandwich between two pieces of transaction packets (bread)
@CheckData(name = "AntiKB", alternativeName = "AntiKnockback", configName = "Knockback", setback = 10, decay = 0.025)
public class KnockbackHandler extends Check implements PostPredictionCheck {
@@ -70,12 +72,12 @@ public class KnockbackHandler extends Check implements PostPredictionCheck {
// Wrap velocity between two transactions
player.sendTransaction();
addPlayerKnockback(entityId, player.lastTransactionSent.get(), new Vector(playerVelocity.getX(), playerVelocity.getY(), playerVelocity.getZ()));
addPlayerKnockback(entityId, player.lastTransactionSent.get(), newVector3D(playerVelocity.getX(), playerVelocity.getY(), playerVelocity.getZ()));
event.getTasksAfterSend().add(player::sendTransaction);
}
}
@NotNull public Pair<VelocityData, Vector> getFutureKnockback() {
@NotNull public Pair<VelocityData, Vector3D> getFutureKnockback() {
// Chronologically in the future
if (firstBreadMap.size() > 0) {
VelocityData data = firstBreadMap.peek();
@@ -97,7 +99,7 @@ public class KnockbackHandler extends Check implements PostPredictionCheck {
return new Pair<>(null, null);
}
private void addPlayerKnockback(int entityID, int breadOne, Vector knockback) {
private void addPlayerKnockback(int entityID, int breadOne, Vector3D knockback) {
firstBreadMap.add(new VelocityData(entityID, breadOne, player.getSetbackTeleportUtil().isSendingSetback, knockback));
}
@@ -19,11 +19,13 @@ import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerJoinGame;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRespawn;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateHealth;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.List;
import java.util.Objects;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
/**
* PlayerRespawnS2CPacket info (1.20.2+):
* If the world is different (check via registry key), world is recreated (all entities etc destroyed).
@@ -185,7 +187,7 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
player.compensatedEntities.hasSprintingAttributeEnabled = false;
}
player.pose = Pose.STANDING;
player.clientVelocity = new Vector();
player.clientVelocity = newVector3D();
player.gamemode = respawn.getGameMode();
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_17)) {
player.compensatedWorld.setDimension(respawn.getDimensionType(), event.getUser());
@@ -19,6 +19,7 @@ import ac.grim.grimac.utils.math.VectorUtils;
import ac.grim.grimac.utils.nmsutil.Collisions;
import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
@@ -31,13 +32,15 @@ import lombok.Getter;
import lombok.Setter;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedQueue;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
// Sync to netty
public final ConcurrentLinkedQueue<TeleportData> pendingTeleports = new ConcurrentLinkedQueue<>();
@@ -65,7 +68,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
@Override
public void onPredictionComplete(final PredictionComplete predictionComplete) {
// Grab friction now when we know player on ground and other variables
Vector afterTickFriction = player.clientVelocity.clone();
Vector3D afterTickFriction = player.clientVelocity.clone();
// We must first check if the player has accepted their setback
// If the setback isn't complete, then this position is illegitimate
@@ -115,7 +118,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
return false;
}
private void simulateFriction(Vector vector) {
private void simulateFriction(Vector3D vector) {
// We must always do this before simulating positions, as this is the last actual (safe) movement
// We must not do this for knockback or explosions, as they are at the start of the tick
if (player.wasTouchingWater) {
@@ -123,9 +126,9 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
} else if (player.wasTouchingLava) {
vector.multiply(0.5D);
if (player.hasGravity)
vector.add(new Vector(0.0D, -player.gravity / 4.0D, 0.0D));
vector.add(newVector3D(0.0D, -player.gravity / 4.0D, 0.0D));
} else if (player.isGliding) {
PredictionEngineElytra.getElytraMovement(player, vector, ReachUtils.getLook(player, player.xRot, player.yRot)).multiply(player.stuckSpeedMultiplier).multiply(new Vector(0.99F, 0.98F, 0.99F));
PredictionEngineElytra.getElytraMovement(player, vector, ReachUtils.getLook(player, player.xRot, player.yRot)).multiply(player.stuckSpeedMultiplier).multiply(newVector3D(0.99F, 0.98F, 0.99F));
vector.setY(vector.getY() - 0.05); // Make the player fall a bit
} else { // Gliding doesn't have friction, we handle it differently
PredictionEngineNormal.staticVectorEndOfTick(player, vector); // Lava and normal movement
@@ -147,9 +150,9 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
lastWorldResync = System.currentTimeMillis();
}
Vector clientVel = lastKnownGoodPosition.vector.clone();
Vector3D clientVel = lastKnownGoodPosition.vector.clone();
Pair<VelocityData, Vector> futureKb = player.checkManager.getKnockbackHandler().getFutureKnockback();
Pair<VelocityData, Vector3D> futureKb = player.checkManager.getKnockbackHandler().getFutureKnockback();
VelocityData futureExplosion = player.checkManager.getExplosionHandler().getFutureExplosion();
// Velocity sets
@@ -169,7 +172,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
// Mini prediction engine - simulate collisions
if (simulateNextTickPosition) {
Vector collide = Collisions.collide(player, clientVel.getX(), clientVel.getY(), clientVel.getZ());
Vector3D collide = Collisions.collide(player, clientVel.getX(), clientVel.getY(), clientVel.getZ());
position = position.withX(position.getX() + collide.getX());
// 1.8 players need the collision epsilon to not phase into blocks when being setback
@@ -412,7 +415,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
data = new TeleportData(safePosition, flags, transaction, teleportId);
requiredSetBack = new SetBackData(data, player.xRot, player.yRot, null, false, plugin);
this.lastKnownGoodPosition = new SetbackPosWithVector(safePosition, new Vector());
this.lastKnownGoodPosition = new SetbackPosWithVector(safePosition, newVector3D());
}
@AllArgsConstructor
@@ -420,6 +423,6 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
@Setter
public static class SetbackPosWithVector {
private Vector3d pos;
private Vector vector;
private Vector3D vector;
}
}
@@ -10,26 +10,29 @@ import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.lists.EvictingQueue;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.util.Vector3d;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import lombok.AllArgsConstructor;
import org.bukkit.util.Vector;
import java.util.*;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public final class SuperDebug extends Check implements PostPredictionCheck {
private static final StringBuilder[] flags = new StringBuilder[256]; // 17 MB of logs in memory
Object2IntMap<StringBuilder> continuedDebug = new Object2IntOpenHashMap<>();
List<VectorData> predicted = new EvictingQueue<>(60);
List<Vector> actually = new EvictingQueue<>(60);
List<Vector3D> actually = new EvictingQueue<>(60);
List<Location> locations = new EvictingQueue<>(60);
List<Vector> startTickClientVel = new EvictingQueue<>(60);
List<Vector> baseTickAddition = new EvictingQueue<>(60);
List<Vector> baseTickWater = new EvictingQueue<>(60);
List<Vector3D> startTickClientVel = new EvictingQueue<>(60);
List<Vector3D> baseTickAddition = new EvictingQueue<>(60);
List<Vector3D> baseTickWater = new EvictingQueue<>(60);
public SuperDebug(GrimPlayer player) {
super(player);
@@ -80,11 +83,11 @@ public final class SuperDebug extends Check implements PostPredictionCheck {
for (int i = 0; i < predicted.size(); i++) {
VectorData predict = predicted.get(i);
Vector actual = actually.get(i);
Vector3D actual = actually.get(i);
Location loc = locations.get(i);
Vector startTickVel = startTickClientVel.get(i);
Vector addition = baseTickAddition.get(i);
Vector water = baseTickWater.get(i);
Vector3D startTickVel = startTickClientVel.get(i);
Vector3D addition = baseTickAddition.get(i);
Vector3D water = baseTickWater.get(i);
appendDebug(sb, predict, actual, loc, startTickVel, addition, water);
}
@@ -189,7 +192,7 @@ public final class SuperDebug extends Check implements PostPredictionCheck {
continuedDebug.put(sb, 40);
}
private void appendDebug(StringBuilder sb, VectorData predict, Vector actual, Location location, Vector startTick, Vector addition, Vector water) {
private void appendDebug(StringBuilder sb, VectorData predict, Vector3D actual, Location location, Vector3D startTick, Vector3D addition, Vector3D water) {
if (predict.isZeroPointZeroThree()) {
sb.append("Movement threshold/tick skipping\n");
}
@@ -225,11 +228,11 @@ public final class SuperDebug extends Check implements PostPredictionCheck {
// Apply 0.003/0.005 to make numbers more accurate
Set<VectorData> set = new HashSet<>(Collections.singletonList(new VectorData(startTick.clone(), VectorData.VectorType.BestVelPicked)));
new PredictionEngine().applyMovementThreshold(player, set);
Vector trueStartVel = ((VectorData) set.toArray()[0]).vector;
Vector3D trueStartVel = ((VectorData) set.toArray()[0]).vector;
Vector clientMovement = getPlayerMathMovement(player, actual.clone().subtract(trueStartVel), location.xRot);
Vector simulatedMovement = getPlayerMathMovement(player, predict.vector.clone().subtract(trueStartVel), location.xRot);
Vector offset = actual.clone().subtract(predict.vector);
Vector3D clientMovement = getPlayerMathMovement(player, actual.clone().subtract(trueStartVel), location.xRot);
Vector3D simulatedMovement = getPlayerMathMovement(player, predict.vector.clone().subtract(trueStartVel), location.xRot);
Vector3D offset = actual.clone().subtract(predict.vector);
trueStartVel.add(addition);
trueStartVel.add(water);
@@ -268,14 +271,14 @@ public final class SuperDebug extends Check implements PostPredictionCheck {
sb.append("\n\n");
}
private Vector getPlayerMathMovement(GrimPlayer player, Vector wantedMovement, float f2) {
private Vector3D getPlayerMathMovement(GrimPlayer player, Vector3D wantedMovement, float f2) {
float f3 = player.trigHandler.sin(f2 * 0.017453292f);
float f4 = player.trigHandler.cos(f2 * 0.017453292f);
float bestTheoreticalX = (float) (f3 * wantedMovement.getZ() + f4 * wantedMovement.getX()) / (f3 * f3 + f4 * f4);
float bestTheoreticalZ = (float) (-f3 * wantedMovement.getX() + f4 * wantedMovement.getZ()) / (f3 * f3 + f4 * f4);
return new Vector(bestTheoreticalX, 0, bestTheoreticalZ);
return newVector3D(bestTheoreticalX, 0, bestTheoreticalZ);
}
@AllArgsConstructor
@@ -56,7 +56,7 @@ import net.kyori.adventure.text.TranslatableComponent;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -66,6 +66,10 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static ac.grim.grimac.utils.data.VectorData.VectorType;
import static ac.grim.grimac.utils.data.VectorData.VectorType.Normal;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
// Everything in this class should be sync'd to the anticheat thread.
// Put variables sync'd to the netty thread in PacketStateData
// Variables that need lag compensation should have their own class
@@ -92,7 +96,7 @@ public class GrimPlayer implements GrimUser {
public MovementCheckRunner movementCheckRunner;
public SyncedTags tagManager;
// End manager like classes
public Vector clientVelocity = new Vector();
public ac.grim.grimac.utils.vector.Vector3D clientVelocity = newVector3D();
PacketTracker packetTracker;
public final PacketOrderProcessor packetOrderProcessor = new PacketOrderProcessor(this);
private long transactionPing = 0;
@@ -106,9 +110,9 @@ public class GrimPlayer implements GrimUser {
public boolean hasGravity = true;
public final long joinTime = System.currentTimeMillis();
public boolean playerEntityHasGravity = true;
public VectorData predictedVelocity = new VectorData(new Vector(), VectorData.VectorType.Normal);
public Vector actualMovement = new Vector();
public Vector stuckSpeedMultiplier = new Vector(1, 1, 1);
public VectorData predictedVelocity = new VectorData(newVector3D(), Normal);
public Vector3D actualMovement = newVector3D();
public Vector3D stuckSpeedMultiplier = newVector3D(1, 1, 1);
public UncertaintyHandler uncertaintyHandler;
public double gravity;
public float friction;
@@ -187,9 +191,9 @@ public class GrimPlayer implements GrimUser {
public TrigHandler trigHandler;
public PacketStateData packetStateData;
// Keep track of basetick stuff
public Vector baseTickAddition = new Vector();
public Vector baseTickWaterPushing = new Vector();
public Vector startTickClientVel = new Vector();
public Vector3D baseTickAddition = newVector3D();
public Vector3D baseTickWaterPushing = newVector3D();
public Vector3D startTickClientVel = newVector3D();
// For syncing the player's full swing in 1.9+
public int movementPackets = 0;
public VelocityData firstBreadKB = null;
@@ -366,15 +370,15 @@ public class GrimPlayer implements GrimUser {
return data != null && data.getFirst() == id;
}
public void baseTickAddWaterPushing(Vector vector) {
public void baseTickAddWaterPushing(ac.grim.grimac.utils.vector.Vector3D vector) {
baseTickWaterPushing.add(vector);
}
public void baseTickAddVector(Vector vector) {
public void baseTickAddVector(Vector3D vector) {
clientVelocity.add(vector);
}
public void trackBaseTickAddition(Vector vector) {
public void trackBaseTickAddition(Vector3D vector) {
baseTickAddition.add(vector);
}
@@ -38,7 +38,11 @@ import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.data.VectorData.VectorType;
import static ac.grim.grimac.utils.data.VectorData.VectorType.Dead;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class MovementCheckRunner extends Check implements PositionCheck {
// Averaged over 500 predictions (Defaults set slightly above my 3600x results)
@@ -138,10 +142,10 @@ public class MovementCheckRunner extends Check implements PositionCheck {
double negX = Math.min(-0.05, GrimMath.clamp(player.actualMovement.getX(), -16, 16) - 0.05);
double negZ = Math.min(-0.05, GrimMath.clamp(player.actualMovement.getZ(), -16, 16) - 0.05);
Vector NE = Collisions.maybeBackOffFromEdge(new Vector(posX, 0, negZ), player, true);
Vector NW = Collisions.maybeBackOffFromEdge(new Vector(negX, 0, negZ), player, true);
Vector SE = Collisions.maybeBackOffFromEdge(new Vector(posX, 0, posZ), player, true);
Vector SW = Collisions.maybeBackOffFromEdge(new Vector(negX, 0, posZ), player, true);
Vector3D NE = Collisions.maybeBackOffFromEdge(newVector3D(posX, 0, negZ), player, true);
Vector3D NW = Collisions.maybeBackOffFromEdge(newVector3D(negX, 0, negZ), player, true);
Vector3D SE = Collisions.maybeBackOffFromEdge(newVector3D(posX, 0, posZ), player, true);
Vector3D SW = Collisions.maybeBackOffFromEdge(newVector3D(negX, 0, posZ), player, true);
boolean isEast = NE.getX() != posX || SE.getX() != posX;
boolean isWest = NW.getX() != negX || SW.getX() != negX;
@@ -184,7 +188,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
player.vehicleData.wasVehicleSwitch = false;
if (riding != null) {
Vector pos = new Vector(player.x, player.y, player.z);
Vector3D pos = newVector3D(player.x, player.y, player.z);
SimpleCollisionBox interTruePositions = riding.getPossibleCollisionBoxes();
// We shrink the expanded bounding box to what the packet positions can be, for a smaller box
@@ -194,7 +198,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
interTruePositions.expand(-width, 0, -width);
interTruePositions.expandMax(0, -height, 0);
Vector cutTo = VectorUtils.cutBoxToVector(pos, interTruePositions);
Vector3D cutTo = VectorUtils.cutBoxToVector(pos, interTruePositions);
// Now we need to simulate a tick starting at the most optimal position
// The start position is never sent, so we assume the most optimal start position
@@ -212,14 +216,14 @@ public class MovementCheckRunner extends Check implements PositionCheck {
} else {
// Server always teleports the player when they eject anyways,
// so just let the player control where they eject within reason, they get set back anyways
if (new Vector(player.lastX, player.lastY, player.lastZ).distance(new Vector(player.x, player.y, player.z)) > 3) {
if (newVector3D(player.lastX, player.lastY, player.lastZ).distance(newVector3D(player.x, player.y, player.z)) > 3) {
player.getSetbackTeleportUtil().executeForceResync(); // Too far! (I think this value is sane)
}
handleTeleport(update);
if (player.isClimbing) {
Vector ladder = player.clientVelocity.clone().setY(0.2);
Vector3D ladder = player.clientVelocity.clone().setY(0.2);
PredictionEngineNormal.staticVectorEndOfTick(player, ladder);
player.lastWasClimbing = ladder.getY();
}
@@ -300,7 +304,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
player.clientControlledVerticalCollision = Math.abs(player.y % (1 / 64D)) < 0.00001;
// This isn't the final velocity of the player in the tick, only the one applied to the player
player.actualMovement = new Vector(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
player.actualMovement = newVector3D(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
if (player.isSprinting != player.lastSprinting) {
player.compensatedEntities.hasSprintingAttributeEnabled = player.isSprinting;
@@ -427,8 +431,8 @@ public class MovementCheckRunner extends Check implements PositionCheck {
// Exempt if the player is dead or is riding a dead entity
if (player.compensatedEntities.getSelf().isDead || (riding != null && riding.isDead)) {
// Dead players can't cheat, if you find a way how they could, open an issue
player.predictedVelocity = new VectorData(new Vector(), VectorData.VectorType.Dead);
player.clientVelocity = new Vector();
player.predictedVelocity = new VectorData(newVector3D(), Dead);
player.clientVelocity = newVector3D();
} else if (player.disableGrim || (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_8) && player.gamemode == GameMode.SPECTATOR) || player.isFlying) {
// We could technically check spectator but what's the point...
// Added complexity to analyze a gamemode used mainly by moderators
@@ -451,7 +455,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
// Riptiding while on the ground moves the hitbox upwards before any movement code runs
// It's a pain to support and this is my best attempt
if (player.lastOnGround && player.packetStateData.tryingToRiptide && !player.compensatedEntities.getSelf().inVehicle()) {
Vector pushingMovement = Collisions.collide(player, 0, 1.1999999F, 0);
Vector3D pushingMovement = Collisions.collide(player, 0, 1.1999999F, 0);
player.verticalCollision = pushingMovement.getY() != 1.1999999F;
double currentY = player.clientVelocity.getY();
@@ -463,7 +467,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
player.lastY += pushingMovement.getY();
new PlayerBaseTick(player).updatePlayerPose();
player.boundingBox = GetBoundingBox.getPlayerBoundingBox(player, player.lastX, player.lastY, player.lastZ);
player.actualMovement = new Vector(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
player.actualMovement = newVector3D(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
player.couldSkipTick = true;
@@ -515,7 +519,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
//
// Checking for oldClientVel being too high fixes BleachHack vertical scaffold
if (player.getSetbackTeleportUtil().getRequiredSetBack() != null && player.getSetbackTeleportUtil().getRequiredSetBack().getTicksComplete() == 1) {
Vector setbackVel = player.getSetbackTeleportUtil().getRequiredSetBack().getVelocity();
Vector3D setbackVel = player.getSetbackTeleportUtil().getRequiredSetBack().getVelocity();
// A player must have velocity going INTO the ground to be able to jump
// Otherwise they could ignore upwards velocity that isn't useful into more useful upwards velocity (towering)
// So if they are supposed to be going upwards, or are supposed to be off the ground, resync
@@ -544,7 +548,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
// Patch sprint jumping with elytra exploit
if (player.bukkitPlayer != null && player.isGliding && player.predictedVelocity.isJump() && player.isSprinting && !allowSprintJumpingWithElytra) {
SetbackTeleportUtil.SetbackPosWithVector lastKnownGoodPosition = player.getSetbackTeleportUtil().lastKnownGoodPosition;
lastKnownGoodPosition.setVector(lastKnownGoodPosition.getVector().multiply(new Vector(0.6 * 0.91, 1, 0.6 * 0.91)));
lastKnownGoodPosition.setVector(lastKnownGoodPosition.getVector().multiply(newVector3D(0.6 * 0.91, 1, 0.6 * 0.91)));
player.getSetbackTeleportUtil().executeNonSimulatingSetback();
}
@@ -621,7 +625,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
* @param pushingMovement The collision result when trying to move the player upwards by 1.2f
* @return Whether it is more likely that this player was on the ground the tick they riptided
*/
private boolean likelyGroundRiptide(Vector pushingMovement) {
private boolean likelyGroundRiptide(Vector3D pushingMovement) {
// Y velocity gets reset if the player collides vertically
double riptideYResult = Riptide.getRiptideVelocity(player).getY();
@@ -9,16 +9,19 @@ import ac.grim.grimac.utils.enums.Pose;
import ac.grim.grimac.utils.latency.CompensatedEntities;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.nmsutil.*;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.Optional;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class PlayerBaseTick {
GrimPlayer player;
@@ -40,11 +43,11 @@ public class PlayerBaseTick {
public void doBaseTick() {
// Keep track of basetick stuff
player.baseTickAddition = new Vector();
player.baseTickWaterPushing = new Vector();
player.baseTickAddition = newVector3D();
player.baseTickWaterPushing = newVector3D();
if (player.isFlying && player.isSneaking && !player.compensatedEntities.getSelf().inVehicle()) {
Vector flyingShift = new Vector(0, player.flySpeed * -3, 0);
Vector3D flyingShift = newVector3D(0, player.flySpeed * -3, 0);
player.baseTickAddVector(flyingShift);
player.trackBaseTickAddition(flyingShift);
}
@@ -60,7 +63,7 @@ public class PlayerBaseTick {
// You cannot crouch while flying, only shift - could be specific to 1.14?
// pre-1.13 clients don't have this code
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) && player.wasTouchingWater && player.isSneaking && !player.isFlying && !player.compensatedEntities.getSelf().inVehicle()) {
Vector waterPushVector = new Vector(0, -0.04f, 0);
Vector3D waterPushVector = newVector3D(0, -0.04f, 0);
player.baseTickAddVector(waterPushVector);
player.trackBaseTickAddition(waterPushVector);
}
@@ -423,7 +426,7 @@ public class PlayerBaseTick {
}
boolean hasPushed = false;
Vector vec3 = new Vector();
Vector3D vec3 = newVector3D();
for (int x = floorX; x < ceilX; ++x) {
for (int y = floorY; y < ceilY; ++y) {
@@ -473,7 +476,7 @@ public class PlayerBaseTick {
}
double d2 = 0.0;
boolean hasTouched = false;
Vector vec3 = new Vector();
Vector3D vec3 = newVector3D();
int n7 = 0;
for (int x = floorX; x < ceilX; ++x) {
@@ -498,7 +501,7 @@ public class PlayerBaseTick {
d2 = Math.max(fluidHeightToWorld - aABB.minY, d2);
if (!player.isFlying) {
Vector vec32 = FluidTypeFlowing.getFlow(player, x, y, z);
Vector3D vec32 = FluidTypeFlowing.getFlow(player, x, y, z);
if (d2 < 0.4) {
vec32 = vec32.multiply(d2);
}
@@ -21,11 +21,13 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.OptionalInt;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
/**
* A lot of care was put into handling all the stupid stuff occurring between events
* <p>
@@ -144,7 +146,7 @@ public class PointThreeEstimator {
isNearBubbleColumn = true;
}
Vector fluidVector = FluidTypeFlowing.getFlow(player, x, y, z);
Vector3D fluidVector = FluidTypeFlowing.getFlow(player, x, y, z);
if (fluidVector.getX() != 0 || fluidVector.getZ() != 0) {
isNearHorizontalFlowingLiquid = true;
}
@@ -316,7 +318,7 @@ public class PointThreeEstimator {
player.boundingBox = player.boundingBox.copy().expand(0.03, 0, 0.03).offset(0, 0.03, 0);
// 0.16 magic value -> 0.03 plus gravity, plus some additional lenience
double searchDistance = -0.2 + Math.min(0, y);
Vector collisionResult = Collisions.collide(player, 0, searchDistance, 0);
Vector3D collisionResult = Collisions.collide(player, 0, searchDistance, 0);
player.boundingBox = playerBox;
return collisionResult.getY() != searchDistance;
}
@@ -350,9 +352,9 @@ public class PointThreeEstimator {
// Takes 0.01 millis, on average, to compute... this should be improved eventually
for (VectorData data : init) {
// Try to get the vector as close to zero as possible to give the best chance at 0.03...
Vector toZeroVec = new PredictionEngine().handleStartingVelocityUncertainty(player, data, new Vector());
Vector3D toZeroVec = new PredictionEngine().handleStartingVelocityUncertainty(player, data, newVector3D());
// Collide to handle mostly gravity, but other scenarios similar to this.
Vector collisionResult = Collisions.collide(player, toZeroVec.getX(), toZeroVec.getY(), toZeroVec.getZ(), Integer.MIN_VALUE, null);
Vector3D collisionResult = Collisions.collide(player, toZeroVec.getX(), toZeroVec.getY(), toZeroVec.getZ(), Integer.MIN_VALUE, null);
// If this tick is the tick after y velocity was by 0, a stepping movement is POSSIBLE to have been hidden
// A bit hacky... is there a better way? I'm unsure...
@@ -13,10 +13,12 @@ import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.*;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class UncertaintyHandler {
private final GrimPlayer player;
// Handles uncertainty when a piston could have pushed a player in a direction
@@ -147,15 +149,15 @@ public class UncertaintyHandler {
entityBox.maxY -= height;
entityBox.expand(-width / 2, 0, -width / 2);
Vector maxLocation = new Vector(entityBox.maxX, entityBox.maxY, entityBox.maxZ);
Vector minLocation = new Vector(entityBox.minX, entityBox.minY, entityBox.minZ);
Vector3D maxLocation = newVector3D(entityBox.maxX, entityBox.maxY, entityBox.maxZ);
Vector3D minLocation = newVector3D(entityBox.minX, entityBox.minY, entityBox.minZ);
Vector diff = minLocation.subtract(new Vector(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ)).multiply(0.1);
Vector3D diff = minLocation.subtract(newVector3D(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ)).multiply(0.1);
fishingRodPullBox.minX = Math.min(0, diff.getX());
fishingRodPullBox.minY = Math.min(0, diff.getY());
fishingRodPullBox.minZ = Math.min(0, diff.getZ());
diff = maxLocation.subtract(new Vector(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ)).multiply(0.1);
diff = maxLocation.subtract(newVector3D(player.lastX, player.lastY + 0.8 * 1.8, player.lastZ)).multiply(0.1);
fishingRodPullBox.maxX = Math.max(0, diff.getX());
fishingRodPullBox.maxY = Math.max(0, diff.getY());
fishingRodPullBox.maxZ = Math.max(0, diff.getZ());
@@ -170,8 +172,8 @@ public class UncertaintyHandler {
fireworksBox = new SimpleCollisionBox();
Vector currentLook = ReachUtils.getLook(player, player.xRot, player.yRot);
Vector lastLook = ReachUtils.getLook(player, player.lastXRot, player.lastYRot);
Vector3D currentLook = ReachUtils.getLook(player, player.xRot, player.yRot);
ac.grim.grimac.utils.vector.Vector3D lastLook = ReachUtils.getLook(player, player.lastXRot, player.lastYRot);
double antiTickSkipping = player.isPointThree() ? 0 : 0.05; // With 0.03, let that handle tick skipping
@@ -24,7 +24,9 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import com.viaversion.viaversion.api.Via;
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class MovementTicker {
public final GrimPlayer player;
@@ -77,9 +79,9 @@ public class MovementTicker {
player.uncertaintyHandler.collidingEntities.add(possibleCollidingEntities);
}
public void move(Vector inputVel, Vector collide) {
public void move(Vector3D inputVel, Vector3D collide) {
if (player.stuckSpeedMultiplier.getX() < 0.99) {
player.clientVelocity = new Vector();
player.clientVelocity = newVector3D();
}
if (inputVel.getX() != collide.getX()) {
@@ -172,21 +174,21 @@ public class MovementTicker {
// The game disregards movements smaller than 1e-7 (such as in boats)
if (collide.lengthSquared() < 1e-7) {
collide = new Vector();
collide = newVector3D();
}
// This is where vanilla moves the bounding box and sets it
player.predictedVelocity = new VectorData(collide.clone(), player.predictedVelocity.lastVector, player.predictedVelocity.vectorType);
float f = BlockProperties.getBlockSpeedFactor(player, player.mainSupportingBlockData, new Vector3d(player.x, player.y, player.z));
player.clientVelocity.multiply(new Vector(f, 1, f));
player.clientVelocity.multiply(newVector3D(f, 1, f));
// Reset stuck speed so it can update
if (player.stuckSpeedMultiplier.getX() < 0.99) {
player.uncertaintyHandler.lastStuckSpeedMultiplier.reset();
}
player.stuckSpeedMultiplier = new Vector(1, 1, 1);
player.stuckSpeedMultiplier = newVector3D(1, 1, 1);
// 1.15 and older clients use the handleInsideBlocks method for lava
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_16))
@@ -201,7 +203,7 @@ public class MovementTicker {
// Flying players are not affected by cobwebs/sweet berry bushes
if (player.isFlying) {
player.stuckSpeedMultiplier = new Vector(1, 1, 1);
player.stuckSpeedMultiplier = newVector3D(1, 1, 1);
}
}
@@ -388,14 +390,14 @@ public class MovementTicker {
// Lava movement changed in 1.16
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_16) && player.slightlyTouchingLava) {
player.clientVelocity = player.clientVelocity.multiply(new Vector(0.5D, 0.800000011920929D, 0.5D));
player.clientVelocity = player.clientVelocity.multiply(newVector3D(0.5D, 0.800000011920929D, 0.5D));
player.clientVelocity = FluidFallingAdjustedMovement.getFluidFallingAdjustedMovement(player, playerGravity, isFalling, player.clientVelocity);
} else {
player.clientVelocity.multiply(0.5D);
}
if (player.hasGravity)
player.clientVelocity.add(new Vector(0.0D, -playerGravity / 4.0D, 0.0D));
player.clientVelocity.add(newVector3D(0.0D, -playerGravity / 4.0D, 0.0D));
} else if (player.isGliding) {
player.friction = 0.99F; // Not vanilla, just useful for other grim stuff
@@ -5,7 +5,9 @@ import ac.grim.grimac.utils.data.packetentity.PacketEntityHorse;
import ac.grim.grimac.utils.nmsutil.Collisions;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class MovementTickerHorse extends MovementTickerLivingVehicle {
@@ -26,7 +28,7 @@ public class MovementTickerHorse extends MovementTickerLivingVehicle {
forwardsInput *= 0.25F;
}
this.movementInput = new Vector(horizInput, 0, forwardsInput);
this.movementInput = newVector3D(horizInput, 0, forwardsInput);
if (movementInput.lengthSquared() > 1) movementInput.normalize();
}
@@ -7,10 +7,13 @@ import ac.grim.grimac.predictionengine.predictions.rideable.PredictionEngineRide
import ac.grim.grimac.predictionengine.predictions.rideable.PredictionEngineRideableWaterLegacy;
import ac.grim.grimac.utils.nmsutil.BlockProperties;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class MovementTickerLivingVehicle extends MovementTicker {
Vector movementInput = new Vector();
Vector3D movementInput = newVector3D();
public MovementTickerLivingVehicle(GrimPlayer player) {
super(player);
@@ -3,12 +3,14 @@ package ac.grim.grimac.predictionengine.movementtick;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.packetentity.PacketEntityRideable;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class MovementTickerPig extends MovementTickerRideable {
public MovementTickerPig(GrimPlayer player) {
super(player);
movementInput = new Vector(0, 0, 1);
movementInput = newVector3D(0, 0, 1);
}
@Override
@@ -11,15 +11,17 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.ArrayList;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class MovementTickerStrider extends MovementTickerRideable {
public MovementTickerStrider(GrimPlayer player) {
super(player);
movementInput = new Vector(0, 0, 1);
movementInput = newVector3D(0, 0, 1);
}
public static void floatStrider(GrimPlayer player) {
@@ -27,7 +29,7 @@ public class MovementTickerStrider extends MovementTickerRideable {
if (isAbove(player) && player.compensatedWorld.getLavaFluidLevelAt((int) Math.floor(player.x), (int) Math.floor(player.y + 1), (int) Math.floor(player.z)) == 0) {
player.onGround = true;
} else {
player.clientVelocity.multiply(0.5).add(new Vector(0, 0.05, 0));
player.clientVelocity.multiply(0.5).add(newVector3D(0, 0.05, 0));
}
}
}
@@ -11,20 +11,31 @@ import ac.grim.grimac.utils.nmsutil.Collisions;
import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import ac.grim.grimac.utils.nmsutil.JumpPower;
import ac.grim.grimac.utils.nmsutil.Riptide;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.*;
import static ac.grim.grimac.utils.data.VectorData.VectorType;
import static ac.grim.grimac.utils.data.VectorData.VectorType.ZeroPointZeroThree;
import static ac.grim.grimac.utils.nmsutil.Collisions.isEmpty;
import static ac.grim.grimac.utils.nmsutil.GetBoundingBox.getBoundingBoxFromPosAndSize;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.attribute.Attributes.GENERIC_GRAVITY;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_13;
import static java.lang.Math.*;
import static java.util.Collections.max;
public class PredictionEngine {
public static Vector clampMovementToHardBorder(GrimPlayer player, Vector outputVel) {
public static Vector3D clampMovementToHardBorder(GrimPlayer player, Vector3D outputVel) {
// TODO: Reimplement
return outputVel;
}
public static Vector transformInputsToVector(GrimPlayer player, Vector theoreticalInput) {
public static Vector3D transformInputsToVector(GrimPlayer player, Vector3D theoreticalInput) {
float bestPossibleX;
float bestPossibleZ;
@@ -42,15 +53,15 @@ public class PredictionEngine {
bestPossibleZ *= 0.2F;
}
Vector inputVector = new Vector(bestPossibleX, 0, bestPossibleZ);
Vector3D inputVector = newVector3D(bestPossibleX, 0, bestPossibleZ);
inputVector.multiply(0.98F);
// Simulate float rounding imprecision
inputVector = new Vector((float) inputVector.getX(), (float) inputVector.getY(), (float) inputVector.getZ());
inputVector = newVector3D((float) inputVector.getX(), (float) inputVector.getY(), (float) inputVector.getZ());
if (inputVector.lengthSquared() > 1) {
double d0 = Math.sqrt(inputVector.getX() * inputVector.getX() + inputVector.getY() * inputVector.getY() + inputVector.getZ() * inputVector.getZ());
inputVector = new Vector(inputVector.getX() / d0, inputVector.getY() / d0, inputVector.getZ() / d0);
double d0 = sqrt(inputVector.getX() * inputVector.getX() + inputVector.getY() * inputVector.getY() + inputVector.getZ() * inputVector.getZ());
inputVector = newVector3D(inputVector.getX() / d0, inputVector.getY() / d0, inputVector.getZ() / d0);
}
return inputVector;
@@ -62,7 +73,7 @@ public class PredictionEngine {
if (player.uncertaintyHandler.influencedByBouncyBlock()) {
for (VectorData data : init) {
// Try to get the vector as close to zero as possible to give the best chance at 0.03...
Vector toZeroVec = new PredictionEngine().handleStartingVelocityUncertainty(player, data, new Vector(0, -1000000000, 0)); // Downwards without overflow risk
Vector3D toZeroVec = new PredictionEngine().handleStartingVelocityUncertainty(player, data, newVector3D(0, -1000000000, 0)); // Downwards without overflow risk
player.uncertaintyHandler.nextTickSlimeBlockUncertainty = Math.max(Math.abs(toZeroVec.getY()), player.uncertaintyHandler.nextTickSlimeBlockUncertainty);
}
@@ -105,8 +116,8 @@ public class PredictionEngine {
double bestInput = Double.MAX_VALUE;
VectorData bestCollisionVel = null;
Vector beforeCollisionMovement = null;
Vector originalClientVel = player.clientVelocity.clone();
Vector3D beforeCollisionMovement = null;
Vector3D originalClientVel = player.clientVelocity.clone();
SimpleCollisionBox originalBB = player.boundingBox;
// 0.03 doesn't exist with vehicles, thank god
@@ -116,9 +127,9 @@ public class PredictionEngine {
player.skippedTickInActualMovement = false;
for (VectorData clientVelAfterInput : possibleVelocities) {
Vector primaryPushMovement = handleStartingVelocityUncertainty(player, clientVelAfterInput, player.actualMovement);
Vector3D primaryPushMovement = handleStartingVelocityUncertainty(player, clientVelAfterInput, player.actualMovement);
Vector bestTheoreticalCollisionResult = VectorUtils.cutBoxToVector(player.actualMovement, new SimpleCollisionBox(0, Math.min(0, primaryPushMovement.getY()), 0, primaryPushMovement.getX(), Math.max(0.6, primaryPushMovement.getY()), primaryPushMovement.getZ()).sort());
Vector3D bestTheoreticalCollisionResult = VectorUtils.cutBoxToVector(player.actualMovement, new SimpleCollisionBox(0, Math.min(0, primaryPushMovement.getY()), 0, primaryPushMovement.getX(), Math.max(0.6, primaryPushMovement.getY()), primaryPushMovement.getZ()).sort());
// Check if this vector could ever possible beat the last vector in terms of accuracy
// This is quite a good optimization :)
if (bestTheoreticalCollisionResult.distanceSquared(player.actualMovement) > bestInput && !clientVelAfterInput.isKnockback() && !clientVelAfterInput.isExplosion()) {
@@ -132,9 +143,9 @@ public class PredictionEngine {
}
// Returns pair of primary push movement, and then outputvel
Pair<Vector, Vector> output = doSeekingWallCollisions(player, primaryPushMovement, originalClientVel, clientVelAfterInput);
Pair<Vector3D, Vector3D> output = doSeekingWallCollisions(player, primaryPushMovement, originalClientVel, clientVelAfterInput);
primaryPushMovement = output.getFirst();
Vector outputVel = clampMovementToHardBorder(player, output.getSecond());
Vector3D outputVel = clampMovementToHardBorder(player, output.getSecond());
double resultAccuracy = outputVel.distanceSquared(player.actualMovement);
@@ -208,7 +219,7 @@ public class PredictionEngine {
}
}
private Pair<Vector, Vector> doSeekingWallCollisions(GrimPlayer player, Vector primaryPushMovement, Vector originalClientVel, VectorData clientVelAfterInput) {
private Pair<Vector3D, Vector3D> doSeekingWallCollisions(GrimPlayer player, Vector3D primaryPushMovement, Vector3D originalClientVel, VectorData clientVelAfterInput) {
boolean vehicleKB = player.compensatedEntities.getSelf().inVehicle() && clientVelAfterInput.isKnockback() && clientVelAfterInput.vector.getY() == 0;
// Extra collision epsilon required for vehicles to be accurate
double xAdditional = Math.signum(primaryPushMovement.getX()) * SimpleCollisionBox.COLLISION_EPSILON;
@@ -221,9 +232,9 @@ public class PredictionEngine {
double testX = primaryPushMovement.getX() + xAdditional;
double testY = primaryPushMovement.getY() + yAdditional;
double testZ = primaryPushMovement.getZ() + zAdditional;
primaryPushMovement = new Vector(testX, testY, testZ);
primaryPushMovement = newVector3D(testX, testY, testZ);
Vector outputVel = Collisions.collide(player, primaryPushMovement.getX(), primaryPushMovement.getY(), primaryPushMovement.getZ(), originalClientVel.getY(), clientVelAfterInput);
Vector3D outputVel = Collisions.collide(player, primaryPushMovement.getX(), primaryPushMovement.getY(), primaryPushMovement.getZ(), originalClientVel.getY(), clientVelAfterInput);
if (testX == outputVel.getX()) { // the player didn't have X collision, don't ruin offset by collision epsilon
primaryPushMovement.setX(primaryPushMovement.getX() - xAdditional);
@@ -249,20 +260,20 @@ public class PredictionEngine {
// For now just let the player control their Y velocity within 0.03. Gravity should stop exploits.
// 0.03 - 0.784 < -0.03 = can't skip next tick
Vector pointThreeVector = new Vector();
Vector3D pointThreeVector = newVector3D();
// Stop a bypass (and fix falses) by carrying over the player's current velocity IF they couldn't have modified it
if (!player.pointThreeEstimator.controlsVerticalMovement()) {
pointThreeVector.setY(player.clientVelocity.getY());
} else { // Carry over the current Y velocity to try and help with gravity issues
pointThreePossibilities.add(new VectorData(new Vector(0, player.clientVelocity.getY(), 0), VectorData.VectorType.ZeroPointZeroThree));
pointThreePossibilities.add(new VectorData(newVector3D(0, player.clientVelocity.getY(), 0), ZeroPointZeroThree));
}
pointThreePossibilities.add(new VectorData(pointThreeVector, VectorData.VectorType.ZeroPointZeroThree));
// Swim hop
if (player.pointThreeEstimator.isNearFluid && !Collisions.isEmpty(player, player.boundingBox.copy().expand(0.4, 0, 0.4)) && !player.onGround) { // onGround can still be used here, else generic 0.03
pointThreePossibilities.add(new VectorData(new Vector(0, 0.3, 0), VectorData.VectorType.ZeroPointZeroThree));
pointThreePossibilities.add(new VectorData(newVector3D(0, 0.3, 0), ZeroPointZeroThree));
}
// Swimming vertically can add more Y velocity than normal
@@ -279,7 +290,7 @@ public class PredictionEngine {
player.clientVelocity.getX(), 0, player.clientVelocity.getZ()).expand(0.5, -SimpleCollisionBox.COLLISION_EPSILON, 0.5)))) {
// Calculate the Y velocity after friction
Vector hackyClimbVector = new Vector(0, 0.2, 0);
Vector3D hackyClimbVector = newVector3D(0, 0.2, 0);
PredictionEngineNormal.staticVectorEndOfTick(player, hackyClimbVector);
pointThreePossibilities.add(new VectorData(hackyClimbVector, VectorData.VectorType.ZeroPointZeroThree));
@@ -290,8 +301,8 @@ public class PredictionEngine {
addExplosionToPossibilities(player, pointThreePossibilities);
if (player.packetStateData.tryingToRiptide) {
Vector riptideAddition = Riptide.getRiptideVelocity(player);
pointThreePossibilities.add(new VectorData(player.clientVelocity.clone().add(riptideAddition), new VectorData(new Vector(), VectorData.VectorType.ZeroPointZeroThree), VectorData.VectorType.Trident));
Vector3D riptideAddition = Riptide.getRiptideVelocity(player);
pointThreePossibilities.add(new VectorData(player.clientVelocity.clone().add(riptideAddition), new VectorData(newVector3D(), ZeroPointZeroThree), VectorData.VectorType.Trident));
}
possibleVelocities.addAll(applyInputsToVelocityPossibilities(player, pointThreePossibilities, speed));
@@ -312,7 +323,7 @@ public class PredictionEngine {
// Water pushing movement is affected by initial velocity due to 0.003 eating pushing in the past
if (vectorData.isKnockback() && player.baseTickWaterPushing.lengthSquared() != 0) {
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13)) {
Vector vec3 = player.baseTickWaterPushing.clone();
Vector3D vec3 = player.baseTickWaterPushing.clone();
if (Math.abs(vectorData.vector.getX()) < 0.003 && Math.abs(vectorData.vector.getZ()) < 0.003 && player.baseTickWaterPushing.length() < 0.0045000000000000005D) {
vec3 = vec3.normalize().multiply(0.0045000000000000005);
}
@@ -332,7 +343,7 @@ public class PredictionEngine {
addExplosionToPossibilities(player, velocities);
if (player.packetStateData.tryingToRiptide) {
Vector riptideAddition = Riptide.getRiptideVelocity(player);
Vector3D riptideAddition = Riptide.getRiptideVelocity(player);
velocities.add(new VectorData(player.clientVelocity.clone().add(riptideAddition), VectorData.VectorType.Trident));
}
@@ -361,7 +372,7 @@ public class PredictionEngine {
private void addAttackSlowToPossibilities(GrimPlayer player, Set<VectorData> velocities) {
for (int x = 1; x <= Math.min(player.maxPlayerAttackSlow, 5); x++) {
for (VectorData data : new HashSet<>(velocities)) {
velocities.add(data.returnNewModified(data.vector.clone().multiply(new Vector(0.6, 1, 0.6)), VectorData.VectorType.AttackSlow));
velocities.add(data.returnNewModified(data.vector.clone().multiply(newVector3D(0.6, 1, 0.6)), VectorData.VectorType.AttackSlow));
}
}
}
@@ -475,15 +486,15 @@ public class PredictionEngine {
return Double.compare(a.vector.distanceSquared(player.actualMovement), b.vector.distanceSquared(player.actualMovement));
}
public Vector handleStartingVelocityUncertainty(GrimPlayer player, VectorData vector, Vector targetVec) {
double avgColliding = Collections.max(player.uncertaintyHandler.collidingEntities);
public Vector3D handleStartingVelocityUncertainty(GrimPlayer player, VectorData vector, Vector3D targetVec) {
double avgColliding = max(player.uncertaintyHandler.collidingEntities);
double additionHorizontal = player.uncertaintyHandler.getOffsetHorizontal(vector);
double additionVertical = player.uncertaintyHandler.getVerticalOffset(vector);
double pistonX = Collections.max(player.uncertaintyHandler.pistonX);
double pistonY = Collections.max(player.uncertaintyHandler.pistonY);
double pistonZ = Collections.max(player.uncertaintyHandler.pistonZ);
double pistonX = max(player.uncertaintyHandler.pistonX);
double pistonY = max(player.uncertaintyHandler.pistonY);
double pistonZ = max(player.uncertaintyHandler.pistonZ);
additionHorizontal += player.uncertaintyHandler.lastHorizontalOffset;
additionVertical += player.uncertaintyHandler.lastVerticalOffset;
@@ -526,13 +537,13 @@ public class PredictionEngine {
// 0.075 seems safe?
//
// Be somewhat careful as there is an antikb (for horizontal) that relies on this lenience
Vector uncertainty = new Vector(avgColliding * 0.08, additionVertical, avgColliding * 0.08);
Vector3D uncertainty = newVector3D(avgColliding * 0.08, additionVertical, avgColliding * 0.08);
Vector min = new Vector(player.uncertaintyHandler.xNegativeUncertainty - additionHorizontal, -bonusY + player.uncertaintyHandler.yNegativeUncertainty, player.uncertaintyHandler.zNegativeUncertainty - additionHorizontal);
Vector max = new Vector(player.uncertaintyHandler.xPositiveUncertainty + additionHorizontal, bonusY + player.uncertaintyHandler.yPositiveUncertainty, player.uncertaintyHandler.zPositiveUncertainty + additionHorizontal);
Vector3D min = newVector3D(player.uncertaintyHandler.xNegativeUncertainty - additionHorizontal, -bonusY + player.uncertaintyHandler.yNegativeUncertainty, player.uncertaintyHandler.zNegativeUncertainty - additionHorizontal);
Vector3D max = newVector3D(player.uncertaintyHandler.xPositiveUncertainty + additionHorizontal, bonusY + player.uncertaintyHandler.yPositiveUncertainty, player.uncertaintyHandler.zPositiveUncertainty + additionHorizontal);
Vector minVector = vector.vector.clone().add(min.subtract(uncertainty));
Vector maxVector = vector.vector.clone().add(max.add(uncertainty));
Vector3D minVector = vector.vector.clone().add(min.subtract(uncertainty));
Vector3D maxVector = vector.vector.clone().add(max.add(uncertainty));
// Handle the player landing within 0.03 movement, which resets Y velocity
if (player.uncertaintyHandler.onGroundUncertain && vector.vector.getY() < 0) {
@@ -559,7 +570,7 @@ public class PredictionEngine {
// We can't simulate the player's Y velocity, unknown number of ticks with a gravity change
// Feel free to simulate all 104857600000000000000000000 possibilities!
if (!player.pointThreeEstimator.canPredictNextVerticalMovement()) {
minVector.setY(minVector.getY() - player.compensatedEntities.getSelf().getAttributeValue(Attributes.GENERIC_GRAVITY));
minVector.setY(minVector.getY() - player.compensatedEntities.getSelf().getAttributeValue(GENERIC_GRAVITY));
}
// Hidden slime block bounces by missing idle tick and 0.03
@@ -599,9 +610,9 @@ public class PredictionEngine {
box.maxZ += sneaking.getSneakingPotentialHiddenVelocity().maxZ;
if (player.uncertaintyHandler.fireworksBox != null) {
double minXdiff = Math.min(0, player.uncertaintyHandler.fireworksBox.minX - originalVec.vector.getX());
double minYdiff = Math.min(0, player.uncertaintyHandler.fireworksBox.minY - originalVec.vector.getY());
double minZdiff = Math.min(0, player.uncertaintyHandler.fireworksBox.minZ - originalVec.vector.getZ());
double minXdiff = min(0, player.uncertaintyHandler.fireworksBox.minX - originalVec.vector.getX());
double minYdiff = min(0, player.uncertaintyHandler.fireworksBox.minY - originalVec.vector.getY());
double minZdiff = min(0, player.uncertaintyHandler.fireworksBox.minZ - originalVec.vector.getZ());
double maxXdiff = Math.max(0, player.uncertaintyHandler.fireworksBox.maxX - originalVec.vector.getX());
double maxYdiff = Math.max(0, player.uncertaintyHandler.fireworksBox.maxY - originalVec.vector.getY());
double maxZdiff = Math.max(0, player.uncertaintyHandler.fireworksBox.maxZ - originalVec.vector.getZ());
@@ -657,7 +668,7 @@ public class PredictionEngine {
//
// Or the player is switching in and out of controlling a vehicle, in which friction messes it up
//
if (player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0) || player.uncertaintyHandler.lastHardCollidingLerpingEntity.hasOccurredSince(3) || (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) && vector.vector.getY() > 0 && vector.isZeroPointZeroThree() && !Collisions.isEmpty(player, GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.lastX, vector.vector.getY() + player.lastY + 0.6, player.lastZ, 0.6f, 1.26f)))) {
if (player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0) || player.uncertaintyHandler.lastHardCollidingLerpingEntity.hasOccurredSince(3) || (player.getClientVersion().isNewerThanOrEquals(V_1_13) && vector.vector.getY() > 0 && vector.isZeroPointZeroThree() && !isEmpty(player, getBoundingBoxFromPosAndSize(player, player.lastX, vector.vector.getY() + player.lastY + 0.6, player.lastZ, 0.6f, 1.26f)))) {
box.expandToAbsoluteCoordinates(0, 0, 0);
}
@@ -669,9 +680,9 @@ public class PredictionEngine {
if (player.wasTouchingWater) trueFriction = 0.96;
double maxY = Math.max(box.maxY, box.maxY + ((box.maxY - player.gravity) * 0.91));
double minY = Math.min(box.minY, box.minY + ((box.minY - player.gravity) * 0.91));
double minX = Math.min(box.minX, box.minX + (-player.speed * trueFriction));
double minZ = Math.min(box.minZ, box.minZ + (-player.speed * trueFriction));
double minY = min(box.minY, box.minY + ((box.minY - player.gravity) * 0.91));
double minX = min(box.minX, box.minX + (-player.speed * trueFriction));
double minZ = min(box.minZ, box.minZ + (-player.speed * trueFriction));
double maxX = Math.max(box.maxX, box.maxX + (player.speed * trueFriction));
double maxZ = Math.max(box.maxZ, box.maxZ + (player.speed * trueFriction));
@@ -687,15 +698,15 @@ public class PredictionEngine {
maxVector = box.max();
if (pistonX != 0) {
minVector.setX(Math.min(minVector.getX() - pistonX, pistonX));
minVector.setX(min(minVector.getX() - pistonX, pistonX));
maxVector.setX(Math.max(maxVector.getX() + pistonX, pistonX));
}
if (pistonY != 0) {
minVector.setY(Math.min(minVector.getY() - pistonY, pistonY));
minVector.setY(min(minVector.getY() - pistonY, pistonY));
maxVector.setY(Math.max(maxVector.getY() + pistonY, pistonY));
}
if (pistonZ != 0) {
minVector.setZ(Math.min(minVector.getZ() - pistonZ, pistonZ));
minVector.setZ(min(minVector.getZ() - pistonZ, pistonZ));
maxVector.setZ(Math.max(maxVector.getZ() + pistonZ, pistonZ));
}
return VectorUtils.cutBoxToVector(targetVec, minVector, maxVector);
@@ -725,7 +736,7 @@ public class PredictionEngine {
if (loopSlowed == 1 && !possibleLastTickOutput.isZeroPointZeroThree()) continue;
for (int x = -1; x <= 1; x++) {
for (int z = zMin; z <= 1; z++) {
VectorData result = new VectorData.MoveVectorData(possibleLastTickOutput.vector.clone().add(getMovementResultFromInput(player, transformInputsToVector(player, new Vector(x, 0, z)), speed, player.xRot)), possibleLastTickOutput, VectorData.VectorType.InputResult, x, z);
VectorData result = new VectorData.MoveVectorData(possibleLastTickOutput.vector.clone().add(getMovementResultFromInput(player, transformInputsToVector(player, newVector3D(x, 0, z)), speed, player.xRot)), possibleLastTickOutput, VectorData.VectorType.InputResult, x, z);
result = result.returnNewModified(result.vector.clone().multiply(player.stuckSpeedMultiplier), VectorData.VectorType.StuckMultiplier);
result = result.returnNewModified(handleOnClimbable(result.vector.clone(), player), VectorData.VectorType.Climbable);
// Signal that we need to flip sneaking bounding box
@@ -792,21 +803,21 @@ public class PredictionEngine {
// This is just the vanilla equation, which accepts invalid inputs greater than 1
// We need it because of collision support when a player is using speed
public Vector getMovementResultFromInput(GrimPlayer player, Vector inputVector, float f, float f2) {
public Vector3D getMovementResultFromInput(GrimPlayer player, Vector3D inputVector, float f, float f2) {
float f3 = player.trigHandler.sin(f2 * 0.017453292f);
float f4 = player.trigHandler.cos(f2 * 0.017453292f);
double xResult = inputVector.getX() * f4 - inputVector.getZ() * f3;
double zResult = inputVector.getZ() * f4 + inputVector.getX() * f3;
return new Vector(xResult * f, 0, zResult * f);
return newVector3D(xResult * f, 0, zResult * f);
}
public Vector handleOnClimbable(Vector vector, GrimPlayer player) {
public Vector3D handleOnClimbable(Vector3D vector, GrimPlayer player) {
return vector;
}
public void doJump(GrimPlayer player, Vector vector) {
public void doJump(GrimPlayer player, Vector3D vector) {
if (!player.lastOnGround || player.onGround)
return;
@@ -3,28 +3,35 @@ package ac.grim.grimac.predictionengine.predictions;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.attribute.Attributes.GENERIC_GRAVITY;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_18_2;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_20_5;
import static java.lang.Math.*;
public class PredictionEngineElytra extends PredictionEngine {
// Inputs have no effect on movement
@Override
public List<VectorData> applyInputsToVelocityPossibilities(GrimPlayer player, Set<VectorData> possibleVectors, float speed) {
List<VectorData> results = new ArrayList<>();
Vector currentLook = ReachUtils.getLook(player, player.xRot, player.yRot);
Vector3D currentLook = ReachUtils.getLook(player, player.xRot, player.yRot);
for (VectorData data : possibleVectors) {
Vector elytraResult = getElytraMovement(player, data.vector.clone(), currentLook).multiply(player.stuckSpeedMultiplier).multiply(new Vector(0.99F, 0.98F, 0.99F));
Vector3D elytraResult = getElytraMovement(player, data.vector.clone(), currentLook).multiply(player.stuckSpeedMultiplier).multiply(newVector3D(0.99F, 0.98F, 0.99F));
results.add(data.returnNewModified(elytraResult, VectorData.VectorType.InputResult));
// We must bruteforce Optifine ShitMath
player.trigHandler.toggleShitMath();
elytraResult = getElytraMovement(player, data.vector.clone(), ReachUtils.getLook(player, player.xRot, player.yRot)).multiply(player.stuckSpeedMultiplier).multiply(new Vector(0.99F, 0.98F, 0.99F));
elytraResult = getElytraMovement(player, data.vector.clone(), ReachUtils.getLook(player, player.xRot, player.yRot)).multiply(player.stuckSpeedMultiplier).multiply(newVector3D(0.99F, 0.98F, 0.99F));
player.trigHandler.toggleShitMath();
results.add(data.returnNewModified(elytraResult, VectorData.VectorType.InputResult));
}
@@ -32,42 +39,42 @@ public class PredictionEngineElytra extends PredictionEngine {
return results;
}
public static Vector getElytraMovement(GrimPlayer player, Vector vector, Vector lookVector) {
public static Vector3D getElytraMovement(GrimPlayer player, Vector3D vector, Vector3D lookVector) {
float yRotRadians = player.yRot * 0.017453292F;
double horizontalSqrt = Math.sqrt(lookVector.getX() * lookVector.getX() + lookVector.getZ() * lookVector.getZ());
double horizontalSqrt = sqrt(lookVector.getX() * lookVector.getX() + lookVector.getZ() * lookVector.getZ());
double horizontalLength = vector.clone().setY(0).length();
double length = lookVector.length();
// Mojang changed from using their math to using regular java math in 1.18.2 elytra movement
double vertCosRotation = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_18_2) ? Math.cos(yRotRadians) : player.trigHandler.cos(yRotRadians);
vertCosRotation = (float) (vertCosRotation * vertCosRotation * Math.min(1.0D, length / 0.4D));
double vertCosRotation = player.getClientVersion().isNewerThanOrEquals(V_1_18_2) ? cos(yRotRadians) : player.trigHandler.cos(yRotRadians);
vertCosRotation = (float) (vertCosRotation * vertCosRotation * min(1.0D, length / 0.4D));
// So we actually use the player's actual movement to get the gravity/slow falling status
// However, this is wrong with elytra movement because players can control vertical movement after gravity is calculated
// Yeah, slow falling needs a refactor in grim.
double recalculatedGravity = player.compensatedEntities.getSelf().getAttributeValue(Attributes.GENERIC_GRAVITY);
double recalculatedGravity = player.compensatedEntities.getSelf().getAttributeValue(GENERIC_GRAVITY);
if (player.clientVelocity.getY() <= 0 && player.compensatedEntities.getSlowFallingAmplifier().isPresent()) {
recalculatedGravity = player.getClientVersion().isOlderThan(ClientVersion.V_1_20_5) ? 0.01 : Math.min(recalculatedGravity, 0.01);
recalculatedGravity = player.getClientVersion().isOlderThan(V_1_20_5) ? 0.01 : min(recalculatedGravity, 0.01);
}
vector.add(new Vector(0.0D, recalculatedGravity * (-1.0D + vertCosRotation * 0.75D), 0.0D));
vector.add(newVector3D(0.0D, recalculatedGravity * (-1.0D + vertCosRotation * 0.75D), 0.0D));
double d5;
// Handle slowing the player down when falling
if (vector.getY() < 0.0D && horizontalSqrt > 0.0D) {
d5 = vector.getY() * -0.1D * vertCosRotation;
vector.add(new Vector(lookVector.getX() * d5 / horizontalSqrt, d5, lookVector.getZ() * d5 / horizontalSqrt));
vector.add(newVector3D(lookVector.getX() * d5 / horizontalSqrt, d5, lookVector.getZ() * d5 / horizontalSqrt));
}
// Handle accelerating the player when they are looking down
if (yRotRadians < 0.0F && horizontalSqrt > 0.0D) {
d5 = horizontalLength * (double) (-player.trigHandler.sin(yRotRadians)) * 0.04D;
vector.add(new Vector(-lookVector.getX() * d5 / horizontalSqrt, d5 * 3.2D, -lookVector.getZ() * d5 / horizontalSqrt));
vector.add(newVector3D(-lookVector.getX() * d5 / horizontalSqrt, d5 * 3.2D, -lookVector.getZ() * d5 / horizontalSqrt));
}
// Handle accelerating the player sideways
if (horizontalSqrt > 0) {
vector.add(new Vector((lookVector.getX() / horizontalSqrt * horizontalLength - vector.getX()) * 0.1D, 0.0D, (lookVector.getZ() / horizontalSqrt * horizontalLength - vector.getZ()) * 0.1D));
vector.add(newVector3D((lookVector.getX() / horizontalSqrt * horizontalLength - vector.getX()) * 0.1D, 0.0D, (lookVector.getZ() / horizontalSqrt * horizontalLength - vector.getZ()) * 0.1D));
}
return vector;
@@ -3,11 +3,13 @@ package ac.grim.grimac.predictionengine.predictions;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.math.GrimMath;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.HashSet;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class PredictionEngineLava extends PredictionEngine {
@Override
public void addJumpsToPossibilities(GrimPlayer player, Set<VectorData> existingVelocities) {
@@ -16,11 +18,11 @@ public class PredictionEngineLava extends PredictionEngine {
double extraVelFromVertTickSkipUpwards = GrimMath.clamp(player.actualMovement.getY(), vector.vector.clone().getY(), vector.vector.clone().getY() + 0.05f);
existingVelocities.add(new VectorData(vector.vector.clone().setY(extraVelFromVertTickSkipUpwards), vector, VectorData.VectorType.Jump));
} else {
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(newVector3D(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
}
if (player.slightlyTouchingLava && player.lastOnGround && !player.onGround) {
Vector withJump = vector.vector.clone();
Vector3D withJump = vector.vector.clone();
super.doJump(player, withJump);
existingVelocities.add(new VectorData(withJump, vector, VectorData.VectorType.Jump));
}
@@ -6,20 +6,26 @@ import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.nmsutil.Collisions;
import ac.grim.grimac.utils.nmsutil.JumpPower;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.HashSet;
import java.util.OptionalInt;
import java.util.Set;
import static ac.grim.grimac.utils.math.GrimMath.clamp;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.world.states.type.StateTypes.SCAFFOLDING;
import static java.lang.Math.max;
public class PredictionEngineNormal extends PredictionEngine {
public static void staticVectorEndOfTick(GrimPlayer player, Vector vector) {
public static void staticVectorEndOfTick(GrimPlayer player, Vector3D vector) {
double adjustedY = vector.getY();
final OptionalInt levitation = player.compensatedEntities.getPotionLevelForPlayer(PotionTypes.LEVITATION);
if (levitation.isPresent()) {
@@ -38,7 +44,7 @@ public class PredictionEngineNormal extends PredictionEngine {
@Override
public void addJumpsToPossibilities(GrimPlayer player, Set<VectorData> existingVelocities) {
for (VectorData vector : new HashSet<>(existingVelocities)) {
Vector jump = vector.vector.clone();
Vector3D jump = vector.vector.clone();
if (!player.isFlying) {
// Negative jump boost does not allow the player to leave the ground
@@ -52,9 +58,9 @@ public class PredictionEngineNormal extends PredictionEngine {
JumpPower.jumpFromGround(player, jump);
} else {
jump.add(new Vector(0, player.flySpeed * 3, 0));
jump.add(newVector3D(0, player.flySpeed * 3, 0));
if (!player.wasFlying) {
Vector edgeCaseJump = jump.clone();
Vector3D edgeCaseJump = jump.clone();
JumpPower.jumpFromGround(player, edgeCaseJump);
existingVelocities.add(vector.returnNewModified(edgeCaseJump, VectorData.VectorType.Jump));
}
@@ -82,7 +88,7 @@ public class PredictionEngineNormal extends PredictionEngine {
if (player.lastWasClimbing == 0 && (player.pointThreeEstimator.isNearClimbable() || player.isClimbing) && (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)
|| !Collisions.isEmpty(player, player.boundingBox.copy().expand(
player.clientVelocity.getX(), 0, player.clientVelocity.getZ()).expand(0.5, -SimpleCollisionBox.COLLISION_EPSILON, 0.5))) || walkingOnPowderSnow) {
Vector ladderVelocity = player.clientVelocity.clone().setY(0.2);
Vector3D ladderVelocity = player.clientVelocity.clone().setY(0.2);
staticVectorEndOfTick(player, ladderVelocity);
player.lastWasClimbing = ladderVelocity.getY();
}
@@ -93,17 +99,17 @@ public class PredictionEngineNormal extends PredictionEngine {
}
@Override
public Vector handleOnClimbable(Vector vector, GrimPlayer player) {
public Vector3D handleOnClimbable(Vector3D vector, GrimPlayer player) {
if (player.isClimbing) {
// Reset fall distance when climbing
player.fallDistance = 0;
vector.setX(GrimMath.clamp(vector.getX(), -0.15F, 0.15F));
vector.setZ(GrimMath.clamp(vector.getZ(), -0.15F, 0.15F));
vector.setY(Math.max(vector.getY(), -0.15F));
vector.setX(clamp(vector.getX(), -0.15F, 0.15F));
vector.setZ(clamp(vector.getZ(), -0.15F, 0.15F));
vector.setY(max(vector.getY(), -0.15F));
// Yes, this uses shifting not crouching
if (vector.getY() < 0.0 && !(player.compensatedWorld.getStateTypeAt(player.lastX, player.lastY, player.lastZ) == StateTypes.SCAFFOLDING) && player.isSneaking && !player.isFlying) {
if (vector.getY() < 0.0 && !(player.compensatedWorld.getStateTypeAt(player.lastX, player.lastY, player.lastZ) == SCAFFOLDING) && player.isSneaking && !player.isFlying) {
vector.setY(0.0);
}
}
@@ -9,11 +9,15 @@ import ac.grim.grimac.utils.nmsutil.Collisions;
import ac.grim.grimac.utils.nmsutil.FluidFallingAdjustedMovement;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.HashSet;
import java.util.Set;
import static ac.grim.grimac.utils.data.VectorData.VectorType;
import static ac.grim.grimac.utils.data.VectorData.VectorType.SwimmingSpace;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class PredictionEngineWater extends PredictionEngine {
boolean isFalling;
double playerGravity;
@@ -21,9 +25,9 @@ public class PredictionEngineWater extends PredictionEngine {
float swimmingFriction;
double lastY;
public static void staticVectorEndOfTick(GrimPlayer player, Vector vector, float swimmingFriction, double playerGravity, boolean isFalling) {
vector.multiply(new Vector(swimmingFriction, 0.8F, swimmingFriction));
Vector fluidVector = FluidFallingAdjustedMovement.getFluidFallingAdjustedMovement(player, playerGravity, isFalling, vector);
public static void staticVectorEndOfTick(GrimPlayer player, Vector3D vector, float swimmingFriction, double playerGravity, boolean isFalling) {
vector.multiply(newVector3D(swimmingFriction, 0.8F, swimmingFriction));
Vector3D fluidVector = FluidFallingAdjustedMovement.getFluidFallingAdjustedMovement(player, playerGravity, isFalling, vector);
vector.setX(fluidVector.getX());
vector.setY(fluidVector.getY());
vector.setZ(fluidVector.getZ());
@@ -47,7 +51,7 @@ public class PredictionEngineWater extends PredictionEngine {
double scalar = lookYAmount < -0.2 ? 0.085 : 0.06;
// The player can always press jump and activate this
swimmingVelocities.add(vector.returnNewModified(new Vector(vector.vector.getX(), vector.vector.getY() + ((lookYAmount - vector.vector.getY()) * scalar), vector.vector.getZ()), VectorData.VectorType.SwimmingSpace));
swimmingVelocities.add(vector.returnNewModified(newVector3D(vector.vector.getX(), vector.vector.getY() + ((lookYAmount - vector.vector.getY()) * scalar), vector.vector.getZ()), SwimmingSpace));
// This scenario will occur if the player does not press jump and the other conditions are met
// Theoretically we should check this BEFORE allowing no look, but there isn't a cheat that takes advantage of this yet
@@ -80,11 +84,11 @@ public class PredictionEngineWater extends PredictionEngine {
double extraVelFromVertTickSkipUpwards = GrimMath.clamp(player.actualMovement.getY(), vector.vector.clone().getY(), vector.vector.clone().getY() + 0.05f);
existingVelocities.add(new VectorData(vector.vector.clone().setY(extraVelFromVertTickSkipUpwards), vector, VectorData.VectorType.Jump));
} else {
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(newVector3D(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
}
if (player.slightlyTouchingWater && player.lastOnGround && !player.onGround) {
Vector withJump = vector.vector.clone();
Vector3D withJump = vector.vector.clone();
super.doJump(player, withJump);
existingVelocities.add(new VectorData(withJump, vector, VectorData.VectorType.Jump));
}
@@ -2,11 +2,15 @@ package ac.grim.grimac.predictionengine.predictions;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.VectorData;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.HashSet;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static java.lang.Math.sqrt;
public class PredictionEngineWaterLegacy extends PredictionEngine {
double playerGravity;
float swimmingSpeed;
@@ -23,11 +27,11 @@ public class PredictionEngineWaterLegacy extends PredictionEngine {
// This is just the vanilla equation for legacy water movement
@Override
public Vector getMovementResultFromInput(GrimPlayer player, Vector inputVector, float f, float f2) {
public Vector3D getMovementResultFromInput(GrimPlayer player, Vector3D inputVector, float f, float f2) {
float lengthSquared = (float) inputVector.lengthSquared();
if (lengthSquared >= 1.0E-4F) {
lengthSquared = (float) Math.sqrt(lengthSquared);
lengthSquared = (float) sqrt(lengthSquared);
if (lengthSquared < 1.0F) {
lengthSquared = 1.0F;
@@ -38,21 +42,20 @@ public class PredictionEngineWaterLegacy extends PredictionEngine {
float sinResult = player.trigHandler.sin(player.xRot * 0.017453292F);
float cosResult = player.trigHandler.cos(player.xRot * 0.017453292F);
return new Vector(inputVector.getX() * cosResult - inputVector.getZ() * sinResult,
inputVector.getY(), inputVector.getZ() * cosResult + inputVector.getX() * sinResult);
return newVector3D(inputVector.getX() * cosResult - inputVector.getZ() * sinResult, inputVector.getY(), inputVector.getZ() * cosResult + inputVector.getX() * sinResult);
}
return new Vector();
return newVector3D();
}
@Override
public void addJumpsToPossibilities(GrimPlayer player, Set<VectorData> existingVelocities) {
for (VectorData vector : new HashSet<>(existingVelocities)) {
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(newVector3D(0, 0.04f, 0)), vector, VectorData.VectorType.Jump));
if (player.skippedTickInActualMovement) {
existingVelocities.add(new VectorData(vector.vector.clone().add(new Vector(0, 0.02f, 0)), vector, VectorData.VectorType.Jump));
existingVelocities.add(new VectorData(vector.vector.clone().add(newVector3D(0, 0.02f, 0)), vector, VectorData.VectorType.Jump));
}
}
}
@@ -62,7 +65,7 @@ public class PredictionEngineWaterLegacy extends PredictionEngine {
super.endOfTick(player, playerGravity);
for (VectorData vector : player.getPossibleVelocitiesMinusKnockback()) {
vector.vector.multiply(new Vector(swimmingFriction, 0.8F, swimmingFriction));
vector.vector.multiply(newVector3D(swimmingFriction, 0.8F, swimmingFriction));
// Gravity
vector.vector.setY(vector.vector.getY() - 0.02D);
@@ -13,12 +13,15 @@ import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static java.lang.Math.PI;
public class BoatPredictionEngine extends PredictionEngine {
public BoatPredictionEngine(GrimPlayer player) {
player.uncertaintyHandler.collidingEntities.add(0); // We don't do collisions like living entities
@@ -147,7 +150,7 @@ public class BoatPredictionEngine extends PredictionEngine {
// so if a player tries to move in both directions, a packet will
// show that the player is staying, but the boat will move anyway
if (player.vehicleData.vehicleForward == 0) {
Vector vector = data.vector.clone();
Vector3D vector = data.vector.clone();
controlBoat(player, vector, true);
vector.multiply(player.stuckSpeedMultiplier);
vectors.add(data.returnNewModified(vector, VectorData.VectorType.InputResult));
@@ -184,7 +187,7 @@ public class BoatPredictionEngine extends PredictionEngine {
return false;
}
private void floatBoat(GrimPlayer player, Vector vector) {
private void floatBoat(GrimPlayer player, Vector3D vector) {
double d1 = player.hasGravity ? -0.04f : 0;
double d2 = 0.0D;
float invFriction = 0.05F;
@@ -194,7 +197,7 @@ public class BoatPredictionEngine extends PredictionEngine {
player.lastY = getWaterLevelAbove(player) - 0.5625F + 0.101D;
player.boundingBox = GetBoundingBox.getCollisionBoxForPlayer(player, player.lastX, player.lastY, player.lastZ);
player.actualMovement = new Vector(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
player.actualMovement = newVector3D(player.x - player.lastX, player.y - player.lastY, player.z - player.lastZ);
vector.setY(0);
player.vehicleData.lastYd = 0.0D;
@@ -260,7 +263,7 @@ public class BoatPredictionEngine extends PredictionEngine {
return (float) (l + 1);
}
private void controlBoat(GrimPlayer player, Vector vector, boolean intermediate) {
private void controlBoat(GrimPlayer player, Vector3D vector, boolean intermediate) {
float f = 0.0F;
if (player.vehicleData.vehicleHorizontal != 0 && (!intermediate && player.vehicleData.vehicleForward == 0)) {
f += 0.005F;
@@ -275,6 +278,6 @@ public class BoatPredictionEngine extends PredictionEngine {
f -= 0.005F;
}
vector.add(new Vector(player.trigHandler.sin(-player.xRot * ((float) Math.PI / 180F)) * f, 0, (double) (player.trigHandler.cos(player.xRot * ((float) Math.PI / 180F)) * f)));
vector.add(newVector3D(player.trigHandler.sin(-player.xRot * ((float) PI / 180F)) * f, 0, (double) (player.trigHandler.cos(player.xRot * ((float) PI / 180F)) * f)));
}
}
@@ -3,16 +3,16 @@ package ac.grim.grimac.predictionengine.predictions.rideable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.predictionengine.predictions.PredictionEngineLava;
import ac.grim.grimac.utils.data.VectorData;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.List;
import java.util.Set;
public class PredictionEngineRideableLava extends PredictionEngineLava {
Vector movementVector;
Vector3D movementVector;
public PredictionEngineRideableLava(Vector movementVector) {
public PredictionEngineRideableLava(Vector3D movementVector) {
this.movementVector = movementVector;
}
@@ -3,16 +3,16 @@ package ac.grim.grimac.predictionengine.predictions.rideable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.predictionengine.predictions.PredictionEngineNormal;
import ac.grim.grimac.utils.data.VectorData;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.List;
import java.util.Set;
public class PredictionEngineRideableNormal extends PredictionEngineNormal {
Vector movementVector;
Vector3D movementVector;
public PredictionEngineRideableNormal(Vector movementVector) {
public PredictionEngineRideableNormal(Vector3D movementVector) {
this.movementVector = movementVector;
}
@@ -8,13 +8,15 @@ import ac.grim.grimac.utils.data.packetentity.PacketEntityHorse;
import ac.grim.grimac.utils.nmsutil.JumpPower;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;
import java.util.Set;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class PredictionEngineRideableUtils {
public static Set<VectorData> handleJumps(GrimPlayer player, Set<VectorData> possibleVectors) {
if (!(player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityHorse)) return possibleVectors;
@@ -57,7 +59,7 @@ public class PredictionEngineRideableUtils {
for (VectorData vectorData : possibleVectors) {
vectorData.vector.setY(d1);
if (f1 > 0.0F) {
vectorData.vector.add(new Vector(-0.4F * f2 * player.vehicleData.horseJump, 0.0D, 0.4F * f3 * player.vehicleData.horseJump));
vectorData.vector.add(newVector3D(-0.4F * f2 * player.vehicleData.horseJump, 0.0D, 0.4F * f3 * player.vehicleData.horseJump));
}
}
@@ -73,7 +75,7 @@ public class PredictionEngineRideableUtils {
return possibleVectors;
}
public static List<VectorData> applyInputsToVelocityPossibilities(Vector movementVector, GrimPlayer player, Set<VectorData> possibleVectors, float speed) {
public static List<VectorData> applyInputsToVelocityPossibilities(Vector3D movementVector, GrimPlayer player, Set<VectorData> possibleVectors, float speed) {
List<VectorData> returnVectors = new ArrayList<>();
for (VectorData possibleLastTickOutput : possibleVectors) {
@@ -3,16 +3,16 @@ package ac.grim.grimac.predictionengine.predictions.rideable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.predictionengine.predictions.PredictionEngineWater;
import ac.grim.grimac.utils.data.VectorData;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.List;
import java.util.Set;
public class PredictionEngineRideableWater extends PredictionEngineWater {
Vector movementVector;
Vector3D movementVector;
public PredictionEngineRideableWater(Vector movementVector) {
public PredictionEngineRideableWater(Vector3D movementVector) {
this.movementVector = movementVector;
}
@@ -3,15 +3,15 @@ package ac.grim.grimac.predictionengine.predictions.rideable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.predictionengine.predictions.PredictionEngineWaterLegacy;
import ac.grim.grimac.utils.data.VectorData;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.List;
import java.util.Set;
public class PredictionEngineRideableWaterLegacy extends PredictionEngineWaterLegacy {
Vector movementVector;
Vector3D movementVector;
public PredictionEngineRideableWaterLegacy(Vector movementVector) {
public PredictionEngineRideableWaterLegacy(Vector3D movementVector) {
this.movementVector = movementVector;
}
@@ -17,6 +17,7 @@ import ac.grim.grimac.utils.nmsutil.BoundingBoxSize;
import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import ac.grim.grimac.utils.nmsutil.Materials;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
@@ -35,12 +36,17 @@ import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.util.Vector3i;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import static ac.grim.grimac.utils.nmsutil.ReachUtils.calculateIntercept;
import static ac.grim.grimac.utils.nmsutil.ReachUtils.getLook;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.attribute.Attributes.PLAYER_BLOCK_INTERACTION_RANGE;
public class BlockPlace {
protected static final BlockFace[] UPDATE_SHAPE_ORDER = new BlockFace[]{BlockFace.WEST, BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.DOWN, BlockFace.UP};
private static final BlockFace[] BY_2D = new BlockFace[]{BlockFace.SOUTH, BlockFace.WEST, BlockFace.NORTH, BlockFace.EAST};
@@ -668,18 +674,18 @@ public class BlockPlace {
// You also have the desync caused by eye height as apparently tracking the player's ticks wasn't important to you
// No mojang, you really do need to track client ticks to get their accurate eye height.
// another damn desync added... maybe next decade it will get fixed and double the amount of issues.
public Vector getClickedLocation() {
public Vector3D getClickedLocation() {
SimpleCollisionBox box = new SimpleCollisionBox(getPlacedAgainstBlockLocation());
Vector look = ReachUtils.getLook(player, player.xRot, player.yRot);
Vector3D look = getLook(player, player.xRot, player.yRot);
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE) + 3;
Vector eyePos = new Vector(player.x, player.y + player.getEyeHeight(), player.z);
Vector endReachPos = eyePos.clone().add(new Vector(look.getX() * distance, look.getY() * distance, look.getZ() * distance));
Vector intercept = ReachUtils.calculateIntercept(box, eyePos, endReachPos).getFirst();
final double distance = player.compensatedEntities.getSelf().getAttributeValue(PLAYER_BLOCK_INTERACTION_RANGE) + 3;
Vector3D eyePos = newVector3D(player.x, player.y + player.getEyeHeight(), player.z);
Vector3D endReachPos = eyePos.clone().add(newVector3D(look.getX() * distance, look.getY() * distance, look.getZ() * distance));
Vector3D intercept = calculateIntercept(box, eyePos, endReachPos).getFirst();
// Bring this back to relative to the block
// The player didn't even click the block... (we should force resync BEFORE we get here!)
if (intercept == null) return new Vector();
if (intercept == null) return newVector3D();
intercept.setX(intercept.getX() - box.minX);
intercept.setY(intercept.getY() - box.minY);
@@ -21,11 +21,13 @@ 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.protocol.world.states.type.StateValue;
import com.github.retrooper.packetevents.util.Vector3i;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.*;
import java.util.stream.Collectors;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public enum BlockPlaceResult {
// If the block only has directional data
@@ -80,7 +82,7 @@ public enum BlockPlaceResult {
}, ItemTypes.SNOW),
SLAB((player, place) -> {
Vector clickedPos = place.getClickedLocation();
Vector3D clickedPos = place.getClickedLocation();
WrappedBlockState slabData = place.getMaterial().createBlockState(CompensatedWorld.blockVersion);
WrappedBlockState existing = place.getExistingBlockData();
@@ -909,7 +911,7 @@ public enum BlockPlaceResult {
WrappedBlockState ccwState = place.getDirectionalState(ccw);
CollisionBox ccwBox = CollisionData.getData(ccwState.getType()).getMovementCollisionBox(player, player.getClientVersion(), ccwState);
Vector aboveCCWPos = place.getClickedLocation().add(new Vector(ccw.getModX(), ccw.getModY(), ccw.getModZ())).add(new Vector(0, 1, 0));
Vector3D aboveCCWPos = place.getClickedLocation().add(newVector3D(ccw.getModX(), ccw.getModY(), ccw.getModZ())).add(newVector3D(0, 1, 0));
WrappedBlockState aboveCCWState = player.compensatedWorld.getWrappedBlockStateAt(aboveCCWPos);
CollisionBox aboveCCWBox = CollisionData.getData(aboveCCWState.getType()).getMovementCollisionBox(player, player.getClientVersion(), aboveCCWState);
@@ -917,7 +919,7 @@ public enum BlockPlaceResult {
WrappedBlockState cwState = place.getDirectionalState(cw);
CollisionBox cwBox = CollisionData.getData(cwState.getType()).getMovementCollisionBox(player, player.getClientVersion(), cwState);
Vector aboveCWPos = place.getClickedLocation().add(new Vector(cw.getModX(), cw.getModY(), cw.getModZ())).add(new Vector(0, 1, 0));
Vector3D aboveCWPos = place.getClickedLocation().add(newVector3D(cw.getModX(), cw.getModY(), cw.getModZ())).add(newVector3D(0, 1, 0));
WrappedBlockState aboveCWState = player.compensatedWorld.getWrappedBlockStateAt(aboveCWPos);
CollisionBox aboveCWBox = CollisionData.getData(aboveCWState.getType()).getMovementCollisionBox(player, player.getClientVersion(), aboveCWState);
@@ -934,7 +936,7 @@ public enum BlockPlaceResult {
if ((!isCWLower || isCCWLower) && i >= 0) {
int j = playerFacing.getModX();
int k = playerFacing.getModZ();
Vector vec3 = place.getClickedLocation();
Vector3D vec3 = place.getClickedLocation();
double d0 = vec3.getX();
double d1 = vec3.getY();
hinge = (j >= 0 || d1 >= 0.5D) && (j <= 0 || d1 <= 0.5D) && (k >= 0 || d0 <= 0.5D) && (k <= 0 || d0 >= 0.5D) ? Hinge.LEFT : Hinge.RIGHT;
@@ -1,7 +1,8 @@
package ac.grim.grimac.utils.blockstate.helper;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
public class BlockFaceHelper {
public static boolean isFaceVertical(BlockFace face) {
@@ -78,7 +79,7 @@ public class BlockFaceHelper {
}
}
public Vector offset(Vector toOffset, BlockFace face) {
public Vector3D offset(Vector3D toOffset, BlockFace face) {
toOffset.setX(toOffset.getX() + face.getModX());
toOffset.setY(toOffset.getY() + face.getModY());
toOffset.setZ(toOffset.getZ() + face.getModZ());
@@ -1,6 +1,9 @@
package ac.grim.grimac.utils.collisions.datatypes;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class BoundingBox {
@@ -15,7 +18,7 @@ public class BoundingBox {
this.maxZ = maxZ;
}
public BoundingBox(Vector min, Vector max) {
public BoundingBox(Vector3D min, Vector3D max) {
this.minX = (float) Math.min(min.getX(), max.getX());
this.minY = (float) Math.min(min.getY(), max.getY());
this.minZ = (float) Math.min(min.getZ(), max.getZ());
@@ -44,7 +47,7 @@ public class BoundingBox {
return new BoundingBox(newMinX, newMinY, newMinZ, newMaxX, newMaxY, newMaxZ);
}
public BoundingBox add(Vector vector) {
public BoundingBox add(Vector3D vector) {
float x = (float) vector.getX(), y = (float) vector.getY(), z = (float) vector.getZ();
float newMinX = minX + x;
@@ -87,27 +90,27 @@ public class BoundingBox {
return new BoundingBox(this.minX - minX, this.minY - minY, this.minZ - minZ, this.maxX - maxX, this.maxY - maxY, this.maxZ - maxZ);
}
public boolean intersectsWithBox(Vector vector) {
public boolean intersectsWithBox(Vector3D vector) {
return (vector.getX() > this.minX && vector.getX() < this.maxX) && ((vector.getY() > this.minY && vector.getY() < this.maxY) && (vector.getZ() > this.minZ && vector.getZ() < this.maxZ));
}
public Vector getMinimum() {
return new Vector(minX, minY, minZ);
public Vector3D getMinimum() {
return newVector3D(minX, minY, minZ);
}
public Vector getMaximum() {
return new Vector(maxX, maxY, maxZ);
public Vector3D getMaximum() {
return newVector3D(maxX, maxY, maxZ);
}
public boolean collides(Vector vector) {
public boolean collides(Vector3D vector) {
return (vector.getX() >= this.minX && vector.getX() <= this.maxX) && ((vector.getY() >= this.minY && vector.getY() <= this.maxY) && (vector.getZ() >= this.minZ && vector.getZ() <= this.maxZ));
}
public boolean collidesHorizontally(Vector vector) {
public boolean collidesHorizontally(Vector3D vector) {
return (vector.getX() >= this.minX && vector.getX() <= this.maxX) && ((vector.getY() > this.minY && vector.getY() < this.maxY) && (vector.getZ() >= this.minZ && vector.getZ() <= this.maxZ));
}
public boolean collidesVertically(Vector vector) {
public boolean collidesVertically(Vector3D vector) {
return (vector.getX() > this.minX && vector.getX() < this.maxX) && ((vector.getY() >= this.minY && vector.getY() <= this.maxY) && (vector.getZ() > this.minZ && vector.getZ() < this.maxZ));
}
@@ -1,6 +1,7 @@
package ac.grim.grimac.utils.collisions.datatypes;
import ac.grim.grimac.utils.nmsutil.Ray;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
@@ -8,9 +9,12 @@ import it.unimi.dsi.fastutil.doubles.AbstractDoubleList;
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.doubles.DoubleList;
import org.bukkit.Location;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.List;
import java.util.Vector;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class SimpleCollisionBox implements CollisionBox {
@@ -46,7 +50,7 @@ public class SimpleCollisionBox implements CollisionBox {
isFullBlock = fullBlock;
}
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());
}
@@ -85,10 +89,10 @@ public class SimpleCollisionBox implements CollisionBox {
}
public SimpleCollisionBox(Location loc, double width, double height) {
this(loc.toVector(), width, height);
this(newVector3D(loc.getX(), loc.getY(), loc.getZ()), width, height);
}
public SimpleCollisionBox(Vector vec, double width, double 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);
@@ -151,16 +155,16 @@ public class SimpleCollisionBox implements CollisionBox {
return this;
}
public Vector[] corners() {
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);
public Vector3D[] corners() {
Vector3D[] vectors = new Vector3D[8];
vectors[0] = newVector3D(minX, minY, minZ);
vectors[1] = newVector3D(minX, minY, maxZ);
vectors[2] = newVector3D(maxX, minY, minZ);
vectors[3] = newVector3D(maxX, minY, maxZ);
vectors[4] = newVector3D(minX, maxY, minZ);
vectors[5] = newVector3D(minX, maxY, maxZ);
vectors[6] = newVector3D(maxX, maxY, minZ);
vectors[7] = newVector3D(maxX, maxY, maxZ);
return vectors;
}
@@ -414,14 +418,14 @@ public class SimpleCollisionBox implements CollisionBox {
*/
// Copied from hawk lol
// I would like to point out that this is magic to me and I have not attempted to understand this code
public Vector intersectsRay(Ray ray, float minDist, float maxDist) {
Vector invDir = new Vector(1f / ray.calculateDirection().getX(), 1f / ray.calculateDirection().getY(), 1f / ray.calculateDirection().getZ());
public Vector3D intersectsRay(Ray ray, float minDist, float maxDist) {
Vector3D invDir = newVector3D(1f / ray.calculateDirection().getX(), 1f / ray.calculateDirection().getY(), 1f / ray.calculateDirection().getZ());
boolean signDirX = invDir.getX() < 0;
boolean signDirY = invDir.getY() < 0;
boolean signDirZ = invDir.getZ() < 0;
Vector bbox = signDirX ? max() : min();
Vector3D bbox = signDirX ? max() : min();
double tmin = (bbox.getX() - ray.getOrigin().getX()) * invDir.getX();
bbox = signDirX ? min() : max();
double tmax = (bbox.getX() - ray.getOrigin().getX()) * invDir.getX();
@@ -460,12 +464,12 @@ public class SimpleCollisionBox implements CollisionBox {
return null;
}
public Vector max() {
return new Vector(maxX, maxY, maxZ);
public Vector3D max() {
return newVector3D(maxX, maxY, maxZ);
}
public Vector min() {
return new Vector(minX, minY, minZ);
public Vector3D min() {
return newVector3D(minX, minY, minZ);
}
public DoubleList getYPointPositions() {
@@ -6,18 +6,18 @@ import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import lombok.Getter;
import lombok.ToString;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
@Getter
@ToString
public class HitData {
Vector3i position;
Vector blockHitLocation;
Vector3D blockHitLocation;
WrappedBlockState state;
BlockFace closestDirection;
public Boolean success;
public HitData(Vector3i position, Vector blockHitLocation, BlockFace closestDirection, WrappedBlockState state) {
public HitData(Vector3i position, Vector3D blockHitLocation, BlockFace closestDirection, WrappedBlockState state) {
this.position = position;
this.blockHitLocation = blockHitLocation;
this.closestDirection = closestDirection;
@@ -25,7 +25,7 @@ public class HitData {
this.success = null;
}
public HitData(Vector3i position, Vector blockHitLocation, BlockFace closestDirection, WrappedBlockState state, Boolean success) {
public HitData(Vector3i position, Vector3D blockHitLocation, BlockFace closestDirection, WrappedBlockState state, Boolean success) {
this.position = position;
this.blockHitLocation = blockHitLocation;
this.closestDirection = closestDirection;
@@ -3,7 +3,7 @@ package ac.grim.grimac.utils.data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
@Getter
@Setter
@@ -11,14 +11,14 @@ import org.bukkit.util.Vector;
public class SetBackData {
TeleportData teleportData;
float xRot, yRot;
Vector velocity;
Vector3D velocity;
boolean vehicle;
boolean isComplete = false;
// TODO: Rethink when we block movements for teleports, perhaps after 10 ticks or 5 blocks?
boolean isPlugin = false;
int ticksComplete = 0;
public SetBackData(TeleportData teleportData, float xRot, float yRot, Vector velocity, boolean vehicle, boolean isPlugin) {
public SetBackData(TeleportData teleportData, float xRot, float yRot, Vector3D velocity, boolean vehicle, boolean isPlugin) {
this.teleportData = teleportData;
this.xRot = xRot;
this.yRot = yRot;
@@ -1,7 +1,7 @@
package ac.grim.grimac.utils.data;
import lombok.Getter;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.Objects;
@@ -10,7 +10,7 @@ public class VectorData {
public int x;
public int z;
public MoveVectorData(Vector vector, VectorData lastVector, VectorType vectorType, int x, int z) {
public MoveVectorData(Vector3D vector, VectorData lastVector, VectorType vectorType, int x, int z) {
super(vector, lastVector, vectorType);
this.x = x;
this.z = z;
@@ -20,7 +20,7 @@ public class VectorData {
}
}
public MoveVectorData(Vector vector, VectorType vectorType, int x, int z) {
public MoveVectorData(Vector3D vector, VectorType vectorType, int x, int z) {
super(vector, vectorType);
this.x = x;
this.z = z;
@@ -34,13 +34,13 @@ public class VectorData {
public VectorType vectorType;
public VectorData lastVector;
public VectorData preUncertainty;
public Vector vector;
public Vector3D vector;
@Getter
private boolean isKnockback, firstBreadKb, isExplosion, firstBreadExplosion, isTrident, isZeroPointZeroThree, isSwimHop, isFlipSneaking, isFlipItem, isJump, isAttackSlow, isWithInput;
// For handling replacing the type of vector it is while keeping data
public VectorData(Vector vector, VectorData lastVector, VectorType vectorType) {
public VectorData(Vector3D vector, VectorData lastVector, VectorType vectorType) {
this.vector = vector;
this.lastVector = lastVector;
this.vectorType = vectorType;
@@ -64,7 +64,7 @@ public class VectorData {
addVectorType(vectorType);
}
public VectorData(Vector vector, VectorType vectorType) {
public VectorData(Vector3D vector, VectorType vectorType) {
this.vector = vector;
this.vectorType = vectorType;
addVectorType(vectorType);
@@ -74,7 +74,7 @@ public class VectorData {
return new VectorData(vector, this, type);
}
public VectorData returnNewModified(Vector newVec, VectorType type) {
public VectorData returnNewModified(Vector3D newVec, VectorType type) {
return new VectorData(newVec, this, type);
}
@@ -1,15 +1,15 @@
package ac.grim.grimac.utils.data;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
public class VelocityData {
public final Vector vector;
public final Vector3D vector;
public final int entityID;
public final int transaction;
public double offset = Integer.MAX_VALUE;
public boolean isSetback;
public VelocityData(int entityID, int transaction, boolean isSetback, Vector vector) {
public VelocityData(int entityID, int transaction, boolean isSetback, Vector3D vector) {
this.entityID = entityID;
this.vector = vector;
this.transaction = transaction;
@@ -17,7 +17,7 @@ public class VelocityData {
}
// First bread last tick -> Required this tick = don't require kb twice
public VelocityData(int entityID, int transaction, Vector vector, boolean isSetback, double offset) {
public VelocityData(int entityID, int transaction, Vector3D vector, boolean isSetback, double offset) {
this.entityID = entityID;
this.vector = vector;
this.transaction = transaction;
@@ -49,7 +49,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import org.bukkit.Bukkit;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.*;
@@ -686,7 +686,7 @@ public class CompensatedWorld {
return maxHeight;
}
public WrappedBlockState getWrappedBlockStateAt(Vector aboveCCWPos) {
public WrappedBlockState getWrappedBlockStateAt(Vector3D aboveCCWPos) {
return getWrappedBlockStateAt(aboveCCWPos.getX(), aboveCCWPos.getY(), aboveCCWPos.getZ());
}
}
@@ -1,9 +1,14 @@
package ac.grim.grimac.utils.math;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import lombok.Getter;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_8;
import static java.lang.Math.abs;
public class TrigHandler {
GrimPlayer player;
@@ -19,24 +24,24 @@ public class TrigHandler {
isVanillaMath = !isVanillaMath;
}
public Vector getVanillaMathMovement(Vector wantedMovement, float f, float f2) {
public Vector3D getVanillaMathMovement(Vector3D wantedMovement, float f, float f2) {
float f3 = VanillaMath.sin(f2 * 0.017453292f);
float f4 = VanillaMath.cos(f2 * 0.017453292f);
float bestTheoreticalX = (float) (f3 * wantedMovement.getZ() + f4 * wantedMovement.getX()) / (f3 * f3 + f4 * f4) / f;
float bestTheoreticalZ = (float) (-f3 * wantedMovement.getX() + f4 * wantedMovement.getZ()) / (f3 * f3 + f4 * f4) / f;
return new Vector(bestTheoreticalX, 0, bestTheoreticalZ);
return newVector3D(bestTheoreticalX, 0, bestTheoreticalZ);
}
public Vector getShitMathMovement(Vector wantedMovement, float f, float f2) {
float f3 = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? OptifineFastMath.sin(f2 * 0.017453292f) : LegacyFastMath.sin(f2 * 0.017453292f);
float f4 = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? OptifineFastMath.cos(f2 * 0.017453292f) : LegacyFastMath.cos(f2 * 0.017453292f);
public Vector3D getShitMathMovement(Vector3D wantedMovement, float f, float f2) {
float f3 = player.getClientVersion().isNewerThanOrEquals(V_1_8) ? OptifineFastMath.sin(f2 * 0.017453292f) : LegacyFastMath.sin(f2 * 0.017453292f);
float f4 = player.getClientVersion().isNewerThanOrEquals(V_1_8) ? OptifineFastMath.cos(f2 * 0.017453292f) : LegacyFastMath.cos(f2 * 0.017453292f);
float bestTheoreticalX = (float) (f3 * wantedMovement.getZ() + f4 * wantedMovement.getX()) / (f3 * f3 + f4 * f4) / f;
float bestTheoreticalZ = (float) (-f3 * wantedMovement.getX() + f4 * wantedMovement.getZ()) / (f3 * f3 + f4 * f4) / f;
return new Vector(bestTheoreticalX, 0, bestTheoreticalZ);
return newVector3D(bestTheoreticalX, 0, bestTheoreticalZ);
}
public void setOffset(double offset) {
@@ -49,12 +54,12 @@ public class TrigHandler {
}
if (offset > 1e-5) {
Vector trueMovement = player.actualMovement.clone().subtract(player.startTickClientVel);
Vector correctMath = getVanillaMathMovement(trueMovement, 0.1f, player.xRot);
Vector fastMath = getShitMathMovement(trueMovement, 0.1f, player.xRot);
Vector3D trueMovement = player.actualMovement.clone().subtract(player.startTickClientVel);
Vector3D correctMath = getVanillaMathMovement(trueMovement, 0.1f, player.xRot);
Vector3D fastMath = getShitMathMovement(trueMovement, 0.1f, player.xRot);
correctMath = new Vector(Math.abs(correctMath.getX()), 0, Math.abs(correctMath.getZ()));
fastMath = new Vector(Math.abs(fastMath.getX()), 0, Math.abs(fastMath.getZ()));
correctMath = newVector3D(abs(correctMath.getX()), 0, abs(correctMath.getZ()));
fastMath = newVector3D(abs(fastMath.getX()), 0, abs(fastMath.getZ()));
double minCorrectHorizontal = Math.min(correctMath.getX(), correctMath.getZ());
// Support diagonal inputs
@@ -1,23 +1,25 @@
package ac.grim.grimac.utils.math;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.util.Vector3d;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.math.GrimMath.clamp;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class VectorUtils {
public static Vector cutBoxToVector(Vector vectorToCutTo, Vector min, Vector max) {
public static Vector3D cutBoxToVector(Vector3D vectorToCutTo, Vector3D min, Vector3D max) {
SimpleCollisionBox box = new SimpleCollisionBox(min, max).sort();
return cutBoxToVector(vectorToCutTo, box);
}
public static Vector cutBoxToVector(Vector vectorCutTo, SimpleCollisionBox box) {
return new Vector(GrimMath.clamp(vectorCutTo.getX(), box.minX, box.maxX),
GrimMath.clamp(vectorCutTo.getY(), box.minY, box.maxY),
GrimMath.clamp(vectorCutTo.getZ(), box.minZ, box.maxZ));
public static Vector3D cutBoxToVector(Vector3D vectorCutTo, SimpleCollisionBox box) {
return newVector3D(clamp(vectorCutTo.getX(), box.minX, box.maxX), clamp(vectorCutTo.getY(), box.minY, box.maxY), clamp(vectorCutTo.getZ(), box.minZ, box.maxZ));
}
public static Vector fromVec3d(Vector3d vector3d) {
return new Vector(vector3d.getX(), vector3d.getY(), vector3d.getZ());
public static Vector3D fromVec3d(Vector3d vector3d) {
return newVector3D(vector3d.getX(), vector3d.getY(), vector3d.getZ());
}
// Clamping stops the player from causing an integer overflow and crashing the netty thread
@@ -19,13 +19,15 @@ 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.Vector3i;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Map;
import java.util.function.BiFunction;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class BlockRayTrace {
// Copied from MCP...
@@ -232,7 +234,7 @@ public class BlockRayTrace {
bestHitLoc = hitLoc;
bestFace = intercept.getSecond();
if (isTargetBlock && (bestFace == expectedBlockFace || player.checkManager.getBlockPlaceCheck(LineOfSightPlace.class).blocksChangedList.get(vector3i) != null)) {
return new HitData(vector3i, new Vector(bestHitLoc[0], bestHitLoc[1], bestHitLoc[2]), expectedBlockFace, block, true);
return new HitData(vector3i, newVector3D(bestHitLoc[0], bestHitLoc[1], bestHitLoc[2]), expectedBlockFace, block, true);
}
}
}
@@ -248,11 +250,11 @@ public class BlockRayTrace {
// because that is version-specific, will break if the implementation of the returned ComplexCollisionBox changes
// and again, lots of code complexity for little performance gain
if (bestHitLoc != null) {
HitData hitData = new HitData(vector3i, new Vector(bestHitLoc[0], bestHitLoc[1], bestHitLoc[2]), bestFace, block, isTargetBlock);
HitData hitData = new HitData(vector3i, newVector3D(bestHitLoc[0], bestHitLoc[1], bestHitLoc[2]), bestFace, block, isTargetBlock);
if (!raycastContext) {
HitData hitData2 = BlockRayTrace.getNearestReachHitResult(player, startPos, lookVec, maxDistance, maxDistance, targetBlockVec, expectedBlockFace, boxes, blockOverrides, true);
if (hitData2 != null) {
Vector startVector = new Vector(startPos[0], startPos[1], startPos[2]);
Vector3D startVector = newVector3D(startPos[0], startPos[1], startPos[2]);
if (hitData2.getBlockHitLocation().subtract(startVector).lengthSquared() <
hitData.getBlockHitLocation().subtract(startVector).lengthSquared()) {
return new HitData(vector3i, hitData.getBlockHitLocation(), hitData2.getClosestDirection(), block, isTargetBlock);
@@ -275,39 +277,39 @@ public class BlockRayTrace {
public static HitData getNearestHitResult(GrimPlayer player, StateType heldItem, boolean sourcesHaveHitbox) {
Vector3d startingPos = new Vector3d(player.x, player.y + player.getEyeHeight(), player.z);
Vector startingVec = new Vector(startingPos.getX(), startingPos.getY(), startingPos.getZ());
Vector3D startingVec = newVector3D(startingPos.getX(), startingPos.getY(), startingPos.getZ());
Ray trace = new Ray(player, startingPos.getX(), startingPos.getY(), startingPos.getZ(), player.xRot, player.yRot);
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
Vector endVec = trace.getPointAtDistance(distance);
Vector3D endVec = trace.getPointAtDistance(distance);
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
return getTraverseResult(player, heldItem, startingPos, startingVec, trace, endPos, sourcesHaveHitbox, false, distance + 3);
}
@Nullable
public static HitData getNearestReachHitResult(GrimPlayer player, Vector eyePos, Vector lookVec, double currentDistance, double maxDistance) {
public static HitData getNearestReachHitResult(GrimPlayer player, Vector3D eyePos, Vector3D lookVec, double currentDistance, double maxDistance) {
Vector3d startingPos = new Vector3d(eyePos.getX(), eyePos.getY(), eyePos.getZ());
Vector startingVec = new Vector(startingPos.getX(), startingPos.getY(), startingPos.getZ());
Vector3D startingVec = newVector3D(startingPos.getX(), startingPos.getY(), startingPos.getZ());
Ray trace = new Ray(eyePos, lookVec);
Vector endVec = trace.getPointAtDistance(maxDistance);
Vector3D endVec = trace.getPointAtDistance(maxDistance);
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
return getTraverseResult(player, null, startingPos, startingVec, trace, endPos, false, true, currentDistance);
}
private static HitData getTraverseResult(GrimPlayer player, @Nullable StateType heldItem, Vector3d startingPos, Vector startingVec, Ray trace, Vector3d endPos, boolean sourcesHaveHitbox, boolean checkInside, double knownDistance) {
private static HitData getTraverseResult(GrimPlayer player, @Nullable StateType heldItem, Vector3d startingPos, Vector3D startingVec, Ray trace, Vector3d endPos, boolean sourcesHaveHitbox, boolean checkInside, double knownDistance) {
return traverseBlocks(player, startingPos, endPos, (block, vector3i) -> {
CollisionBox data = HitboxData.getBlockHitbox(player, heldItem, player.getClientVersion(), block, vector3i.getX(), vector3i.getY(), vector3i.getZ());
SimpleCollisionBox[] boxes = new SimpleCollisionBox[ComplexCollisionBox.DEFAULT_MAX_COLLISION_BOX_SIZE];
int size = data.downCast(boxes);
double bestHitResult = Double.MAX_VALUE;
Vector bestHitLoc = null;
Vector3D bestHitLoc = null;
BlockFace bestFace = null;
for (int i = 0; i < size; i++) {
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(boxes[i], trace.getOrigin(), trace.getPointAtDistance(knownDistance));
Pair<Vector3D, BlockFace> intercept = ReachUtils.calculateIntercept(boxes[i], trace.getOrigin(), trace.getPointAtDistance(knownDistance));
if (intercept.getFirst() == null) continue; // No intercept
Vector hitLoc = intercept.getFirst();
Vector3D hitLoc = intercept.getFirst();
// If inside a block, return empty result for reach check (don't bother checking this?)
if (checkInside && ReachUtils.isVecInside(boxes[i], trace.getOrigin())) {
@@ -331,7 +333,7 @@ public class BlockRayTrace {
double waterHeight = player.compensatedWorld.getFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ());
SimpleCollisionBox box = new SimpleCollisionBox(vector3i.getX(), vector3i.getY(), vector3i.getZ(), vector3i.getX() + 1, vector3i.getY() + waterHeight, vector3i.getZ() + 1);
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(knownDistance));
Pair<Vector3D, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(knownDistance));
if (intercept.getFirst() != null) {
return new HitData(vector3i, intercept.getFirst(), intercept.getSecond(), block, null);
@@ -12,6 +12,7 @@ import ac.grim.grimac.utils.data.tags.SyncedTags;
import ac.grim.grimac.utils.latency.CompensatedWorld;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.math.VectorUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
@@ -26,7 +27,7 @@ import it.unimi.dsi.fastutil.floats.FloatArraySet;
import it.unimi.dsi.fastutil.floats.FloatArrays;
import it.unimi.dsi.fastutil.floats.FloatSet;
import org.bukkit.Location;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.ArrayList;
import java.util.Arrays;
@@ -34,6 +35,13 @@ import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import static ac.grim.grimac.utils.nmsutil.Collisions.Axis.*;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.*;
import static java.lang.Double.MAX_VALUE;
import static java.lang.Math.max;
import static java.lang.Math.min;
public class Collisions {
private static final double COLLISION_EPSILON = 1.0E-7;
@@ -71,12 +79,12 @@ public class Collisions {
}
// Call this when there isn't uncertainty on the Y axis
public static Vector collide(GrimPlayer player, double desiredX, double desiredY, double desiredZ) {
public static Vector3D collide(GrimPlayer player, double desiredX, double desiredY, double desiredZ) {
return collide(player, desiredX, desiredY, desiredZ, desiredY, null);
}
public static Vector collide(GrimPlayer player, double desiredX, double desiredY, double desiredZ, double clientVelY, VectorData data) {
if (desiredX == 0 && desiredY == 0 && desiredZ == 0) return new Vector();
public static Vector3D collide(GrimPlayer player, double desiredX, double desiredY, double desiredZ, double clientVelY, VectorData data) {
if (desiredX == 0 && desiredY == 0 && desiredZ == 0) return newVector3D();
final SimpleCollisionBox grabBoxesBB = player.boundingBox.copy();
final double stepUpHeight = player.getMaxUpStep();
@@ -94,7 +102,7 @@ public class Collisions {
grabBoxesBB.expandToCoordinate(desiredX, desiredY, desiredZ);
grabBoxesBB.maxY += stepUpHeight;
} else {
grabBoxesBB.expandToCoordinate(desiredX, Math.max(stepUpHeight, desiredY), desiredZ);
grabBoxesBB.expandToCoordinate(desiredX, max(stepUpHeight, desiredY), desiredZ);
}
} else {
grabBoxesBB.expandToCoordinate(desiredX, desiredY, desiredZ);
@@ -104,14 +112,14 @@ public class Collisions {
List<SimpleCollisionBox> desiredMovementCollisionBoxes = new ArrayList<>();
getCollisionBoxes(player, grabBoxesBB, desiredMovementCollisionBoxes, false);
double bestInput = Double.MAX_VALUE;
Vector bestOrderResult = null;
double bestInput = MAX_VALUE;
Vector3D bestOrderResult = null;
Vector bestTheoreticalCollisionResult = VectorUtils.cutBoxToVector(player.actualMovement, new SimpleCollisionBox(0, Math.min(0, desiredY), 0, desiredX, Math.max(stepUpHeight, desiredY), desiredZ).sort());
Vector3D bestTheoreticalCollisionResult = VectorUtils.cutBoxToVector(player.actualMovement, new SimpleCollisionBox(0, min(0, desiredY), 0, desiredX, max(stepUpHeight, desiredY), desiredZ).sort());
int zeroCount = (desiredX == 0 ? 1 : 0) + (desiredY == 0 ? 1 : 0) + (desiredZ == 0 ? 1 : 0);
for (List<Axis> order : (data != null && data.isZeroPointZeroThree() ? allAxisCombinations : nonStupidityCombinations)) {
Vector collisionResult = collideBoundingBoxLegacy(new Vector(desiredX, desiredY, desiredZ), player.boundingBox, desiredMovementCollisionBoxes, order);
Vector3D collisionResult = collideBoundingBoxLegacy(newVector3D(desiredX, desiredY, desiredZ), player.boundingBox, desiredMovementCollisionBoxes, order);
// While running up stairs and holding space, the player activates the "lastOnGround" part without otherwise being able to step
// 0.03 movement must compensate for stepping elsewhere. Too much of a hack to include in this met5hod.
@@ -123,7 +131,7 @@ public class Collisions {
if (stepUpHeight > 0.0F && movingIntoGround && (collisionResult.getX() != desiredX || collisionResult.getZ() != desiredZ)) {
player.uncertaintyHandler.isStepMovement = true;
// 1.21 significantly refactored this
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21)) {
if (player.getClientVersion().isNewerThanOrEquals(V_1_21)) {
SimpleCollisionBox box2 = movingIntoGroundReal ? player.boundingBox.copy().offset(0.0, collisionResult.getY(), 0.0) : player.boundingBox.copy();
SimpleCollisionBox box3 = box2.copy().expandToCoordinate(desiredX, stepUpHeight, desiredZ);
if (!movingIntoGroundReal) {
@@ -135,21 +143,21 @@ public class Collisions {
final float[] stepHeights = collectStepHeights(box2, list2, (float) stepUpHeight, (float) collisionResult.getY());
for (float stepHeight : stepHeights) {
Vector vec3d2 = collideBoundingBoxLegacy(new Vector(desiredX, stepHeight, desiredZ), box2, list2, order);
Vector3D vec3d2 = collideBoundingBoxLegacy(newVector3D(desiredX, stepHeight, desiredZ), box2, list2, order);
if (getHorizontalDistanceSqr(vec3d2) > getHorizontalDistanceSqr(collisionResult)) {
final double d = player.boundingBox.minY - box2.minY;
collisionResult = vec3d2.add(new Vector(0.0, -d, 0.0));
collisionResult = vec3d2.add(newVector3D(0.0, -d, 0.0));
break;
}
}
} else {
Vector regularStepUp = collideBoundingBoxLegacy(new Vector(desiredX, stepUpHeight, desiredZ), player.boundingBox, desiredMovementCollisionBoxes, order);
Vector3D regularStepUp = collideBoundingBoxLegacy(newVector3D(desiredX, stepUpHeight, desiredZ), player.boundingBox, desiredMovementCollisionBoxes, order);
// 1.7 clients do not have this stepping bug fix
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8)) {
Vector stepUpBugFix = collideBoundingBoxLegacy(new Vector(0, stepUpHeight, 0), player.boundingBox.copy().expandToCoordinate(desiredX, 0, desiredZ), desiredMovementCollisionBoxes, order);
if (player.getClientVersion().isNewerThanOrEquals(V_1_8)) {
Vector3D stepUpBugFix = collideBoundingBoxLegacy(newVector3D(0, stepUpHeight, 0), player.boundingBox.copy().expandToCoordinate(desiredX, 0, desiredZ), desiredMovementCollisionBoxes, order);
if (stepUpBugFix.getY() < stepUpHeight) {
Vector stepUpBugFixResult = collideBoundingBoxLegacy(new Vector(desiredX, 0, desiredZ), player.boundingBox.copy().offset(0, stepUpBugFix.getY(), 0), desiredMovementCollisionBoxes, order).add(stepUpBugFix);
Vector3D stepUpBugFixResult = collideBoundingBoxLegacy(newVector3D(desiredX, 0, desiredZ), player.boundingBox.copy().offset(0, stepUpBugFix.getY(), 0), desiredMovementCollisionBoxes, order).add(stepUpBugFix);
if (getHorizontalDistanceSqr(stepUpBugFixResult) > getHorizontalDistanceSqr(regularStepUp)) {
regularStepUp = stepUpBugFixResult;
}
@@ -157,7 +165,7 @@ public class Collisions {
}
if (getHorizontalDistanceSqr(regularStepUp) > getHorizontalDistanceSqr(collisionResult)) {
collisionResult = regularStepUp.add(collideBoundingBoxLegacy(new Vector(0, -regularStepUp.getY() + (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14) ? desiredY : 0), 0), player.boundingBox.copy().offset(regularStepUp.getX(), regularStepUp.getY(), regularStepUp.getZ()), desiredMovementCollisionBoxes, order));
collisionResult = regularStepUp.add(collideBoundingBoxLegacy(newVector3D(0, -regularStepUp.getY() + (player.getClientVersion().isNewerThanOrEquals(V_1_14) ? desiredY : 0), 0), player.boundingBox.copy().offset(regularStepUp.getX(), regularStepUp.getY(), regularStepUp.getZ()), desiredMovementCollisionBoxes, order));
}
}
}
@@ -342,7 +350,7 @@ public class Collisions {
return false;
}
public static Vector collideBoundingBoxLegacy(Vector toCollide, SimpleCollisionBox
public static Vector3D collideBoundingBoxLegacy(Vector3D toCollide, SimpleCollisionBox
box, List<SimpleCollisionBox> desiredMovementCollisionBoxes, List<Axis> order) {
double x = toCollide.getX();
double y = toCollide.getY();
@@ -351,17 +359,17 @@ public class Collisions {
SimpleCollisionBox setBB = box.copy();
for (Axis axis : order) {
if (axis == Axis.X) {
if (axis == X) {
for (SimpleCollisionBox bb : desiredMovementCollisionBoxes) {
x = bb.collideX(setBB, x);
}
setBB.offset(x, 0.0D, 0.0D);
} else if (axis == Axis.Y) {
} else if (axis == Y) {
for (SimpleCollisionBox bb : desiredMovementCollisionBoxes) {
y = bb.collideY(setBB, y);
}
setBB.offset(0.0D, y, 0.0D);
} else if (axis == Axis.Z) {
} else if (axis == Z) {
for (SimpleCollisionBox bb : desiredMovementCollisionBoxes) {
z = bb.collideZ(setBB, z);
}
@@ -369,23 +377,23 @@ public class Collisions {
}
}
return new Vector(x, y, z);
return newVector3D(x, y, z);
}
public static boolean isEmpty(GrimPlayer player, SimpleCollisionBox playerBB) {
return !getCollisionBoxes(player, playerBB, null, true);
}
private static double getHorizontalDistanceSqr(Vector vector) {
private static double getHorizontalDistanceSqr(Vector3D vector) {
return vector.getX() * vector.getX() + vector.getZ() * vector.getZ();
}
public static Vector maybeBackOffFromEdge(Vector vec3, GrimPlayer player, boolean overrideVersion) {
public static Vector3D maybeBackOffFromEdge(Vector3D vec3, GrimPlayer player, boolean overrideVersion) {
if (!player.isFlying && player.isSneaking && isAboveGround(player)) {
double x = vec3.getX();
double z = vec3.getZ();
double maxStepDown = overrideVersion || player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_11) ? -player.getMaxUpStep() : -1 + COLLISION_EPSILON;
double maxStepDown = overrideVersion || player.getClientVersion().isNewerThanOrEquals(V_1_11) ? -player.getMaxUpStep() : -1 + COLLISION_EPSILON;
while (x != 0.0 && isEmpty(player, player.boundingBox.copy().offset(x, maxStepDown, 0.0))) {
if (x < 0.05D && x >= -0.05D) {
@@ -422,7 +430,7 @@ public class Collisions {
z += 0.05D;
}
}
vec3 = new Vector(x, vec3.getY(), z);
vec3 = newVector3D(x, vec3.getY(), z);
}
return vec3;
@@ -453,20 +461,20 @@ public class Collisions {
if (blockType == StateTypes.COBWEB) {
if (player.compensatedEntities.hasPotionEffect(PotionTypes.WEAVING)) {
player.stuckSpeedMultiplier = new Vector(0.5, 0.25, 0.5);
player.stuckSpeedMultiplier = newVector3D(0.5, 0.25, 0.5);
} else {
player.stuckSpeedMultiplier = new Vector(0.25, 0.05000000074505806, 0.25);
player.stuckSpeedMultiplier = newVector3D(0.25, 0.05000000074505806, 0.25);
}
}
if (blockType == StateTypes.SWEET_BERRY_BUSH
&& player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)) {
player.stuckSpeedMultiplier = new Vector(0.800000011920929, 0.75, 0.800000011920929);
player.stuckSpeedMultiplier = newVector3D(0.800000011920929, 0.75, 0.800000011920929);
}
if (blockType == StateTypes.POWDER_SNOW && i == Math.floor(player.x) && j == Math.floor(player.y) && k == Math.floor(player.z)
&& player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_17)) {
player.stuckSpeedMultiplier = new Vector(0.8999999761581421, 1.5, 0.8999999761581421);
player.stuckSpeedMultiplier = newVector3D(0.8999999761581421, 1.5, 0.8999999761581421);
}
if (blockType == StateTypes.SOUL_SAND && player.getClientVersion().isOlderThan(ClientVersion.V_1_15)) {
@@ -533,7 +541,7 @@ public class Collisions {
}
}
private static boolean isSlidingDown(Vector vector, GrimPlayer player, int locationX, int locationY,
private static boolean isSlidingDown(Vector3D vector, GrimPlayer player, int locationX, int locationY,
int locationZ) {
if (player.onGround) {
return false;
@@ -1,15 +1,20 @@
package ac.grim.grimac.utils.nmsutil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_14;
import static java.lang.Math.abs;
public class FluidFallingAdjustedMovement {
public static Vector getFluidFallingAdjustedMovement(GrimPlayer player, double d, boolean bl, Vector vec3) {
public static Vector3D getFluidFallingAdjustedMovement(GrimPlayer player, double d, boolean bl, Vector3D vec3) {
if (player.hasGravity && !player.isSprinting) {
boolean falling = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14) ? bl : vec3.getY() < 0;
double d2 = falling && Math.abs(vec3.getY() - 0.005) >= 0.003 && Math.abs(vec3.getY() - d / 16.0) < 0.003 ? -0.003 : vec3.getY() - d / 16.0;
return new Vector(vec3.getX(), d2, vec3.getZ());
boolean falling = player.getClientVersion().isNewerThanOrEquals(V_1_14) ? bl : vec3.getY() < 0;
double d2 = falling && abs(vec3.getY() - 0.005) >= 0.003 && abs(vec3.getY() - d / 16.0) < 0.003 ? -0.003 : vec3.getY() - d / 16.0;
return newVector3D(vec3.getX(), d2, vec3.getZ());
}
return vec3;
}
@@ -3,29 +3,37 @@ package ac.grim.grimac.utils.nmsutil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.CollisionData;
import ac.grim.grimac.utils.collisions.blocks.DoorHandler;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
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.defaulttags.BlockTags;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.nmsutil.Materials.isSolidBlockingBlacklist;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.world.BlockFace.*;
import static com.github.retrooper.packetevents.protocol.world.states.type.StateTypes.LAVA;
import static com.github.retrooper.packetevents.protocol.world.states.type.StateTypes.WATER;
import static java.lang.Math.min;
public class FluidTypeFlowing {
public static Vector getFlow(GrimPlayer player, int originalX, int originalY, int originalZ) {
float fluidLevel = (float) Math.min(player.compensatedWorld.getFluidLevelAt(originalX, originalY, originalZ), 8 / 9D);
public static Vector3D getFlow(GrimPlayer player, int originalX, int originalY, int originalZ) {
float fluidLevel = (float) min(player.compensatedWorld.getFluidLevelAt(originalX, originalY, originalZ), 8 / 9D);
ClientVersion version = player.getClientVersion();
if (fluidLevel == 0) return new Vector();
if (fluidLevel == 0) return newVector3D();
double d0 = 0.0D;
double d1 = 0.0D;
for (BlockFace enumdirection : new BlockFace[]{BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST}) {
for (BlockFace enumdirection : new BlockFace[]{NORTH, EAST, SOUTH, WEST}) {
int modifiedX = originalX + enumdirection.getModX();
int modifiedZ = originalZ + enumdirection.getModZ();
if (affectsFlow(player, originalX, originalY, originalZ, modifiedX, originalY, modifiedZ)) {
float f = (float) Math.min(player.compensatedWorld.getFluidLevelAt(modifiedX, originalY, modifiedZ), 8 / 9D);
float f = (float) min(player.compensatedWorld.getFluidLevelAt(modifiedX, originalY, modifiedZ), 8 / 9D);
float f1 = 0.0F;
if (f == 0.0F) {
StateType mat = player.compensatedWorld.getStateTypeAt(modifiedX, originalY, modifiedZ);
@@ -33,9 +41,9 @@ public class FluidTypeFlowing {
// Grim's definition of solid is whether the block has a hitbox
// Minecraft is... it's whatever Mojang was feeling like, but it's very consistent
// Use method call to support 1.13-1.15 clients and banner oddity
if (Materials.isSolidBlockingBlacklist(mat, version)) {
if (isSolidBlockingBlacklist(mat, version)) {
if (affectsFlow(player, originalX, originalY, originalZ, modifiedX, originalY - 1, modifiedZ)) {
f = (float) Math.min(player.compensatedWorld.getFluidLevelAt(modifiedX, originalY - 1, modifiedZ), 8 / 9D);
f = (float) min(player.compensatedWorld.getFluidLevelAt(modifiedX, originalY - 1, modifiedZ), 8 / 9D);
if (f > 0.0F) {
f1 = fluidLevel - (f - 0.8888889F);
}
@@ -53,15 +61,15 @@ public class FluidTypeFlowing {
}
}
Vector vec3d = new Vector(d0, 0.0D, d1);
Vector3D vec3d = newVector3D(d0, 0.0D, d1);
// Fluid level 1-7 is for regular fluid heights
// Fluid level 8-15 is for falling fluids
WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(originalX, originalY, originalZ);
if ((state.getType() == StateTypes.WATER || state.getType() == StateTypes.LAVA) && state.getLevel() >= 8) {
for (BlockFace enumdirection : new BlockFace[]{BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST}) {
if ((state.getType() == WATER || state.getType() == LAVA) && state.getLevel() >= 8) {
for (BlockFace enumdirection : new BlockFace[]{NORTH, EAST, SOUTH, WEST}) {
if (isSolidFace(player, originalX, originalY, originalZ, enumdirection) || isSolidFace(player, originalX, originalY + 1, originalZ, enumdirection)) {
vec3d = normalizeVectorWithoutNaN(vec3d).add(new Vector(0.0D, -6.0D, 0.0D));
vec3d = normalizeVectorWithoutNaN(vec3d).add(newVector3D(0.0D, -6.0D, 0.0D));
break;
}
}
@@ -150,9 +158,9 @@ public class FluidTypeFlowing {
}
}
private static Vector normalizeVectorWithoutNaN(Vector vector) {
private static Vector3D normalizeVectorWithoutNaN(Vector3D vector) {
double var0 = vector.length();
return var0 < 1.0E-4 ? new Vector() : vector.multiply(1 / var0);
return var0 < 1.0E-4 ? newVector3D() : vector.multiply(1 / var0);
}
public static boolean isEmpty(GrimPlayer player, int x, int y, int z) {
@@ -5,12 +5,14 @@ import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import java.util.OptionalInt;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
public class JumpPower {
public static void jumpFromGround(GrimPlayer player, Vector vector) {
public static void jumpFromGround(GrimPlayer player, Vector3D vector) {
float jumpPower = getJumpPower(player);
final OptionalInt jumpBoost = player.compensatedEntities.getPotionLevelForPlayer(PotionTypes.JUMP_BOOST);
@@ -24,7 +26,7 @@ public class JumpPower {
if (player.isSprinting) {
float radRotation = player.xRot * ((float) Math.PI / 180F);
vector.add(new Vector(-player.trigHandler.sin(radRotation) * 0.2f, 0.0, player.trigHandler.cos(radRotation) * 0.2f));
vector.add(newVector3D(-player.trigHandler.sin(radRotation) * 0.2f, 0.0, player.trigHandler.cos(radRotation) * 0.2f));
}
}
@@ -2,30 +2,34 @@ package ac.grim.grimac.utils.nmsutil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.Pair;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static java.lang.Math.toRadians;
// Copied directly from Hawk
public class Ray implements Cloneable {
private Vector origin;
private Vector direction;
private Vector3D origin;
private Vector3D direction;
public Ray(Vector origin, Vector direction) {
public Ray(Vector3D origin, Vector3D direction) {
this.origin = origin;
this.direction = direction;
}
public Ray(GrimPlayer player, double x, double y, double z, float xRot, float yRot) {
this.origin = new Vector(x, y, z);
this.origin = newVector3D(x, y, z);
this.direction = calculateDirection(player, xRot, yRot);
}
// Account for FastMath by using player's trig handler
// Copied from hawk which probably copied it from NMS
public static Vector calculateDirection(GrimPlayer player, float xRot, float yRot) {
Vector vector = new Vector();
float rotX = (float) Math.toRadians(xRot);
float rotY = (float) Math.toRadians(yRot);
public static Vector3D calculateDirection(GrimPlayer player, float xRot, float yRot) {
Vector3D vector = newVector3D();
float rotX = (float) toRadians(xRot);
float rotY = (float) toRadians(yRot);
vector.setY(-player.trigHandler.sin(rotY));
double xz = player.trigHandler.cos(rotY);
vector.setX(-xz * player.trigHandler.sin(rotX));
@@ -50,28 +54,28 @@ public class Ray implements Cloneable {
return "origin: " + origin + " direction: " + direction;
}
public Vector getPointAtDistance(double distance) {
Vector dir = new Vector(direction.getX(), direction.getY(), direction.getZ());
Vector orig = new Vector(origin.getX(), origin.getY(), origin.getZ());
public Vector3D getPointAtDistance(double distance) {
Vector3D dir = newVector3D(direction.getX(), direction.getY(), direction.getZ());
Vector3D orig = newVector3D(origin.getX(), origin.getY(), origin.getZ());
return orig.add(dir.multiply(distance));
}
//https://en.wikipedia.org/wiki/Skew_lines#Nearest_Points
public Pair<Vector, Vector> closestPointsBetweenLines(Ray other) {
Vector n1 = direction.clone().crossProduct(other.direction.clone().crossProduct(direction));
Vector n2 = other.direction.clone().crossProduct(direction.clone().crossProduct(other.direction));
public Pair<Vector3D, Vector3D> closestPointsBetweenLines(Ray other) {
Vector3D n1 = direction.clone().crossProduct(other.direction.clone().crossProduct(direction));
Vector3D n2 = other.direction.clone().crossProduct(direction.clone().crossProduct(other.direction));
Vector c1 = origin.clone().add(direction.clone().multiply(other.origin.clone().subtract(origin).dot(n2) / direction.dot(n2)));
Vector c2 = other.origin.clone().add(other.direction.clone().multiply(origin.clone().subtract(other.origin).dot(n1) / other.direction.dot(n1)));
Vector3D c1 = origin.clone().add(direction.clone().multiply(other.origin.clone().subtract(origin).dot(n2) / direction.dot(n2)));
Vector3D c2 = other.origin.clone().add(other.direction.clone().multiply(origin.clone().subtract(other.origin).dot(n1) / other.direction.dot(n1)));
return new Pair<>(c1, c2);
}
public Vector getOrigin() {
public Vector3D getOrigin() {
return origin;
}
public Vector calculateDirection() {
public Vector3D calculateDirection() {
return direction;
}
}
@@ -5,19 +5,24 @@ import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.Pair;
import ac.grim.grimac.utils.math.VectorUtils;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.protocol.player.ClientVersion.V_1_12_2;
import static java.lang.Math.PI;
public class ReachUtils {
// Copied from 1.8... I couldn't figure out 1.14+. "Enterprise" java code is unreadable!
public static Pair<Vector, BlockFace> calculateIntercept(SimpleCollisionBox self, Vector origin, Vector end) {
Vector minX = getIntermediateWithXValue(origin, end, self.minX);
Vector maxX = getIntermediateWithXValue(origin, end, self.maxX);
Vector minY = getIntermediateWithYValue(origin, end, self.minY);
Vector maxY = getIntermediateWithYValue(origin, end, self.maxY);
Vector minZ = getIntermediateWithZValue(origin, end, self.minZ);
Vector maxZ = getIntermediateWithZValue(origin, end, self.maxZ);
public static Pair<Vector3D, BlockFace> calculateIntercept(SimpleCollisionBox self, Vector3D origin, Vector3D end) {
Vector3D minX = getIntermediateWithXValue(origin, end, self.minX);
Vector3D maxX = getIntermediateWithXValue(origin, end, self.maxX);
Vector3D minY = getIntermediateWithYValue(origin, end, self.minY);
Vector3D maxY = getIntermediateWithYValue(origin, end, self.maxY);
Vector3D minZ = getIntermediateWithZValue(origin, end, self.minZ);
Vector3D maxZ = getIntermediateWithZValue(origin, end, self.maxZ);
BlockFace bestFace = null;
@@ -45,7 +50,7 @@ public class ReachUtils {
maxZ = null;
}
Vector best = null;
Vector3D best = null;
if (minX != null) {
best = minX;
@@ -84,7 +89,7 @@ public class ReachUtils {
* Returns a new vector with x value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*/
public static Vector getIntermediateWithXValue(Vector self, Vector other, double x) {
public static Vector3D getIntermediateWithXValue(Vector3D self, Vector3D other, double x) {
double d0 = other.getX() - self.getX();
double d1 = other.getY() - self.getY();
double d2 = other.getZ() - self.getZ();
@@ -93,7 +98,7 @@ public class ReachUtils {
return null;
} else {
double d3 = (x - self.getX()) / d0;
return d3 >= 0.0D && d3 <= 1.0D ? new Vector(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
return d3 >= 0.0D && d3 <= 1.0D ? newVector3D(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
}
}
@@ -101,7 +106,7 @@ public class ReachUtils {
* Returns a new vector with y value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*/
public static Vector getIntermediateWithYValue(Vector self, Vector other, double y) {
public static Vector3D getIntermediateWithYValue(Vector3D self, Vector3D other, double y) {
double d0 = other.getX() - self.getX();
double d1 = other.getY() - self.getY();
double d2 = other.getZ() - self.getZ();
@@ -110,7 +115,7 @@ public class ReachUtils {
return null;
} else {
double d3 = (y - self.getY()) / d1;
return d3 >= 0.0D && d3 <= 1.0D ? new Vector(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
return d3 >= 0.0D && d3 <= 1.0D ? newVector3D(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
}
}
@@ -118,7 +123,7 @@ public class ReachUtils {
* Returns a new vector with z value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*/
public static Vector getIntermediateWithZValue(Vector self, Vector other, double z) {
public static Vector3D getIntermediateWithZValue(Vector3D self, Vector3D other, double z) {
double d0 = other.getX() - self.getX();
double d1 = other.getY() - self.getY();
double d2 = other.getZ() - self.getZ();
@@ -127,51 +132,51 @@ public class ReachUtils {
return null;
} else {
double d3 = (z - self.getZ()) / d2;
return d3 >= 0.0D && d3 <= 1.0D ? new Vector(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
return d3 >= 0.0D && d3 <= 1.0D ? newVector3D(self.getX() + d0 * d3, self.getY() + d1 * d3, self.getZ() + d2 * d3) : null;
}
}
/**
* Checks if the specified vector is within the YZ dimensions of the bounding box. Args: Vec3D
*/
private static boolean isVecInYZ(SimpleCollisionBox self, Vector vec) {
private static boolean isVecInYZ(SimpleCollisionBox self, Vector3D vec) {
return vec != null && vec.getY() >= self.minY && vec.getY() <= self.maxY && vec.getZ() >= self.minZ && vec.getZ() <= self.maxZ;
}
/**
* Checks if the specified vector is within the XZ dimensions of the bounding box. Args: Vec3D
*/
private static boolean isVecInXZ(SimpleCollisionBox self, Vector vec) {
private static boolean isVecInXZ(SimpleCollisionBox self, Vector3D vec) {
return vec != null && vec.getX() >= self.minX && vec.getX() <= self.maxX && vec.getZ() >= self.minZ && vec.getZ() <= self.maxZ;
}
/**
* Checks if the specified vector is within the XY dimensions of the bounding box. Args: Vec3D
*/
private static boolean isVecInXY(SimpleCollisionBox self, Vector vec) {
private static boolean isVecInXY(SimpleCollisionBox self, Vector3D vec) {
return vec != null && vec.getX() >= self.minX && vec.getX() <= self.maxX && vec.getY() >= self.minY && vec.getY() <= self.maxY;
}
// Look vector accounting for optifine FastMath, and client version differences
public static Vector getLook(GrimPlayer player, float yaw, float pitch) {
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_12_2)) {
float f = player.trigHandler.cos(-yaw * 0.017453292F - (float)Math.PI);
float f1 = player.trigHandler.sin(-yaw * 0.017453292F - (float)Math.PI);
public static Vector3D getLook(GrimPlayer player, float yaw, float pitch) {
if (player.getClientVersion().isOlderThanOrEquals(V_1_12_2)) {
float f = player.trigHandler.cos(-yaw * 0.017453292F - (float) PI);
float f1 = player.trigHandler.sin(-yaw * 0.017453292F - (float) PI);
float f2 = -player.trigHandler.cos(-pitch * 0.017453292F);
float f3 = player.trigHandler.sin(-pitch * 0.017453292F);
return new Vector(f1 * f2, f3, f * f2);
return newVector3D(f1 * f2, f3, f * f2);
} else {
float f = pitch * ((float) Math.PI / 180F);
float f1 = -yaw * ((float) Math.PI / 180F);
float f = pitch * ((float) PI / 180F);
float f1 = -yaw * ((float) PI / 180F);
float f2 = player.trigHandler.cos(f1);
float f3 = player.trigHandler.sin(f1);
float f4 = player.trigHandler.cos(f);
float f5 = player.trigHandler.sin(f);
return new Vector(f3 * f4, -f5, (double) (f2 * f4));
return newVector3D(f3 * f4, -f5, (double) (f2 * f4));
}
}
public static boolean isVecInside(SimpleCollisionBox self, Vector vec) {
public static boolean isVecInside(SimpleCollisionBox self, Vector3D vec) {
return vec.getX() > self.minX && vec.getX() < self.maxX && (vec.getY() > self.minY && vec.getY() < self.maxY && vec.getZ() > self.minZ && vec.getZ() < self.maxZ);
}
@@ -184,8 +189,8 @@ public class ReachUtils {
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (double eyes : possibleEyeHeights) {
if (giveMovementThresholdLenience) targetBox.expand(player.getMovementThreshold());
Vector from = new Vector(player.x, player.y + eyes, player.z);
Vector closestPoint = VectorUtils.cutBoxToVector(from, targetBox);
Vector3D from = newVector3D(player.x, player.y + eyes, player.z);
Vector3D closestPoint = VectorUtils.cutBoxToVector(from, targetBox);
lowest = Math.min(lowest, closestPoint.distance(from));
}
@@ -1,32 +1,40 @@
package ac.grim.grimac.utils.nmsutil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.vector.Vector3D;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentTypes;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import org.bukkit.util.Vector;
import ac.grim.grimac.utils.vector.Vector3D;
import static ac.grim.grimac.utils.vector.VectorFactory.newVector3D;
import static com.github.retrooper.packetevents.PacketEvents.getAPI;
import static com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentTypes.RIPTIDE;
import static com.github.retrooper.packetevents.protocol.item.type.ItemTypes.TRIDENT;
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
public class Riptide {
public static Vector getRiptideVelocity(GrimPlayer player) {
public static Vector3D getRiptideVelocity(GrimPlayer player) {
ItemStack main = player.getInventory().getHeldItem();
ItemStack off = player.getInventory().getOffHand();
int j;
if (main.getType() == ItemTypes.TRIDENT) {
j = main.getEnchantmentLevel(EnchantmentTypes.RIPTIDE, PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
} else if (off.getType() == ItemTypes.TRIDENT) {
j = off.getEnchantmentLevel(EnchantmentTypes.RIPTIDE, PacketEvents.getAPI().getServerManager().getVersion().toClientVersion());
if (main.getType() == TRIDENT) {
j = main.getEnchantmentLevel(RIPTIDE, getAPI().getServerManager().getVersion().toClientVersion());
} else if (off.getType() == TRIDENT) {
j = off.getEnchantmentLevel(RIPTIDE, getAPI().getServerManager().getVersion().toClientVersion());
} else {
return new Vector(); // Can't riptide
return newVector3D(); // Can't riptide
}
float f7 = player.xRot;
float f = player.yRot;
float f1 = -player.trigHandler.sin(f7 * ((float) Math.PI / 180F)) * player.trigHandler.cos(f * ((float) Math.PI / 180F));
float f2 = -player.trigHandler.sin(f * ((float) Math.PI / 180F));
float f3 = player.trigHandler.cos(f7 * ((float) Math.PI / 180F)) * player.trigHandler.cos(f * ((float) Math.PI / 180F));
float f4 = (float) Math.sqrt(f1 * f1 + f2 * f2 + f3 * f3);
float f1 = -player.trigHandler.sin(f7 * ((float) PI / 180F)) * player.trigHandler.cos(f * ((float) PI / 180F));
float f2 = -player.trigHandler.sin(f * ((float) PI / 180F));
float f3 = player.trigHandler.cos(f7 * ((float) PI / 180F)) * player.trigHandler.cos(f * ((float) PI / 180F));
float f4 = (float) sqrt(f1 * f1 + f2 * f2 + f3 * f3);
float f5 = 3.0F * ((1.0F + j) / 4.0F);
f1 = f1 * (f5 / f4);
f2 = f2 * (f5 / f4);
@@ -34,8 +42,8 @@ public class Riptide {
// If the player collided vertically with the 1.199999F pushing movement, then the Y additional movement was added
// (We switched the order around as our prediction engine isn't designed for the proper implementation)
if (player.verticalCollision) return new Vector(f1, 0, f3);
if (player.verticalCollision) return newVector3D(f1, 0, f3);
return new Vector(f1, f2, f3);
return newVector3D(f1, f2, f3);
}
}
@@ -0,0 +1,18 @@
package ac.grim.grimac.utils.vector;
public class BasicVectorOps implements VectorOperations {
@Override
public Vector3D newVector(double x, double y, double z) {
return new ScalarVector3D(x, y, z);
}
@Override
public double[] add(double[] a, double[] b) {
double[] result = new double[a.length];
for (int i = 0; i < a.length; i++) {
result[i] = a[i] + b[i];
}
return result;
}
}
@@ -0,0 +1,135 @@
package ac.grim.grimac.utils.vector;
import org.jetbrains.annotations.NotNull;
public class ScalarVector3D implements Vector3D {
double x, y ,z;
public ScalarVector3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public double getX() {
return this.x;
}
@Override
public double getY() {
return this.y;
}
@Override
public double getZ() {
return this.z;
}
@Override
public Vector3D setX(double x) {
this.x = x;
return this;
}
@NotNull
public Vector3D setY(double y) {
this.y =y;
return this;
}
@Override
public Vector3D setZ(double z) {
this.z = z;
return this;
}
@Override
public double length() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
@Override
public double lengthSquared() {
return this.x * this.x + this.y * this.y + this.z * this.z;
}
@Override
public @NotNull Vector3D multiply(double m) {
this.x *= m;
this.y *= m;
this.z *= m;
return this;
}
@Override
public @NotNull Vector3D normalize() {
double length = this.length();
this.x /= length;
this.y /= length;
this.z /= length;
return this;
}
@Override
public @NotNull Vector3D crossProduct(@NotNull Vector3D o) {
double newX = this.y * o.getZ() - o.getY() * this.z;
double newY = this.z * o.getX() - o.getZ() * this.x;
double newZ = this.x * o.getY() - o.getX() * this.y;
this.x = newX;
this.y = newY;
this.z = newZ;
return this;
}
@NotNull
public Vector3D add(@NotNull Vector3D vec) {
this.x += vec.getX();
this.y += vec.getY();
this.z += vec.getZ();
return this;
}
@NotNull
public Vector3D subtract(@NotNull Vector3D vec) {
this.x -= vec.getX();
this.y -= vec.getY();
this.z -= vec.getZ();
return this;
}
@NotNull
public Vector3D multiply(@NotNull Vector3D vec) {
this.x *= vec.getX();
this.y *= vec.getY();
this.z *= vec.getZ();
return this;
}
@Override
public double distance(@NotNull Vector3D o) {
double dSquared = this.distanceSquared(o);
return dSquared * dSquared;
}
@Override
public double distanceSquared(@NotNull Vector3D o) {
return (this.x - o.getX()) + (this.y - o.getY()) + (this.z - o.getZ());
}
@Override
public double dot(@NotNull Vector3D other) {
return this.x * other.getX() + this.y * other.getY() + this.z * other.getZ();
}
@NotNull
public Vector3D clone() {
try {
return (Vector3D) super.clone();
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
}
@@ -0,0 +1,28 @@
package ac.grim.grimac.utils.vector;
import org.jetbrains.annotations.NotNull;
public interface Vector3D {
double getX();
double getY();
double getZ();
Vector3D setX(double x);
Vector3D setY(double y);
Vector3D setZ(double z);
double length();
double lengthSquared();
@NotNull Vector3D multiply(double m);
@NotNull Vector3D normalize();
@NotNull Vector3D crossProduct(@NotNull Vector3D o);
@NotNull Vector3D add(@NotNull Vector3D o);
@NotNull Vector3D subtract(@NotNull Vector3D o);
@NotNull Vector3D multiply(@NotNull Vector3D o);
double distance(@NotNull Vector3D o);
double distanceSquared(@NotNull Vector3D o);
double dot(@NotNull Vector3D o);
@NotNull Vector3D clone();
}
@@ -0,0 +1,80 @@
package ac.grim.grimac.utils.vector;
import ac.grim.grimac.utils.anticheat.LogUtil;
import java.lang.reflect.InvocationTargetException;
// Factory that loads once at startup
public final class VectorFactory {
public static final VectorOperations INSTANCE;
static {
// This happens once during class initialization
VectorOperations ops;
try {
if (isSimdApiAvailable()) {
ops = (VectorOperations) Class
.forName("ac.grim.grimac.utils.vector.VectorOperationsJava18")
.getDeclaredConstructor()
.newInstance();
} else {
LogUtil.info("java.lang.vector.VectorSpecies not found. SIMD is unavailable falling back to Scalar Operations.");
ops = new BasicVectorOps();
}
} catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | InstantiationException |
IllegalAccessException e) {
LogUtil.error("SIMD is unavailable falling back to Scalar Operations: " + e.getMessage());
ops = new BasicVectorOps();
}
INSTANCE = ops;
}
public static Vector3D newVector3D() {
return INSTANCE.newVector(0 ,0, 0);
}
public static Vector3D newVector3D(int x, int y, int z) {
return INSTANCE.newVector(x, y, z);
}
public static Vector3D newVector3D(float x, float y, float z) {
return INSTANCE.newVector(x, y, z);
}
public static Vector3D newVector3D(double x, double y, double z) {
return INSTANCE.newVector(x, y, z);
}
private static boolean isSimdApiAvailable() {
int javaVersion = getJavaVersion();
if (javaVersion >= 18) {
try {
// Attempt to load a class that uses the Vector API
Class.forName("java.lang.vector.VectorSpecies");
return true;
} catch (ClassNotFoundException e) {
// Vector API not available
return false;
}
}
return false;
}
private static int getJavaVersion() {
String versionString = System.getProperty("java.version");
if (versionString.startsWith("1.")) {
versionString = versionString.substring(2, 3);
} else {
int dotIndex = versionString.indexOf(".");
if (dotIndex != -1) {
versionString = versionString.substring(0, dotIndex);
}
}
try {
return Integer.parseInt(versionString);
} catch (NumberFormatException e) {
// Fallback to assuming Java 8 if parsing fails
return 8;
}
}
}
@@ -0,0 +1,6 @@
package ac.grim.grimac.utils.vector;
public interface VectorOperations {
Vector3D newVector(double x, double y, double z);
}