Rewrite minecraft's movement handling to move it into the main tick loop

This commit is contained in:
Thinkofdeath 2014-07-07 10:24:24 +01:00
parent 0b49f96812
commit 5fb051b619

View file

@ -0,0 +1,421 @@
From d522552c015ee9437dabb05d05e59c276ecdca43 Mon Sep 17 00:00:00 2001
From: Thinkofdeath <thinkofdeath@spigotmc.org>
Date: Fri, 4 Jul 2014 09:50:02 +0100
Subject: [PATCH] Move player ticking into the main loop
diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java
index de20c6a..108552e 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -175,7 +175,17 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
return 1.62F;
}
+ // Spigot start
+ private AxisAlignedBB groundCheck = AxisAlignedBB.a( 0, 0, 0, 0, 0, 0 );
+ public double stance;
+ private int offGroundTicks = 0;
+ private int moveHelper = 1;
+ private long lastMovementTick = System.nanoTime();
+
public void h() {
+ validateMovement();
+ // Spigot end
+
// CraftBukkit start
if (this.joining) {
this.joining = false;
@@ -254,8 +264,230 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
if (this.bX > 0L && this.server.getIdleTimeout() > 0 && MinecraftServer.ar() - this.bX > (long) (this.server.getIdleTimeout() * 1000 * 60)) {
this.playerConnection.disconnect("You have been idle for too long!");
}
+ // Spigot start
+ this.i();
+ }
+
+ private void validateMovement()
+ {
+ long currentTime = System.nanoTime();
+ if ( !playerConnection.checkMovement )
+ {
+ double diffX = Math.abs( locX - lastX );
+ double diffY = Math.abs( locY - lastY );
+ double diffZ = Math.abs( locZ - lastZ );
+ if ( diffX < 0.01 && diffY < 0.01 && diffZ < 0.01 )
+ {
+ playerConnection.checkMovement = true;
+ } else
+ {
+ playerConnection.a( lastX, lastY, lastZ, lastYaw, lastPitch );
+ }
+ MinecraftServer.getServer().getPlayerList().d( this );
+ }
+ if ( !dead && playerConnection.checkMovement )
+ {
+
+ double diffX = locX - lastX;
+ double diffY = locY - lastY;
+ double diffZ = locZ - lastZ;
+
+ if ( diffX != 0 || diffY != 0 || diffZ != 0 )
+ {
+ // Can't move while sleeping
+ if ( isSleeping() )
+ {
+ setLocation( lastX, lastY, lastZ, lastYaw, lastPitch );
+ lastMovementTick = currentTime;
+ return;
+ }
+
+ // Vehicle handling
+ if ( vehicle != null )
+ {
+ float f = yaw;
+ float f1 = pitch;
+
+ vehicle.ab();
+ double d1 = locX;
+ double d2 = locY;
+ double d3 = locZ;
+
+ V = 0.0F;
+ setLocation( d1, d2, d3, f, f1 );
+ if ( vehicle != null )
+ {
+ vehicle.ab();
+ }
+
+ MinecraftServer.getServer().getPlayerList().d( this );
+ lastMovementTick = currentTime;
+ return;
+ }
+
+ AxisAlignedBB newBounds = boundingBox.clone().c( diffX, diffY, diffZ ).shrink( 0.01, 0.01, 0.01 );
+ if ( !world.getCubes( this, newBounds ).isEmpty() )
+ {
+ playerConnection.a( lastX, lastY, lastZ, lastYaw, lastPitch );
+ lastMovementTick = currentTime;
+ return;
+ }
+ newBounds.grow( 0.01, 0.01, 0.01 );
+
+ // Speed checks
+
+ double moveX = Math.max( Math.abs( diffX ), Math.abs( motX ) );
+ double moveY = Math.max( Math.abs( diffY ), Math.abs( motY ) );
+ double moveZ = Math.max( Math.abs( diffZ ), Math.abs( motZ ) );
+ double totalMovement = moveX * moveX + moveY * moveY + moveZ * moveZ;
+
+ double limit = 100.0 * Math.max( 1.0, (currentTime - lastMovementTick) / 50000000.0);
+ if ( totalMovement > limit )
+ {
+ bL.warn( getName() + " moved too quickly! " + diffX + "," + diffY + "," + diffZ + " (" + moveX + ", " + moveY + ", " + moveZ + ") with a limit of " + limit );
+ playerConnection.a( lastX, lastY, lastZ, lastYaw, lastPitch );
+ lastMovementTick = currentTime;
+ return;
+ }
+
+ groundCheck.b( locX - 0.3, locY - 0.1, locZ - 0.3, locX + 0.3, locY, locZ + 0.3 );
+ onGround = !world.getCubes( this, groundCheck ).isEmpty();
+ if (!onGround && diffY < 0) {
+ groundCheck.b( locX - 0.3, locY - 0.25, locZ - 0.3, locX + 0.3, locY, locZ + 0.3 );
+ onGround = !world.getCubes( this, groundCheck ).isEmpty();
+ if (onGround) {
+ fallDistance += 0.1; // Account for client 'hover'
+ }
+ }
+
+ // Fly detection
+ if ( !onGround && !MinecraftServer.getServer().getAllowFlight() && !abilities.canFly
+ && diffY >= -0.03125D )
+ {
+ offGroundTicks++;
+ if ( offGroundTicks > 80 )
+ {
+ bL.warn( getName() + " was kicked for floating too long!" );
+ playerConnection.disconnect( "Flying is not enabled on this server" );
+ return;
+ }
+ } else
+ {
+ offGroundTicks = 0;
+ }
+
+ // Block interactions
+
+ boolean isTouching = this.onGround && this.isSneaking();
+ double diffY1 = diffY;
+
+ if ( this.g_() && !isTouching && this.vehicle == null )
+ {
+ int l = MathHelper.floor( this.locX );
+
+ int k = MathHelper.floor( this.locY - 0.20000000298023224D - (double) this.height );
+ int i1 = MathHelper.floor( this.locZ );
+ Block block = this.world.getType( l, k, i1 );
+ int j1 = this.world.getType( l, k - 1, i1 ).b();
+
+ if ( j1 == 11 || j1 == 32 || j1 == 21 )
+ {
+ block = this.world.getType( l, k - 1, i1 );
+ }
+
+ if ( block != Blocks.LADDER )
+ {
+ diffY1 = 0.0D;
+ }
+
+ this.P = (float) ( (double) this.P + (double) MathHelper.sqrt( diffX * diffX + diffZ * diffZ ) * 0.6D );
+ this.Q = (float) ( (double) this.Q + (double) MathHelper.sqrt( diffX * diffX + diffY1 * diffY1 + diffZ * diffZ ) * 0.6D );
+ if ( this.Q > (float) this.moveHelper && block.getMaterial() != Material.AIR )
+ {
+ this.moveHelper = (int) this.Q + 1;
+ if ( this.L() )
+ {
+ float f = MathHelper.sqrt( this.motX * this.motX * 0.20000000298023224D + this.motY * this.motY + this.motZ * this.motZ * 0.20000000298023224D ) * 0.35F;
+
+ if ( f > 1.0F )
+ {
+ f = 1.0F;
+ }
+
+ this.makeSound( this.G(), f, 1.0F + ( this.random.nextFloat() - this.random.nextFloat() ) * 0.4F );
+ }
+
+ this.a( l, k, i1, block );
+ block.b( this.world, l, k, i1, this );
+ }
+ }
+
+ // Fire damage
+
+ boolean isWet = this.K();
+
+ if ( this.world.e( newBounds ) )
+ {
+ this.burn( 1 );
+ if ( !isWet )
+ {
+ ++this.fireTicks;
+ // CraftBukkit start - Not on fire yet
+ if ( this.fireTicks <= 0 )
+ { // Only throw events on the first combust, otherwise it spams
+ org.bukkit.event.entity.EntityCombustEvent event = new org.bukkit.event.entity.EntityCombustEvent( this.getBukkitEntity(), 8 );
+ this.world.getServer().getPluginManager().callEvent( event );
+
+ if ( !event.isCancelled() )
+ {
+ this.setOnFire( event.getDuration() );
+ }
+ } else
+ {
+ // CraftBukkit end
+ this.setOnFire( 8 );
+ }
+ }
+ } else if ( this.fireTicks <= 0 )
+ {
+ this.fireTicks = -this.maxFireTicks;
+ }
+
+ if ( isWet && this.fireTicks > 0 )
+ {
+ this.makeSound( "random.fizz", 0.7F, 1.6F + ( this.random.nextFloat() - this.random.nextFloat() ) * 0.4F );
+ this.fireTicks = -this.maxFireTicks;
+ }
+
+ this.b( locY - lastY, onGround );
+ checkMovement( diffX, diffY, diffZ );
+ setLocation( locX, locY, locZ, yaw, pitch );
+ MinecraftServer.getServer().getPlayerList().d( this );
+ }
+
+ // Block collisions
+ try
+ {
+ this.H();
+ } catch ( Throwable throwable )
+ {
+ CrashReport crashreport = CrashReport.a( throwable, "Checking entity block collision" );
+ CrashReportSystemDetails crashreportsystemdetails = crashreport.a( "Entity being checked for collision" );
+
+ this.a( crashreportsystemdetails );
+ throw new ReportedException( crashreport );
+ }
+ }
+ lastMovementTick = currentTime;
}
+ @Override
+ public void move(double d0, double d1, double d2)
+ {
+ }
+
+ // Spigot end
+
public void i() {
try {
super.h();
diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
index 1221319..7266c39 100644
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
@@ -105,7 +105,7 @@ public class PlayerConnection implements PacketPlayInListener {
private double lastPosZ = Double.MAX_VALUE;
private float lastPitch = Float.MAX_VALUE;
private float lastYaw = Float.MAX_VALUE;
- private boolean justTeleported = false;
+ public boolean justTeleported = false; // Spigot
private boolean hasMoved; // Spigot
// For the PacketPlayOutBlockPlace hack :(
@@ -180,13 +180,129 @@ public class PlayerConnection implements PacketPlayInListener {
this.player.a(packetplayinsteervehicle.c(), packetplayinsteervehicle.d(), packetplayinsteervehicle.e(), packetplayinsteervehicle.f());
}
- public void a(PacketPlayInFlying packetplayinflying) {
+ public void a(PacketPlayInFlying packetplayinflying)
+ {
// CraftBukkit start - Check for NaN
- if (Double.isNaN(packetplayinflying.x) || Double.isNaN(packetplayinflying.y) || Double.isNaN(packetplayinflying.z) || Double.isNaN(packetplayinflying.stance)) {
- c.warn(player.getName() + " was caught trying to crash the server with an invalid position.");
- getPlayer().kickPlayer("NaN in position (Hacking?)"); //Spigot "Nope" -> Descriptive reason
+ if ( Double.isNaN( packetplayinflying.x ) || Double.isNaN( packetplayinflying.y ) || Double.isNaN( packetplayinflying.z ) || Double.isNaN( packetplayinflying.stance ) )
+ {
+ c.warn( player.getName() + " was caught trying to crash the server with an invalid position." );
+ getPlayer().kickPlayer( "NaN in position (Hacking?)" ); //Spigot "Nope" -> Descriptive reason
+ return;
+ }
+ // Spigot start
+ if ( packetplayinflying.hasPos )
+ {
+ if (Math.abs(packetplayinflying.c()) > 3.2E7D || Math.abs(packetplayinflying.e()) > 3.2E7D) {
+ this.disconnect("Illegal position");
+ return;
+ }
+ player.locX = packetplayinflying.x;
+ player.locY = packetplayinflying.y;
+ player.stance = packetplayinflying.stance;
+ player.locZ = packetplayinflying.z;
+ }
+ if ( packetplayinflying.hasLook )
+ {
+ player.yaw = packetplayinflying.yaw;
+ player.pitch = packetplayinflying.pitch;
+ }
+
+ double d4 = player.lastX - this.player.locX;
+ double d5 = player.lastY - this.player.locY;
+ double d6 = player.lastZ - this.player.locZ;
+ // CraftBukkit start - min to max
+ double d7 = Math.max(Math.abs(d4), Math.abs(this.player.motX));
+ double d8 = Math.max(Math.abs(d5), Math.abs(this.player.motY));
+ double d9 = Math.max(Math.abs(d6), Math.abs(this.player.motZ));
+ // CraftBukkit end
+ double d10 = d7 * d7 + d8 * d8 + d9 * d9;
+
+ if (d10 > 100.0D && this.checkMovement && (!this.minecraftServer.N() || !this.minecraftServer.M().equals(this.player.getName()))) { // CraftBukkit - Added this.checkMovement condition to solve this check being triggered by teleports
+ c.warn(this.player.getName() + " moved too quickly! " + d4 + "," + d5 + "," + d6 + " (" + d7 + ", " + d8 + ", " + d9 + ")");
+ this.a(this.y, this.z, this.q, this.player.yaw, this.player.pitch);
return;
}
+
+ // CraftBukkit start - fire PlayerMoveEvent
+ Player player = this.getPlayer();
+ // Spigot Start
+ if ( !hasMoved )
+ {
+ Location curPos = player.getLocation();
+ lastPosX = curPos.getX();
+ lastPosY = curPos.getY();
+ lastPosZ = curPos.getZ();
+ lastYaw = curPos.getYaw();
+ lastPitch = curPos.getPitch();
+ hasMoved = true;
+ }
+ // Spigot End
+ Location from = new Location( player.getWorld(), lastPosX, lastPosY, lastPosZ, lastYaw, lastPitch ); // Get the Players previous Event location.
+ Location to = player.getLocation().clone(); // Start off the To location as the Players current location.
+
+ // If the packet contains movement information then we update the To location with the correct XYZ.
+ if ( packetplayinflying.hasPos && !( packetplayinflying.hasPos && packetplayinflying.y == -999.0D && packetplayinflying.stance == -999.0D ) )
+ {
+ to.setX( packetplayinflying.x );
+ to.setY( packetplayinflying.y );
+ to.setZ( packetplayinflying.z );
+ }
+
+ // If the packet contains look information then we update the To location with the correct Yaw & Pitch.
+ if ( packetplayinflying.hasLook )
+ {
+ to.setYaw( packetplayinflying.yaw );
+ to.setPitch( packetplayinflying.pitch );
+ }
+
+ // Prevent 40 event-calls for less than a single pixel of movement >.>
+ double delta = Math.pow( this.lastPosX - to.getX(), 2 ) + Math.pow( this.lastPosY - to.getY(), 2 ) + Math.pow( this.lastPosZ - to.getZ(), 2 );
+ float deltaAngle = Math.abs( this.lastYaw - to.getYaw() ) + Math.abs( this.lastPitch - to.getPitch() );
+
+ if ( ( delta > 1f / 256 || deltaAngle > 10f ) && ( this.checkMovement && !this.player.dead ) )
+ {
+ this.lastPosX = to.getX();
+ this.lastPosY = to.getY();
+ this.lastPosZ = to.getZ();
+ this.lastYaw = to.getYaw();
+ this.lastPitch = to.getPitch();
+
+ // Skip the first time we do this
+ if ( true )
+ { // Spigot - don't skip any move events
+ PlayerMoveEvent event = new PlayerMoveEvent( player, from, to );
+ this.server.getPluginManager().callEvent( event );
+
+ // If the event is cancelled we move the player back to their old location.
+ if ( event.isCancelled() )
+ {
+ this.player.playerConnection.sendPacket( new PacketPlayOutPosition( from.getX(), from.getY() + 1.6200000047683716D, from.getZ(), from.getYaw(), from.getPitch(), false ) );
+ return;
+ }
+
+ /* If a Plugin has changed the To destination then we teleport the Player
+ there to avoid any 'Moved wrongly' or 'Moved too quickly' errors.
+ We only do this if the Event was not cancelled. */
+ if ( !to.equals( event.getTo() ) && !event.isCancelled() )
+ {
+ this.player.getBukkitEntity().teleport( event.getTo(), PlayerTeleportEvent.TeleportCause.UNKNOWN );
+ return;
+ }
+
+ /* Check to see if the Players Location has some how changed during the call of the event.
+ This can happen due to a plugin teleporting the player instead of using .setTo() */
+ if ( !from.equals( this.getPlayer().getLocation() ) && this.justTeleported )
+ {
+ this.justTeleported = false;
+ return;
+ }
+ }
+ }
+
+ }
+
+ private void noop(PacketPlayInFlying packetplayinflying) {
+ // Spigot end
// CraftBukkit end
WorldServer worldserver = this.minecraftServer.getWorldServer(this.player.dimension);
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index 06284ad..a2f1010 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -262,6 +262,7 @@ public class ActivationRange
*/
public static boolean checkIfActive(Entity entity)
{
+ if ( entity instanceof net.minecraft.server.EntityPlayer ) return true;
SpigotTimings.checkIfActiveTimer.startTiming();
boolean isActive = entity.activatedTick >= MinecraftServer.currentTick || entity.defaultActivationState;
--
1.9.1