1 parent
73e862a782
commit
b447154d52
9 files changed
+86
-151
No files matched your search
@@ -8,10 +8,10 @@ import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import io.github.retrooper.packetevents.util.folia.RegionScheduler;
|
||||
import me.caseload.knockbacksync.Base;
|
||||
import me.caseload.knockbacksync.BukkitBase;
|
||||
import me.caseload.knockbacksync.async.AsyncOperation;
|
||||
import me.caseload.knockbacksync.async.FoliaOperation;
|
||||
import me.caseload.knockbacksync.listener.bukkit.BukkitPlayerKnockbackListener;
|
||||
import me.caseload.knockbacksync.world.raytrace.FluidHandling;
|
||||
import me.caseload.knockbacksync.world.raytrace.RayTraceResult;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
@@ -32,7 +32,7 @@ public class FoliaWorld extends SpigotWorld {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncOperation<WrappedBlockState> getBlockStateAt(int x, int y, int z) {
|
||||
public WrappedBlockState getBlockStateAt(int x, int y, int z) {
|
||||
Location location = new Location(super.world, x, y, z);
|
||||
CompletableFuture<WrappedBlockState> future = new CompletableFuture<>();
|
||||
|
||||
@@ -41,37 +41,49 @@ public class FoliaWorld extends SpigotWorld {
|
||||
future.complete(SpigotConversionUtil.fromBukkitBlockData(block.getBlockData()));
|
||||
});
|
||||
|
||||
return new FoliaOperation<>(future);
|
||||
try {
|
||||
return future.get(); // Wait for the result
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null; // Handle error appropriately
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncOperation<RayTraceResult> rayTraceBlocks(Vector3d start, Vector3d direction, double maxDistance, FluidHandling fluidHandling, boolean ignorePassableBlocks) {
|
||||
public RayTraceResult rayTraceBlocks(Vector3d start, Vector3d direction, double maxDistance, FluidHandling fluidHandling, boolean ignorePassableBlocks) {
|
||||
Location location = new Location(super.world, start.getX(), start.getY(), start.getZ());
|
||||
CompletableFuture<RayTraceResult> future = new CompletableFuture<>();
|
||||
|
||||
// Yes this code is bad; I know it's bad. We did not design this plugin around Folia, too bad!
|
||||
scheduler.execute(plugin, location, () -> {
|
||||
Vector startVec = new Vector(start.getX(), start.getY(), start.getZ());
|
||||
Vector directionVec = new Vector(direction.getX(), direction.getY(), direction.getZ());
|
||||
// Existing 1.13+ code using world.rayTraceBlocks
|
||||
Vector startVec = new Vector(start.getX(), start.getY(), start.getZ());
|
||||
Vector directionVec = new Vector(direction.getX(), direction.getY(), direction.getZ());
|
||||
|
||||
FluidCollisionMode fluidMode = (fluidHandling == FluidHandling.NONE) ? FluidCollisionMode.NEVER :
|
||||
(fluidHandling == FluidHandling.SOURCE_ONLY) ? FluidCollisionMode.SOURCE_ONLY :
|
||||
FluidCollisionMode.ALWAYS;
|
||||
FluidCollisionMode fluidMode = (fluidHandling == FluidHandling.NONE) ? FluidCollisionMode.NEVER :
|
||||
(fluidHandling == FluidHandling.SOURCE_ONLY) ? FluidCollisionMode.SOURCE_ONLY :
|
||||
FluidCollisionMode.ALWAYS;
|
||||
|
||||
org.bukkit.util.RayTraceResult result = super.world.rayTraceBlocks(startVec.toLocation(super.world), directionVec, maxDistance, fluidMode, ignorePassableBlocks);
|
||||
org.bukkit.util.RayTraceResult result = super.world.rayTraceBlocks(startVec.toLocation(super.world), directionVec, maxDistance, fluidMode, ignorePassableBlocks);
|
||||
|
||||
if (result == null) {
|
||||
future.complete(null);
|
||||
return;
|
||||
}
|
||||
if (result == null) {
|
||||
future.complete(null);
|
||||
return;
|
||||
}
|
||||
|
||||
future.complete(new RayTraceResult(
|
||||
new Vector3d(result.getHitPosition().getX(), result.getHitPosition().getY(), result.getHitPosition().getZ()),
|
||||
getBlockFaceFrom(result.getHitBlockFace()),
|
||||
new Vector3i(result.getHitBlock().getX(), result.getHitBlock().getY(), result.getHitBlock().getY()),
|
||||
result.getHitBlock() != null ? SpigotConversionUtil.fromBukkitBlockData(result.getHitBlock().getBlockData()) : null
|
||||
));
|
||||
future.complete(new RayTraceResult(
|
||||
new Vector3d(result.getHitPosition().getX(), result.getHitPosition().getY(), result.getHitPosition().getZ()),
|
||||
getBlockFaceFrom(result.getHitBlockFace()),
|
||||
new Vector3i(result.getHitBlock().getX(), result.getHitBlock().getY(), result.getHitBlock().getY()),
|
||||
result.getHitBlock() != null ? SpigotConversionUtil.fromBukkitBlockData(result.getHitBlock().getBlockData()) : null
|
||||
));
|
||||
});
|
||||
|
||||
return new FoliaOperation<>(future);
|
||||
try {
|
||||
return future.get(); // Wait for the result
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null; // Handle error appropriately
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,6 @@ import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import me.caseload.knockbacksync.async.AsyncOperation;
|
||||
import me.caseload.knockbacksync.async.SyncOperation;
|
||||
import me.caseload.knockbacksync.world.raytrace.FluidHandling;
|
||||
import me.caseload.knockbacksync.world.raytrace.RayTraceResult;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -80,18 +78,18 @@ public class SpigotWorld implements PlatformWorld {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncOperation<WrappedBlockState> getBlockStateAt(int x, int y, int z) {
|
||||
public WrappedBlockState getBlockStateAt(int x, int y, int z) {
|
||||
Block block = world.getBlockAt(x, y, z);
|
||||
return new SyncOperation<>(SpigotConversionUtil.fromBukkitBlockData(block.getBlockData()));
|
||||
return SpigotConversionUtil.fromBukkitBlockData(block.getBlockData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncOperation<WrappedBlockState> getBlockStateAt(Vector3d loc) {
|
||||
public WrappedBlockState getBlockStateAt(Vector3d loc) {
|
||||
return getBlockStateAt((int) Math.floor(loc.x), (int) Math.floor(loc.y), (int) Math.floor(loc.z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncOperation<RayTraceResult> rayTraceBlocks(Vector3d start, Vector3d direction, double maxDistance, FluidHandling fluidHandling, boolean ignorePassableBlocks) {
|
||||
public RayTraceResult rayTraceBlocks(Vector3d start, Vector3d direction, double maxDistance, FluidHandling fluidHandling, boolean ignorePassableBlocks) {
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_12_2)) {
|
||||
Vector startVec = new Vector(start.getX(), start.getY(), start.getZ());
|
||||
Vector directionVec = new Vector(direction.getX(), direction.getY(), direction.getZ());
|
||||
@@ -104,12 +102,12 @@ public class SpigotWorld implements PlatformWorld {
|
||||
|
||||
if (result == null) return null;
|
||||
|
||||
return new SyncOperation<>(new RayTraceResult(
|
||||
return new RayTraceResult(
|
||||
new Vector3d(result.getHitPosition().getX(), result.getHitPosition().getY(), result.getHitPosition().getZ()),
|
||||
getBlockFaceFrom(result.getHitBlockFace()),
|
||||
new Vector3i(result.getHitBlock().getX(), result.getHitBlock().getY(), result.getHitBlock().getZ()),
|
||||
result.getHitBlock() != null ? SpigotConversionUtil.fromBukkitBlockData(result.getHitBlock().getBlockData()) : null
|
||||
));
|
||||
);
|
||||
// Only tested on 1.12.2
|
||||
} else {
|
||||
try {
|
||||
@@ -132,14 +130,14 @@ public class SpigotWorld implements PlatformWorld {
|
||||
Object hitDirection = hitResult.getClass().getField("direction").get(hitResult);
|
||||
Object hitBlock = hitResult.getClass().getField("e").get(hitResult); // e = BlockHitResult
|
||||
|
||||
return new SyncOperation<>(new RayTraceResult(
|
||||
return new RayTraceResult(
|
||||
hitPosition,
|
||||
getHitBlockFace(hitDirection),
|
||||
new Vector3i((int) hitBlock.getClass().getField("x").get(hitBlock),
|
||||
(int) hitBlock.getClass().getField("y").get(hitBlock),
|
||||
(int) hitBlock.getClass().getField("z").get(hitBlock)),
|
||||
hitBlock != null ? WrappedBlockState.getByString(hitBlock.getClass().getField("type").get(hitBlock).toString()) : null
|
||||
));
|
||||
);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null; // Return null if there was an error during ray tracing
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package me.caseload.knockbacksync.async;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
// Platform-agnostic interface
|
||||
public interface AsyncOperation<T> {
|
||||
CompletableFuture<T> asFuture();
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package me.caseload.knockbacksync.async;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
// Async implementation for Folia
|
||||
public class FoliaOperation<T> implements AsyncOperation<T> {
|
||||
private final CompletableFuture<T> future;
|
||||
|
||||
public FoliaOperation(CompletableFuture<T> future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<T> asFuture() {
|
||||
return future;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package me.caseload.knockbacksync.async;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
// Paper/Fabric implementation
|
||||
public class SyncOperation<T> implements AsyncOperation<T> {
|
||||
private final T result;
|
||||
|
||||
public SyncOperation(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<T> asFuture() {
|
||||
return CompletableFuture.completedFuture(result);
|
||||
}
|
||||
}
|
||||
+22
-28
@@ -8,8 +8,6 @@ import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||
import me.caseload.knockbacksync.player.PlayerData;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public abstract class PlayerKnockbackListener {
|
||||
|
||||
public void onPlayerVelocity(PlatformPlayer victim, Vector3d velocity) {
|
||||
@@ -23,35 +21,31 @@ public abstract class PlayerKnockbackListener {
|
||||
if (victimPlayerData.getNotNullPing() < PlayerData.PING_OFFSET)
|
||||
return;
|
||||
|
||||
victimPlayerData.getDistanceToGround().asFuture()
|
||||
.thenCompose(distanceToGround -> {
|
||||
if (distanceToGround <= 0)
|
||||
return CompletableFuture.completedFuture(null);
|
||||
double distanceToGround = victimPlayerData.getDistanceToGround();
|
||||
if (distanceToGround <= 0)
|
||||
return; // minecraft already does the work for us
|
||||
|
||||
return victim.getWorld().getBlockStateAt(victim.getLocation()).asFuture()
|
||||
.thenAccept(blockState -> {
|
||||
if (victim.isGliding() ||
|
||||
blockState.getType() == StateTypes.WATER ||
|
||||
blockState.getType() == StateTypes.LAVA ||
|
||||
blockState.getType() == StateTypes.COBWEB ||
|
||||
blockState.getType() == StateTypes.SCAFFOLDING)
|
||||
return;
|
||||
WrappedBlockState blockState = victim.getWorld().getBlockStateAt(victim.getLocation());
|
||||
if (victim.isGliding() ||
|
||||
blockState.getType() == StateTypes.WATER ||
|
||||
blockState.getType() == StateTypes.LAVA ||
|
||||
blockState.getType() == StateTypes.COBWEB ||
|
||||
blockState.getType() == StateTypes.SCAFFOLDING)
|
||||
return;
|
||||
|
||||
Vector3d adjustedVelocity;
|
||||
if (victimPlayerData.isOnGroundClientSide(velocity.getY(), distanceToGround)) {
|
||||
Integer damageTicks = victimPlayerData.getLastDamageTicks();
|
||||
if (damageTicks != null && damageTicks > 8)
|
||||
return;
|
||||
Vector3d adjustedVelocity;
|
||||
if (victimPlayerData.isOnGroundClientSide(velocity.getY(), distanceToGround)) {
|
||||
Integer damageTicks = victimPlayerData.getLastDamageTicks();
|
||||
if (damageTicks != null && damageTicks > 8)
|
||||
return;
|
||||
|
||||
adjustedVelocity = velocity.withY(victimPlayerData.getVerticalVelocity());
|
||||
}
|
||||
else if (victimPlayerData.isOffGroundSyncEnabled())
|
||||
adjustedVelocity = velocity.withY(victimPlayerData.getCompensatedOffGroundVelocity());
|
||||
else
|
||||
return;
|
||||
adjustedVelocity = velocity.withY(victimPlayerData.getVerticalVelocity()); // Should be impossible to produce a NPE in this context
|
||||
}
|
||||
else if (victimPlayerData.isOffGroundSyncEnabled())
|
||||
adjustedVelocity = velocity.withY(victimPlayerData.getCompensatedOffGroundVelocity());
|
||||
else
|
||||
return;
|
||||
|
||||
victim.setVelocity(adjustedVelocity);
|
||||
});
|
||||
});
|
||||
victim.setVelocity(adjustedVelocity);
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,6 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerWi
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.caseload.knockbacksync.Base;
|
||||
import me.caseload.knockbacksync.async.AsyncOperation;
|
||||
import me.caseload.knockbacksync.async.FoliaOperation;
|
||||
import me.caseload.knockbacksync.async.SyncOperation;
|
||||
import me.caseload.knockbacksync.command.subcommand.ToggleOffGroundSubcommand;
|
||||
import me.caseload.knockbacksync.event.KBSyncEventHandler;
|
||||
import me.caseload.knockbacksync.event.events.ToggleOnOffEvent;
|
||||
@@ -34,7 +31,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
@Getter
|
||||
@@ -235,35 +231,23 @@ public class PlayerData {
|
||||
*
|
||||
* @return The distance to the ground in blocks
|
||||
*/
|
||||
public AsyncOperation<Double> getDistanceToGround() {
|
||||
public double getDistanceToGround() {
|
||||
double collisionDist = 5;
|
||||
|
||||
PlatformWorld world = platformPlayer.getWorld();
|
||||
Vector3d[] corners = getBBCorners();
|
||||
|
||||
// Start with the first corner
|
||||
CompletableFuture<Double> future = processCorner(world, corners, 0, 5.0);
|
||||
for (Vector3d corner : getBBCorners()) {
|
||||
RayTraceResult result = world.rayTraceBlocks(corner, new Vector3d(0, -1, 0), 5, FluidHandling.NONE, true);
|
||||
|
||||
return new FoliaOperation<>(future);
|
||||
}
|
||||
if (result == null || result.getHitBlock() == null)
|
||||
continue;
|
||||
|
||||
private CompletableFuture<Double> processCorner(PlatformWorld world, Vector3d[] corners, int index, double currentMin) {
|
||||
if (index >= corners.length) {
|
||||
return CompletableFuture.completedFuture(currentMin - 1);
|
||||
collisionDist = Math.min(collisionDist, corner.getY() - result.getHitBlockPosition().getY());
|
||||
}
|
||||
|
||||
return world.rayTraceBlocks(corners[index], new Vector3d(0, -1, 0), 5, FluidHandling.NONE, true)
|
||||
.asFuture()
|
||||
.thenCompose(result -> {
|
||||
double newMin = currentMin;
|
||||
if (result != null && result.getHitBlock() != null) {
|
||||
newMin = Math.min(currentMin, corners[index].getY() - result.getHitBlockPosition().getY());
|
||||
}
|
||||
|
||||
// Process next corner
|
||||
return processCorner(world, corners, index + 1, newMin);
|
||||
});
|
||||
return collisionDist - 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the corners of the Player's bounding box.
|
||||
*
|
||||
|
||||
@@ -2,12 +2,13 @@ package me.caseload.knockbacksync.world;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import me.caseload.knockbacksync.async.AsyncOperation;
|
||||
import me.caseload.knockbacksync.world.raytrace.FluidHandling;
|
||||
import me.caseload.knockbacksync.world.raytrace.RayTraceResult;
|
||||
|
||||
public interface PlatformWorld {
|
||||
AsyncOperation<WrappedBlockState> getBlockStateAt(int x, int y, int z);
|
||||
AsyncOperation<WrappedBlockState> getBlockStateAt(Vector3d loc);
|
||||
AsyncOperation<RayTraceResult> rayTraceBlocks(Vector3d start, Vector3d direction, double maxDistance, FluidHandling fluidHandling, boolean ignorePassableBlocks);
|
||||
WrappedBlockState getBlockStateAt(int x, int y, int z);
|
||||
|
||||
WrappedBlockState getBlockStateAt(Vector3d loc);
|
||||
|
||||
RayTraceResult rayTraceBlocks(Vector3d start, Vector3d direction, double maxDistance, FluidHandling fluidHandling, boolean ignorePassableBlocks);
|
||||
}
|
||||
@@ -4,8 +4,6 @@ import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import me.caseload.knockbacksync.async.AsyncOperation;
|
||||
import me.caseload.knockbacksync.async.SyncOperation;
|
||||
import me.caseload.knockbacksync.world.raytrace.FluidHandling;
|
||||
import me.caseload.knockbacksync.world.raytrace.RayTraceResult;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -19,8 +17,6 @@ import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class FabricWorld implements PlatformWorld {
|
||||
private final Level world;
|
||||
|
||||
@@ -29,18 +25,18 @@ public class FabricWorld implements PlatformWorld {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncOperation<WrappedBlockState> getBlockStateAt(int x, int y, int z) {
|
||||
public WrappedBlockState getBlockStateAt(int x, int y, int z) {
|
||||
BlockState blockState = this.world.getBlockState(new BlockPos(x, y, z));
|
||||
return new SyncOperation<>(WrappedBlockState.getByGlobalId(Block.BLOCK_STATE_REGISTRY.getId(blockState)));
|
||||
return WrappedBlockState.getByGlobalId(Block.BLOCK_STATE_REGISTRY.getId(blockState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncOperation<WrappedBlockState> getBlockStateAt(Vector3d loc) {
|
||||
public WrappedBlockState getBlockStateAt(Vector3d loc) {
|
||||
return getBlockStateAt((int) Math.floor(loc.x), (int) Math.floor(loc.x), (int) Math.floor(loc.x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncOperation<RayTraceResult> rayTraceBlocks(Vector3d start, Vector3d direction, double maxDistance, FluidHandling fluidHandling, boolean ignorePassableBlocks) {
|
||||
public RayTraceResult rayTraceBlocks(Vector3d start, Vector3d direction, double maxDistance, FluidHandling fluidHandling, boolean ignorePassableBlocks) {
|
||||
Vec3 startVec = new Vec3(start.getX(), start.getY(), start.getZ());
|
||||
Vec3 endVec = startVec.add(direction.getX() * maxDistance, direction.getY() * maxDistance, direction.getZ() * maxDistance);
|
||||
|
||||
@@ -54,21 +50,15 @@ public class FabricWorld implements PlatformWorld {
|
||||
CollisionContext.empty()
|
||||
));
|
||||
|
||||
if (result.getType() == HitResult.Type.MISS) {
|
||||
return new SyncOperation<>(null);
|
||||
}
|
||||
if (result.getType() == HitResult.Type.MISS) return null;
|
||||
|
||||
Vec3 hitLocation = result.getLocation();
|
||||
BlockPos blockPos = result.getBlockPos();
|
||||
|
||||
// Since we're in Fabric, we can just get the block state synchronously
|
||||
WrappedBlockState blockState = getBlockStateAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()).asFuture().join();
|
||||
|
||||
return new SyncOperation<>(new RayTraceResult(
|
||||
return new RayTraceResult(
|
||||
new Vector3d(hitLocation.x, hitLocation.y, hitLocation.z),
|
||||
BlockFace.getBlockFaceByValue(result.getDirection().ordinal()),
|
||||
new Vector3i(blockPos.getX(), blockPos.getY(), blockPos.getZ()),
|
||||
blockState
|
||||
));
|
||||
getBlockStateAt(blockPos.getX(), blockPos.getY(), blockPos.getZ())
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user