package fr.xephi.authme.data.limbo; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.data.limbo.persistence.LimboPersistence; import fr.xephi.authme.output.ConsoleLoggerFactory; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.SpawnLoader; import org.bukkit.Location; import org.bukkit.entity.Player; import javax.inject.Inject; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import static fr.xephi.authme.settings.properties.LimboSettings.RESTORE_ALLOW_FLIGHT; import static fr.xephi.authme.settings.properties.LimboSettings.RESTORE_FLY_SPEED; import static fr.xephi.authme.settings.properties.LimboSettings.RESTORE_WALK_SPEED; /** * Service for managing players that are in "limbo," a temporary state players are * put in which have joined but not yet logged in. */ public class LimboService { private final ConsoleLogger logger = ConsoleLoggerFactory.get(LimboService.class); private final Map<String, LimboPlayer> entries = new ConcurrentHashMap<>(); @Inject private Settings settings; @Inject private LimboPlayerTaskManager taskManager; @Inject private LimboServiceHelper helper; @Inject private LimboPersistence persistence; @Inject private AuthGroupHandler authGroupHandler; @Inject private SpawnLoader spawnLoader; LimboService() { } /** * Creates a LimboPlayer for the given player and revokes all "limbo data" from the player. * * @param player the player to process * @param isRegistered whether or not the player is registered */ public void createLimboPlayer(Player player, boolean isRegistered) { final String name = player.getName().toLowerCase(); LimboPlayer limboFromDisk = persistence.getLimboPlayer(player); if (limboFromDisk != null) { logger.debug("LimboPlayer for `{0}` already exists on disk", name); } LimboPlayer existingLimbo = entries.remove(name); if (existingLimbo != null) { existingLimbo.clearTasks(); logger.debug("LimboPlayer for `{0}` already present in memory", name); } Location location = spawnLoader.getPlayerLocationOrSpawn(player); LimboPlayer limboPlayer = helper.merge(existingLimbo, limboFromDisk); limboPlayer = helper.merge(helper.createLimboPlayer(player, isRegistered, location), limboPlayer); taskManager.registerMessageTask(player, limboPlayer, isRegistered ? LimboMessageType.LOG_IN : LimboMessageType.REGISTER); taskManager.registerTimeoutTask(player, limboPlayer); helper.revokeLimboStates(player); authGroupHandler.setGroup(player, limboPlayer, isRegistered ? AuthGroupType.REGISTERED_UNAUTHENTICATED : AuthGroupType.UNREGISTERED); entries.put(name, limboPlayer); persistence.saveLimboPlayer(player, limboPlayer); } /** * Returns the limbo player for the given name, or null otherwise. * * @param name the name to retrieve the data for * @return the associated limbo player, or null if none available */ public LimboPlayer getLimboPlayer(String name) { return entries.get(name.toLowerCase()); } /** * Returns whether there is a limbo player for the given name. * * @param name the name to check * @return true if present, false otherwise */ public boolean hasLimboPlayer(String name) { return entries.containsKey(name.toLowerCase()); } /** * Restores the limbo data and subsequently deletes the entry. * <p> * Note that teleportation on the player is performed by {@link fr.xephi.authme.service.TeleportationService} and * changing the permission group is handled by {@link fr.xephi.authme.data.limbo.AuthGroupHandler}. * * @param player the player whose data should be restored */ public void restoreData(Player player) { String lowerName = player.getName().toLowerCase(); LimboPlayer limbo = entries.remove(lowerName); if (limbo == null) { logger.debug("No LimboPlayer found for `{0}` - cannot restore", lowerName); } else { player.setOp(limbo.isOperator()); settings.getProperty(RESTORE_ALLOW_FLIGHT).restoreAllowFlight(player, limbo); settings.getProperty(RESTORE_FLY_SPEED).restoreFlySpeed(player, limbo); settings.getProperty(RESTORE_WALK_SPEED).restoreWalkSpeed(player, limbo); limbo.clearTasks(); logger.debug("Restored LimboPlayer stats for `{0}`", lowerName); persistence.removeLimboPlayer(player); } authGroupHandler.setGroup(player, limbo, AuthGroupType.LOGGED_IN); } /** * Creates new tasks for the given player and cancels the old ones for a newly registered player. * This resets his time to log in (TimeoutTask) and updates the message he is shown (MessageTask). * * @param player the player to reset the tasks for */ public void replaceTasksAfterRegistration(Player player) { Optional<LimboPlayer> limboPlayer = getLimboOrLogError(player, "reset tasks"); limboPlayer.ifPresent(limbo -> { taskManager.registerTimeoutTask(player, limbo); taskManager.registerMessageTask(player, limbo, LimboMessageType.LOG_IN); }); authGroupHandler.setGroup(player, limboPlayer.orElse(null), AuthGroupType.REGISTERED_UNAUTHENTICATED); } /** * Resets the message task associated with the player's LimboPlayer. * * @param player the player to set a new message task for * @param messageType the message to show for the limbo player */ public void resetMessageTask(Player player, LimboMessageType messageType) { getLimboOrLogError(player, "reset message task") .ifPresent(limbo -> taskManager.registerMessageTask(player, limbo, messageType)); } /** * @param player the player whose message task should be muted */ public void muteMessageTask(Player player) { getLimboOrLogError(player, "mute message task") .ifPresent(limbo -> LimboPlayerTaskManager.setMuted(limbo.getMessageTask(), true)); } /** * @param player the player whose message task should be unmuted */ public void unmuteMessageTask(Player player) { getLimboOrLogError(player, "unmute message task") .ifPresent(limbo -> LimboPlayerTaskManager.setMuted(limbo.getMessageTask(), false)); } /** * Returns the limbo player for the given player or logs an error. * * @param player the player to retrieve the limbo player for * @param context the action for which the limbo player is being retrieved (for logging) * @return Optional with the limbo player */ private Optional<LimboPlayer> getLimboOrLogError(Player player, String context) { LimboPlayer limbo = entries.get(player.getName().toLowerCase()); if (limbo == null) { logger.debug("No LimboPlayer found for `{0}`. Action: {1}", player.getName(), context); } return Optional.ofNullable(limbo); } }