Fixed server sometimes ignoring players due to our custom

NetServerHandler.
This commit is contained in:
NeatMonster 2012-08-13 17:10:31 +02:00
parent f515f57231
commit 96a7f493f8
7 changed files with 105 additions and 41 deletions

View File

@ -6,11 +6,12 @@ import java.util.List;
import net.minecraft.server.DedicatedServer; import net.minecraft.server.DedicatedServer;
import net.minecraft.server.EntityPlayer; import net.minecraft.server.EntityPlayer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.NetServerHandler; import net.minecraft.server.NetServerHandler;
import net.minecraft.server.NetworkManager; import net.minecraft.server.NetworkManager;
import net.minecraft.server.ServerConnection;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -103,8 +104,10 @@ public class NoCheatPlus extends JavaPlugin implements Listener {
getCommand("nocheatplus").setExecutor(new CommandHandler(this)); getCommand("nocheatplus").setExecutor(new CommandHandler(this));
// Set the NetServerHandler of every player. // Set the NetServerHandler of every player.
for (final Player player : Bukkit.getOnlinePlayers()) for (final Player player : Bukkit.getOnlinePlayers()) {
setCustomNetServerHandler(player); resetNetServerHandler(player);
updateNetServerHandler(player);
}
// Tell the server administrator that we finished loading NoCheatPlus now. // Tell the server administrator that we finished loading NoCheatPlus now.
System.out.println("[NoCheatPlus] Version " + getDescription().getVersion() + " is enabled."); System.out.println("[NoCheatPlus] Version " + getDescription().getVersion() + " is enabled.");
@ -216,33 +219,87 @@ public class NoCheatPlus extends JavaPlugin implements Listener {
* Setting the net server handler at the earliest possible point. * Setting the net server handler at the earliest possible point.
* *
* @param event * @param event
* the event
*/ */
@EventHandler( @EventHandler(
priority = EventPriority.LOWEST) priority = EventPriority.LOWEST)
public void onPlayerJoinLowest(final PlayerJoinEvent event) { public void onPlayerJoinLowest(final PlayerJoinEvent event) {
// Set the NetServerHandler of the player. // Set the NetServerHandler of the player.
setCustomNetServerHandler(event.getPlayer()); resetNetServerHandler(event.getPlayer());
updateNetServerHandler(event.getPlayer());
} }
private boolean setCustomNetServerHandler(final Player player) { /**
* Reset the net server handler of the player.
*
* @param player
* the player
* @return true, if needed
*/
private boolean resetNetServerHandler(final Player player) {
final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
final NetServerHandler oldNSH = entityPlayer.netServerHandler;
if (!(oldNSH instanceof CustomNetServerHandler))
return false;
final DedicatedServer server = (DedicatedServer) MinecraftServer.getServer();
final NetServerHandler newNSH = new NetServerHandler(server, oldNSH.networkManager, entityPlayer);
newNSH.a(player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), player
.getLocation().getYaw(), player.getLocation().getPitch());
entityPlayer.netServerHandler = newNSH;
setNetServerHandler(server, oldNSH, newNSH);
oldNSH.disconnected = true;
return true;
}
/**
* Sets the net server handler.
*
* @param server
* the server
* @param oldNSH
* the old net server handler
* @param newNSH
* the new net server handler
* @return true, if successful
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private boolean setNetServerHandler(final DedicatedServer server, final NetServerHandler oldNSH,
final NetServerHandler newNSH) {
try {
Field field = NetworkManager.class.getDeclaredField("packetListener");
field.setAccessible(true);
field.set(oldNSH.networkManager, newNSH);
field = ServerConnection.class.getDeclaredField("d");
field.setAccessible(true);
final List handlerList = (List) field.get(server.ac());
handlerList.remove(oldNSH);
handlerList.add(newNSH);
return true;
} catch (final Exception e) {
e.printStackTrace();
}
return false;
}
/**
* Update the net server handler of the player.
*
* @param player
* the player
* @return true, if needed
*/
private boolean updateNetServerHandler(final Player player) {
final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
final NetServerHandler oldNSH = entityPlayer.netServerHandler; final NetServerHandler oldNSH = entityPlayer.netServerHandler;
if (oldNSH instanceof CustomNetServerHandler) if (oldNSH instanceof CustomNetServerHandler)
return false; return false;
final DedicatedServer server = ((CraftServer) Bukkit.getServer()).getHandle().getServer(); final DedicatedServer server = (DedicatedServer) MinecraftServer.getServer();
final NetServerHandler newNSH = new CustomNetServerHandler(server, oldNSH.networkManager, entityPlayer); final NetServerHandler newNSH = new CustomNetServerHandler(server, oldNSH.networkManager, entityPlayer);
newNSH.a(player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), player newNSH.a(player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), player
.getLocation().getYaw(), player.getLocation().getPitch()); .getLocation().getYaw(), player.getLocation().getPitch());
entityPlayer.netServerHandler = newNSH; entityPlayer.netServerHandler = newNSH;
try { setNetServerHandler(server, oldNSH, newNSH);
final Field field = NetworkManager.class.getDeclaredField("packetListener");
field.setAccessible(true);
field.set(oldNSH.networkManager, newNSH);
} catch (final Exception e) {
e.printStackTrace();
}
oldNSH.disconnected = true; oldNSH.disconnected = true;
server.ac().a(newNSH);
return true; return true;
} }
} }

View File

@ -52,7 +52,7 @@ public abstract class ActionWithParameters extends Action {
} }
/** /**
* Get a string with all the wildcards replaced with data from LogData. * Get a string with all the wildcards replaced with data from the violation data.
* *
* @param check * @param check
* the check * the check

View File

@ -57,7 +57,7 @@ public class CommandAction extends ActionWithParameters {
} }
/** /**
* Convert the commands into a string that can be used in the configuration files. * Convert the commands data into a string that can be used in the configuration files.
* *
* @return the string * @return the string
*/ */

View File

@ -167,7 +167,6 @@ public class NoPwnage extends Check {
boolean cancel = false; boolean cancel = false;
String message = ""; String message = "";
if (event instanceof AsyncPlayerChatEvent) if (event instanceof AsyncPlayerChatEvent)
message = ((AsyncPlayerChatEvent) event).getMessage(); message = ((AsyncPlayerChatEvent) event).getMessage();
@ -176,8 +175,8 @@ public class NoPwnage extends Check {
final boolean isCommand = event instanceof PlayerCommandPreprocessEvent; final boolean isCommand = event instanceof PlayerCommandPreprocessEvent;
final long now = System.currentTimeMillis(); final long now = System.currentTimeMillis();
if (!data.noPwnageHasFilledCaptcha) { if (!data.noPwnageHasFilledCaptcha)
if (cc.noPwnageCaptchaCheck && data.noPwnageHasStartedCaptcha) { if (cc.noPwnageCaptchaCheck && data.noPwnageHasStartedCaptcha) {
// Correct answer to the captcha? // Correct answer to the captcha?
if (message.equals(data.noPwnageGeneratedCaptcha)) { if (message.equals(data.noPwnageGeneratedCaptcha)) {
// Yes, clear his data and do not worry anymore about him. // Yes, clear his data and do not worry anymore about him.
@ -206,7 +205,6 @@ public class NoPwnage extends Check {
((PlayerCommandPreprocessEvent) event).setCancelled(true); ((PlayerCommandPreprocessEvent) event).setCancelled(true);
return cancel; return cancel;
} }
}
if (data.noPwnageLastLocation == null) if (data.noPwnageLastLocation == null)
data.noPwnageLastLocation = player.getLocation(); data.noPwnageLastLocation = player.getLocation();
@ -296,7 +294,6 @@ public class NoPwnage extends Check {
lastGlobalMessage = message; lastGlobalMessage = message;
lastGlobalMessageTime = now; lastGlobalMessageTime = now;
return cancel; return cancel;
} }

View File

@ -46,7 +46,7 @@ public class InstantEat extends Check {
if (data.instantEatFood == null || level <= player.getFoodLevel()) if (data.instantEatFood == null || level <= player.getFoodLevel())
return false; return false;
// rough estimation about how long it should take to eat // Rough estimation about how long it should take to eat
final long expectedTimeWhenEatingFinished = data.instantEatLastTime + 700L; final long expectedTimeWhenEatingFinished = data.instantEatLastTime + 700L;
if (expectedTimeWhenEatingFinished < System.currentTimeMillis()) if (expectedTimeWhenEatingFinished < System.currentTimeMillis())

View File

@ -6,8 +6,6 @@ import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle; import org.bukkit.entity.Vehicle;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -137,6 +135,31 @@ public class MovingListener implements Listener {
} }
} }
/**
* We listen to EntityDamage events the reset the fall distance when a damage is dealt.
*
* @param event
* the event
*/
@EventHandler(
priority = EventPriority.MONITOR, ignoreCancelled = false)
public void onEntityDamage(final EntityDamageEvent event) {
/*
* _____ _ _ _ ____
* | ____|_ __ | |_(_) |_ _ _ | _ \ __ _ _ __ ___ __ _ __ _ ___
* | _| | '_ \| __| | __| | | | | | | |/ _` | '_ ` _ \ / _` |/ _` |/ _ \
* | |___| | | | |_| | |_| |_| | | |_| | (_| | | | | | | (_| | (_| | __/
* |_____|_| |_|\__|_|\__|\__, | |____/ \__,_|_| |_| |_|\__,_|\__, |\___|
* |___/ |___/
*/
// Workaround fix attempt for NoFall multiple damage.
if (event.getCause() == DamageCause.FALL && event.getEntity() instanceof Player) {
final MovingData data = MovingData.getData((Player) event.getEntity());
// Simple model: once damage dealt the fall distance is reset.
data.noFallFallDistance = data.noFallNewFallDistance = 0D;
}
}
/** /**
* We listen to this event to prevent player from flying by sending bed leaving packets. * We listen to this event to prevent player from flying by sending bed leaving packets.
* *
@ -181,8 +204,8 @@ public class MovingListener implements Listener {
} }
/** /**
* Just for security, if a player switches between worlds, reset the fly and more packets checks data, * Just for security, if a player switches between worlds, reset the fly and more packets checks data, because it is
* because it is definitely invalid now. * definitely invalid now.
* *
* @param event * @param event
* the event * the event
@ -519,16 +542,4 @@ public class MovingListener implements Listener {
} }
}.set(event.getVehicle(), newTo), 1L); }.set(event.getVehicle(), newTo), 1L);
} }
@EventHandler(priority=EventPriority.MONITOR, ignoreCancelled=false)
public void onEntityDamage(final EntityDamageEvent event){
// Workaround fix attempt for NoFall multiple damage.
if (event.getCause() != DamageCause.FALL) return;
final Entity entity = event.getEntity();
if (entity.getType() != EntityType.PLAYER) return;
final Player player = (Player) entity;
final MovingData data = MovingData.getData(player);
// Simple model: Once damage dealt the fall distance is reset.
data.noFallFallDistance = data.noFallNewFallDistance = 0.0;
}
} }

View File

@ -56,7 +56,6 @@ public class NoFall extends Check {
// Reset his fall distance. // Reset his fall distance.
data.noFallFallDistance = data.noFallNewFallDistance = 0D; data.noFallFallDistance = data.noFallNewFallDistance = 0D;
// If the player just touched the ground for the server, but no for the client. // If the player just touched the ground for the server, but no for the client.
if (!data.noFallWasOnGroundServer && data.noFallOnGroundServer if (!data.noFallWasOnGroundServer && data.noFallOnGroundServer
&& (data.noFallWasOnGroundClient || !data.noFallOnGroundClient)) { && (data.noFallWasOnGroundClient || !data.noFallOnGroundClient)) {