Adding raycasting check

This commit is contained in:
Dawson
2022-09-16 17:52:16 -04:00
parent 927834762e
commit b24053f1ca
27 changed files with 576 additions and 298 deletions
@@ -3,6 +3,7 @@ package dev.brighten.ac.api.check;
public enum CheckType {
COMBAT,
AUTOCLICKER,
KILLAURA,
MOVEMENT,
BLOCK,
CHAT,
+13 -5
View File
@@ -11,7 +11,7 @@ import dev.brighten.ac.api.event.result.PunishResult;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.utils.*;
import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.MillisTimer;
import dev.brighten.ac.utils.timer.impl.TickTimer;
import lombok.Getter;
import lombok.Setter;
import lombok.val;
@@ -21,6 +21,7 @@ import org.bukkit.Bukkit;
import org.bukkit.Location;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class Check implements ECheck {
@@ -37,7 +38,8 @@ public class Check implements ECheck {
@Getter
@Setter
private int punishVl;
private final Timer lastAlert = new MillisTimer();
private static final Timer alertCountReset = new TickTimer();
private static final AtomicInteger alertCount = new AtomicInteger(0);
public static Set<UUID> alertsEnabled = new HashSet<>();
@@ -96,7 +98,8 @@ public class Check implements ECheck {
} else {
player.getInfo().getLastCancel().reset();
Location ground = player.getInfo().isServerGround() ? player.getMovement().getFrom().getLoc()
Location ground = player.getInfo().isServerGround() && player.getMovement().getLastTeleport().isPassed(1)
? player.getMovement().getFrom().getLoc()
.toLocation(player.getBukkitPlayer().getWorld())
: MovementUtils.findGroundLocation(player.getMovement().getFrom().getLoc()
.toLocation(player.getBukkitPlayer().getWorld()), 10);
@@ -176,7 +179,12 @@ public class Check implements ECheck {
.execute(() -> Anticheat.INSTANCE.getLogManager()
.insertLog(player, checkData, vl, System.currentTimeMillis(), info));
if(lastAlert.isPassed(200L)) {
if(alertCountReset.isPassed(20)) {
alertCount.set(0);
alertCountReset.reset();
}
if(alertCount.incrementAndGet() < 30) {
boolean dev = Anticheat.INSTANCE.getTps() < 18;
//if(vl > 0) Anticheat.INSTANCE.loggerManager.addLog(player, this, info);
@@ -206,7 +214,7 @@ public class Check implements ECheck {
.ifPresent(apl -> apl.getBukkitPlayer().spigot().sendMessage(toSend
.toArray(new BaseComponent[0])));
}
lastAlert.reset();
alertCountReset.reset();
}
if(punish && vl >= punishVl) {
punish();
@@ -0,0 +1,29 @@
package dev.brighten.ac.check.impl.combat.killaura;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInUseEntity;
import lombok.val;
@CheckData(name = "KillAura (Bot)", checkId = "kabot", type = CheckType.KILLAURA)
public class KABot extends Check {
public KABot(APlayer player) {
super(player);
}
private int buffer = 0;
WAction<WPacketPlayInUseEntity> packet = packet -> {
val optional = player.getEntityLocationHandler().getFakeMob(packet.getEntityId());
if(optional.isPresent()) {
if(++buffer > 1) {
flag("Attacked player without attacking bot!");
}
} else buffer = 0;
};
}
@@ -0,0 +1,87 @@
package dev.brighten.ac.check.impl.combat.killaura;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.ProtocolVersion;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInUseEntity;
import dev.brighten.ac.utils.KLocation;
import dev.brighten.ac.utils.MathUtils;
import dev.brighten.ac.utils.world.CollisionBox;
import dev.brighten.ac.utils.world.EntityData;
import dev.brighten.ac.utils.world.types.RayCollision;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
import org.bukkit.util.Vector;
@CheckData(name = "KillAura (Trace)", checkId = "katrace", type = CheckType.KILLAURA)
public class KATrace extends Check {
private float sneakY = 1.54f;
public KATrace(APlayer player) {
super(player);
sneakY = player.getPlayerVersion().isBelow(ProtocolVersion.V1_14) ? 1.27f : 1.54f;
}
private int buffer;
WAction<WPacketPlayInUseEntity> useEntity = packet -> {
if(player.getInfo().getTarget() == null
|| packet.getAction() != WPacketPlayInUseEntity.EnumEntityUseAction.ATTACK)
return;
if(player.getMovement().getLookingAtBoxes().size() == 0) {
debug("No boxes to look at!");
buffer = 0;
return;
}
SimpleCollisionBox targetBox = (SimpleCollisionBox) EntityData.getEntityBox(player.getInfo().getTarget().getLocation(),
player.getInfo().target);
if(targetBox == null) return;
KLocation origin = player.getMovement().getTo().getLoc().clone();
origin.y+= player.getInfo().isSneaking() ? sneakY : 1.62f;
RayCollision collision = new RayCollision(origin.toVector(), MathUtils.getDirection(origin));
Vector targetPoint = collision.collisionPoint(targetBox);
//If the ray isn't collided, we might as well not run this check. Just a simple boxes on array check
if(targetPoint == null) return;
double dist = origin.toVector().distanceSquared(targetPoint);
boolean rayCollidedOnBlock = false;
synchronized (player.getMovement().getLookingAtBoxes()) {
for (CollisionBox lookingAtBox : player.getMovement().getLookingAtBoxes()) {
if((lookingAtBox instanceof SimpleCollisionBox)) {
SimpleCollisionBox box = (SimpleCollisionBox) lookingAtBox;
if(box.xMin % 1 != 0 || box.yMin % 1 != 0 || box.zMin % 1 != 0
|| box.xMax % 1 != 0 || box.yMax % 1 != 0 || box.zMax % 1 != 0)
continue;
Vector point = collision.collisionPoint(box.copy().shrink(0.005f, 0.005f, 0.005f));
if (point != null && origin.toVector().distanceSquared(point) < dist - 0.2) {
rayCollidedOnBlock = true;
break;
}
}
}
}
if(rayCollidedOnBlock) {
if(++buffer > 2) {
flag("Attacker hit through block! [b=%s s=%s]",
buffer, player.getMovement().getLookingAtBoxes().size());
}
} else if(buffer > 0) buffer--;
debug("b=%s collides=%s", buffer, rayCollidedOnBlock);
};
}
@@ -1,15 +1,15 @@
package dev.brighten.ac.check.impl.movement.fly;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.ProtocolVersion;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
import dev.brighten.ac.utils.annotation.Async;
import dev.brighten.ac.utils.MathUtils;
import dev.brighten.ac.utils.MovementUtils;
import dev.brighten.ac.utils.annotation.Async;
import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.MillisTimer;
@@ -41,10 +41,6 @@ public class FlyA extends Check {
predicted = MovementUtils.getJumpHeight(player);
}
if(Math.abs(predicted) < 0.005 && ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9)) {
predicted = 0;
}
// There will be missed movements that we can't account for if we had to predict the player's next position
// twice, so we shouldn't flag regardless.
boolean willBeWeirdNext = didNextPrediction;
@@ -61,6 +57,13 @@ public class FlyA extends Check {
}
}
if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) {
if(Math.abs(predicted) < 0.005)
predicted = 0;
} else if(Math.abs(predicted) < 0.003) {
predicted = 0;
}
double deltaPredict = MathUtils.getDelta(player.getMovement().getDeltaY(), predicted);
if(!player.getInfo().isGeneralCancel()
@@ -77,7 +80,8 @@ public class FlyA extends Check {
&& !player.getInfo().isServerGround()
&& !player.getBlockInfo().onHalfBlock
&& player.getInfo().getVelocity().isPassed(1)
&& !player.getBlockInfo().onSlime && deltaPredict > 0.001) {
&& !player.getBlockInfo().onSlime
&& deltaPredict > (player.getInfo().getClientAirTicks() < 3 ? 0.017 : 0.001)) {
if(++buffer > 3) {
buffer = 3;
flag("dY=%.3f p=%.3f dx=%.3f", player.getMovement().getDeltaY(), predicted,
@@ -21,13 +21,15 @@ public class FlyB extends Check {
@Async
WAction<WPacketPlayInFlying> flying = packet -> {
if(player.getInfo().isNearGround()) lastNearGround.reset();
if((player.getInfo().isNearGround() && !player.getBlockInfo().collidesHorizontally)
|| player.getInfo().isServerGround()) lastNearGround.reset();
if(!packet.isMoved() || player.getInfo().isGeneralCancel()) return;
if(player.getMovement().getDeltaY() - player.getMovement().getLDeltaY() > 0.01
&& player.getMovement().getMoveTicks() > 3
&& player.getMovement().getMoveTicks() > 1
&& player.getInfo().getLastPlace().isPassed(3)
&& lastNearGround.isPassed(2)
&& !player.getInfo().onLadder
&& player.getInfo().lastLiquid.isPassed(1)
&& player.getInfo().climbTimer.isPassed(1)
&& player.getInfo().getVelocity().isPassed(2)
@@ -0,0 +1,42 @@
package dev.brighten.ac.check.impl.movement.fly;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@CheckData(name = "Fly (E)", checkId = "flye", type = CheckType.MOVEMENT)
public class FlyE extends Check {
public FlyE(APlayer player) {
super(player);
}
private int buffer;
WAction<WPacketPlayInFlying> flying = packet -> {
if(player.getInfo().getVelocity().isNotPassed(20)
|| player.getMovement().getMoveTicks() == 0
|| player.getInfo().isCreative()
|| player.getBlockInfo().blocksAbove
|| player.getMovement().getTeleportsToConfirm() > 0
|| player.getInfo().isCanFly()
|| player.getInfo().getLastElytra().isNotPassed(5))
return;
final double deltaY = player.getMovement().getDeltaY(),
lDeltaY = player.getMovement().getLDeltaY();
if(Math.abs(deltaY + lDeltaY) < 0.05 && player.getInfo().lastHalfBlock.isPassed(2)
&& player.getInfo().slimeTimer.isPassed(5)
&& Math.abs(deltaY) > 0.2) {
buffer+= 15;
if(buffer > 20) {
flag("dy=%s ly=%s", deltaY, lDeltaY);
buffer= 20; // Prevents flagging too much
}
} else if(buffer > 0) buffer--;
};
}
@@ -0,0 +1,30 @@
package dev.brighten.ac.check.impl.movement.fly;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@CheckData(name = "Fly (F)", checkId = "flyf", type = CheckType.MOVEMENT)
public class FlyF extends Check {
public FlyF(APlayer player) {
super(player);
}
WAction<WPacketPlayInFlying> flying = packet -> {
if(!packet.isMoved()
|| player.getInfo().blockAbove.isNotPassed(4)
|| player.getInfo().climbTimer.isNotPassed(2)
|| packet.isOnGround()
|| player.getMovement().getMoveTicks() < 3
|| player.getInfo().isGeneralCancel()) return;
double acceleration = player.getMovement().getDeltaY() - player.getMovement().getLDeltaY();
if(acceleration < (player.getMovement().getDeltaXZ() < 0.1 ? -0.17 : -0.1)) {
flag("acceleration=%.4f", acceleration);
}
};
}
@@ -36,6 +36,7 @@ public class NoFallA extends Check {
&& player.getInfo().slimeTimer.isPassed(2)
&& player.getInfo().getBlockAbove().isPassed(3)
&& !player.getInfo().isServerGround()
&& !player.getBlockInfo().fenceNear
&& (player.getMovement().getDeltaY() >= 0
&& (Math.abs(player.getMovement().getTo().getLoc().y) % divisor != 0
|| Math.abs(player.getMovement().getDeltaY()) % divisor != 0)
@@ -41,6 +41,7 @@ public class Horizontal extends Check {
if (!packet.isMoved()
|| player.getMovement().getMoveTicks() == 0
|| player.getMovement().getLastTeleport().isNotPassed(1)
|| player.getInfo().getVelocity().isNotPassed(2)
|| player.getInfo().isGeneralCancel()
|| player.getBlockInfo().onClimbable
@@ -54,10 +55,10 @@ public class Horizontal extends Check {
Deque<Material> frictionList = player.getBlockUpdateHandler()
.getPossibleMaterials(new IntVector(MathHelper.floor_double(underBlockLoc.x),
MathHelper.floor_double(underBlockLoc.y), MathHelper.floor_double(underBlockLoc.z))),
MathHelper.floor_double(underBlockLoc.y - 1), MathHelper.floor_double(underBlockLoc.z))),
lfrictionList = player.getBlockUpdateHandler()
.getPossibleMaterials(new IntVector(MathHelper.floor_double(lastUnderBlockLoc.x),
MathHelper.floor_double(lastUnderBlockLoc.y),
MathHelper.floor_double(lastUnderBlockLoc.y - 1),
MathHelper.floor_double(lastUnderBlockLoc.z)));
double smallestDelta = Double.MAX_VALUE;
@@ -123,6 +124,16 @@ public class Horizontal extends Check {
}
}
/*if(!sneaking && player.getBlockInfo().onSlime
&& player.getBlockInfo().collisionMaterialCount
.containsKey(Material.SLIME_BLOCK)) {
for(int i = 0 ; i < player.getBlockInfo()
.collisionMaterialCount
.get(Material.SLIME_BLOCK) ; i++) {
lmotionX*=
}
}*/
if(player.getBlockInfo().inWeb) {
lmotionX*= 0.25;
lmotionZ*= 0.25;
@@ -281,7 +292,7 @@ public class Horizontal extends Check {
}
private static boolean[] getSneakingIteration(boolean sprinting) {
return sprinting ? new boolean[] {false} : new boolean[] {true, false};
return new boolean[] {true, false};
}
private static boolean[] getJumpingIteration(boolean sprinting) {
@@ -0,0 +1,39 @@
package dev.brighten.ac.check.impl.packet;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutEntityMetadata;
import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutSpawnEntityLiving;
@CheckData(name = "Metadata", checkId = "metadata", type = CheckType.BADPACKETS)
public class Metadata extends Check {
public Metadata(APlayer player) {
super(player);
}
WAction<WPacketPlayOutEntityMetadata> packet = packet -> {
debug("entityId: " + packet.getEntityId());
packet.getWatchedObjects().forEach(watchedObject -> {
debug("watchedObject: " + watchedObject.getObjectType() + "," + watchedObject.getDataValueId() + ", " + watchedObject.getWatchedObject());
});
};
WAction<WPacketPlayOutSpawnEntityLiving> spawn = packet -> {
debug("(spawned) entityId: " + packet.getEntityId());
packet.getWatchedObjects().forEach(watchedObject -> {
if(watchedObject.getDataValueId() == 0) {
byte bitInfo = (byte) watchedObject.getWatchedObject();
boolean sneaking = (bitInfo & 1 << 1) != 0;
boolean sprinting = (bitInfo & 1 << 3) != 0;
boolean invisible = (bitInfo & 1 << 5) != 0;
debug("sneaking:%s sprinting:%s invisible:%s", sneaking, sprinting, invisible);
}
debug("watchedObject: " + watchedObject.getObjectType() + "," + watchedObject.getDataValueId() + ", " + watchedObject.getWatchedObject());
});
};
}
@@ -32,6 +32,7 @@ import net.minecraft.server.v1_8_R3.PacketPlayOutTitle;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.v1_8_R3.util.CraftChatMessage;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.plugin.InvalidDescriptionException;
import org.bukkit.plugin.Plugin;
@@ -211,13 +212,12 @@ public class AnticheatCommand extends BaseCommand {
@Subcommand("spawnbot")
@CommandPermission("anticheat.command.spawnbot")
@Description("Spawn test bot")
public void onBot(Player player) {
FakeMob fakePlayer = new FakeMob(player.getLocation().getWorld());
public void onBot(APlayer player) {
FakeMob fakePlayer = new FakeMob(EntityType.ZOMBIE);
fakePlayer.spawn(player.getLocation(), Anticheat.INSTANCE.getPlayerRegistry()
.getPlayer(player.getUniqueId()).orElseThrow(() -> new RuntimeException("shit")));
fakePlayer.spawn(true, player.getBukkitPlayer().getLocation(), player);
player.sendMessage(Color.Green + "Spawned entity with ID: " + fakePlayer.getEntityId());
player.getBukkitPlayer().sendMessage(Color.Green + "Spawned entity with ID: " + fakePlayer.getEntityId());
}
@Subcommand("botinvis")
@@ -2,22 +2,21 @@ package dev.brighten.ac.handler;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.handler.entity.FakeMob;
import dev.brighten.ac.packet.ProtocolVersion;
import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutEntity;
import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutEntityTeleport;
import dev.brighten.ac.packet.wrapper.out.*;
import dev.brighten.ac.utils.EntityLocation;
import dev.brighten.ac.utils.Tuple;
import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.MillisTimer;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import java.util.EnumSet;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@RequiredArgsConstructor
@@ -26,7 +25,11 @@ public class EntityLocationHandler {
private final APlayer data;
private final Map<UUID, Tuple<EntityLocation, EntityLocation>> entityLocationMap = new ConcurrentHashMap<>();
private final Map<Integer, FakeMob> fakeMobs = new Int2ObjectArrayMap<>();
private final Map<Integer, Integer> fakeMobToEntityId = new Int2ObjectArrayMap<>();
private final Timer lastFlying = new MillisTimer();
public Set<Integer> canCreateMob = new HashSet<>();
public int streak;
private static final EnumSet<EntityType> allowedEntityTypes = EnumSet.of(EntityType.ZOMBIE, EntityType.SHEEP,
@@ -45,6 +48,14 @@ public class EntityLocationHandler {
return Optional.ofNullable(entityLocationMap.get(entity.getUniqueId()));
}
public Optional<FakeMob> getFakeMob(int entityId) {
return Optional.ofNullable(fakeMobs.get(entityId));
}
public Optional<Integer> getTargetOfFakeMob(int fakeMobId) {
return Optional.ofNullable(fakeMobToEntityId.get(fakeMobId));
}
/**
*
* We are processing PacketPlayInFlying to iterate the tracked entity locations
@@ -90,7 +101,12 @@ public class EntityLocationHandler {
if(!allowedEntityTypes.contains(entity.getType())) return;
val tuple = entityLocationMap.computeIfAbsent(entity.getUniqueId(),
key -> new Tuple<>(new EntityLocation(entity), null));
key -> {
createFakeMob(packet.getId(), entity.getLocation());
return new Tuple<>(new EntityLocation(entity), null);
});
processFakeMobs(packet.getId(), true, packet.getX(), packet.getY(), packet.getZ());
EntityLocation eloc = tuple.one;
@@ -123,8 +139,14 @@ public class EntityLocationHandler {
if(!allowedEntityTypes.contains(entity.getType())) return;
val tuple = entityLocationMap.computeIfAbsent(entity.getUniqueId(),
key -> new Tuple<>(new EntityLocation(entity), null));
key -> {
createFakeMob(packet.getEntityId(), entity.getLocation());
return new Tuple<>(new EntityLocation(entity), null);
});
processFakeMobs(packet.getEntityId(), false, packet.getX(), packet.getY(), packet.getZ());
EntityLocation eloc = tuple.one;
@@ -188,4 +210,64 @@ public class EntityLocationHandler {
entityLocationMap.get(entity.getUniqueId()).two = null, 1);
}
}
public void onSpawnEntity(WPacketPlayOutNamedEntitySpawn packet) {
createFakeMob(packet.getEntityId(), new Location(data.getBukkitPlayer().getWorld(), packet.getX(), packet.getY(), packet.getZ()));
}
public void onSpawnEntity(WPacketPlayOutSpawnEntityLiving packet) {
if(!allowedEntityTypes.contains(packet.getType())) return;
createFakeMob(packet.getEntityId(), new Location(data.getBukkitPlayer().getWorld(), packet.getX(), packet.getY(), packet.getZ()));
}
public void onEntityDestroy(WPacketPlayOutEntityDestroy packet) {
for(int id : packet.getEntityIds()) {
if(fakeMobs.containsKey(id)) {
FakeMob mob = fakeMobs.get(id);
mob.despawn();
fakeMobToEntityId.remove(mob.getEntityId());
fakeMobs.remove(id);
}
}
}
public void removeFakeMob(int id) {
if(fakeMobs.containsKey(id)) {
FakeMob mob = fakeMobs.get(id);
mob.despawn();
fakeMobToEntityId.remove(mob.getEntityId());
fakeMobs.remove(id);
}
}
private void createFakeMob(int entityId, Location location) {
if(!canCreateMob.contains(entityId)) return;
FakeMob mob = new FakeMob(EntityType.GIANT);
mob.spawn(true, location, data);
this.fakeMobs.put(entityId, mob);
fakeMobToEntityId.put(mob.getEntityId(), entityId);
canCreateMob.remove(entityId);
}
public void processFakeMobs(int entityId, boolean rel, double x, double y, double z) {
FakeMob fakeMob = fakeMobs.get(entityId);
if(fakeMob == null) {
if(!rel) {
createFakeMob(entityId, new Location(data.getBukkitPlayer().getWorld(), x, y, z));
fakeMob = fakeMobs.get(entityId);
if(fakeMob == null) return;
} else return;
}
if(rel) {
fakeMob.move(x, y, z);
} else {
fakeMob.teleport(x, y, z, 0, 0);
}
}
}
@@ -10,6 +10,8 @@ import dev.brighten.ac.utils.*;
import dev.brighten.ac.utils.objects.evicting.EvictingList;
import dev.brighten.ac.utils.timer.Timer;
import dev.brighten.ac.utils.timer.impl.TickTimer;
import dev.brighten.ac.utils.world.CollisionBox;
import dev.brighten.ac.utils.world.types.RayCollision;
import dev.brighten.ac.utils.world.types.SimpleCollisionBox;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -39,7 +41,9 @@ public class MovementHandler {
private int moveTicks;
private final List<KLocation> posLocs = new ArrayList<>();
@Getter
private boolean checkMovement, accurateYawData, cinematic, jumped, inAir;
private final List<CollisionBox> lookingAtBoxes = new ArrayList<>();
@Getter
private boolean checkMovement, accurateYawData, cinematic, jumped, inAir, lookingAtBlock;
@Getter
@Setter
private boolean excuseNextFlying;
@@ -141,7 +145,18 @@ public class MovementHandler {
val origin = this.to.getLoc().clone();
origin.y += player.getInfo().isSneaking() ? 1.54 : 1.62;
origin.y += player.getInfo().isSneaking()
? (player.getPlayerVersion().isBelow(ProtocolVersion.V1_14) ? 1.54 : 1.27f) : 1.62;
RayCollision collision = new RayCollision(origin.toVector(), MathUtils.getDirection(origin));
synchronized (lookingAtBoxes) {
lookingAtBoxes.clear();
lookingAtBoxes.addAll(collision
.boxesOnRay(player.getBukkitPlayer().getWorld(),
player.getBukkitPlayer().getGameMode().equals(GameMode.CREATIVE) ? 6.0 : 5.0));
lookingAtBlock = lookingAtBoxes.size() > 0;
}
if (lastTeleport.isPassed(1)) {
predictionHandling:
@@ -3,6 +3,7 @@ package dev.brighten.ac.handler;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.data.obj.NormalAction;
import dev.brighten.ac.handler.entity.FakeMob;
import dev.brighten.ac.packet.ProtocolVersion;
import dev.brighten.ac.packet.wrapper.PacketType;
import dev.brighten.ac.packet.wrapper.in.*;
@@ -228,6 +229,12 @@ public class PacketHandler {
}
break;
}
case ENTITY_DESTROY: {
WPacketPlayOutEntityDestroy packet = (WPacketPlayOutEntityDestroy) packetObject;
player.getEntityLocationHandler().onEntityDestroy(packet);
break;
}
case ENTITY_ACTION: {
WPacketPlayInEntityAction packet = (WPacketPlayInEntityAction) packetObject;
@@ -269,10 +276,22 @@ public class PacketHandler {
case USE_ENTITY: {
WPacketPlayInUseEntity packet = (WPacketPlayInUseEntity) packetObject;
Entity target = packet.getEntity(player.getBukkitPlayer().getWorld());
FakeMob mob = Anticheat.INSTANCE.getFakeTracker().getEntityById(packet.getEntityId());
if(target instanceof LivingEntity) {
player.getInfo().setTarget((LivingEntity) target);
if(mob != null) {
player.getEntityLocationHandler().getTargetOfFakeMob(mob.getEntityId())
.ifPresent(targetId -> {
player.getEntityLocationHandler().removeFakeMob(targetId);
});
} else {
Entity target = packet.getEntity(player.getBukkitPlayer().getWorld());
if(target instanceof LivingEntity) {
if(Math.random() > 0.9) {
player.getEntityLocationHandler().canCreateMob.add(target.getEntityId());
}
player.getInfo().setTarget((LivingEntity) target);
}
}
break;
}
@@ -164,6 +164,13 @@ public class BlockUpdateHandler {
blockI.add(type);
blockInformation.put(loc, blockI);
} else if(blockI.size() == 0) {
Material type = Wrapper.getInstance().getType(player.getBukkitPlayer().getWorld(),
loc.getX(), loc.getY(), loc.getZ());
blockI.add(type);
blockInformation.put(loc, blockI);
}
@@ -22,7 +22,7 @@ public class FakeEntityTracker {
}
public void despawnAll() {
entityMap.forEach((id, entity) -> entity.despawn());
entityMap.values().forEach(FakeMob::despawn);
entityMap.clear();
}
}
@@ -2,19 +2,15 @@ package dev.brighten.ac.handler.entity;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.objects.WrappedWatchableObject;
import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutEntity;
import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutEntityEffect;
import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutEntityMetadata;
import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutEntityTeleport;
import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutRemoveEntityEffect;
import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutSpawnEntityLiving;
import lombok.Getter;
import net.minecraft.server.v1_8_R3.EntityZombie;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
import org.bukkit.entity.EntityType;
import org.bukkit.potion.PotionEffectType;
import java.util.ArrayList;
import java.util.Collections;
@@ -25,32 +21,52 @@ import java.util.concurrent.ThreadLocalRandom;
public class FakeMob {
private int entityId;
private EntityType type;
private EntityZombie zombie;
private List<APlayer> watching = Collections.emptyList();
public FakeMob(World world) {
public FakeMob(EntityType type) {
entityId = ThreadLocalRandom.current().nextInt(15000, 20000);
zombie = new EntityZombie(((CraftWorld)world).getHandle());
entityId = zombie.getId();
this.type = type;
}
public void spawn(Location location, APlayer... players) {
/*
protected void b(int i, boolean flag) {
byte b0 = this.datawatcher.getByte(0);
if (flag) {
this.datawatcher.watch(0, (byte)(b0 | 1 << i));
} else {
this.datawatcher.watch(0, (byte)(b0 & ~(1 << i)));
}
}
*/
public void spawn(boolean invisible, Location location, APlayer... players) {
if(watching.size() > 0) {
despawn();
}
zombie = new EntityZombie(((CraftWorld)location.getWorld()).getHandle());
zombie.setInvisible(true);
zombie.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
zombie.setHealth(20f);
entityId = zombie.getId();
watching = new ArrayList<>();
for (APlayer player : players) {
PacketPlayOutSpawnEntityLiving living = new PacketPlayOutSpawnEntityLiving(zombie);
player.sendPacket(living);
List<WrappedWatchableObject> objects = new ArrayList<>();
if(invisible) {
objects.add(new WrappedWatchableObject(0, 0, (byte)((byte)1 << 5)));
}
WPacketPlayOutSpawnEntityLiving packet = WPacketPlayOutSpawnEntityLiving.builder()
.entityId(entityId)
.type(type)
.x(location.getX())
.y(location.getY())
.z(location.getZ())
.yaw(location.getYaw())
.pitch(location.getPitch())
.headYaw(location.getYaw())
.motionX(0)
.motionY(0)
.motionZ(0)
.watchedObjects(objects)
.build();
player.sendPacket(packet);
watching.add(player);
}
@@ -58,23 +74,20 @@ public class FakeMob {
}
public void setInvisible(boolean invisible) {
List<WrappedWatchableObject> objects = new ArrayList<>();
if(invisible) {
WPacketPlayOutEntityEffect packet = WPacketPlayOutEntityEffect.builder().entityId(entityId)
.effectId(PotionEffectType.INVISIBILITY.getId() & 255).amplifier((byte)0).duration(32767).flags((byte)0x02).build();
for (APlayer player : watching) {
player.sendPacket(packet);
}
zombie.setInvisible(true);
objects.add(new WrappedWatchableObject(0, 0, (byte)((byte)1 << 5)));
} else {
WPacketPlayOutRemoveEntityEffect packet = WPacketPlayOutRemoveEntityEffect.builder()
.effect(PotionEffectType.INVISIBILITY).entityId(entityId).build();
for (APlayer player : watching) {
player.sendPacket(packet);
}
zombie.setInvisible(false);
objects.add(new WrappedWatchableObject(0, 0, (byte)~((byte)1 << 5)));
}
WPacketPlayOutEntityMetadata packet = WPacketPlayOutEntityMetadata.builder()
.entityId(entityId)
.watchedObjects(objects)
.build();
watching.forEach(player -> player.sendPacket(packet));
}
public void despawn() {
@@ -84,13 +97,12 @@ public class FakeMob {
aPlayer.sendPacket(destroyEntity);
}
watching = Collections.emptyList();
zombie = null;
Anticheat.INSTANCE.getFakeTracker().untrackEntity(this);
}
public void move(double dx, double dy, double dz) {
WPacketPlayOutEntity packet = WPacketPlayOutEntity.builder().x(dx).y(dy).z(dz).moved(true).build();
WPacketPlayOutEntity packet = WPacketPlayOutEntity.builder().id(entityId).x(dx).y(dy).z(dz).moved(true).build();
for (APlayer player : watching) {
player.sendPacket(packet);
@@ -98,7 +110,7 @@ public class FakeMob {
}
public void move(double dx, double dy, double dz, float dyaw, float dpitch) {
WPacketPlayOutEntity packet = WPacketPlayOutEntity.builder().x(dx).y(dy).z(dz).yaw(dyaw)
WPacketPlayOutEntity packet = WPacketPlayOutEntity.builder().id(entityId).x(dx).y(dy).z(dz).yaw(dyaw)
.pitch(dpitch).moved(true).looked(true).build();
for (APlayer player : watching) {
@@ -107,7 +119,7 @@ public class FakeMob {
}
public void move(float dyaw, float dpitch) {
WPacketPlayOutEntity packet = WPacketPlayOutEntity.builder().yaw(dyaw).pitch(dpitch)
WPacketPlayOutEntity packet = WPacketPlayOutEntity.builder().id(entityId).yaw(dyaw).pitch(dpitch)
.looked(true).build();
for (APlayer player : watching) {
@@ -1,4 +0,0 @@
package dev.brighten.ac.handler.entity.hit;
public class HitEntityTracker {
}
@@ -75,4 +75,6 @@ public interface PacketConverter {
WPacketPlayOutEntityMetadata processEntityMetadata(Object object);
Object processEntityMetadata(WPacketPlayOutEntityMetadata packet);
WPacketPlayOutEntityDestroy processEntityDestroy(Object object);
}
@@ -140,6 +140,10 @@ public enum PacketType {
return convert.processSpawnLiving(object);
case REMOVE_EFFECT:
return convert.processRemoveEffect(object);
case ENTITY_METADATA:
return convert.processEntityMetadata(object);
case ENTITY_DESTROY:
return convert.processEntityDestroy(object);
default:
return object;
}
@@ -14,6 +14,8 @@ import dev.brighten.ac.utils.math.IntVector;
import dev.brighten.ac.utils.reflections.types.WrappedClass;
import dev.brighten.ac.utils.reflections.types.WrappedField;
import io.netty.buffer.Unpooled;
import lombok.SneakyThrows;
import lombok.val;
import net.minecraft.server.v1_8_R3.*;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;
@@ -23,8 +25,7 @@ import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
public class Processor_18 implements PacketConverter {
@@ -391,7 +392,7 @@ public class Processor_18 implements PacketConverter {
serial.writeBoolean(packet.isOnGround());
try {
vanilla.b(serial);
vanilla.a(serial);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -626,24 +627,33 @@ public class Processor_18 implements PacketConverter {
return vanilla;
}
private static WrappedClass classSpawnEntityLiving = new WrappedClass(PacketPlayOutSpawnEntityLiving.class);
private static WrappedField splDataWatcher = classSpawnEntityLiving.getFieldByType(DataWatcher.class, 0),
splWatchList = classSpawnEntityLiving.getFieldByType(List.class, 0);
@SneakyThrows
@Override
public WPacketPlayOutSpawnEntityLiving processSpawnLiving(Object object) {
PacketPlayOutSpawnEntityLiving packet = (PacketPlayOutSpawnEntityLiving) object;
PacketDataSerializer s = serialize(packet);
WPacketPlayOutSpawnEntityLiving sel = WPacketPlayOutSpawnEntityLiving.builder().entityId(s.e())
val builder = WPacketPlayOutSpawnEntityLiving.builder().entityId(s.e())
.type(EntityType.fromId(s.readByte() & 255)).x(s.readInt() / 32.).y(s.readInt() / 32.)
.z(s.readInt()/ 32.).yaw(s.readByte() * 360.F / 256.F).pitch(s.readByte() * 360.F / 256.F)
.headYaw(s.readByte() * 360.F / 256.F).motionX(s.readShort() / 8000.).motionY(s.readShort() / 8000.)
.motionZ(s.readShort() / 8000.).build();
.motionZ(s.readShort() / 8000.);
val watchedObjects = DataWatcher.b(s);
if(watchedObjects != null) {
builder.watchedObjects(watchedObjects.stream().map(WrappedWatchableObject::new).collect(Collectors.toList()));
} else builder.watchedObjects(new ArrayList<>());
return sel;
return builder.build();
}
private static WrappedClass classSpawnEntityLiving = new WrappedClass(PacketPlayOutSpawnEntityLiving.class);
private static WrappedField splDataWatcher = classSpawnEntityLiving.getFieldByType(DataWatcher.class, 0);
private static WrappedClass dataWatcherClass = new WrappedClass(DataWatcher.class);
private static WrappedField watchableMap = dataWatcherClass.getFieldByName("d");
@Override
public Object processSpawnLiving(WPacketPlayOutSpawnEntityLiving packet) {
PacketPlayOutSpawnEntityLiving vanilla = new PacketPlayOutSpawnEntityLiving();
@@ -663,8 +673,14 @@ public class Processor_18 implements PacketConverter {
try {
DataWatcher watcher = new DataWatcher(null);
splDataWatcher.set(vanilla, watcher);
packet.getWatchedObjects().forEach(w ->{
watcher.a(w.getDataValueId(), w.getWatchedObject());
System.out.println("Adding object: " + w.getDataValueId() + ";" + w.getWatchedObject());
});
watcher.a(serializer);
splDataWatcher.set(vanilla, watcher);
vanilla.a(serializer);
} catch (IOException e) {
throw new RuntimeException(e);
@@ -747,6 +763,21 @@ public class Processor_18 implements PacketConverter {
return vanilla;
}
@Override
public WPacketPlayOutEntityDestroy processEntityDestroy(Object object) {
PacketPlayOutEntityDestroy packet = (PacketPlayOutEntityDestroy) object;
PacketDataSerializer serialized = serialize(packet);
int[] entityIds = new int[serialized.e()];
for(int var2 = 0; var2 < entityIds.length; ++var2) {
entityIds[var2] = serialized.e();
}
return WPacketPlayOutEntityDestroy.builder().entityIds(entityIds).build();
}
private PacketDataSerializer serialize(Packet<?> packet) {
PacketDataSerializer serial = new PacketDataSerializer(Unpooled.buffer());
try {
@@ -756,4 +787,54 @@ public class Processor_18 implements PacketConverter {
}
return serial;
}
private static void writePacketData(PacketDataSerializer serializer, List<WrappedWatchableObject> objects) {
for (WrappedWatchableObject object : objects) {
System.out.println("Writing object:" + object.getDataValueId() + ";" + object.getWatchedObject());
int i = (object.getObjectType() << 5 | object.getDataValueId() & 31) & 255;
serializer.writeByte(i);
switch (object.getObjectType()) {
case 0: {
serializer.writeByte((Byte)object.getWatchedObject());
break;
}
case 1: {
serializer.writeShort((Short)object.getWatchedObject());
break;
}
case 2: {
serializer.writeInt((Integer)object.getWatchedObject());
break;
}
case 3: {
serializer.writeFloat((Float)object.getWatchedObject());
break;
}
case 4: {
serializer.a((String)object.getWatchedObject());
break;
}
case 5: {
ItemStack itemStack = (ItemStack)object.getWatchedObject();
serializer.a(itemStack);
break;
}
case 6: {
BlockPosition blockPosition = (BlockPosition)object.getWatchedObject();
serializer.writeInt(blockPosition.getX());
serializer.writeInt(blockPosition.getY());
serializer.writeInt(blockPosition.getZ());
break;
}
case 7: {
Vector3f vector3f = (Vector3f)object.getWatchedObject();
serializer.writeFloat(vector3f.getX());
serializer.writeFloat(vector3f.getY());
serializer.writeFloat(vector3f.getZ());
break;
}
}
}
serializer.writeByte(127);
}
}
@@ -23,7 +23,7 @@ public class WrappedWatchableObject extends WObject {
private static WrappedField firstIntField, dataValueIdField, dataWatcherObjectField,
dataWatcherObjectIdField, dataSerializerField, watchedObjectField, watchedField;
private int firstInt, dataValueId;
private int objectType, dataValueId;
private Object watchedObject, dataWatcherObject, serializer;
private boolean watched;
@@ -31,13 +31,20 @@ public class WrappedWatchableObject extends WObject {
super(object);
}
public WrappedWatchableObject(int objectType, int dataValueId, Object watchedObject) {
super(constructor.newInstance(objectType, dataValueId, watchedObject));
this.dataValueId = dataValueId;
this.watchedObject = watchedObject;
}
@Override
public void processVanilla() {
if(ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) {
firstInt = fetch(firstIntField);
objectType = fetch(firstIntField);
dataValueId = fetch(dataValueIdField);
} else {
firstInt = -1;
objectType = -1;
dataWatcherObject = fetch(dataWatcherObjectField);
dataValueId = dataWatcherObjectIdField.get(dataWatcherObject);
serializer = dataSerializerField.get(dataWatcherObject);
@@ -48,7 +55,7 @@ public class WrappedWatchableObject extends WObject {
@Override
public Object toVanillaObject() {
return constructor.newInstance(firstInt, dataValueId, watchedObject);
return constructor.newInstance(objectType, dataValueId, watchedObject);
}
static {
@@ -3,10 +3,13 @@ package dev.brighten.ac.packet.wrapper.out;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.packet.wrapper.PacketType;
import dev.brighten.ac.packet.wrapper.WPacket;
import dev.brighten.ac.packet.wrapper.objects.WrappedWatchableObject;
import lombok.Builder;
import lombok.Getter;
import org.bukkit.entity.EntityType;
import java.util.List;
@Getter
@Builder
public class WPacketPlayOutSpawnEntityLiving extends WPacket {
@@ -16,6 +19,7 @@ public class WPacketPlayOutSpawnEntityLiving extends WPacket {
private double x, y, z;
private float yaw, pitch, headYaw;
private double motionX, motionY, motionZ;
private List<WrappedWatchableObject> watchedObjects;
@Override
public PacketType getPacketType() {
@@ -1,92 +0,0 @@
package dev.brighten.ac.utils;
public final class Base64 {
private static final int BYTES_PER_UNENCODED_BLOCK = 3;
private static final int BYTES_PER_ENCODED_BLOCK = 4;
private static final int SIX_BIT_MASK = 63;
private static final byte PAD = 61;
private static final byte[] ENCODE_TABLE = new byte[]{65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47};
private static final int[] DECODE_TABLE = new int[128];
public static byte[] decode(String s) {
int delta = s.endsWith("==") ? 2 : (s.endsWith("=") ? 1 : 0);
byte[] buffer = new byte[s.length() * 3 / 4 - delta];
int mask = 255;
int pos = 0;
for(int i = 0; i < s.length(); i += 4) {
int c0 = DECODE_TABLE[s.charAt(i)];
int c1 = DECODE_TABLE[s.charAt(i + 1)];
buffer[pos++] = (byte)((c0 << 2 | c1 >> 4) & mask);
if (pos >= buffer.length) {
return buffer;
}
int c2 = DECODE_TABLE[s.charAt(i + 2)];
buffer[pos++] = (byte)((c1 << 4 | c2 >> 2) & mask);
if (pos >= buffer.length) {
return buffer;
}
int c3 = DECODE_TABLE[s.charAt(i + 3)];
buffer[pos++] = (byte)((c2 << 6 | c3) & mask);
}
return buffer;
}
public static String encode(byte[] in) {
int modulus = 0;
int bitWorkArea = 0;
int numEncodedBytes = in.length / 3 * 4 + (in.length % 3 == 0 ? 0 : 4);
byte[] buffer = new byte[numEncodedBytes];
int pos = 0;
byte[] var6 = in;
int var7 = in.length;
for(int var8 = 0; var8 < var7; ++var8) {
int b = var6[var8];
modulus = (modulus + 1) % 3;
if (b < 0) {
b += 256;
}
bitWorkArea = (bitWorkArea << 8) + b;
if (0 == modulus) {
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 18 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 12 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 6 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea & 63];
}
}
switch (modulus) {
case 1:
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 2 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea << 4 & 63];
buffer[pos++] = 61;
buffer[pos] = 61;
break;
case 2:
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 10 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea >> 4 & 63];
buffer[pos++] = ENCODE_TABLE[bitWorkArea << 2 & 63];
buffer[pos] = 61;
}
return byteArrayToString(buffer);
}
private static String byteArrayToString(byte[] buffer) {
return new String(buffer, 0, 0, buffer.length);
}
private Base64() {
}
static {
for(int i = 0; i < ENCODE_TABLE.length; DECODE_TABLE[ENCODE_TABLE[i]] = i++) {
}
}
}
@@ -1,63 +0,0 @@
package dev.brighten.ac.utils;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import java.util.concurrent.TimeUnit;
public class ExpTimer {
public final Player player;
public long timerEnd;
public final long extense;
public final Runnable onComplete;
public BukkitTask levelTask, expTask;
private final int previousLevel;
private final float previousExp;
public ExpTimer(Player player, long time, TimeUnit unit, Runnable onComplete) {
this.player = player;
this.extense = unit.toMillis(time);
this.timerEnd = System.currentTimeMillis() + extense;
this.onComplete = onComplete;
previousExp = player.getExp();
previousLevel = player.getLevel();
levelTask = RunUtils.taskTimer(() -> {
if(getMillisLeft() <= 0) {
levelTask.cancel();
levelTask = null;
return;
}
player.setLevel((int)Math.floor(getMillisLeft() / 1000D));
}, 2, 20);
expTask = RunUtils.taskTimer(() -> {
if(getMillisLeft() <= 0 && levelTask == null) {
expTask.cancel();
expTask = null;
player.setLevel(previousLevel);
player.setExp(previousExp);
onComplete.run();
return;
}
player.setExp(getMillisLeft() / (float)extense);
}, 2, 2);
}
private long getMillisLeft() {
return timerEnd - System.currentTimeMillis();
}
public void stop() {
timerEnd = System.currentTimeMillis();
}
public void cancel() {
levelTask.cancel();
expTask.cancel();
levelTask = expTask = null;
player.setExp(previousExp);
player.setLevel(previousLevel);
}
}
@@ -1,50 +0,0 @@
package dev.brighten.ac.utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
public class StreamUtils {
public static void streamCopy(InputStream in, OutputStream out) throws IOException {
assert (in != null);
assert (out != null);
ReadableByteChannel inChannel = Channels.newChannel(in);
WritableByteChannel outChannel = Channels.newChannel(out);
channelCopy(inChannel, outChannel);
}
/**
* A fast method to copy bytes from one channel to another; uses direct 16k
* buffers to minimize copies and OS overhead.
* @author http://thomaswabner.wordpress.com/2007/10/09/fast-stream-copy-using-javanio-channels/
* @param src - a non-null readable bytechannel to read the data from
* @param dest - a non-null writeable byte channel to write the data to
*/
public static void channelCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException {
assert (src != null);
assert (dest != null);
final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (src.read(buffer) != -1) {
// prepare the buffer to be drained
buffer.flip();
// write to the channel, may block
dest.write(buffer);
// If partial transfer, shift remainder down
// If buffer is empty, same as doing clear()
buffer.compact();
}
// EOF will leave buffer in fill state
buffer.flip();
// make sure the buffer is fully drained.
while (buffer.hasRemaining()) {
dest.write(buffer);
}
}
}