Listener optimizations (#1884)

* Drop CraftBukkit support, listeners cleanup

* Codestyle

* Codestyle

* Remove useless player.saveData() calls

* Micro optimization on the join process

* Requested changes

* Fix unit test

* Test onPlayerHeldItem listener

* Requested changes

* Remove unused import
This commit is contained in:
Gabriele C
2019-08-11 23:47:50 +02:00
committed by GitHub
parent e2f2ff0763
commit d30580d5d4
24 changed files with 498 additions and 557 deletions
+4 -2
View File
@@ -125,8 +125,10 @@ public class AuthMe extends JavaPlugin {
logger = ConsoleLoggerFactory.get(AuthMe.class);
// Check server version
if (!isClassLoaded("org.bukkit.event.player.PlayerInteractAtEntityEvent")) {
logger.warning("You are running an unsupported server version! AuthMe requires MC 1.8.X or later!");
if (!isClassLoaded("org.spigotmc.event.player.PlayerSpawnLocationEvent")
|| !isClassLoaded("org.bukkit.event.player.PlayerInteractAtEntityEvent")) {
logger.warning("You are running an unsupported server version!"
+ "AuthMe requires Spigot 1.8.X or later!");
stopOrUnload();
return;
}
@@ -25,5 +25,4 @@ public class BlockListener implements Listener {
event.setCancelled(true);
}
}
}
@@ -1,8 +1,5 @@
package fr.xephi.authme.listener;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
@@ -16,32 +13,19 @@ import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.projectiles.ProjectileSource;
import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class EntityListener implements Listener {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(EntityListener.class);
private final ListenerService listenerService;
private Method getShooter;
private boolean shooterIsLivingEntity;
@Inject
EntityListener(ListenerService listenerService) {
this.listenerService = listenerService;
try {
getShooter = Projectile.class.getDeclaredMethod("getShooter");
shooterIsLivingEntity = getShooter.getReturnType() == LivingEntity.class;
} catch (NoSuchMethodException | SecurityException e) {
logger.logException("Cannot load getShooter() method on Projectile class", e);
}
}
// Note #360: npc status can be used to bypass security!!!
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onDamage(EntityDamageEvent event) {
if (listenerService.shouldCancelEvent(event)) {
@@ -81,6 +65,7 @@ public class EntityListener implements Listener {
}
}
//TODO sgdc3 20190808: We listen at the same event twice, does it make any sense?
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onEntityInteract(EntityInteractEvent event) {
if (listenerService.shouldCancelEvent(event)) {
@@ -97,26 +82,10 @@ public class EntityListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onProjectileLaunch(ProjectileLaunchEvent event) {
if (event.getEntity() == null) {
return;
}
final Projectile projectile = event.getEntity();
Projectile projectile = event.getEntity();
// In the Bukkit API prior to 1.7, getShooter() returns a LivingEntity instead of a ProjectileSource
Object shooterRaw = null;
if (shooterIsLivingEntity) {
try {
if (getShooter == null) {
getShooter = Projectile.class.getMethod("getShooter");
}
shooterRaw = getShooter.invoke(projectile);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
logger.logException("Error getting shooter", e);
}
} else {
shooterRaw = projectile.getShooter();
}
if (shooterRaw instanceof Player && listenerService.shouldCancelEvent((Player) shooterRaw)) {
ProjectileSource shooter = projectile.getShooter();
if (shooter instanceof Player && listenerService.shouldCancelEvent((Player) shooter)) {
event.setCancelled(true);
}
}
@@ -127,5 +96,4 @@ public class EntityListener implements Listener {
event.setCancelled(true);
}
}
}
@@ -1,66 +0,0 @@
package fr.xephi.authme.listener;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager;
import org.bukkit.entity.Player;
import java.util.function.BiFunction;
/**
* Represents a player joining the server, which depending on the available
* information may be his name or the actual Player object.
*/
public final class JoiningPlayer {
private final String name;
private final BiFunction<PermissionsManager, PermissionNode, Boolean> permissionLookupFunction;
/**
* Hidden constructor.
*
* @param name the player's name
* @param permFunction the function to use for permission lookups
*/
private JoiningPlayer(String name, BiFunction<PermissionsManager, PermissionNode, Boolean> permFunction) {
this.name = name;
this.permissionLookupFunction = permFunction;
}
/**
* Creates a {@link JoiningPlayer} instance from the given name.
*
* @param name the player's name
* @return the created instance
*/
public static JoiningPlayer fromName(String name) {
return new JoiningPlayer(name, (manager, perm) -> manager.hasPermissionOffline(name, perm));
}
/**
* Creates a {@link JoiningPlayer} instance from the given Player object.
*
* @param player the player
* @return the created instance
*/
public static JoiningPlayer fromPlayerObject(Player player) {
return new JoiningPlayer(player.getName(), (manager, perm) -> manager.hasPermission(player, perm));
}
/**
* @return the player's name
*/
public String getName() {
return name;
}
/**
* Returns the function to use for permission lookups. Takes two arguments: the PermissionsManager instance,
* and the permission node to look up. The result is a boolean indicating whether or not this joining player
* has permission.
*
* @return the permissions lookup function to use
*/
public BiFunction<PermissionsManager, PermissionNode, Boolean> getPermissionLookupFunction() {
return permissionLookupFunction;
}
}
@@ -31,7 +31,7 @@ import java.util.regex.Pattern;
* Service for performing various verifications when a player joins.
*/
public class OnJoinVerifier implements Reloadable {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(OnJoinVerifier.class);
@Inject
@@ -67,16 +67,16 @@ public class OnJoinVerifier implements Reloadable {
/**
* Checks if Antibot is enabled.
*
* @param joiningPlayer the joining player to check
* @param name the joining player name to check
* @param isAuthAvailable whether or not the player is registered
* @throws FailedVerificationException if the verification fails
*/
public void checkAntibot(JoiningPlayer joiningPlayer, boolean isAuthAvailable) throws FailedVerificationException {
if (isAuthAvailable || permissionsManager.hasPermission(joiningPlayer, PlayerStatePermission.BYPASS_ANTIBOT)) {
public void checkAntibot(String name, boolean isAuthAvailable) throws FailedVerificationException {
if (isAuthAvailable || permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_ANTIBOT)) {
return;
}
if (antiBotService.shouldKick()) {
antiBotService.addPlayerKick(joiningPlayer.getName());
antiBotService.addPlayerKick(name);
throw new FailedVerificationException(MessageKey.KICK_ANTIBOT);
}
}
@@ -170,16 +170,16 @@ public class OnJoinVerifier implements Reloadable {
/**
* Checks that the player's country is admitted.
*
* @param joiningPlayer the joining player to verify
* @param name the joining player name to verify
* @param address the player address
* @param isAuthAvailable whether or not the user is registered
* @throws FailedVerificationException if the verification fails
*/
public void checkPlayerCountry(JoiningPlayer joiningPlayer, String address,
public void checkPlayerCountry(String name, String address,
boolean isAuthAvailable) throws FailedVerificationException {
if ((!isAuthAvailable || settings.getProperty(ProtectionSettings.ENABLE_PROTECTION_REGISTERED))
&& settings.getProperty(ProtectionSettings.ENABLE_PROTECTION)
&& !permissionsManager.hasPermission(joiningPlayer, PlayerStatePermission.BYPASS_COUNTRY_CHECK)
&& !permissionsManager.hasPermissionOffline(name, PlayerStatePermission.BYPASS_COUNTRY_CHECK)
&& !validationService.isCountryAdmitted(address)) {
throw new FailedVerificationException(MessageKey.COUNTRY_BANNED_ERROR);
}
@@ -1,30 +1,23 @@
package fr.xephi.authme.listener;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.QuickCommandsProtectionManager;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.message.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.permission.handlers.PermissionLoadUserException;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.service.AntiBotService;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.JoinMessageService;
import fr.xephi.authme.service.TeleportationService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.bungeecord.BungeeSender;
import fr.xephi.authme.service.bungeecord.MessageType;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.entity.HumanEntity;
@@ -59,7 +52,6 @@ import org.bukkit.event.player.PlayerShearEntityEvent;
import org.bukkit.inventory.InventoryView;
import javax.inject.Inject;
import java.util.HashSet;
import java.util.Set;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_MOVEMENT_RADIUS;
@@ -70,8 +62,6 @@ import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOW_UNAU
*/
public class PlayerListener implements Listener {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(PlayerListener.class);
@Inject
private Settings settings;
@Inject
@@ -100,106 +90,104 @@ public class PlayerListener implements Listener {
private PermissionsManager permissionsManager;
@Inject
private QuickCommandsProtectionManager quickCommandsProtectionManager;
@Inject
private BungeeSender bungeeSender;
private boolean isAsyncPlayerPreLoginEventCalled = false;
private Set<String> unresolvedPlayerHostname = new HashSet<>();
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
String cmd = event.getMessage().split(" ")[0].toLowerCase();
if (settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD) && "/motd".equals(cmd)) {
// Lowest priority to apply fast protection checks
@EventHandler(priority = EventPriority.LOWEST)
public void onAsyncPlayerPreLoginEventLowest(AsyncPlayerPreLoginEvent event) {
if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
return;
}
if (settings.getProperty(RestrictionSettings.ALLOW_COMMANDS).contains(cmd)) {
final String name = event.getName();
// NOTE: getAddress() sometimes returning null, we don't want to handle this race condition
if (event.getAddress() == null) {
event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER,
messages.retrieveSingle(name, MessageKey.KICK_UNRESOLVED_HOSTNAME));
return;
}
if (validationService.isUnrestricted(name)) {
return;
}
// Non-blocking checks
try {
onJoinVerifier.checkSingleSession(name);
onJoinVerifier.checkIsValidName(name);
} catch (FailedVerificationException e) {
event.setKickMessage(messages.retrieveSingle(name, e.getReason(), e.getArgs()));
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
}
}
/*
* Login/join/leave events
*/
// Note: at this stage (HIGHEST priority) the user's permission data should already have been loaded by
// the permission handler, we don't need to call permissionsManager.loadUserData()
@EventHandler(priority = EventPriority.HIGHEST)
public void onAsyncPlayerPreLoginEventHighest(AsyncPlayerPreLoginEvent event) {
if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
return;
}
final String name = event.getName();
if (validationService.isUnrestricted(name)) {
return;
}
// Slow, blocking checks
try {
final PlayerAuth auth = dataSource.getAuth(name);
final boolean isAuthAvailable = auth != null;
onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
onJoinVerifier.checkAntibot(name, isAuthAvailable);
onJoinVerifier.checkNameCasing(name, auth);
final String ip = event.getAddress().getHostAddress();
onJoinVerifier.checkPlayerCountry(name, ip, isAuthAvailable);
} catch (FailedVerificationException e) {
event.setKickMessage(messages.retrieveSingle(name, e.getReason(), e.getArgs()));
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
}
}
// Note: We can't teleport the player in the PlayerLoginEvent listener
// as the new player location will be reverted by the server.
@EventHandler(priority = EventPriority.LOW)
public void onPlayerLogin(PlayerLoginEvent event) {
final Player player = event.getPlayer();
if (!quickCommandsProtectionManager.isAllowed(player.getName())) {
event.setCancelled(true);
player.kickPlayer(messages.retrieveSingle(player, MessageKey.QUICK_COMMAND_PROTECTION_KICK));
final String name = player.getName();
if (validationService.isUnrestricted(name)) {
return;
}
if (listenerService.shouldCancelEvent(player)) {
event.setCancelled(true);
messages.send(player, MessageKey.DENIED_COMMAND);
}
onJoinVerifier.refusePlayerForFullServer(event);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerChat(AsyncPlayerChatEvent event) {
if (settings.getProperty(RestrictionSettings.ALLOW_CHAT)) {
return;
}
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer();
final boolean mayPlayerSendChat = !listenerService.shouldCancelEvent(player)
|| permissionsManager.hasPermission(player, PlayerStatePermission.ALLOW_CHAT_BEFORE_LOGIN);
if (mayPlayerSendChat) {
removeUnauthorizedRecipients(event);
} else {
event.setCancelled(true);
messages.send(player, MessageKey.DENIED_CHAT);
}
}
private void removeUnauthorizedRecipients(AsyncPlayerChatEvent event) {
if (settings.getProperty(RestrictionSettings.HIDE_CHAT)) {
event.getRecipients().removeIf(listenerService::shouldCancelEvent);
if (event.getRecipients().isEmpty()) {
event.setCancelled(true);
}
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerMove(PlayerMoveEvent event) {
if (settings.getProperty(ALLOW_UNAUTHED_MOVEMENT) && settings.getProperty(ALLOWED_MOVEMENT_RADIUS) <= 0) {
return;
if (!PlayerListener19Spigot.isPlayerSpawnLocationEventCalled()) {
teleportationService.teleportOnJoin(player);
}
/*
* Limit player X and Z movements to 1 block
* Deny player Y+ movements (allows falling)
*/
Location from = event.getFrom();
Location to = event.getTo();
if (from.getBlockX() == to.getBlockX()
&& from.getBlockZ() == to.getBlockZ()
&& from.getY() - to.getY() >= 0) {
return;
}
quickCommandsProtectionManager.processJoin(player);
Player player = event.getPlayer();
if (!listenerService.shouldCancelEvent(player)) {
return;
}
management.performJoin(player);
if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) {
// "cancel" the event
event.setTo(event.getFrom());
return;
}
if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
return;
}
Location spawn = spawnLoader.getSpawnLocation(player);
if (spawn != null && spawn.getWorld() != null) {
if (!player.getWorld().equals(spawn.getWorld())) {
player.teleport(spawn);
} else if (spawn.distance(player.getLocation()) > settings.getProperty(ALLOWED_MOVEMENT_RADIUS)) {
player.teleport(spawn);
}
}
teleportationService.teleportNewPlayerToFirstSpawn(player);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onJoinMessage(PlayerJoinEvent event) {
final Player player = event.getPlayer();
// Note: join message can be null, despite api documentation says not
if (settings.getProperty(RegistrationSettings.REMOVE_JOIN_MESSAGE)) {
event.setJoinMessage(null);
return;
@@ -229,131 +217,11 @@ public class PlayerListener implements Listener {
}
}
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer();
if (unresolvedPlayerHostname.remove(player.getName())) {
try {
runOnJoinChecks(JoiningPlayer.fromPlayerObject(player), PlayerUtils.getPlayerIp(player));
} catch (FailedVerificationException e) {
player.kickPlayer(messages.retrieveSingle(player, e.getReason(), e.getArgs()));
return;
}
}
if (!PlayerListener19Spigot.isPlayerSpawnLocationEventCalled()) {
teleportationService.teleportOnJoin(player);
}
quickCommandsProtectionManager.processJoin(player);
management.performJoin(player);
teleportationService.teleportNewPlayerToFirstSpawn(player);
}
private void runOnJoinChecks(JoiningPlayer joiningPlayer, String ip) throws FailedVerificationException {
// Fast stuff
final String name = joiningPlayer.getName();
onJoinVerifier.checkSingleSession(name);
onJoinVerifier.checkIsValidName(name);
// Get the auth later as this may cause the single session check to fail
// Slow stuff
final PlayerAuth auth = dataSource.getAuth(name);
final boolean isAuthAvailable = auth != null;
onJoinVerifier.checkKickNonRegistered(isAuthAvailable);
onJoinVerifier.checkAntibot(joiningPlayer, isAuthAvailable);
onJoinVerifier.checkNameCasing(name, auth);
onJoinVerifier.checkPlayerCountry(joiningPlayer, ip, isAuthAvailable);
}
// Note #831: AsyncPlayerPreLoginEvent is not fired by all servers in offline mode
// e.g. CraftBukkit does not fire it. So we need to run crucial things with PlayerLoginEvent.
// Single session feature can be implemented for Spigot and CraftBukkit by canceling a kick
// event caused by "logged in from another location". The nicer way, but only for Spigot, would be
// to check in the AsyncPlayerPreLoginEvent. To support all servers, we use the less nice way.
@EventHandler(priority = EventPriority.HIGHEST)
public void onAsyncPlayerPreLoginEvent(AsyncPlayerPreLoginEvent event) {
isAsyncPlayerPreLoginEventCalled = true;
if (!settings.getProperty(PluginSettings.USE_ASYNC_PRE_LOGIN_EVENT)) {
return;
}
final String name = event.getName();
if (validationService.isUnrestricted(name)) {
return;
}
// Keep pre-UUID compatibility
try {
permissionsManager.loadUserData(event.getUniqueId());
} catch (PermissionLoadUserException e) {
logger.logException("Unable to load the permission data of user " + name, e);
}
// getAddress() sometimes returning null if not yet resolved
// skip it and let PlayerLoginEvent to handle it
if (event.getAddress() == null) {
unresolvedPlayerHostname.add(event.getName());
return;
} else {
unresolvedPlayerHostname.remove(event.getName());
}
try {
runOnJoinChecks(JoiningPlayer.fromName(name), event.getAddress().getHostAddress());
} catch (FailedVerificationException e) {
event.setKickMessage(messages.retrieveSingle(name, e.getReason(), e.getArgs()));
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
}
}
//Note: We can't teleport the player in the PlayerLoginEvent listener
//as the new player location will be reverted by the server.
@EventHandler(priority = EventPriority.LOW)
public void onPlayerLogin(PlayerLoginEvent event) {
final Player player = event.getPlayer();
final String name = player.getName();
if (validationService.isUnrestricted(name)) {
return;
}
if (onJoinVerifier.refusePlayerForFullServer(event)) {
return;
}
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
return;
}
if (event.getAddress() == null) { // Address still null
unresolvedPlayerHostname.add(name);
return;
} else {
unresolvedPlayerHostname.remove(name);
}
if (!isAsyncPlayerPreLoginEventCalled || !settings.getProperty(PluginSettings.USE_ASYNC_PRE_LOGIN_EVENT)) {
try {
// Player.getAddress() can be null at this event, use event.getAddress()
runOnJoinChecks(JoiningPlayer.fromPlayerObject(player), event.getAddress().getHostAddress());
} catch (FailedVerificationException e) {
event.setKickMessage(messages.retrieveSingle(player, e.getReason(), e.getArgs()));
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
}
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
// Note: quit message can be null, despite api documentation says not
if (settings.getProperty(RegistrationSettings.REMOVE_LEAVE_MESSAGE)) {
event.setQuitMessage(null);
} else if (settings.getProperty(RegistrationSettings.REMOVE_UNLOGGED_LEAVE_MESSAGE)) {
@@ -385,6 +253,195 @@ public class PlayerListener implements Listener {
}
}
/*
* Chat/command events
*/
private void removeUnauthorizedRecipients(AsyncPlayerChatEvent event) {
if (settings.getProperty(RestrictionSettings.HIDE_CHAT)) {
event.getRecipients().removeIf(listenerService::shouldCancelEvent);
if (event.getRecipients().isEmpty()) {
event.setCancelled(true);
}
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerChat(AsyncPlayerChatEvent event) {
if (settings.getProperty(RestrictionSettings.ALLOW_CHAT)) {
return;
}
final Player player = event.getPlayer();
final boolean mayPlayerSendChat = !listenerService.shouldCancelEvent(player)
|| permissionsManager.hasPermission(player, PlayerStatePermission.ALLOW_CHAT_BEFORE_LOGIN);
if (mayPlayerSendChat) {
removeUnauthorizedRecipients(event);
} else {
event.setCancelled(true);
messages.send(player, MessageKey.DENIED_CHAT);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
String cmd = event.getMessage().split(" ")[0].toLowerCase();
if (settings.getProperty(HooksSettings.USE_ESSENTIALS_MOTD) && "/motd".equals(cmd)) {
return;
}
if (settings.getProperty(RestrictionSettings.ALLOW_COMMANDS).contains(cmd)) {
return;
}
final Player player = event.getPlayer();
if (!quickCommandsProtectionManager.isAllowed(player.getName())) {
event.setCancelled(true);
player.kickPlayer(messages.retrieveSingle(player, MessageKey.QUICK_COMMAND_PROTECTION_KICK));
return;
}
if (listenerService.shouldCancelEvent(player)) {
event.setCancelled(true);
messages.send(player, MessageKey.DENIED_COMMAND);
}
}
/*
* Movement events
*/
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerMove(PlayerMoveEvent event) {
if (settings.getProperty(ALLOW_UNAUTHED_MOVEMENT) && settings.getProperty(ALLOWED_MOVEMENT_RADIUS) <= 0) {
return;
}
Location from = event.getFrom();
Location to = event.getTo();
if (to == null) {
return;
}
/*
* Limit player X and Z movements to 1 block
* Deny player Y+ movements (allows falling)
*/
if (from.getBlockX() == to.getBlockX()
&& from.getBlockZ() == to.getBlockZ()
&& from.getY() - to.getY() >= 0) {
return;
}
Player player = event.getPlayer();
if (!listenerService.shouldCancelEvent(player)) {
return;
}
if (!settings.getProperty(RestrictionSettings.ALLOW_UNAUTHED_MOVEMENT)) {
// "cancel" the event
event.setTo(event.getFrom());
return;
}
if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
return;
}
Location spawn = spawnLoader.getSpawnLocation(player);
if (spawn != null && spawn.getWorld() != null) {
if (!player.getWorld().equals(spawn.getWorld())) {
player.teleport(spawn);
} else if (spawn.distance(player.getLocation()) > settings.getProperty(ALLOWED_MOVEMENT_RADIUS)) {
player.teleport(spawn);
}
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerRespawn(PlayerRespawnEvent event) {
if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
return;
}
if (!listenerService.shouldCancelEvent(event)) {
return;
}
Location spawn = spawnLoader.getSpawnLocation(event.getPlayer());
if (spawn != null && spawn.getWorld() != null) {
event.setRespawnLocation(spawn);
}
}
/*
* Entity/block interaction events
*/
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInteract(PlayerInteractEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerHitPlayerEvent(EntityDamageByEntityEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerShear(PlayerShearEntityEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerFish(PlayerFishEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerBedEnter(PlayerBedEnterEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerEditBook(PlayerEditBookEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onSignChange(SignChangeEvent event) {
Player player = event.getPlayer();
if (listenerService.shouldCancelEvent(player)) {
event.setCancelled(true);
}
}
/*
* Inventory interactions
*/
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerPickupItem(PlayerPickupItemEvent event) {
if (listenerService.shouldCancelEvent(event)) {
@@ -393,14 +450,14 @@ public class PlayerListener implements Listener {
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerHeldItem(PlayerItemHeldEvent event) {
public void onPlayerDropItem(PlayerDropItemEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInteract(PlayerInteractEvent event) {
public void onPlayerHeldItem(PlayerItemHeldEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
@@ -444,95 +501,4 @@ public class PlayerListener implements Listener {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerHitPlayerEvent(EntityDamageByEntityEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerDropItem(PlayerDropItemEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerBedEnter(PlayerBedEnterEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onSignChange(SignChangeEvent event) {
Player player = event.getPlayer();
if (listenerService.shouldCancelEvent(player)) {
event.setCancelled(true);
}
}
//TODO: check this, why do we need to update the quit loc? -sgdc3
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerRespawn(PlayerRespawnEvent event) {
if (settings.getProperty(RestrictionSettings.NO_TELEPORT)) {
return;
}
if (!listenerService.shouldCancelEvent(event)) {
return;
}
Player player = event.getPlayer();
String name = player.getName().toLowerCase();
Location spawn = spawnLoader.getSpawnLocation(player);
if (settings.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION) && dataSource.isAuthAvailable(name)) {
PlayerAuth auth = PlayerAuth.builder()
.name(name)
.realName(player.getName())
.location(spawn)
.build();
dataSource.updateQuitLoc(auth);
bungeeSender.sendAuthMeBungeecordMessage(MessageType.REFRESH_QUITLOC, name);
}
if (spawn != null && spawn.getWorld() != null) {
event.setRespawnLocation(spawn);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerShear(PlayerShearEntityEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerFish(PlayerFishEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerEditBook(PlayerEditBookEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) {
if (listenerService.shouldCancelEvent(event)) {
event.setCancelled(true);
}
}
}
@@ -21,5 +21,4 @@ public class PlayerListener19 implements Listener {
event.setCancelled(true);
}
}
}
@@ -33,5 +33,4 @@ public class PlayerListener19Spigot implements Listener {
event.setSpawnLocation(customSpawnLocation);
}
}
}
@@ -32,11 +32,6 @@ public class ServerListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST)
public void onPluginDisable(PluginDisableEvent event) {
// Make sure the plugin instance isn't null
if (event.getPlugin() == null) {
return;
}
final String pluginName = event.getPlugin().getName();
// Call the onPluginDisable method in the permissions manager
@@ -63,11 +58,6 @@ public class ServerListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST)
public void onPluginEnable(PluginEnableEvent event) {
// Make sure the plugin instance isn't null
if (event.getPlugin() == null) {
return;
}
final String pluginName = event.getPlugin().getName();
// Call the onPluginEnable method in the permissions manager
@@ -146,6 +146,9 @@ public enum MessageKey {
/** The server is full, try again later! */
KICK_FULL_SERVER("on_join_validation.kick_full_server"),
/** An error occurred: unresolved player hostname! **/
KICK_UNRESOLVED_HOSTNAME("error.kick_unresolved_hostname"),
/** Usage: /email add &lt;email&gt; &lt;confirmEmail&gt; */
USAGE_ADD_EMAIL("email.usage_email_add"),
@@ -4,7 +4,6 @@ import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.initialization.Reloadable;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.listener.JoiningPlayer;
import fr.xephi.authme.permission.handlers.LuckPermsHandler;
import fr.xephi.authme.permission.handlers.PermissionHandler;
import fr.xephi.authme.permission.handlers.PermissionHandlerException;
@@ -227,18 +226,6 @@ public class PermissionsManager implements Reloadable {
return player.hasPermission(permissionNode.getNode());
}
/**
* Check if the given player has permission for the given permission node.
*
* @param joiningPlayer The player to check
* @param permissionNode The permission node to verify
*
* @return true if the player has permission, false otherwise
*/
public boolean hasPermission(JoiningPlayer joiningPlayer, PermissionNode permissionNode) {
return joiningPlayer.getPermissionLookupFunction().apply(this, permissionNode);
}
/**
* Check if a player has permission for the given permission node. This is for offline player checks.
* If no permissions system is used, then the player will not have permission.
@@ -89,8 +89,9 @@ public class AsynchronousJoin implements AsynchronousProcess {
}
if (service.getProperty(RestrictionSettings.FORCE_SURVIVAL_MODE)
&& player.getGameMode() != GameMode.SURVIVAL
&& !service.hasPermission(player, PlayerStatePermission.BYPASS_FORCE_SURVIVAL)) {
bukkitService.runTask(() -> player.setGameMode(GameMode.SURVIVAL));
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> player.setGameMode(GameMode.SURVIVAL));
}
if (service.getProperty(HooksSettings.DISABLE_SOCIAL_SPY)) {
@@ -100,7 +100,6 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
// The Login event now fires (as intended) after everything is processed
bukkitService.callEvent(new LoginEvent(player));
player.saveData();
// Login is done, display welcome message
welcomeMessageConfiguration.sendWelcomeMessage(player);
@@ -41,7 +41,6 @@ public class ProcessSyncEmailRegister implements SynchronousProcess {
service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
limboService.replaceTasksAfterRegistration(player);
player.saveData();
bukkitService.callEvent(new RegisterEvent(player));
logger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player));
}
@@ -67,7 +67,6 @@ public class ProcessSyncPasswordRegister implements SynchronousProcess {
service.send(player, MessageKey.ADD_EMAIL_MESSAGE);
}
player.saveData();
bukkitService.callEvent(new RegisterEvent(player));
logger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player));
@@ -128,7 +128,6 @@ public class AsynchronousUnregister implements AsynchronousProcess {
if (service.getProperty(RegistrationSettings.FORCE)) {
teleportationService.teleportOnJoin(player);
player.saveData();
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
limboService.createLimboPlayer(player, false);
@@ -82,14 +82,6 @@ public final class PluginSettings implements SettingsHolder {
public static final Property<Boolean> USE_ASYNC_TASKS =
newProperty("settings.useAsyncTasks", true);
@Comment({
"By default we handle the AsyncPlayerPreLoginEvent which makes the plugin faster",
"but it is incompatible with any permission plugin not included in our compatibility list.",
"If you have issues with permission checks on player join please disable this option."
})
public static final Property<Boolean> USE_ASYNC_PRE_LOGIN_EVENT =
newProperty("settings.useAsyncPreLoginEvent", true);
@Comment("The name of the server, used in some placeholders.")
public static final Property<String> SERVER_NAME = newProperty("settings.serverName", "Your Minecraft Server");
@@ -41,6 +41,7 @@ error:
unexpected_error: '&4An unexpected error occurred, please contact an administrator!'
kick_for_vip: '&3A VIP player has joined the server when it was full!'
logged_in: '&cYou''re already logged in!'
kick_unresolved_hostname: '&cAn error occurred: unresolved player hostname!'
# AntiBot
antibot: