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.EntityPlayer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.NetServerHandler;
import net.minecraft.server.NetworkManager;
import net.minecraft.server.ServerConnection;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -103,8 +104,10 @@ public class NoCheatPlus extends JavaPlugin implements Listener {
getCommand("nocheatplus").setExecutor(new CommandHandler(this));
// Set the NetServerHandler of every player.
for (final Player player : Bukkit.getOnlinePlayers())
setCustomNetServerHandler(player);
for (final Player player : Bukkit.getOnlinePlayers()) {
resetNetServerHandler(player);
updateNetServerHandler(player);
}
// Tell the server administrator that we finished loading NoCheatPlus now.
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.
*
* @param event
* the event
*/
@EventHandler(
priority = EventPriority.LOWEST)
public void onPlayerJoinLowest(final PlayerJoinEvent event) {
// 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 NetServerHandler oldNSH = entityPlayer.netServerHandler;
if (oldNSH instanceof CustomNetServerHandler)
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);
newNSH.a(player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), player
.getLocation().getYaw(), player.getLocation().getPitch());
entityPlayer.netServerHandler = newNSH;
try {
final Field field = NetworkManager.class.getDeclaredField("packetListener");
field.setAccessible(true);
field.set(oldNSH.networkManager, newNSH);
} catch (final Exception e) {
e.printStackTrace();
}
setNetServerHandler(server, oldNSH, newNSH);
oldNSH.disconnected = true;
server.ac().a(newNSH);
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
* 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
*/

View File

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

View File

@ -46,7 +46,7 @@ public class InstantEat extends Check {
if (data.instantEatFood == null || level <= player.getFoodLevel())
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;
if (expectedTimeWhenEatingFinished < System.currentTimeMillis())

View File

@ -6,8 +6,6 @@ import org.bukkit.Bukkit;
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;
@ -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.
*
@ -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,
* because it is definitely invalid now.
* Just for security, if a player switches between worlds, reset the fly and more packets checks data, because it is
* definitely invalid now.
*
* @param event
* the event
@ -519,16 +542,4 @@ public class MovingListener implements Listener {
}
}.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

@ -50,12 +50,11 @@ public class NoFall extends Check {
public void check(final Player player, final PlayerLocation from, final PlayerLocation to) {
final MovingConfig cc = MovingConfig.getConfig(player);
final MovingData data = MovingData.getData(player);
// If the player has just started falling, is falling into a liquid, in web or is on a ladder.
if (to.isInLiquid() || to.isInWeb() || to.isOnLadder())
// Reset his fall distance.
data.noFallFallDistance = data.noFallNewFallDistance = 0D;
// If the player just touched the ground for the server, but no for the client.
if (!data.noFallWasOnGroundServer && data.noFallOnGroundServer