This commit is contained in:
mrchefran 2024-03-26 02:50:37 +04:00 committed by GitHub
commit f823606e5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 208 additions and 3 deletions

View File

@ -24,6 +24,7 @@ import fr.xephi.authme.security.crypts.Sha256;
import fr.xephi.authme.service.BackupService;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.MigrationService;
import fr.xephi.authme.service.SpectateLoginService;
import fr.xephi.authme.service.bungeecord.BungeeReceiver;
import fr.xephi.authme.service.yaml.YamlParseException;
import fr.xephi.authme.settings.Settings;
@ -69,6 +70,7 @@ public class AuthMe extends JavaPlugin {
private Injector injector;
private BackupService backupService;
private ConsoleLogger logger;
private SpectateLoginService spectateLoginService;
/**
* Constructor.
@ -246,6 +248,7 @@ public class AuthMe extends JavaPlugin {
bukkitService = injector.getSingleton(BukkitService.class);
commandHandler = injector.getSingleton(CommandHandler.class);
backupService = injector.getSingleton(BackupService.class);
spectateLoginService = injector.getSingleton(SpectateLoginService.class);
// Trigger instantiation (class not used elsewhere)
injector.getSingleton(BungeeReceiver.class);
@ -316,6 +319,9 @@ public class AuthMe extends JavaPlugin {
// Wait for tasks and close data source
new TaskCloser(this, database).run();
// Remove all armorstands so that the players do not get Spectator gamemode
spectateLoginService.removeArmorstands();
// Disabled correctly
Consumer<String> infoLogMethod = logger == null ? getLogger()::info : logger::info;
infoLogMethod.accept("AuthMe " + this.getDescription().getVersion() + " disabled!");

View File

@ -11,6 +11,7 @@ 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.SpectateLoginService;
import fr.xephi.authme.service.TeleportationService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.Settings;
@ -19,6 +20,7 @@ import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
@ -49,6 +51,8 @@ import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerShearEntityEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.inventory.InventoryView;
import javax.inject.Inject;
@ -91,6 +95,8 @@ public class PlayerListener implements Listener {
private PermissionsManager permissionsManager;
@Inject
private QuickCommandsProtectionManager quickCommandsProtectionManager;
@Inject
private SpectateLoginService spectateLoginService;
// Lowest priority to apply fast protection checks
@EventHandler(priority = EventPriority.LOWEST)
@ -376,6 +382,36 @@ public class PlayerListener implements Listener {
if (spawn != null && spawn.getWorld() != null) {
event.setRespawnLocation(spawn);
}
if (settings.getProperty(RestrictionSettings.SPECTATE_STAND_LOGIN)
|| spectateLoginService.hasStand(event.getPlayer())) {
// If a player is dead, no stand will be created for him
// therefore we can be sure that there will not be two stands
bukkitService.runTaskLater(() -> {
spectateLoginService.createStand(event.getPlayer());
}, 1L);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onToggleSneak(PlayerToggleSneakEvent event) {
if (listenerService.shouldCancelEvent(event.getPlayer())
&& (settings.getProperty(RestrictionSettings.SPECTATE_STAND_LOGIN)
|| spectateLoginService.hasStand(event.getPlayer()))) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onTeleport(PlayerTeleportEvent event) {
if (listenerService.shouldCancelEvent(event.getPlayer())
&& event.getCause() == PlayerTeleportEvent.TeleportCause.SPECTATE
&& event.getPlayer().getGameMode() == GameMode.SPECTATOR
&& (settings.getProperty(RestrictionSettings.SPECTATE_STAND_LOGIN)
|| spectateLoginService.hasStand(event.getPlayer()))) {
spectateLoginService.updateTarget(event.getPlayer());
event.setCancelled(true);
}
}
/*
@ -509,4 +545,5 @@ public class PlayerListener implements Listener {
event.setCancelled(true);
}
}
}

View File

@ -14,6 +14,7 @@ import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.PluginHookService;
import fr.xephi.authme.service.SessionService;
import fr.xephi.authme.service.SpectateLoginService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.bungeecord.BungeeSender;
import fr.xephi.authme.service.bungeecord.MessageType;
@ -41,7 +42,7 @@ import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_IN
* Asynchronous process for when a player joins.
*/
public class AsynchronousJoin implements AsynchronousProcess {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsynchronousJoin.class);
@Inject
@ -83,6 +84,9 @@ public class AsynchronousJoin implements AsynchronousProcess {
@Inject
private ProxySessionManager proxySessionManager;
@Inject
private SpectateLoginService spectateLoginService;
AsynchronousJoin() {
}
@ -181,7 +185,7 @@ public class AsynchronousJoin implements AsynchronousProcess {
* Performs various operations in sync mode for an unauthenticated player (such as blindness effect and
* limbo player creation).
*
* @param player the player to process
* @param player the player to process
* @param isAuthAvailable true if the player is registered, false otherwise
*/
private void processJoinSync(Player player, boolean isAuthAvailable) {
@ -199,6 +203,13 @@ public class AsynchronousJoin implements AsynchronousProcess {
int blindTimeOut = (registrationTimeout <= 0) ? 99999 : registrationTimeout;
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, blindTimeOut, 2));
}
if (service.getProperty(RestrictionSettings.SPECTATE_STAND_LOGIN)) {
// The delay is necessary in order to make sure that the player is teleported to spawn
// and after authorization appears in the same place
bukkitService.runTaskLater(() -> spectateLoginService.createStand(player), 1L);
}
commandManager.runCommandsOnJoin(player);
});
}
@ -209,7 +220,6 @@ public class AsynchronousJoin implements AsynchronousProcess {
*
* @param player the player to verify
* @param ip the ip address of the player
*
* @return true if the verification is OK (no infraction), false if player has been kicked
*/
private boolean validatePlayerCountForIp(Player player, String ip) {

View File

@ -12,11 +12,13 @@ import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.JoinMessageService;
import fr.xephi.authme.service.SpectateLoginService;
import fr.xephi.authme.service.TeleportationService;
import fr.xephi.authme.service.bungeecord.BungeeSender;
import fr.xephi.authme.settings.WelcomeMessageConfiguration;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
@ -58,6 +60,9 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
@Inject
private PermissionsManager permissionsManager;
@Inject
private SpectateLoginService spectateLoginService;
ProcessSyncPlayerLogin() {
}
@ -99,6 +104,11 @@ public class ProcessSyncPlayerLogin implements SynchronousProcess {
player.removePotionEffect(PotionEffectType.BLINDNESS);
}
if (commonService.getProperty(RestrictionSettings.SPECTATE_STAND_LOGIN)
|| spectateLoginService.hasStand(player)) {
spectateLoginService.removeStand(player);
}
// The Login event now fires (as intended) after everything is processed
bukkitService.callEvent(new LoginEvent(player));

View File

@ -9,6 +9,7 @@ import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.SpectateLoginService;
import fr.xephi.authme.service.TeleportationService;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.RegistrationSettings;
@ -44,6 +45,9 @@ public class ProcessSyncPlayerLogout implements SynchronousProcess {
@Inject
private CommandManager commandManager;
@Inject
private SpectateLoginService spectateLoginService;
ProcessSyncPlayerLogout() {
}
@ -65,6 +69,10 @@ public class ProcessSyncPlayerLogout implements SynchronousProcess {
service.send(player, MessageKey.LOGOUT_SUCCESS);
logger.info(player.getName() + " logged out");
if (service.getProperty(RestrictionSettings.SPECTATE_STAND_LOGIN)) {
spectateLoginService.createStand(player);
}
}
private void applyLogoutEffect(Player player) {

View File

@ -2,7 +2,10 @@ package fr.xephi.authme.process.quit;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.SpectateLoginService;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.entity.Player;
import javax.inject.Inject;
@ -10,12 +13,18 @@ import javax.inject.Inject;
public class ProcessSyncPlayerQuit implements SynchronousProcess {
@Inject
private CommonService service;
@Inject
private LimboService limboService;
@Inject
private CommandManager commandManager;
@Inject
private SpectateLoginService spectateLoginService;
/**
* Processes a player having quit.
*
@ -26,6 +35,11 @@ public class ProcessSyncPlayerQuit implements SynchronousProcess {
if (wasLoggedIn) {
commandManager.runCommandsOnLogout(player);
} else {
if (service.getProperty(RestrictionSettings.SPECTATE_STAND_LOGIN)
|| spectateLoginService.hasStand(player)) {
spectateLoginService.removeStand(player);
}
limboService.restoreData(player);
player.saveData(); // #1238: Speed is sometimes not restored properly
}

View File

@ -0,0 +1,104 @@
package fr.xephi.authme.service;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.HashMap;
import java.util.Map;
/**
* Sets the player gamemode to Spectator, puts the player in an invisible armorstand and fixes the direction of the view
*/
public class SpectateLoginService {
private Map<Player, ArmorStand> armorStands = new HashMap<>();
private Map<Player, GameMode> gameModeMap = new HashMap<>();
@Inject
private CommonService service;
/**
* Creates a stand for the player
*
* @param player the player
*/
public void createStand(Player player) {
if (player.isDead()) {
return;
}
Location location = player.getLocation();
ArmorStand stand = spawnStand(location);
armorStands.put(player, stand);
gameModeMap.put(player, player.getGameMode());
player.setGameMode(GameMode.SPECTATOR);
player.setSpectatorTarget(stand);
}
/**
* Updates spectator target for the player
*
* @param player the player
*/
public void updateTarget(Player player) {
ArmorStand stand = armorStands.get(player);
if (stand != null) {
player.setSpectatorTarget(stand);
}
}
/**
* Removes the player's stand and deletes effects
*
* @param player the player
*/
public void removeStand(Player player) {
ArmorStand stand = armorStands.get(player);
if (stand != null) {
stand.remove();
player.setSpectatorTarget(null);
player.setGameMode(gameModeMap.get(player));
gameModeMap.remove(player);
armorStands.remove(player);
}
}
/**
* Removes all armorstands and restores player gamemode
*/
public void removeArmorstands() {
for (Player player : armorStands.keySet()) {
removeStand(player);
}
gameModeMap.clear();
armorStands.clear();
}
public boolean hasStand(Player player) {
return armorStands.containsKey(player);
}
private ArmorStand spawnStand(Location loc) {
double pitch = service.getProperty(RestrictionSettings.HEAD_PITCH);
double yaw = service.getProperty(RestrictionSettings.HEAD_YAW);
Location location = new Location(loc.getWorld(), loc.getX(), loc.getY(), loc.getBlockZ(),
(float) yaw, (float) pitch);
ArmorStand stand = location.getWorld().spawn(location, ArmorStand.class);
stand.setGravity(false);
stand.setAI(false);
stand.setInvisible(true);
return stand;
}
}

View File

@ -193,6 +193,22 @@ public final class RestrictionSettings implements SettingsHolder {
public static final Property<Set<String>> UNRESTRICTED_INVENTORIES =
newLowercaseStringSetProperty("settings.unrestrictions.UnrestrictedInventories");
@Comment({
"While in unregistered/logged out state, should players be set to spectator mode and",
"forced to spectate within a spawn point invisible armor stand, for 0 movement and head",
"pitch + yaw? may be more effective than 'allowMovement' at locking the player in place."
})
public static final Property<Boolean> SPECTATE_STAND_LOGIN =
newProperty("settings.restrictions.spectateStandLogin.enabled", false);
@Comment("Head Yaw position for 'spectateStandLogin'.")
public static final Property<Double> HEAD_YAW =
newProperty("settings.restrictions.spectateStandLogin.headYaw", 0.0f);
@Comment("Head Pitch position for 'spectateStandLogin'.")
public static final Property<Double> HEAD_PITCH =
newProperty("settings.restrictions.spectateStandLogin.headPitch", 0.0f);
private RestrictionSettings() {
}