[BLEEDING] Add the capability to load chunks on moving and teleporting.

Except with join/respawn, the methods will not load chunks if close by
past moves have extra properties set, assuming the chunks are already
loaded then.
This commit is contained in:
asofold 2016-06-12 20:07:01 +02:00
parent 3bfd3a7aff
commit 245f5389a0
6 changed files with 137 additions and 11 deletions

View File

@ -186,6 +186,9 @@ public class MovingConfig extends ACheckConfig {
public final boolean ignoreStance;
public final boolean tempKickIllegal;
public final boolean loadChunksOnJoin;
public final boolean loadChunksOnMove;
public final boolean loadChunksOnTeleport;
public final boolean loadChunksOnWorldChange;
public final long sprintingGrace;
public final boolean assumeSprint;
public final int speedGrace;
@ -308,6 +311,9 @@ public class MovingConfig extends ACheckConfig {
ignoreStance = refIgnoreStance == AlmostBoolean.MAYBE ? ServerVersion.compareMinecraftVersion("1.8") >= 0 : refIgnoreStance.decide();
tempKickIllegal = config.getBoolean(ConfPaths.MOVING_TEMPKICKILLEGAL);
loadChunksOnJoin = config.getBoolean(ConfPaths.MOVING_LOADCHUNKS_JOIN);
loadChunksOnMove = config.getBoolean(ConfPaths.MOVING_LOADCHUNKS_MOVE);
loadChunksOnTeleport = config.getBoolean(ConfPaths.MOVING_LOADCHUNKS_TELEPORT);
loadChunksOnWorldChange = config.getBoolean(ConfPaths.MOVING_LOADCHUNKS_WORLDCHANGE);
sprintingGrace = Math.max(0L, (long) (config.getDouble(ConfPaths.MOVING_SPRINTINGGRACE) * 1000.0)); // Config: seconds.
assumeSprint = config.getBoolean(ConfPaths.MOVING_ASSUMESPRINT);
speedGrace = Math.max(0, (int) Math.round(config.getDouble(ConfPaths.MOVING_SPEEDGRACE) * 20.0)); // Config: seconds

View File

@ -308,6 +308,9 @@ 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);
if (cc.loadChunksOnWorldChange) {
ensureChunksLoaded(player, loc, "world change", data, cc);
}
aux.resetPositionsAndMediumProperties(player, loc, data, cc);
data.resetTrace(loc, TickTask.getTick(), cc);
if (cc.enforceLocation) {
@ -423,6 +426,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final PlayerMoveInfo moveInfo = aux.usePlayerMoveInfo();
final Location loc = player.getLocation(moveInfo.useLoc);
final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
if (cc.loadChunksOnMove) {
ensureChunksLoaded(player, from, to, lastMove, data, cc);
}
// TODO: On pistons pulling the player back: -1.15 yDistance for split move 1 (untracked position > 0.5 yDistance!).
if (
// Handling split moves has been disabled.
@ -463,6 +469,89 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
aux.returnPlayerMoveInfo(moveInfo);
}
/**
* Ensure chunks are loaded so that the move can be processed at all. Assume
* too big moves to be cancelled anyway and/or passable accounting for chunk
* load.
*
* @param from
* @param to
* @param lastMove
* @param data
* @param cc
*/
private void ensureChunksLoaded(final Player player, final Location from, final Location to, final PlayerMoveData lastMove,
final MovingData data, final MovingConfig cc) {
// (Worlds must be equal. Ensured in player move handling.)
final double x0 = from.getX();
final double z0 = from.getZ();
final double x1 = to.getX();
final double z1 = to.getZ();
if (TrigUtil.distanceSquared(x0, z0, x1, z1) > 2.0 * Magic.CHUNK_LOAD_MARGIN_MIN) {
// Assume extreme move to trigger.
return;
}
boolean loadFrom = true;
boolean loadTo = true;
double margin = Magic.CHUNK_LOAD_MARGIN_MIN;
// Heuristic for if loading may be necessary at all.
if (lastMove.toIsValid && lastMove.to.extraPropertiesValid) {
if (TrigUtil.distanceSquared(lastMove.to, x0, z0) < 1.0) {
loadFrom = false;
}
if (TrigUtil.distanceSquared(lastMove.to, x1, z1) < 1.0) {
loadTo = false;
}
}
else if (lastMove.valid && lastMove.from.extraPropertiesValid
&& cc.loadChunksOnJoin) {
// TODO: Might need to distinguish join/teleport/world-change later.
if (TrigUtil.distanceSquared(lastMove.from, x0, z0) < 1.0) {
loadFrom = false;
}
if (TrigUtil.distanceSquared(lastMove.from, x1, z1) < 1.0) {
loadTo = false;
}
}
int loaded = 0;
if (loadFrom) {
loaded += BlockCache.ensureChunksLoaded(from.getWorld(), x0, z0, margin);
if (TrigUtil.distanceSquared(x0, z0, x1, z1) < 1.0) {
loadTo = false;
}
}
if (loadTo) {
loaded += BlockCache.ensureChunksLoaded(to.getWorld(), x1, z1, margin);
}
if (loaded > 0 && data.debug) {
StaticLog.logInfo("Player move: Loaded " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + from.getWorld().getName() + " for player: " + player.getName());
}
}
private void ensureChunksLoaded(final Player player, final Location loc, final String tag,
final MovingData data, final MovingConfig cc) {
final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
final double x0 = loc.getX();
final double z0 = loc.getZ();
// Heuristic for if loading may be necessary at all.
if (lastMove.toIsValid && lastMove.to.extraPropertiesValid) {
if (TrigUtil.distanceSquared(lastMove.to, x0, z0) < 1.0) {
return;
}
}
else if (lastMove.valid && lastMove.from.extraPropertiesValid
&& cc.loadChunksOnJoin) {
// TODO: Might need to distinguish join/teleport/world-change later.
if (TrigUtil.distanceSquared(lastMove.from, x0, z0) < 1.0) {
return;
}
}
int loaded = BlockCache.ensureChunksLoaded(loc.getWorld(), loc.getX(), loc.getZ(), Magic.CHUNK_LOAD_MARGIN_MIN);
if (loaded > 0 && data.debug) {
StaticLog.logInfo("Player " + tag + ": Loaded " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + loc.getWorld().getName() + " for player: " + player.getName());
}
}
/**
*
* @param player
@ -882,6 +971,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Horizontal move.
if (thisMove.hDistance > Magic.EXTREME_MOVE_DIST_HORIZONTAL) {
// Exclude valid moves first.
// TODO: Attributes might allow unhealthy moves as well.
// Observed maximum use so far: 5.515
// TODO: Velocity flag too (if combined with configurable distances)?
final double amount = thisMove.hDistance - data.getHorizontalFreedom(); // Will change with model change.
@ -1237,13 +1327,18 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Teleport to untracked locations.
else if (cause == TeleportCause.COMMAND) { // TODO: TeleportCause.PLUGIN?
// Attempt to prevent teleporting to players inside of blocks at untracked coordinates.
if (cc.passableUntrackedTeleportCheck && MovingUtil.shouldCheckUntrackedLocation(player, to)) {
final Location newTo = MovingUtil.checkUntrackedLocation(to);
if (newTo != null) {
// Adjust the teleport to go to the last tracked to-location of the other player.
event.setTo(newTo);
// TODO: Consider console, consider data.debug.
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.TRACE_FILE, player.getName() + " correct untracked teleport destination (" + to + " corrected to " + newTo + ").");
if (cc.passableUntrackedTeleportCheck) {
if (cc.loadChunksOnTeleport) {
ensureChunksLoaded(player, to, "teleport", data, cc);
}
if (cc.passableUntrackedTeleportCheck && MovingUtil.shouldCheckUntrackedLocation(player, to)) {
final Location newTo = MovingUtil.checkUntrackedLocation(to);
if (newTo != null) {
// Adjust the teleport to go to the last tracked to-location of the other player.
event.setTo(newTo);
// TODO: Consider console, consider data.debug.
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.TRACE_FILE, player.getName() + " correct untracked teleport destination (" + to + " corrected to " + newTo + ").");
}
}
}
}
@ -1339,6 +1434,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final Location teleported = data.getTeleported();
final PlayerMoveInfo moveInfo = aux.usePlayerMoveInfo();
moveInfo.set(player, teleported, null, cc.yOnGround);
if (cc.loadChunksOnTeleport) {
ensureChunksLoaded(player, teleported, "teleport", data, cc);
}
data.onSetBack(moveInfo.from);
aux.returnPlayerMoveInfo(moveInfo);
@ -1377,6 +1475,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.clearPlayerMorePacketsData();
data.setSetBack(to);
data.sfHoverTicks = -1; // Important against concurrent modification exception.
if (cc.loadChunksOnTeleport) {
ensureChunksLoaded(player, to, "teleport", 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) {
@ -1565,9 +1666,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final String tag = isRespawn ? "Respawn" : "Join";
// Check loaded chunks.
if (cc.loadChunksOnJoin) {
final int loaded = BlockCache.ensureChunksLoaded(loc.getWorld(), loc.getX(), loc.getZ(), 3.0);
if (loaded > 0 && data.debug && BuildParameters.debugLevel > 0) {
// DEBUG
// (Don't use past-move heuristic for skipping here.)
final int loaded = BlockCache.ensureChunksLoaded(loc.getWorld(), loc.getX(), loc.getZ(), Magic.CHUNK_LOAD_MARGIN_MIN);
if (loaded > 0 && data.debug) {
StaticLog.logInfo("Player " + tag + ": Loaded " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + loc.getWorld().getName() + " for player: " + player.getName());
}
}
@ -1854,7 +1955,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final boolean res;
// TODO: Collect flags, more margin ?
final int loaded = info.from.ensureChunksLoaded();
if (loaded > 0 && data.debug && BuildParameters.debugLevel > 0) {
if (loaded > 0 && data.debug) {
// DEBUG
StaticLog.logInfo("Hover check: Needed to load " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + loc.getWorld().getName() + " around " + loc.getBlockX() + "," + loc.getBlockZ() + " in order to check player: " + player.getName());
}

View File

@ -100,6 +100,8 @@ public class Magic {
*/
public static final double EXTREME_MOVE_DIST_VERTICAL = 4.0;
public static final double EXTREME_MOVE_DIST_HORIZONTAL = 22.0;
/** Minimal xz-margin for chunk load. */
public static final double CHUNK_LOAD_MARGIN_MIN = 3.0;
/**
* The absolute per-tick base speed for swimming vertically.

View File

@ -644,6 +644,9 @@ public abstract class ConfPaths {
// TODO: Might add a section for illegal move.
private static final String MOVING_LOADCHUNKS = MOVING + "loadchunks.";
public static final String MOVING_LOADCHUNKS_JOIN = MOVING_LOADCHUNKS + "join";
public static final String MOVING_LOADCHUNKS_MOVE = MOVING_LOADCHUNKS + "move";
public static final String MOVING_LOADCHUNKS_TELEPORT = MOVING_LOADCHUNKS + "teleport";
public static final String MOVING_LOADCHUNKS_WORLDCHANGE = MOVING_LOADCHUNKS + "worldchange";
public static final String MOVING_SPRINTINGGRACE = MOVING + "sprintinggrace";
public static final String MOVING_ASSUMESPRINT = MOVING + "assumesprint";
public static final String MOVING_SPEEDGRACE = MOVING + "speedgrace";

View File

@ -455,6 +455,9 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.MOVING_IGNORESTANCE, "default");
set(ConfPaths.MOVING_TEMPKICKILLEGAL, true);
set(ConfPaths.MOVING_LOADCHUNKS_JOIN, true);
set(ConfPaths.MOVING_LOADCHUNKS_MOVE, true);
set(ConfPaths.MOVING_LOADCHUNKS_TELEPORT, true);
set(ConfPaths.MOVING_LOADCHUNKS_WORLDCHANGE, true);
set(ConfPaths.MOVING_SPRINTINGGRACE, 2.0);
set(ConfPaths.MOVING_ASSUMESPRINT, true);
set(ConfPaths.MOVING_SPEEDGRACE, 4.0);

View File

@ -288,6 +288,17 @@ public class TrigUtil {
return distanceSquared(location1.getX(), location1.getY(), location1.getZ(), location2.getX(), location2.getY(), location2.getZ());
}
/**
* Horizontal: squared distance.
* @param location1
* @param x1
* @return
*/
public static final double distanceSquared(final IGetPosition location, final double x, final double z)
{
return distanceSquared(location.getX(), location.getZ(), x, z);
}
public static final double distanceSquared(final IGetPosition location1, final Location location2)
{
return distanceSquared(location1.getX(), location1.getY(), location1.getZ(), location2.getX(), location2.getY(), location2.getZ());