package world.bentobox.bentobox.listeners; import java.util.Collections; import java.util.Objects; import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.addons.GameModeAddon; import world.bentobox.bentobox.api.events.island.IslandEvent; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Players; import world.bentobox.bentobox.lists.Flags; import world.bentobox.bentobox.managers.BlueprintsManager; import world.bentobox.bentobox.managers.PlayersManager; import world.bentobox.bentobox.managers.RanksManager; import world.bentobox.bentobox.util.Util; public class JoinLeaveListener implements Listener { private final BentoBox plugin; private final PlayersManager players; /** * @param plugin - plugin object */ public JoinLeaveListener(@NonNull BentoBox plugin) { this.plugin = plugin; players = plugin.getPlayers(); } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onPlayerJoin(final PlayerJoinEvent event) { // Remove them from the cache, just in case they were not removed for some // reason User.removePlayer(event.getPlayer()); User user = User.getInstance(event.getPlayer()); if (!user.isPlayer() || user.getUniqueId() == null) { // This should never be the case, but it might be caused by some fake player // plugins return; } UUID playerUUID = event.getPlayer().getUniqueId(); // Check if player hasn't joined before if (!players.isKnown(playerUUID)) { firstTime(user); } // Make sure the player is loaded into the cache or create the player if they // don't exist players.addPlayer(playerUUID); // Reset island resets if required plugin.getIWM().getOverWorlds().stream() .filter(w -> event.getPlayer().getLastPlayed() < plugin.getIWM().getResetEpoch(w)) .forEach(w -> players.setResets(w, playerUUID, 0)); // Update the island range of the islands the player owns updateIslandRange(user); // Set the player's name (it may have changed), but only if it isn't empty if (!user.getName().isEmpty()) { players.setPlayerName(user); players.save(playerUUID); } else { plugin.logWarning("Player that just logged in has no name! " + playerUUID); } // Set the primary island to the player's location if this is their island plugin.getIslands().getIslandAt(user.getLocation()).filter(i -> user.getUniqueId().equals(i.getOwner())) .ifPresent(i -> plugin.getIslands().setPrimaryIsland(playerUUID, i)); // If mobs have to be removed when a player joins, then wipe all the mobs on his // island. if (plugin.getIslands().locationIsOnIsland(event.getPlayer(), user.getLocation()) && Flags.REMOVE_MOBS.isSetForWorld(user.getWorld())) { Bukkit.getScheduler().runTask(plugin, () -> plugin.getIslands().clearArea(user.getLocation())); } // Clear inventory if required clearPlayersInventory(Util.getWorld(event.getPlayer().getWorld()), user); // Set island max members and homes based on permissions if this player is the // owner of an island plugin.getIWM().getOverWorlds().stream().map(w -> plugin.getIslands().getIsland(w, playerUUID)) .filter(Objects::nonNull).filter(i -> playerUUID.equals(i.getOwner())).forEach(i -> { plugin.getIslands().getMaxMembers(i, RanksManager.MEMBER_RANK); plugin.getIslands().getMaxMembers(i, RanksManager.COOP_RANK); plugin.getIslands().getMaxMembers(i, RanksManager.TRUSTED_RANK); plugin.getIslands().getMaxHomes(i); }); // Add a player to the bStats cache. plugin.getMetrics().ifPresent(bStats -> bStats.addPlayer(playerUUID)); } private void firstTime(User user) { // Make sure the player is loaded into the cache or create the player if they // don't exist players.addPlayer(user.getUniqueId()); plugin.getIWM().getOverWorlds().stream().filter(w -> plugin.getIWM().isCreateIslandOnFirstLoginEnabled(w)) .forEach(w -> { // Even if that'd be extremely unlikely, it's better to check if the player // doesn't have an island already. if (!(plugin.getIslands().hasIsland(w, user) || plugin.getIslands().inTeam(w, user.getUniqueId()))) { int delay = plugin.getIWM().getCreateIslandOnFirstLoginDelay(w); user.sendMessage("commands.island.create.on-first-login", TextVariables.NUMBER, String.valueOf(delay)); Runnable createIsland = () -> { // should only execute if: // - abort on logout is false // - abort on logout is true && user is online if (!plugin.getIWM().isCreateIslandOnFirstLoginAbortOnLogout(w) || user.isOnline()) { plugin.getIWM().getAddon(w) .flatMap(addon -> addon.getPlayerCommand() .flatMap(command -> command.getSubCommand("create"))) .ifPresent(command -> command.execute(user, "create", Collections.singletonList(BlueprintsManager.DEFAULT_BUNDLE_NAME))); } }; if (delay <= 0) { Bukkit.getScheduler().runTask(plugin, createIsland); } else { Bukkit.getScheduler().runTaskLater(plugin, createIsland, delay * 20L); } } }); } /** * This event will clean players inventory * * @param event SwitchWorld event. */ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onPlayerSwitchWorld(final PlayerChangedWorldEvent event) { World world = Util.getWorld(event.getPlayer().getWorld()); // Clear inventory if required if (world != null) { clearPlayersInventory(world, User.getInstance(event.getPlayer())); } } /** * This method clears player inventory and ender chest if given world is * quarantined in user data file and it is required by plugin settings. * * @param world World where cleaning must occur. * @param user Targeted user. */ private void clearPlayersInventory(@Nullable World world, @NonNull User user) { if (user.getUniqueId() == null || world == null) return; // Clear inventory if required Players playerData = players.getPlayer(user.getUniqueId()); if (playerData != null && playerData.getPendingKicks().contains(world.getName())) { if (plugin.getIWM().isOnLeaveResetEnderChest(world)) { user.getPlayer().getEnderChest().clear(); } if (plugin.getIWM().isOnLeaveResetInventory(world)) { user.getPlayer().getInventory().clear(); } playerData.getPendingKicks().remove(world.getName()); players.save(user.getUniqueId()); } } private void updateIslandRange(User user) { plugin.getIslands().getIslands().stream() .filter(island -> island.getOwner() != null && island.getOwner().equals(user.getUniqueId())) .forEach(island -> { // Check if new owner has a different range permission than the island size int range = user.getPermissionValue(plugin.getIWM().getAddon(island.getWorld()) .map(GameModeAddon::getPermissionPrefix).orElse("") + "island.range", island.getRawProtectionRange()); // Range cannot be greater than the island distance range = Math.min(range, plugin.getIWM().getIslandDistance(island.getWorld())); // Range can go up or down if (range != island.getRawProtectionRange()) { user.sendMessage("commands.admin.setrange.range-updated", TextVariables.NUMBER, String.valueOf(range)); int oldRange = island.getProtectionRange(); island.setProtectionRange(range); plugin.log("Island protection range changed from " + oldRange + " to " + island.getProtectionRange() + " for " + user.getName() + " due to permission."); // Call Protection Range Change event. Does not support canceling. IslandEvent.builder().island(island).location(island.getProtectionCenter()) .reason(IslandEvent.Reason.RANGE_CHANGE).involvedPlayer(user.getUniqueId()).admin(true) .protectionRange(island.getProtectionRange(), oldRange).build(); } }); } @EventHandler(priority = EventPriority.NORMAL) public void onPlayerQuit(final PlayerQuitEvent event) { // Remove any coops if all the island players have left // Go through all the islands this player is a member of, check if all members // have left, remove coops plugin.getIslands().getIslands().stream() .filter(island -> island.getMembers().containsKey(event.getPlayer().getUniqueId())).forEach(island -> { // Are there any online players still for this island? if (Bukkit.getOnlinePlayers().stream().filter(p -> !event.getPlayer().equals(p)) .noneMatch(p -> island.inTeam(p.getUniqueId()))) { // No, there are no more players online on this island // Tell players they are being removed island.getMembers().entrySet().stream().filter(e -> e.getValue() == RanksManager.COOP_RANK) .forEach(e -> User.getInstance(e.getKey()).sendMessage( "commands.island.team.uncoop.all-members-logged-off", TextVariables.NAME, plugin.getPlayers().getName(island.getOwner()))); // Remove any coop players on this island island.removeRank(RanksManager.COOP_RANK); } }); // Remove any coop associations from the player logging out plugin.getIslands().clearRank(RanksManager.COOP_RANK, event.getPlayer().getUniqueId()); players.save(event.getPlayer().getUniqueId()); User.removePlayer(event.getPlayer()); } }