Skip to content

Commit

Permalink
Merge pull request GrimAnticheat#1709 from Cyramek/fix-main-supportin…
Browse files Browse the repository at this point in the history
…g-block

fix searching for main supporting block
  • Loading branch information
SamB440 committed Sep 11, 2024
2 parents 0293606 + 95955b8 commit c4c0634
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 11 deletions.
82 changes: 81 additions & 1 deletion src/main/java/ac/grim/grimac/utils/nmsutil/Collisions.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

public class Collisions {
Expand Down Expand Up @@ -699,7 +700,7 @@ public static boolean hasMaterial(GrimPlayer player, SimpleCollisionBox checkBox
int x = currX | chunkXGlobalPos;
int z = currZ | chunkZGlobalPos;

WrappedBlockState data = section.get(CompensatedWorld.blockVersion, x & 0xF, y & 0xF, z & 0xF);
WrappedBlockState data = section.get(CompensatedWorld.blockVersion, x & 0xF, y & 0xF, z & 0xF, false);

if (searchingFor.test(new Pair<>(data, new Vector3d(x, y, z)))) return true;
}
Expand All @@ -710,6 +711,85 @@ public static boolean hasMaterial(GrimPlayer player, SimpleCollisionBox checkBox
return false;
}

// Thanks Tuinity
public static void forEachCollisionBox(GrimPlayer player, SimpleCollisionBox checkBox, Consumer<Vector3d> searchingFor) {
int minBlockX = (int) Math.floor(checkBox.minX - COLLISION_EPSILON) - 1;
int maxBlockX = (int) Math.floor(checkBox.maxX + COLLISION_EPSILON) + 1;
int minBlockY = (int) Math.floor(checkBox.minY - COLLISION_EPSILON) - 1;
int maxBlockY = (int) Math.floor(checkBox.maxY + COLLISION_EPSILON) + 1;
int minBlockZ = (int) Math.floor(checkBox.minZ - COLLISION_EPSILON) - 1;
int maxBlockZ = (int) Math.floor(checkBox.maxZ + COLLISION_EPSILON) + 1;

final int minSection = player.compensatedWorld.getMinHeight() >> 4;
final int minBlock = minSection << 4;
final int maxBlock = player.compensatedWorld.getMaxHeight() - 1;

int minChunkX = minBlockX >> 4;
int maxChunkX = maxBlockX >> 4;

int minChunkZ = minBlockZ >> 4;
int maxChunkZ = maxBlockZ >> 4;

int minYIterate = Math.max(minBlock, minBlockY);
int maxYIterate = Math.min(maxBlock, maxBlockY);

for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
int minZ = currChunkZ == minChunkZ ? minBlockZ & 15 : 0; // coordinate in chunk
int maxZ = currChunkZ == maxChunkZ ? maxBlockZ & 15 : 15; // coordinate in chunk

for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) {
int minX = currChunkX == minChunkX ? minBlockX & 15 : 0; // coordinate in chunk
int maxX = currChunkX == maxChunkX ? maxBlockX & 15 : 15; // coordinate in chunk

int chunkXGlobalPos = currChunkX << 4;
int chunkZGlobalPos = currChunkZ << 4;

Column chunk = player.compensatedWorld.getChunk(currChunkX, currChunkZ);

if (chunk == null) continue;
BaseChunk[] sections = chunk.getChunks();

for (int y = minYIterate; y <= maxYIterate; ++y) {
BaseChunk section = sections[(y >> 4) - minSection];

if (section == null || (IS_FOURTEEN && section.isEmpty())) { // Check for empty on 1.13+ servers
// empty
// skip to next section
y = (y & ~(15)) + 15; // increment by 15: iterator loop increments by the extra one
continue;
}

for (int currZ = minZ; currZ <= maxZ; ++currZ) {
for (int currX = minX; currX <= maxX; ++currX) {
int x = currX | chunkXGlobalPos;
int z = currZ | chunkZGlobalPos;

WrappedBlockState data = section.get(CompensatedWorld.blockVersion, x & 0xF, y & 0xF, z & 0xF, false);

// Works on both legacy and modern! Faster than checking for material types, most common case
if (data.getGlobalId() == 0) continue;

// Thanks SpottedLeaf for this optimization, I took edgeCount from Tuinity
int edgeCount = ((x == minBlockX || x == maxBlockX) ? 1 : 0) +
((y == minBlockY || y == maxBlockY) ? 1 : 0) +
((z == minBlockZ || z == maxBlockZ) ? 1 : 0);

final StateType type = data.getType();
if (edgeCount != 3 && (edgeCount != 1 || Materials.isShapeExceedsCube(type))
&& (edgeCount != 2 || type == StateTypes.PISTON_HEAD)) {
final CollisionBox collisionBox = CollisionData.getData(type).getMovementCollisionBox(player, player.getClientVersion(), data, x, y, z);

if (collisionBox.isIntersected(checkBox)) {
searchingFor.accept(new Vector3d(x, y, z));
}
}
}
}
}
}
}
}

public static boolean onClimbable(GrimPlayer player, double x, double y, double z) {
WrappedBlockState blockState = player.compensatedWorld.getWrappedBlockStateAt(x, y, z);
StateType blockMaterial = blockState.getType();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
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.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.MainSupportingBlockData;
import com.github.retrooper.packetevents.util.Vector3d;
Expand Down Expand Up @@ -42,21 +40,15 @@ private Optional<Vector3i> findSupportingBlock(GrimPlayer player, SimpleCollisio
AtomicReference<Vector3i> bestBlockPos = new AtomicReference<>();
AtomicDouble blockPosDistance = new AtomicDouble(Double.MAX_VALUE);

Collisions.hasMaterial(player, searchBox, (thing) -> {
Vector3i blockPos = thing.getSecond().toVector3i();

CollisionBox collision = CollisionData.getData(thing.getFirst().getType()).getMovementCollisionBox(player, player.getClientVersion(), thing.getFirst(), blockPos.getX(), blockPos.getY(), blockPos.getZ());
if (!collision.isIntersected(searchBox)) return false;

Collisions.forEachCollisionBox(player, searchBox, (pos) -> {
Vector3i blockPos = pos.toVector3i();
Vector3d blockPosAsVector3d = new Vector3d(blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5);
double distance = playerPos.distanceSquared(blockPosAsVector3d);

if (distance < blockPosDistance.get() || distance == blockPosDistance.get() && (bestBlockPos.get() == null || firstHasPriorityOverSecond(blockPos, bestBlockPos.get()))) {
bestBlockPos.set(blockPos);
blockPosDistance.set(distance);
}

return false;
});


Expand Down

0 comments on commit c4c0634

Please sign in to comment.