[BREAKING] Prepare more refined vehicle checks.

* Split vehicle checks to another class. Needs refactoring.
* Add ability for simple generic instance registration by an interface.
* Add new sub check type MOVING_VEHICLE, with configuration section,
move existing stuff there (moving.vehicles.., morepacketsvehicle).
* Breaks at least the use of check type MOVING_MOREPACKETSVEHICLE.

FunFact:
* Try CheckType setup with MOVING_MOREPACKETS_VEHICLE(MOVING, ...) to
see why there is a test for this kind of thing.

Bugs:
* Old configuration paths don't seem to get removed with @Moved.

Missing:
* More refined vehicle checks.
This commit is contained in:
asofold 2016-04-21 15:12:39 +02:00
parent 6f95111304
commit 5d595cd275
11 changed files with 564 additions and 421 deletions

View File

@ -93,10 +93,11 @@ public enum CheckType {
MOVING(MovingConfig.factory, MovingData.factory, Permissions.MOVING),
MOVING_CREATIVEFLY(MOVING, Permissions.MOVING_CREATIVEFLY),
MOVING_MOREPACKETS(MOVING, Permissions.MOVING_MOREPACKETS),
MOVING_MOREPACKETSVEHICLE(MOVING, Permissions.MOVING_MOREPACKETSVEHICLE),
MOVING_NOFALL(MOVING, Permissions.MOVING_NOFALL),
MOVING_PASSABLE(MOVING, Permissions.MOVING_PASSABLE),
MOVING_SURVIVALFLY(MOVING, Permissions.MOVING_SURVIVALFLY),
MOVING_VEHICLE(MOVING, Permissions.MOVING_VEHICLE),
MOVING_VEHICLE_MOREPACKETS(MOVING_VEHICLE, Permissions.MOVING_VEHICLE_MOREPACKETS),
NET(new NetConfigCache(), new NetDataFactory(), Permissions.NET),
NET_ATTACKFREQUENCY(NET, Permissions.NET_ATTACKFREQUENCY),

View File

@ -323,7 +323,7 @@ public class MovingConfig extends ACheckConfig {
return passableCheck;
case MOVING_MOREPACKETS:
return morePacketsCheck;
case MOVING_MOREPACKETSVEHICLE:
case MOVING_VEHICLE_MOREPACKETS:
return morePacketsVehicleCheck;
case MOVING_CREATIVEFLY:
return creativeFlyCheck;

View File

@ -2,22 +2,17 @@ package fr.neatmonster.nocheatplus.checks.moving;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockPlaceEvent;
@ -37,12 +32,7 @@ import org.bukkit.event.player.PlayerToggleFlightEvent;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.event.player.PlayerToggleSprintEvent;
import org.bukkit.event.player.PlayerVelocityEvent;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.event.vehicle.VehicleExitEvent;
import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
@ -59,11 +49,11 @@ import fr.neatmonster.nocheatplus.checks.combined.CombinedConfig;
import fr.neatmonster.nocheatplus.checks.combined.CombinedData;
import fr.neatmonster.nocheatplus.checks.moving.locations.LocUtil;
import fr.neatmonster.nocheatplus.checks.moving.locations.MoveInfo;
import fr.neatmonster.nocheatplus.checks.moving.locations.VehicleSetBack;
import fr.neatmonster.nocheatplus.checks.moving.magic.Magic;
import fr.neatmonster.nocheatplus.checks.moving.model.MoveConsistency;
import fr.neatmonster.nocheatplus.checks.moving.model.MoveData;
import fr.neatmonster.nocheatplus.checks.moving.util.AuxMoving;
import fr.neatmonster.nocheatplus.checks.moving.util.MovingUtil;
import fr.neatmonster.nocheatplus.checks.moving.vehicle.VehicleChecks;
import fr.neatmonster.nocheatplus.checks.moving.velocity.AccountEntry;
import fr.neatmonster.nocheatplus.checks.moving.velocity.SimpleEntry;
import fr.neatmonster.nocheatplus.checks.net.NetConfig;
@ -106,35 +96,25 @@ import fr.neatmonster.nocheatplus.utilities.build.BuildParameters;
*/
public class MovingListener extends CheckListener implements TickListener, IRemoveData, IHaveCheckType, INotifyReload, INeedConfig, JoinLeaveListener{
/** The instance of NoCheatPlus. */
private final Plugin plugin = Bukkit.getPluginManager().getPlugin("NoCheatPlus"); // TODO
/** The no fall check. **/
public final NoFall noFall = addCheck(new NoFall());
public final NoFall noFall = addCheck(new NoFall());
/** The creative fly check. */
private final CreativeFly creativeFly = addCheck(new CreativeFly());
private final CreativeFly creativeFly = addCheck(new CreativeFly());
/** The more packets check. */
private final MorePackets morePackets = addCheck(new MorePackets());
private final MorePackets morePackets = addCheck(new MorePackets());
/** The more packets vehicle check. */
private final MorePacketsVehicle morePacketsVehicle = addCheck(new MorePacketsVehicle());
private final VehicleChecks vehicleChecks = new VehicleChecks();
/** The survival fly check. */
private final SurvivalFly survivalFly = addCheck(new SurvivalFly());
private final SurvivalFly survivalFly = addCheck(new SurvivalFly());
/** The Passable (simple no-clip) check.*/
private final Passable passable = addCheck(new Passable());
private final Passable passable = addCheck(new Passable());
/** Combined check but handled here (subject to change!) */
private final BedLeave bedLeave = addCheck(new BedLeave());
/**
* Unused instances.<br>
* Might be better due to cascading events in case of actions or plugins doing strange things.
*/
private final List<MoveInfo> parkedInfo = new ArrayList<MoveInfo>(10);
private final BedLeave bedLeave = addCheck(new BedLeave());
/**
* Store events by player name, in order to invalidate moving processing on higher priority level in case of teleports.
@ -149,11 +129,12 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
private int hoverTicksStep = 5;
private final Set<EntityType> normalVehicles = new HashSet<EntityType>();
/** Location for temporary use with getLocation(useLoc). Always call setWorld(null) after use. Use LocUtil.clone before passing to other API. */
final Location useLoc = new Location(null, 0, 0, 0); // TODO: Put to use...
/** Auxiliary functionality. */
private final AuxMoving aux = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(AuxMoving.class);
/** Statistics / debugging counters. */
private final Counters counters = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class);
private final int idMoveHandled = counters.registerKey("event.player.move.handled");
@ -164,24 +145,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
public MovingListener() {
super(CheckType.MOVING);
}
private MoveInfo useMoveInfo() {
if (parkedInfo.isEmpty()) {
return new MoveInfo(mcAccess);
}
else {
return parkedInfo.remove(parkedInfo.size() - 1);
}
}
/**
* Cleanup and add to parked.
* @param moveInfo
*/
private void returnMoveInfo(final MoveInfo moveInfo) {
moveInfo.cleanup();
parkedInfo.add(moveInfo);
// Register vehicleChecks.
NCPAPIProvider.getNoCheatPlusAPI().addComponent(vehicleChecks);
}
/**
@ -214,15 +179,15 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final MovingData data = MovingData.getData(player);
final MovingConfig cc = MovingConfig.getConfig(player);
final MoveInfo moveInfo = useMoveInfo();
final MoveInfo moveInfo = aux.useMoveInfo();
final Location loc = player.getLocation(useLoc);
moveInfo.set(player, loc, null, cc.yOnGround);
if (!MovingUtil.shouldCheckSurvivalFly(player, moveInfo.from, data, cc)) {
returnMoveInfo(moveInfo);
aux.returnMoveInfo(moveInfo);
useLoc.setWorld(null);
return;
}
returnMoveInfo(moveInfo);
aux.returnMoveInfo(moveInfo);
if (!data.hasSetBack() || blockY + 1D < data.getSetBackY()) {
useLoc.setWorld(null);
@ -272,10 +237,10 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final Location loc = player.getLocation(useLoc);
final MovingData data = MovingData.getData(player);
Location target = null;
final MoveInfo moveInfo = useMoveInfo();
final MoveInfo moveInfo = aux.useMoveInfo();
moveInfo.set(player, loc, null, cc.yOnGround);
final boolean sfCheck = MovingUtil.shouldCheckSurvivalFly(player, moveInfo.from, data, cc);
returnMoveInfo(moveInfo);
aux.returnMoveInfo(moveInfo);
if (sfCheck) {
target = data.getSetBack(loc);
}
@ -322,7 +287,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// TODO: Might omit this if neither check is activated.
final Location loc = player.getLocation(useLoc);
data.setSetBack(loc);
resetPositionsAndMediumProperties(player, loc, data, cc);
aux.resetPositionsAndMediumProperties(player, loc, data, cc);
data.resetTrace(loc, TickTask.getTick(), cc.traceSize, cc.traceMergeDist);
if (cc.enforceLocation) {
// Just in case.
@ -381,7 +346,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final boolean earlyReturn;
if (player.isInsideVehicle()) {
// No full processing for players in vehicles.
newTo = onPlayerMoveVehicle(player, from, to, data);
newTo = vehicleChecks.onPlayerMoveVehicle(player, from, to, data);
earlyReturn = true;
} else if (player.isDead() || player.isSleeping()) {
// Ignore dead players.
@ -423,7 +388,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Fire one or two moves here.
final MovingConfig cc = MovingConfig.getConfig(player);
final MoveInfo moveInfo = useMoveInfo();
final MoveInfo moveInfo = aux.useMoveInfo();
final Location loc = player.getLocation(moveInfo.useLoc);
final MoveData lastMove = data.moveData.getFirst();
// TODO: On pistons pulling the player back: -1.15 yDistance for split move 1 (untracked position > 0.5 yDistance!).
@ -463,7 +428,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
// Cleanup.
data.joinOrRespawn = false;
returnMoveInfo(moveInfo);
aux.returnMoveInfo(moveInfo);
}
/**
@ -568,7 +533,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// HOT FIX - for VehicleLeaveEvent missing.
if (data.wasInVehicle) {
onVehicleLeaveMiss(player, data, cc);
vehicleChecks.onVehicleLeaveMiss(player, data, cc);
}
// Set some data for this move.
@ -791,12 +756,12 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// 1: With carpet. TODO: Magic block id.
|| to.getTypeId() == 171 && to.getY() - to.getBlockY() <= 0.9
)
&& MovingUtil.getRealisticFallDistance(player, from.getY(), to.getY(), data) > 1.0
// 0: Within wobble-distance.
|| to.getY() - to.getBlockY() < 0.286 && to.getY() - from.getY() > -0.5
&& to.getY() - from.getY() < -Magic.GRAVITY_MIN
&& !to.isOnGround()
;
&& MovingUtil.getRealisticFallDistance(player, from.getY(), to.getY(), data) > 1.0
// 0: Within wobble-distance.
|| to.getY() - to.getBlockY() < 0.286 && to.getY() - from.getY() > -0.5
&& to.getY() - from.getY() < -Magic.GRAVITY_MIN
&& !to.isOnGround()
;
}
/**
@ -858,7 +823,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
if (lastMove.toIsValid && Math.abs(thisMove.yDistance) < Math.abs(lastMove.yDistance)
&& (thisMove.yDistance > 0.0 && lastMove.yDistance > 0.0
|| thisMove.yDistance < 0.0 && lastMove.yDistance < 0.0)
|| allowVerticalVelocity && data.getOrUseVerticalVelocity(thisMove.yDistance) != null) {
|| allowVerticalVelocity && data.getOrUseVerticalVelocity(thisMove.yDistance) != null) {
// Speed decreased or velocity is present.
}
else {
@ -1015,7 +980,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Reset some data.
data.prepareSetBack(newTo);
resetPositionsAndMediumProperties(player, newTo, data, cc); // TODO: Might move into prepareSetBack, experimental here.
aux.resetPositionsAndMediumProperties(player, newTo, data, cc); // TODO: Might move into prepareSetBack, experimental here.
// Set new to-location.
event.setTo(newTo);
@ -1026,68 +991,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
}
/**
* Called from player-move checking, if the player is inside of a vehicle.
* @param player
* @param from
* @param to
* @param data
*/
private Location onPlayerMoveVehicle(final Player player, final Location from, final Location to, final MovingData data) {
// Workaround for pigs and other (1.5.x and before)!
// Note that with 1.6 not even PlayerMove fires for horses and pigs.
// (isInsideVehicle is the faster check without object creation, do re-check though, if it changes to only check for Vehicle instances.)
final Entity vehicle = CheckUtils.getLastNonPlayerVehicle(player);
data.wasInVehicle = true;
data.sfHoverTicks = -1;
data.removeAllVelocity();
data.sfLowJump = false;
// TODO: What with processingEvents.remove(player.getName());
if (vehicle != null) {
final Location vLoc = vehicle.getLocation(); // TODO: Use a location as argument.
// (Auto detection of missing events, might fire one time too many per plugin run.)
if (!normalVehicles.contains(vehicle.getType())) {
onVehicleMove(vehicle, vLoc, vLoc, true);
return null;
} else {
data.vehicleConsistency = MoveConsistency.getConsistency(from, to, vLoc);
// TODO: Consider TeleportUtil.forceMount or similar.
final MovingConfig cc = MovingConfig.getConfig(player);
if (data.vehicleConsistency == MoveConsistency.INCONSISTENT) {
if (cc.vehicleEnforceLocation) {
return vLoc;
} else {
return null;
}
} else {
resetPositionsAndMediumProperties(player, vLoc, data, cc);
return null;
}
}
}
return null;
}
/**
* Called from player-move checking, if vehicle-leave has not been called after entering, but the player is not inside of a vehicle anymore.
* @param player
* @param data
* @param cc
*/
private void onVehicleLeaveMiss(final Player player, final MovingData data, final MovingConfig cc) {
if (data.debug) {
StaticLog.logWarning("VehicleExitEvent missing for: " + player.getName());
}
onPlayerVehicleLeave(player, null);
// if (BlockProperties.isRails(pFrom.getTypeId())) {
// Always clear no fall data, let Minecraft do fall damage.
data.noFallSkipAirCheck = true; // Might allow one time cheat.
data.sfLowJump = false;
data.clearNoFallData();
// TODO: What with processingEvents.remove(player.getName());
// }
}
/**
* Monitor level PlayerMoveEvent. Uses useLoc.
* @param event
@ -1148,7 +1051,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.lastMoveTime = now; // TODO: Move to MovingData?
// TODO: teleported + other resetting ?
Combined.feedYawRate(player, from.getYaw(), now, from.getWorld().getName(), data);
resetPositionsAndMediumProperties(player, from, mData, mCc);
aux.resetPositionsAndMediumProperties(player, from, mData, mCc);
mData.resetTrace(player, from, tick); // TODO: Should probably leave this to the teleport event!
if (((NetConfig) CheckType.NET_FLYINGFREQUENCY.getConfigFactory().getConfig(player)).flyingFrequencyActive) {
((NetData) CheckType.NET_FLYINGFREQUENCY.getDataFactory().getData(player)).teleportQueue.onTeleportEvent(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch());
@ -1173,13 +1076,13 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
if (player.isInsideVehicle()) {
// TODO: refine (!).
final Location ref = player.getVehicle().getLocation(useLoc);
resetPositionsAndMediumProperties(player, ref, mData, mCc); // TODO: Consider using to and intercept cheat attempts in another way.
aux.resetPositionsAndMediumProperties(player, ref, mData, mCc); // TODO: Consider using to and intercept cheat attempts in another way.
useLoc.setWorld(null);
mData.updateTrace(player, to, tick); // TODO: Can you become invincible by sending special moves?
}
else if (!from.getWorld().getName().equals(toWorldName)) {
// A teleport event should follow.
resetPositionsAndMediumProperties(player, to, mData, mCc);
aux.resetPositionsAndMediumProperties(player, to, mData, mCc);
mData.resetTrace(player, to, tick);
}
else {
@ -1187,7 +1090,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final MoveData lastMove = mData.moveData.getFirst();
if (!lastMove.toIsValid || !TrigUtil.isSamePos(to, lastMove.to.x, lastMove.to.y, lastMove.to.z)) {
// Something odd happened.
resetPositionsAndMediumProperties(player, to, mData, mCc);
aux.resetPositionsAndMediumProperties(player, to, mData, mCc);
} else {
// Normal move, nothing to do.
}
@ -1386,10 +1289,10 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
if (data.isTeleported(to)) {
// Set-back.
final Location teleported = data.getTeleported();
final MoveInfo moveInfo = useMoveInfo();
final MoveInfo moveInfo = aux.useMoveInfo();
moveInfo.set(player, teleported, null, cc.yOnGround);
data.onSetBack(moveInfo.from);
returnMoveInfo(moveInfo);
aux.returnMoveInfo(moveInfo);
// Reset stuff.
Combined.resetYawRate(player, teleported.getYaw(), System.currentTimeMillis(), true); // TODO: Not sure.
@ -1423,7 +1326,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.noFallSkipAirCheck = true;
}
data.sfHoverTicks = -1; // Important against concurrent modification exception.
resetPositionsAndMediumProperties(player, to, data, cc);
aux.resetPositionsAndMediumProperties(player, to, data, cc);
// TODO: Decide to remove the LiftOffEnvelope thing completely.
// if (TrigUtil.maxDistance(from.getX(), from.getY(), from.getZ(), to.getX(), to.getY(), to.getZ()) <= 12.0) {
// // TODO: Might happen with bigger distances (mainly ender pearl thrown at others).
@ -1441,24 +1344,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
}
/**
* Convenience method to do both data.resetPositions and
* data.adjustMediumProperties, wrapping given loc with a PlayerLocation
* instance.
*
* @param player
* @param loc
* @param data
* @param cc
*/
private void resetPositionsAndMediumProperties(final Player player, final Location loc, final MovingData data, final MovingConfig cc) {
final MoveInfo moveInfo = useMoveInfo();
moveInfo.set(player, loc, null, cc.yOnGround);
data.resetPositions(moveInfo.from);
data.adjustMediumProperties(moveInfo.from);
returnMoveInfo(moveInfo);
}
/**
* Player got a velocity packet. The server can't keep track of actual velocity values (by design), so we have to
* try and do that ourselves. Very rough estimates.
@ -1481,97 +1366,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.addVelocity(player, cc, velocity.getX(), velocity.getY(), velocity.getZ());
}
/**
* When a vehicle moves, its player will be checked for various suspicious behaviors.
*
* @param event
* the event
*/
@EventHandler(
ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onVehicleMove(final VehicleMoveEvent event) {
final Vehicle vehicle = event.getVehicle();
final EntityType entityType = vehicle.getType();
if (!normalVehicles.contains(entityType)) {
// A little extra sweep to check for debug flags.
normalVehicles.add(entityType);
if (MovingConfig.getConfig(vehicle.getWorld().getName()).debug) {
debug(null, "VehicleMoveEvent fired for: " + entityType);
}
}
// TODO: Might account for the case of a player letting the vehicle move but not themselves (do mind latency).
// Mind that players could be riding horses inside of minecarts etc.
if (vehicle.getVehicle() != null) {
// Do ignore events for vehicles inside of other vehicles.
return;
}
onVehicleMove(vehicle, event.getFrom(), event.getTo(), false);
}
public void onVehicleMove(final Entity vehicle, final Location from, final Location to, final boolean fake) {
// (No re-check for vehicles that have vehicles, pre condition is that this has already been checked.)
final Player player = CheckUtils.getFirstPlayerPassenger(vehicle);
if (player == null) {
return;
}
if (vehicle.isDead() || !vehicle.isValid()) {
onPlayerVehicleLeave(player, vehicle);
return;
}
if (!from.getWorld().equals(to.getWorld())) return;
final MovingData data = MovingData.getData(player);
final MovingConfig cc = MovingConfig.getConfig(player);
data.joinOrRespawn = false;
data.vehicleConsistency = MoveConsistency.getConsistency(from, to, player.getLocation(useLoc));
switch (data.vehicleConsistency) {
case FROM:
case TO:
resetPositionsAndMediumProperties(player, player.getLocation(useLoc), data, cc); // TODO: Drop MC 1.4!
break;
case INCONSISTENT:
// TODO: Any exploits exist? -> TeleportUtil.forceMount(player, vehicle)
// TODO: Test with latency.
break;
}
Location newTo = null;
data.sfNoLowJump = true;
if (cc.noFallVehicleReset) {
// Reset noFall data.
data.noFallSkipAirCheck = true; // Might allow one time cheat.
data.sfLowJump = false;
data.clearNoFallData();
}
if (data.debug) {
// Log move.
outputDebugVehicleMove(player, vehicle, from, to, fake);
}
if (morePacketsVehicle.isEnabled(player, data, cc)) {
// If the player is handled by the more packets vehicle check, execute it.
newTo = morePacketsVehicle.check(player, from, to, data, cc);
}
else {
// Otherwise we need to clear their data.
data.clearMorePacketsData();
}
// Schedule a set-back?
if (newTo != null && data.morePacketsVehicleTaskId == -1) {
// Schedule a delayed task to teleport back the vehicle with the player.
// (Only schedule if not already scheduled.)
// TODO: Might log debug if skipping.
// TODO: Problem: scheduling allows a lot of things to happen until the task is run. Thus control about some things might be necessary.
// TODO: Reset on world changes or not?
data.morePacketsVehicleTaskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new VehicleSetBack(vehicle, player, newTo, data.debug));
}
useLoc.setWorld(null);
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = false)
public void onEntityDamage(final EntityDamageEvent event) {
if (event.getCause() != DamageCause.FALL) {
@ -1589,7 +1383,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
return;
}
final MovingConfig cc = MovingConfig.getConfig(player);
final MoveInfo moveInfo = useMoveInfo();
final MoveInfo moveInfo = aux.useMoveInfo();
final double yOnGround = Math.max(cc.noFallyOnGround, cc.yOnGround);
final Location loc = player.getLocation(useLoc);
moveInfo.set(player, loc, null, yOnGround);
@ -1598,7 +1392,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
if (event.isCancelled() || !MovingUtil.shouldCheckSurvivalFly(player, pLoc, data, cc) || !noFall.isEnabled(player, cc)) {
data.clearNoFallData();
useLoc.setWorld(null);
returnMoveInfo(moveInfo);
aux.returnMoveInfo(moveInfo);
return;
}
boolean allowReset = true;
@ -1622,7 +1416,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// TODO: Also reset in other cases (moved too quickly)?
}
}
returnMoveInfo(moveInfo);
aux.returnMoveInfo(moveInfo);
final float fallDistance = player.getFallDistance();
final double damage = BridgeHealth.getDamage(event);
final float yDiff = (float) (data.noFallMaxY - loc.getY());
@ -1728,7 +1522,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// More resetting.
data.vDistAcc.clear();
resetPositionsAndMediumProperties(player, loc, data, cc);
aux.resetPositionsAndMediumProperties(player, loc, data, cc);
// Enforcing the location.
if (cc.enforceLocation) {
@ -1822,121 +1616,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
MovingData.onWorldUnload(event.getWorld());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVehicleExit(final VehicleExitEvent event) {
final Entity entity = event.getExited();
if (!(entity instanceof Player)) {
return;
}
onPlayerVehicleLeave((Player) entity, event.getVehicle());
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onVehicleDestroyLowest(final VehicleDestroyEvent event) {
// Prevent destroying ones own vehicle.
final Entity attacker = event.getAttacker();
if (attacker instanceof Player && attacker.equals(event.getVehicle().getPassenger())) {
final Player player = (Player) attacker;
final MovingConfig cc = MovingConfig.getConfig(player);
if (survivalFly.isEnabled(player, cc) || creativeFly.isEnabled(player, cc)) {
if (cc.vehiclePreventDestroyOwn) {
event.setCancelled(true);
player.sendMessage(ChatColor.DARK_RED + "Destroying your own vehicle is disabled.");
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVehicleDestroy(final VehicleDestroyEvent event) {
final Entity entity = event.getVehicle().getPassenger();
if (!(entity instanceof Player)) return;
onPlayerVehicleLeave((Player) entity, event.getVehicle());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerVehicleEnter(final VehicleEnterEvent event) {
final Entity entity = event.getEntered();
if (!(entity instanceof Player)) {
return;
}
final Player player = (Player) entity;
final MovingData data = MovingData.getData(player);
data.joinOrRespawn = false;
data.removeAllVelocity();
// Event should have a vehicle, in case check this last.
data.vehicleConsistency = MoveConsistency.getConsistency(event.getVehicle().getLocation(), null, player.getLocation(useLoc));
useLoc.setWorld(null); // TODO: A pool ?
// TODO: more resetting, visible check ?
}
/**
* Call on leaving or just having left a vehicle.
* @param player
* @param vehicle May be null in case of "not possible to determine".
*/
private void onPlayerVehicleLeave(final Player player, final Entity vehicle) {
final MovingData data = MovingData.getData(player);
data.wasInVehicle = false;
data.joinOrRespawn = false;
// if (data.morePacketsVehicleTaskId != -1) {
// // Await set-back.
// // TODO: might still set ordinary set-backs ?
// return;
// }
final MovingConfig cc = MovingConfig.getConfig(player);
// TODO: Loc can be inconsistent, determine which to use !
final Location pLoc = player.getLocation(useLoc);
Location loc = pLoc; // The location to use as set-back.
// TODO: Which vehicle to use ?
// final Entity vehicle = player.getVehicle();
if (vehicle != null) {
final Location vLoc = vehicle.getLocation();
// Workaround for some entities/animals that don't fire VehicleMoveEventS.
if (!normalVehicles.contains(vehicle.getType()) || cc.noFallVehicleReset) {
data.noFallSkipAirCheck = true; // Might allow one time cheat.
data.clearNoFallData();
}
// Check consistency with vehicle location.
if (MoveConsistency.getConsistency(vLoc, null, pLoc) == MoveConsistency.INCONSISTENT) {
// TODO: Consider teleporting the player (...)
// TODO: What with the case of vehicle moved to another world !?
loc = vLoc; //
if (data.vehicleConsistency != MoveConsistency.INCONSISTENT) {
final MoveData lastMove = data.moveData.getFirst();
if (lastMove.toIsValid) {
final Location oldLoc = new Location(pLoc.getWorld(), lastMove.to.x, lastMove.to.y, lastMove.to.z);
if (MoveConsistency.getConsistency(oldLoc, null, pLoc) != MoveConsistency.INCONSISTENT) {
loc = oldLoc;
}
}
}
}
if (data.debug) {
debug(player, "Vehicle leave: " + vehicle.getType() + "@" + pLoc.distance(vLoc));
}
}
// Adjust loc if in liquid (meant for boats !?).
if (BlockProperties.isLiquid(loc.getBlock().getType())) {
loc.setY(Location.locToBlock(loc.getY()) + 1.25);
}
if (data.debug) {
debug(player, "Vehicle leave: " + pLoc.toString() + (pLoc.equals(loc) ? "" : " / player at: " + pLoc.toString()));
}
resetPositionsAndMediumProperties(player, loc, data, cc);
data.setSetBack(loc);
// Give some freedom to allow the "exiting move".
data.removeAllVelocity();
// TODO: Use-once entries usually are intended to allow one offset, but not jumping/flying on.
data.addHorizontalVelocity(new AccountEntry(0.9, 1, 1));
data.addVerticalVelocity(new SimpleEntry(0.6, 1)); // TODO: Typical margin?
useLoc.setWorld(null);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerToggleSneak(final PlayerToggleSneakEvent event) {
survivalFly.setReallySneaking(event.getPlayer(), event.isSneaking());
@ -1958,17 +1637,17 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
final MovingData data = MovingData.getData(player);
final MovingConfig cc = MovingConfig.getConfig(player);
final MoveInfo moveInfo = useMoveInfo();
final MoveInfo moveInfo = aux.useMoveInfo();
final Location loc = player.getLocation(useLoc);
moveInfo.set(player, loc, null, cc.yOnGround);
// TODO: data.isVelocityJumpPhase() might be too harsh, but prevents too easy abuse.
if (!MovingUtil.shouldCheckSurvivalFly(player, moveInfo.from, data, cc) || data.isVelocityJumpPhase() ||
BlockProperties.isOnGroundOrResetCond(player, loc, cc.yOnGround)) {
useLoc.setWorld(null);
returnMoveInfo(moveInfo);
aux.returnMoveInfo(moveInfo);
return;
}
returnMoveInfo(moveInfo);
aux.returnMoveInfo(moveInfo);
useLoc.setWorld(null);
// TODO: Configurable.
// TODO: Confine to minimum activation ticks.
@ -2006,7 +1685,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Only check every so and so ticks.
return;
}
final MoveInfo info = useMoveInfo();
final MoveInfo info = aux.useMoveInfo();
for (final String playerName : hoverTicks) {
// TODO: put players into the set (+- one tick would not matter ?)
// TODO: might add an online flag to data !
@ -2049,7 +1728,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
hoverTicks.removeAll(rem);
rem.clear();
returnMoveInfo(info);
aux.returnMoveInfo(info);
useLoc.setWorld(null);
}
@ -2098,7 +1777,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
else {
if (data.sfHoverTicks > cc.sfHoverTicks) {
// Re-Check if survivalfly can apply at all.
final MoveInfo moveInfo = useMoveInfo();
final MoveInfo moveInfo = aux.useMoveInfo();
moveInfo.set(player, loc, null, cc.yOnGround);
if (MovingUtil.shouldCheckSurvivalFly(player, moveInfo.from, data, cc)) {
handleHoverViolation(player, loc, cc, data);
@ -2111,7 +1790,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
res = false;
data.sfHoverTicks = 0;
}
returnMoveInfo(moveInfo);
aux.returnMoveInfo(moveInfo);
}
else res = false;
}
@ -2146,16 +1825,12 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
public void removeAllData() {
hoverTicks.clear();
playersEnforce.clear();
parkedInfo.clear();
aux.clear();
}
@Override
public void onReload() {
for (final MoveInfo info : parkedInfo) {
// Just in case.
info.cleanup();
}
parkedInfo.clear();
aux.clear();
hoverTicksStep = Math.max(1, ConfigManager.getConfigFile().getInt(ConfPaths.MOVING_SURVIVALFLY_HOVER_STEP));
MovingData.onReload();
}
@ -2228,31 +1903,4 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
}
/**
* Intended for vehicle-move events.
*
* @param player
* @param vehicle
* @param from
* @param to
* @param fake true if the event was not fired by an external source (just gets noted).
*/
private void outputDebugVehicleMove(final Player player, final Entity vehicle, final Location from, final Location to, final boolean fake) {
final StringBuilder builder = new StringBuilder(250);
final Location vLoc = vehicle.getLocation();
final Location loc = player.getLocation();
// TODO: Differentiate debug levels (needs setting up some policy + document in BuildParamteres)?
final Entity actualVehicle = player.getVehicle();
final boolean wrongVehicle = actualVehicle == null || actualVehicle.getEntityId() != vehicle.getEntityId();
builder.append(CheckUtils.getLogMessagePrefix(player, checkType));
builder.append("VEHICLE MOVE " + (fake ? "(fake)" : "") + " in world " + from.getWorld().getName() + ":\n");
DebugUtil.addMove(from, to, null, builder);
builder.append("\n Vehicle: ");
DebugUtil.addLocation(vLoc, builder);
builder.append("\n Player: ");
DebugUtil.addLocation(loc, builder);
builder.append("\n Vehicle type: " + vehicle.getType() + (wrongVehicle ? (actualVehicle == null ? " (exited?)" : " actual: " + actualVehicle.getType()) : ""));
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, builder.toString());
}
}

View File

@ -0,0 +1,91 @@
package fr.neatmonster.nocheatplus.checks.moving.util;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
import fr.neatmonster.nocheatplus.checks.moving.locations.MoveInfo;
import fr.neatmonster.nocheatplus.compat.MCAccess;
import fr.neatmonster.nocheatplus.components.IRegisterAsGenericInstance;
import fr.neatmonster.nocheatplus.components.MCAccessHolder;
/**
* Non-static utility, (to be) registered as generic instance.
*
* @author asofold
*
*/
public class AuxMoving implements MCAccessHolder, IRegisterAsGenericInstance {
// TODO: Move more non-static stuff here.
private MCAccess mcAccess = null;
/**
* Unused instances.<br>
* Might be better due to cascading events in case of actions or plugins doing strange things.
*/
private final List<MoveInfo> parkedInfo = new ArrayList<MoveInfo>(10);
public MoveInfo useMoveInfo() {
if (parkedInfo.isEmpty()) {
return new MoveInfo(mcAccess);
}
else {
return parkedInfo.remove(parkedInfo.size() - 1);
}
}
/**
* Cleanup and add to parked.
* @param moveInfo
*/
public void returnMoveInfo(final MoveInfo moveInfo) {
moveInfo.cleanup();
parkedInfo.add(moveInfo);
}
/**
* Convenience method to do both data.resetPositions and
* data.adjustMediumProperties, wrapping given loc with a PlayerLocation
* instance.
*
* @param player
* @param loc
* @param data
* @param cc
*/
public void resetPositionsAndMediumProperties(final Player player, final Location loc, final MovingData data, final MovingConfig cc) {
final MoveInfo moveInfo = useMoveInfo();
moveInfo.set(player, loc, null, cc.yOnGround);
data.resetPositions(moveInfo.from);
data.adjustMediumProperties(moveInfo.from);
returnMoveInfo(moveInfo);
}
@Override
public void setMCAccess(MCAccess mcAccess) {
this.mcAccess = mcAccess;
}
@Override
public MCAccess getMCAccess() {
return mcAccess;
}
/**
* Clear parked MovingInfo instances. Called on reload and data removal.
*/
public void clear() {
// Call cleanup on all parked info, just in case.
for (final MoveInfo info : parkedInfo) {
info.cleanup();
}
parkedInfo.clear();
}
}

View File

@ -1,4 +1,4 @@
package fr.neatmonster.nocheatplus.checks.moving;
package fr.neatmonster.nocheatplus.checks.moving.vehicle;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -8,6 +8,8 @@ import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
/**
* This check does the exact same thing as the MorePacket check but this one works for players inside vehicles.
@ -25,7 +27,7 @@ public class MorePacketsVehicle extends Check {
* Instantiates a new more packet vehicle check.
*/
public MorePacketsVehicle() {
super(CheckType.MOVING_MOREPACKETSVEHICLE);
super(CheckType.MOVING_VEHICLE_MOREPACKETS);
}
/**

View File

@ -0,0 +1,360 @@
package fr.neatmonster.nocheatplus.checks.moving.vehicle;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.event.vehicle.VehicleExitEvent;
import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.bukkit.plugin.Plugin;
import fr.neatmonster.nocheatplus.NCPAPIProvider;
import fr.neatmonster.nocheatplus.checks.CheckListener;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
import fr.neatmonster.nocheatplus.checks.moving.locations.VehicleSetBack;
import fr.neatmonster.nocheatplus.checks.moving.model.MoveConsistency;
import fr.neatmonster.nocheatplus.checks.moving.model.MoveData;
import fr.neatmonster.nocheatplus.checks.moving.util.AuxMoving;
import fr.neatmonster.nocheatplus.checks.moving.velocity.AccountEntry;
import fr.neatmonster.nocheatplus.checks.moving.velocity.SimpleEntry;
import fr.neatmonster.nocheatplus.logging.StaticLog;
import fr.neatmonster.nocheatplus.logging.Streams;
import fr.neatmonster.nocheatplus.logging.debug.DebugUtil;
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
/**
* Aggregate vehicle checks (moving, a player is somewhere above in the
* hierarchy of passengers).
*
* @author asofold
*
*/
public class VehicleChecks extends CheckListener {
/** The instance of NoCheatPlus. */
private final Plugin plugin = Bukkit.getPluginManager().getPlugin("NoCheatPlus"); // TODO
/** The more packets vehicle check. */
private final MorePacketsVehicle morePacketsVehicle = addCheck(new MorePacketsVehicle());
private final Set<EntityType> normalVehicles = new HashSet<EntityType>();
/** Temporary use, reset world to null afterwards, avoid nesting. */
private final Location useLoc = new Location(null, 0, 0, 0);
/** Auxiliary functionality. */
private final AuxMoving aux = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(AuxMoving.class);
public VehicleChecks() {
super(CheckType.MOVING_VEHICLE);
}
/**
* When a vehicle moves, its player will be checked for various suspicious behaviors.
*
* @param event
* the event
*/
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onVehicleMove(final VehicleMoveEvent event) {
final Vehicle vehicle = event.getVehicle();
final EntityType entityType = vehicle.getType();
if (!normalVehicles.contains(entityType)) {
// A little extra sweep to check for debug flags.
normalVehicles.add(entityType);
if (MovingConfig.getConfig(vehicle.getWorld().getName()).debug) {
debug(null, "VehicleMoveEvent fired for: " + entityType);
}
}
// TODO: Might account for the case of a player letting the vehicle move but not themselves (do mind latency).
// Mind that players could be riding horses inside of minecarts etc.
if (vehicle.getVehicle() != null) {
// Do ignore events for vehicles inside of other vehicles.
return;
}
onVehicleMove(vehicle, event.getFrom(), event.getTo(), false);
}
public void onVehicleMove(final Entity vehicle, final Location from, final Location to, final boolean fake) {
// (No re-check for vehicles that have vehicles, pre condition is that this has already been checked.)
final Player player = CheckUtils.getFirstPlayerPassenger(vehicle);
if (player == null) {
return;
}
if (vehicle.isDead() || !vehicle.isValid()) {
onPlayerVehicleLeave(player, vehicle);
return;
}
if (!from.getWorld().equals(to.getWorld())) return;
final MovingData data = MovingData.getData(player);
final MovingConfig cc = MovingConfig.getConfig(player);
data.joinOrRespawn = false;
data.vehicleConsistency = MoveConsistency.getConsistency(from, to, player.getLocation(useLoc));
switch (data.vehicleConsistency) {
case FROM:
case TO:
aux.resetPositionsAndMediumProperties(player, player.getLocation(useLoc), data, cc); // TODO: Drop MC 1.4!
break;
case INCONSISTENT:
// TODO: Any exploits exist? -> TeleportUtil.forceMount(player, vehicle)
// TODO: Test with latency.
break;
}
Location newTo = null;
data.sfNoLowJump = true;
if (cc.noFallVehicleReset) {
// Reset noFall data.
data.noFallSkipAirCheck = true; // Might allow one time cheat.
data.sfLowJump = false;
data.clearNoFallData();
}
if (data.debug) {
// Log move.
outputDebugVehicleMove(player, vehicle, from, to, fake);
}
if (morePacketsVehicle.isEnabled(player, data, cc)) {
// If the player is handled by the more packets vehicle check, execute it.
newTo = morePacketsVehicle.check(player, from, to, data, cc);
}
else {
// Otherwise we need to clear their data.
data.clearMorePacketsData();
}
// Schedule a set-back?
if (newTo != null && data.morePacketsVehicleTaskId == -1) {
// Schedule a delayed task to teleport back the vehicle with the player.
// (Only schedule if not already scheduled.)
// TODO: Might log debug if skipping.
// TODO: Problem: scheduling allows a lot of things to happen until the task is run. Thus control about some things might be necessary.
// TODO: Reset on world changes or not?
data.morePacketsVehicleTaskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new VehicleSetBack(vehicle, player, newTo, data.debug));
}
useLoc.setWorld(null);
}
/**
* Called from player-move checking, if the player is inside of a vehicle.
* @param player
* @param from
* @param to
* @param data
*/
public Location onPlayerMoveVehicle(final Player player, final Location from, final Location to, final MovingData data) {
// Workaround for pigs and other (1.5.x and before)!
// Note that with 1.6 not even PlayerMove fires for horses and pigs.
// (isInsideVehicle is the faster check without object creation, do re-check though, if it changes to only check for Vehicle instances.)
final Entity vehicle = CheckUtils.getLastNonPlayerVehicle(player);
data.wasInVehicle = true;
data.sfHoverTicks = -1;
data.removeAllVelocity();
data.sfLowJump = false;
// TODO: What with processingEvents.remove(player.getName());
if (vehicle != null) {
final Location vLoc = vehicle.getLocation(); // TODO: Use a location as argument.
// (Auto detection of missing events, might fire one time too many per plugin run.)
if (!normalVehicles.contains(vehicle.getType())) {
onVehicleMove(vehicle, vLoc, vLoc, true);
return null;
} else {
data.vehicleConsistency = MoveConsistency.getConsistency(from, to, vLoc);
// TODO: Consider TeleportUtil.forceMount or similar.
final MovingConfig cc = MovingConfig.getConfig(player);
if (data.vehicleConsistency == MoveConsistency.INCONSISTENT) {
if (cc.vehicleEnforceLocation) {
return vLoc;
} else {
return null;
}
} else {
aux.resetPositionsAndMediumProperties(player, vLoc, data, cc);
return null;
}
}
}
return null;
}
/**
* Called from player-move checking, if vehicle-leave has not been called after entering, but the player is not inside of a vehicle anymore.
* @param player
* @param data
* @param cc
*/
public void onVehicleLeaveMiss(final Player player, final MovingData data, final MovingConfig cc) {
if (data.debug) {
StaticLog.logWarning("VehicleExitEvent missing for: " + player.getName());
}
onPlayerVehicleLeave(player, null);
// if (BlockProperties.isRails(pFrom.getTypeId())) {
// Always clear no fall data, let Minecraft do fall damage.
data.noFallSkipAirCheck = true; // Might allow one time cheat.
data.sfLowJump = false;
data.clearNoFallData();
// TODO: What with processingEvents.remove(player.getName());
// }
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVehicleExit(final VehicleExitEvent event) {
final Entity entity = event.getExited();
if (!(entity instanceof Player)) {
return;
}
onPlayerVehicleLeave((Player) entity, event.getVehicle());
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onVehicleDestroyLowest(final VehicleDestroyEvent event) {
// Prevent destroying ones own vehicle.
final Entity attacker = event.getAttacker();
if (attacker instanceof Player && attacker.equals(event.getVehicle().getPassenger())) {
final Player player = (Player) attacker;
final MovingData data = MovingData.getData(player);
final MovingConfig cc = MovingConfig.getConfig(player);
if (cc.vehiclePreventDestroyOwn) {
if (CheckUtils.isEnabled(CheckType.MOVING_SURVIVALFLY, player, data, cc)
|| CheckUtils.isEnabled(CheckType.MOVING_CREATIVEFLY, player, data, cc)) {
}
event.setCancelled(true);
player.sendMessage(ChatColor.DARK_RED + "Destroying your own vehicle is disabled.");
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVehicleDestroy(final VehicleDestroyEvent event) {
final Entity entity = event.getVehicle().getPassenger();
if (!(entity instanceof Player)) return;
onPlayerVehicleLeave((Player) entity, event.getVehicle());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerVehicleEnter(final VehicleEnterEvent event) {
final Entity entity = event.getEntered();
if (!(entity instanceof Player)) {
return;
}
final Player player = (Player) entity;
final MovingData data = MovingData.getData(player);
data.joinOrRespawn = false;
data.removeAllVelocity();
// Event should have a vehicle, in case check this last.
data.vehicleConsistency = MoveConsistency.getConsistency(event.getVehicle().getLocation(), null, player.getLocation(useLoc));
useLoc.setWorld(null); // TODO: A pool ?
// TODO: more resetting, visible check ?
}
/**
* Call on leaving or just having left a vehicle.
* @param player
* @param vehicle May be null in case of "not possible to determine".
*/
private void onPlayerVehicleLeave(final Player player, final Entity vehicle) {
final MovingData data = MovingData.getData(player);
data.wasInVehicle = false;
data.joinOrRespawn = false;
// if (data.morePacketsVehicleTaskId != -1) {
// // Await set-back.
// // TODO: might still set ordinary set-backs ?
// return;
// }
final MovingConfig cc = MovingConfig.getConfig(player);
// TODO: Loc can be inconsistent, determine which to use !
final Location pLoc = player.getLocation(useLoc);
Location loc = pLoc; // The location to use as set-back.
// TODO: Which vehicle to use ?
// final Entity vehicle = player.getVehicle();
if (vehicle != null) {
final Location vLoc = vehicle.getLocation();
// Workaround for some entities/animals that don't fire VehicleMoveEventS.
if (!normalVehicles.contains(vehicle.getType()) || cc.noFallVehicleReset) {
data.noFallSkipAirCheck = true; // Might allow one time cheat.
data.clearNoFallData();
}
// Check consistency with vehicle location.
if (MoveConsistency.getConsistency(vLoc, null, pLoc) == MoveConsistency.INCONSISTENT) {
// TODO: Consider teleporting the player (...)
// TODO: What with the case of vehicle moved to another world !?
loc = vLoc; //
if (data.vehicleConsistency != MoveConsistency.INCONSISTENT) {
final MoveData lastMove = data.moveData.getFirst();
if (lastMove.toIsValid) {
final Location oldLoc = new Location(pLoc.getWorld(), lastMove.to.x, lastMove.to.y, lastMove.to.z);
if (MoveConsistency.getConsistency(oldLoc, null, pLoc) != MoveConsistency.INCONSISTENT) {
loc = oldLoc;
}
}
}
}
if (data.debug) {
debug(player, "Vehicle leave: " + vehicle.getType() + "@" + pLoc.distance(vLoc));
}
}
// Adjust loc if in liquid (meant for boats !?).
if (BlockProperties.isLiquid(loc.getBlock().getType())) {
loc.setY(Location.locToBlock(loc.getY()) + 1.25);
}
if (data.debug) {
debug(player, "Vehicle leave: " + pLoc.toString() + (pLoc.equals(loc) ? "" : " / player at: " + pLoc.toString()));
}
aux.resetPositionsAndMediumProperties(player, loc, data, cc);
data.setSetBack(loc);
// Give some freedom to allow the "exiting move".
data.removeAllVelocity();
// TODO: Use-once entries usually are intended to allow one offset, but not jumping/flying on.
data.addHorizontalVelocity(new AccountEntry(0.9, 1, 1));
data.addVerticalVelocity(new SimpleEntry(0.6, 1)); // TODO: Typical margin?
useLoc.setWorld(null);
}
/**
* Intended for vehicle-move events.
*
* @param player
* @param vehicle
* @param from
* @param to
* @param fake true if the event was not fired by an external source (just gets noted).
*/
private void outputDebugVehicleMove(final Player player, final Entity vehicle, final Location from, final Location to, final boolean fake) {
final StringBuilder builder = new StringBuilder(250);
final Location vLoc = vehicle.getLocation();
final Location loc = player.getLocation();
// TODO: Differentiate debug levels (needs setting up some policy + document in BuildParamteres)?
final Entity actualVehicle = player.getVehicle();
final boolean wrongVehicle = actualVehicle == null || actualVehicle.getEntityId() != vehicle.getEntityId();
builder.append(CheckUtils.getLogMessagePrefix(player, checkType));
builder.append("VEHICLE MOVE " + (fake ? "(fake)" : "") + " in world " + from.getWorld().getName() + ":\n");
DebugUtil.addMove(from, to, null, builder);
builder.append("\n Vehicle: ");
DebugUtil.addLocation(vLoc, builder);
builder.append("\n Player: ");
DebugUtil.addLocation(loc, builder);
builder.append("\n Vehicle type: " + vehicle.getType() + (wrongVehicle ? (actualVehicle == null ? " (exited?)" : " actual: " + actualVehicle.getType()) : ""));
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, builder.toString());
}
}

View File

@ -0,0 +1,10 @@
package fr.neatmonster.nocheatplus.components;
/**
* Register this instance as generic instance (for the class of this instance).
*
* @author asofold
*
*/
public interface IRegisterAsGenericInstance {
}

View File

@ -556,10 +556,6 @@ public abstract class ConfPaths {
public static final String MOVING_MOREPACKETS_BURST_EPM = MOVING_MOREPACKETS_BURST + "epmviolation";
public static final String MOVING_MOREPACKETS_ACTIONS = MOVING_MOREPACKETS + "actions";
private static final String MOVING_MOREPACKETSVEHICLE = MOVING + "morepacketsvehicle.";
public static final String MOVING_MOREPACKETSVEHICLE_CHECK = MOVING_MOREPACKETSVEHICLE + "active";
public static final String MOVING_MOREPACKETSVEHICLE_ACTIONS = MOVING_MOREPACKETSVEHICLE + "actions";
private static final String MOVING_NOFALL = MOVING + "nofall.";
public static final String MOVING_NOFALL_CHECK = MOVING_NOFALL + "active";
public static final String MOVING_NOFALL_DEALDAMAGE = MOVING_NOFALL + "dealdamage";
@ -617,7 +613,7 @@ public abstract class ConfPaths {
private static final String MOVING_VELOCITY = MOVING + "velocity.";
public static final String MOVING_VELOCITY_ACTIVATIONCOUNTER = MOVING_VELOCITY + "activationcounter";
public static final String MOVING_VELOCITY_ACTIVATIONTICKS = MOVING_VELOCITY + "activationticks";
public static final String MOVING_VELOCITY_STRICTINVALIDATION = MOVING_VELOCITY + "strictinvalidation";
public static final String MOVING_VELOCITY_STRICTINVALIDATION = MOVING_VELOCITY + "strictinvalidation";
public static final String MOVING_NOFALL_YONGROUND = MOVING_NOFALL + "yonground";
public static final String MOVING_YONGROUND = MOVING + "yonground";
@ -635,14 +631,17 @@ public abstract class ConfPaths {
public static final String MOVING_SPEEDGRACE = MOVING + "speedgrace";
public static final String MOVING_ENFORCELOCATION = MOVING + "enforcelocation";
private static final String MOVING_VEHICLES = MOVING + "vehicles.";
public static final String MOVING_VEHICLES_ENFORCELOCATION = MOVING_VEHICLES + "enforcelocation";
public static final String MOVING_VEHICLES_PREVENTDESTROYOWN = MOVING_VEHICLES + "preventdestroyown";
private static final String MOVING_TRACE = MOVING + "trace.";
public static final String MOVING_TRACE_SIZE = MOVING_TRACE + "size";
public static final String MOVING_TRACE_MERGEDIST = MOVING_TRACE + "mergedist";
private static final String MOVING_VEHICLE = MOVING + "vehicle.";
public static final String MOVING_VEHICLE_ENFORCELOCATION = MOVING_VEHICLE + "enforcelocation";
public static final String MOVING_VEHICLE_PREVENTDESTROYOWN = MOVING_VEHICLE + "preventdestroyown";
private static final String MOVING_VEHICLE_MOREPACKETS = MOVING_VEHICLE + "morepackets.";
public static final String MOVING_VEHICLE_MOREPACKETS_CHECK = MOVING_VEHICLE_MOREPACKETS + "active";
public static final String MOVING_VEHICLE_MOREPACKETS_ACTIONS = MOVING_VEHICLE_MOREPACKETS + "actions";
public static final String NET = CHECKS + "net.";
private static final String NET_ATTACKFREQUENCY = NET + "attackfrequency.";
@ -740,6 +739,14 @@ public abstract class ConfPaths {
public static final String MOVING_CREATIVEFLY_MAXHEIGHT = "checks.moving.creativefly.maxheight";
@Moved(newPath = MOVING_SURVIVALFLY_SETBACKPOLICY_FALLDAMAGE)
public static final String MOVING_SURVIVALFLY_FALLDAMAGE = "checks.moving.survivalfly.falldamage";
@Moved(newPath=MOVING_VEHICLE_ENFORCELOCATION)
public static final String MOVING_VEHICLES_ENFORCELOCATION = "checks.moving.vehicles.enforcelocation";
@Moved(newPath=MOVING_VEHICLE_PREVENTDESTROYOWN)
public static final String MOVING_VEHICLES_PREVENTDESTROYOWN = "checks.moving.vehicles.preventdestroyown";
@Moved(newPath=MOVING_VEHICLE_MOREPACKETS_CHECK)
public static final String MOVING_MOREPACKETSVEHICLE_CHECK = "checks.moving.morepacketsvehicle.active";
@Moved(newPath=MOVING_VEHICLE_MOREPACKETS_ACTIONS)
public static final String MOVING_MOREPACKETSVEHICLE_ACTIONS = "checks.moving.morepacketsvehicle.actions";
// Deprecated paths (just removed).
@Deprecated
public static final String MISCELLANEOUS_REPORTTOMETRICS = "miscellaneous.reporttometrics";

View File

@ -122,7 +122,6 @@ public class Permissions {
public static final String MOVING = CHECKS + ".moving";
public static final String MOVING_CREATIVEFLY = MOVING + ".creativefly";
public static final String MOVING_MOREPACKETS = MOVING + ".morepackets";
public static final String MOVING_MOREPACKETSVEHICLE = MOVING + ".morepacketsvehicle";
public static final String MOVING_NOFALL = MOVING + ".nofall";
public static final String MOVING_PASSABLE = MOVING + ".passable";
public static final String MOVING_SURVIVALFLY = MOVING + ".survivalfly";
@ -131,6 +130,8 @@ public class Permissions {
public static final String MOVING_SURVIVALFLY_SPEEDING = MOVING_SURVIVALFLY + ".speeding";
public static final String MOVING_SURVIVALFLY_SPRINTING = MOVING_SURVIVALFLY + ".sprinting";
public static final String MOVING_SURVIVALFLY_STEP = MOVING_SURVIVALFLY + ".step";
public static final String MOVING_VEHICLE = MOVING + ".vehicle";
public static final String MOVING_VEHICLE_MOREPACKETS = MOVING_VEHICLE + ".morepackets";
// Permissions for the individual client mods.
private static final String MODS = NOCHEATPLUS + ".mods";

View File

@ -46,6 +46,7 @@ import fr.neatmonster.nocheatplus.checks.combined.CombinedListener;
import fr.neatmonster.nocheatplus.checks.fight.FightListener;
import fr.neatmonster.nocheatplus.checks.inventory.InventoryListener;
import fr.neatmonster.nocheatplus.checks.moving.MovingListener;
import fr.neatmonster.nocheatplus.checks.moving.util.AuxMoving;
import fr.neatmonster.nocheatplus.checks.workaround.WRPT;
import fr.neatmonster.nocheatplus.clients.ModUtil;
import fr.neatmonster.nocheatplus.command.NoCheatPlusCommand;
@ -68,6 +69,7 @@ import fr.neatmonster.nocheatplus.components.DisableListener;
import fr.neatmonster.nocheatplus.components.IHoldSubComponents;
import fr.neatmonster.nocheatplus.components.INeedConfig;
import fr.neatmonster.nocheatplus.components.INotifyReload;
import fr.neatmonster.nocheatplus.components.IRegisterAsGenericInstance;
import fr.neatmonster.nocheatplus.components.JoinLeaveListener;
import fr.neatmonster.nocheatplus.components.MCAccessHolder;
import fr.neatmonster.nocheatplus.components.NCPListener;
@ -433,13 +435,24 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
public boolean addComponent(final Object obj, final boolean allowComponentRegistry) {
// TODO: Allow to add ComponentFactory + contract (renew with reload etc.)?
if (obj == this) throw new IllegalArgumentException("Can not register NoCheatPlus with itself.");
if (obj == this) {
throw new IllegalArgumentException("Can not register NoCheatPlus with itself.");
}
// Don't register twice.
if (allComponents.contains(obj)) {
// All added components are in here.
return false;
}
boolean added = false;
// First register generic instances.
if (obj instanceof IRegisterAsGenericInstance) {
registerGenericInstance(obj);
}
// Other types.
if (obj instanceof Listener) {
addListener((Listener) obj);
added = true;
@ -500,7 +513,9 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
}
// Add to allComponents if in fact added.
if (added) allComponents.add(obj);
if (added) {
allComponents.add(obj);
}
return added;
}
@ -885,6 +900,7 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
// Put ReloadListener first, because Checks could also listen to it.
new ReloadHook(),
dataMan,
new AuxMoving(),
}) {
addComponent(obj);
// Register sub-components (allow later added to use registries, if any).

View File

@ -165,7 +165,9 @@ permissions:
nocheatplus.checks.moving.morepackets:
description: Allow the player to bypass the MorePackets check.
nocheatplus.checks.moving.morepacketsvehicle:
description: Allow the player to bypass the MorePacketsVehicle check.
description: "Legacy permission! Use instead: nocheatplus.checks.moving.vehicle.morepackets"
children:
nocheatplus.checks.moving.vehicle.morepackets: true
nocheatplus.checks.moving.nofall:
description: Allow the player to bypass the NoFall check.
nocheatplus.checks.moving.passable:
@ -183,6 +185,11 @@ permissions:
description: Allow the player to sprint backwards.
nocheatplus.checks.moving.survivalfly.step:
description: Allow the player to use the 'step' functionality of his client.
nocheatplus.checks.moving.vehicle:
description: Allow bypassing all checks for players moving as passengers of vehicles/other.
children:
nocheatplus.checks.moving.vehicle.morepackets:
description: Allow bypassing the morepackets check for vehicles.
nocheatplus.checks.net:
description: Allow a player to bypass the net (packet) checks.
children: