Compare commits

...
22 changed files with 852 additions and 348 deletions

No files matched your search

@@ -11,6 +11,7 @@ import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Flags;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.Syntax;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager;
import com.onarandombox.MultiverseCore.commandtools.MultiverseCommand;
import com.onarandombox.MultiverseCore.destination.DestinationsProvider;
@@ -49,16 +50,18 @@ public class TeleportCommand extends MultiverseCommand {
) {
// TODO Add warning if teleporting too many players at once.
String playerName = players.length == 1
? issuer.getPlayer() == players[0] ? "you" : players[0].getName()
: players.length + " players";
issuer.sendInfo(MVCorei18n.TELEPORT_SUCCESS,
"{player}", playerName, "{destination}", destination.toString());
CompletableFuture.allOf(Arrays.stream(players)
.map(player -> this.destinationsProvider.playerTeleportAsync(issuer, player, destination))
.toArray(CompletableFuture[]::new))
.thenRun(() -> {
String playerName = players.length == 1
? issuer.getPlayer() == players[0] ? "you" : players[0].getName()
: players.length + " players";
issuer.sendInfo(MVCorei18n.TELEPORT_SUCCESS,
"{player}", playerName, "{destination}", destination.toString());
Logging.finer("Async teleport completed.");
});
}
@@ -1,5 +1,6 @@
package com.onarandombox.MultiverseCore.economy;
import com.onarandombox.MultiverseCore.api.MVWorld;
import jakarta.inject.Inject;
import org.bukkit.Material;
import org.bukkit.World;
@@ -91,6 +92,35 @@ public class MVEconomist {
return "Sorry, you don't have enough " + (isItemCurrency(currency) ? "items" : "funds") + ". " + message;
}
/**
* Pays for a given amount of currency either from the player's economy account or inventory if the currency.
*
* @param player the player to deposit currency into.
* @param world the world to take entry fee from.
*/
public void payEntryFee(Player player, MVWorld world) {
payEntryFee(player, world.getPrice(), world.getCurrency());
}
/**
* Pays for a given amount of currency either from the player's economy account or inventory if the currency
*
* @param player the player to take currency from.
* @param price the amount to take.
* @param currency the type of currency.
*/
public void payEntryFee(Player player, double price, Material currency) {
if (price == 0D) {
return;
}
if (price < 0) {
this.deposit(player, -price, currency);
} else {
this.withdraw(player, price, currency);
}
}
/**
* Deposits a given amount of currency either into the player's economy account or inventory if the currency
* is not null.
@@ -43,11 +43,7 @@ public class MVChatListener implements InjectableListener {
// Check whether the Server is set to prefix the chat with the World name.
// If not we do nothing, if so we need to check if the World has an Alias.
if (config.isEnablePrefixChat()) {
String world = playerListener.getPlayerWorld().get(event.getPlayer().getName());
if (world == null) {
world = event.getPlayer().getWorld().getName();
playerListener.getPlayerWorld().put(event.getPlayer().getName(), world);
}
String world = event.getPlayer().getWorld().getName();
String prefix = "";
// If we're not a MV world, don't do anything
if (!this.worldManager.isMVWorld(world)) {
@@ -1,27 +1,23 @@
/******************************************************************************
* Multiverse 2 Copyright (c) the Multiverse Team 2011. *
* Multiverse 2 is licensed under the BSD License. *
* For more information please check the README.md file included *
* with this project. *
******************************************************************************/
package com.onarandombox.MultiverseCore.listeners;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.economy.MVEconomist;
import com.onarandombox.MultiverseCore.event.MVRespawnEvent;
import com.onarandombox.MultiverseCore.inject.InjectableListener;
import com.onarandombox.MultiverseCore.teleportation.TeleportQueue;
import com.onarandombox.MultiverseCore.utils.MVPermissions;
import com.onarandombox.MultiverseCore.utils.PermissionTools;
import com.onarandombox.MultiverseCore.utils.permissions.PermissionsChecker;
import com.onarandombox.MultiverseCore.utils.result.ResultGroup;
import com.onarandombox.MultiverseCore.world.entrycheck.BlacklistResult;
import com.onarandombox.MultiverseCore.world.entrycheck.EntryFeeResult;
import com.onarandombox.MultiverseCore.world.entrycheck.PlayerLimitResult;
import com.onarandombox.MultiverseCore.world.entrycheck.WorldAccessResult;
import com.onarandombox.MultiverseCore.world.entrycheck.WorldEntryCheckerProvider;
import io.vavr.control.Option;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import org.bukkit.GameMode;
@@ -38,366 +34,298 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
/**
* Multiverse's Listener for players.
*/
@Service
public class MVPlayerListener implements InjectableListener {
private final Plugin plugin;
private final MVCoreConfig config;
private final Provider<MVWorldManager> worldManagerProvider;
private final PermissionTools pt;
private final Provider<MVPermissions> mvPermsProvider;
private final SafeTTeleporter safeTTeleporter;
private final Server server;
private final TeleportQueue teleportQueue;
private final Map<String, String> playerWorld = new ConcurrentHashMap<String, String>();
private final @NotNull MultiverseCore plugin;
private final @NotNull MVCoreConfig config;
private final @NotNull Server server;
private final @NotNull TeleportQueue teleportQueue;
private final @NotNull Provider<MVWorldManager> worldManagerProvider;
private final @NotNull WorldEntryCheckerProvider worldEntryCheckerProvider;
private final @NotNull MVEconomist economist;
private final @NotNull PermissionsChecker permissionsChecker;
private final @NotNull SafeTTeleporter safeTTeleporter;
@Inject
public MVPlayerListener(
MultiverseCore plugin,
MVCoreConfig config,
Provider<MVWorldManager> worldManagerProvider,
PermissionTools permissionTools,
Provider<MVPermissions> mvPermsProvider,
SafeTTeleporter safeTTeleporter,
Server server,
TeleportQueue teleportQueue
) {
MVPlayerListener(
@NotNull MultiverseCore plugin,
@NotNull MVCoreConfig config,
@NotNull Server server,
@NotNull TeleportQueue teleportQueue,
@NotNull Provider<MVWorldManager> worldManagerProvider,
@NotNull WorldEntryCheckerProvider worldEntryCheckerProvider,
@NotNull MVEconomist economist,
@NotNull PermissionsChecker permissionsChecker,
@NotNull SafeTTeleporter safeTTeleporter
) {
this.plugin = plugin;
this.config = config;
this.worldManagerProvider = worldManagerProvider;
this.pt = permissionTools;
this.mvPermsProvider = mvPermsProvider;
this.safeTTeleporter = safeTTeleporter;
this.server = server;
this.teleportQueue = teleportQueue;
this.worldManagerProvider = worldManagerProvider;
this.worldEntryCheckerProvider = worldEntryCheckerProvider;
this.economist = economist;
this.permissionsChecker = permissionsChecker;
this.safeTTeleporter = safeTTeleporter;
}
private MVWorldManager getWorldManager() {
return worldManagerProvider.get();
}
@EventHandler
public void playerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
Location spawnLocation = getWorldManager().getFirstSpawnWorld().getSpawnLocation();
private MVPermissions getMVPerms() {
return mvPermsProvider.get();
}
/**
* @return the playerWorld-map
*/
public Map<String, String> getPlayerWorld() {
return playerWorld;
}
/**
* This method is called when a player respawns.
* @param event The Event that was fired.
*/
@EventHandler(priority = EventPriority.LOW)
public void playerRespawn(PlayerRespawnEvent event) {
World world = event.getPlayer().getWorld();
MVWorld mvWorld = getWorldManager().getMVWorld(world.getName());
// If it's not a World MV manages we stop.
if (mvWorld == null) {
if (!player.hasPlayedBefore()) {
Logging.finer("Player joined for the FIRST time!");
if (config.getFirstSpawnOverride()) {
Logging.fine("Moving NEW player to spawn location: %s", spawnLocation);
oneTickLater(() -> player.teleport(spawnLocation));
}
return;
}
if (mvWorld.getBedRespawn() && (event.isBedSpawn() || event.isAnchorSpawn())) {
Logging.finer("Player joined AGAIN!");
MVWorld world = getWorldManager().getMVWorld(player.getWorld());
if (world == null) {
// We don't want to do anything if the player is not in a world managed by MV.
Logging.fine("Player joined in a world not managed by MV.");
return;
}
worldEntryCheckerProvider.forWorld(player, world)
.canStayInWorld()
.onSuccess(() -> oneTickLater(() -> handleGameModeAndFlight(player, world)))
.onFailure(() -> {
player.sendMessage("[MV] - Sorry you can't be in this world anymore!");
oneTickLater(() -> player.teleport(spawnLocation));
});
}
@EventHandler(priority = EventPriority.LOW)
public void playerRespawn(PlayerRespawnEvent event) {
MVWorld playerWorld = getWorldManager().getMVWorld(event.getPlayer().getWorld());
if (playerWorld == null) {
// We don't want to do anything if the player is not in a world managed by MV.
Logging.fine("Player respawned in a world not managed by MV.");
return;
}
if (playerWorld.getBedRespawn() && (event.isBedSpawn() || event.isAnchorSpawn())) {
Logging.fine("Spawning %s at their %s.", event.getPlayer().getName(), event.isBedSpawn() ? "BED" : "ANCHOR");
return;
}
// Get the instance of the World the player should respawn at.
MVWorld respawnWorld = null;
if (getWorldManager().isMVWorld(mvWorld.getRespawnToWorld())) {
respawnWorld = getWorldManager().getMVWorld(mvWorld.getRespawnToWorld());
}
// If it's null then it either means the World doesn't exist or the value is blank, so we don't handle it.
// NOW: We'll always handle it to get more accurate spawns
if (respawnWorld != null) {
world = respawnWorld.getCBWorld();
}
// World has been set to the appropriate world
Location respawnLocation = getMostAccurateRespawnLocation(world);
MVRespawnEvent respawnEvent = new MVRespawnEvent(respawnLocation, event.getPlayer(), "compatability");
Location respawnLocation = getMostAccurateRespawnLocation(playerWorld.getRespawnToWorld());
MVRespawnEvent respawnEvent = new MVRespawnEvent(respawnLocation, event.getPlayer(), "compatability"); //TODO: Update this event with proper respawn method
this.server.getPluginManager().callEvent(respawnEvent);
event.setRespawnLocation(respawnEvent.getPlayersRespawnLocation());
}
private Location getMostAccurateRespawnLocation(World w) {
MVWorld mvw = getWorldManager().getMVWorld(w.getName());
if (mvw != null) {
return mvw.getSpawnLocation();
}
return w.getSpawnLocation();
private Location getMostAccurateRespawnLocation(@NotNull World respawnWorld) {
return Option.of(getWorldManager().getMVWorld(respawnWorld))
.map(MVWorld::getSpawnLocation)
.getOrElse(respawnWorld.getSpawnLocation());
}
/**
* This method is called when a player joins the server.
* @param event The Event that was fired.
*/
@EventHandler
public void playerJoin(PlayerJoinEvent event) {
Player p = event.getPlayer();
if (!p.hasPlayedBefore()) {
Logging.finer("Player joined for the FIRST time!");
if (config.getFirstSpawnOverride()) {
Logging.fine("Moving NEW player to(firstspawnoverride): "
+ getWorldManager().getFirstSpawnWorld().getSpawnLocation());
this.sendPlayerToDefaultWorld(p);
}
return;
} else {
Logging.finer("Player joined AGAIN!");
if (config.getEnforceAccess() // check this only if we're enforcing access!
&& !this.getMVPerms().hasPermission(p, "multiverse.access." + p.getWorld().getName(), false)) {
p.sendMessage("[MV] - Sorry you can't be in this world anymore!");
this.sendPlayerToDefaultWorld(p);
}
}
// Handle the Players GameMode setting for the new world.
this.handleGameModeAndFlight(event.getPlayer(), event.getPlayer().getWorld());
playerWorld.put(p.getName(), p.getWorld().getName());
}
/**
* This method is called when a player changes worlds.
* @param event The Event that was fired.
*/
@EventHandler(priority = EventPriority.MONITOR)
public void playerChangedWorld(PlayerChangedWorldEvent event) {
// Permissions now determine whether or not to handle a gamemode.
this.handleGameModeAndFlight(event.getPlayer(), event.getPlayer().getWorld());
playerWorld.put(event.getPlayer().getName(), event.getPlayer().getWorld().getName());
}
/**
* This method is called when a player teleports anywhere.
* @param event The Event that was fired.
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void playerTeleport(PlayerTeleportEvent event) {
Logging.finer("Got teleport event for player '"
+ event.getPlayer().getName() + "' with cause '" + event.getCause() + "'");
if (event.isCancelled()) {
return;
}
Player teleportee = event.getPlayer();
CommandSender teleporter = null;
Optional<String> teleporterName = teleportQueue.popFromQueue(teleportee.getName());
if (teleporterName.isPresent()) {
if (teleporterName.equals("CONSOLE")) {
Logging.finer("We know the teleporter is the console! Magical!");
teleporter = this.server.getConsoleSender();
} else {
teleporter = this.server.getPlayerExact(teleporterName.get());
}
}
Logging.finer("Inferred sender '" + teleporter + "' from name '"
+ teleporterName + "', fetched from name '" + teleportee.getName() + "'");
MVWorld fromWorld = getWorldManager().getMVWorld(event.getFrom().getWorld().getName());
MVWorld toWorld = getWorldManager().getMVWorld(event.getTo().getWorld().getName());
if (toWorld == null) {
Logging.fine("Player '" + teleportee.getName() + "' is teleporting to world '"
+ event.getTo().getWorld().getName() + "' which is not managed by Multiverse-Core. No further "
+ "actions will be taken by Multiverse-Core.");
return;
}
if (event.getFrom().getWorld().equals(event.getTo().getWorld())) {
// The player is Teleporting to the same world.
Logging.finer("Player '" + teleportee.getName() + "' is teleporting to the same world.");
this.stateSuccess(teleportee.getName(), toWorld.getAlias());
return;
}
// TODO: Refactor these lines.
// Charge the teleporter
event.setCancelled(!pt.playerHasMoneyToEnter(fromWorld, toWorld, teleporter, teleportee, true));
if (event.isCancelled() && teleporter != null) {
Logging.fine("Player '" + teleportee.getName()
+ "' was DENIED ACCESS to '" + toWorld.getAlias()
+ "' because '" + teleporter.getName()
+ "' don't have the FUNDS required to enter it.");
return;
}
// Check if player is allowed to enter the world if we're enforcing permissions
if (config.getEnforceAccess()) {
event.setCancelled(!pt.playerCanGoFromTo(fromWorld, toWorld, teleporter, teleportee));
if (event.isCancelled() && teleporter != null) {
Logging.fine("Player '" + teleportee.getName()
+ "' was DENIED ACCESS to '" + toWorld.getAlias()
+ "' because '" + teleporter.getName()
+ "' don't have: multiverse.access." + event.getTo().getWorld().getName());
return;
}
} else {
Logging.fine("Player '" + teleportee.getName()
+ "' was allowed to go to '" + toWorld.getAlias() + "' because enforceaccess is off.");
}
// Does a limit actually exist?
if (toWorld.getPlayerLimit() > -1) {
// Are there equal or more people on the world than the limit?
if (toWorld.getCBWorld().getPlayers().size() >= toWorld.getPlayerLimit()) {
// Ouch the world is full, lets see if the player can bypass that limitation
if (!pt.playerCanBypassPlayerLimit(toWorld, teleporter, teleportee)) {
Logging.fine("Player '" + teleportee.getName()
+ "' was DENIED ACCESS to '" + toWorld.getAlias()
+ "' because the world is full and '" + teleporter.getName()
+ "' doesn't have: mv.bypass.playerlimit." + event.getTo().getWorld().getName());
event.setCancelled(true);
return;
}
}
}
// By this point anything cancelling the event has returned on the method, meaning the teleport is a success \o/
this.stateSuccess(teleportee.getName(), toWorld.getAlias());
}
private void stateSuccess(String playerName, String worldName) {
Logging.fine("MV-Core is allowing Player '" + playerName
+ "' to go to '" + worldName + "'.");
}
/**
* This method is called to adjust the portal location to the actual portal location (and not
* right outside of it.
* @param event The Event that was fired.
*/
@EventHandler(priority = EventPriority.LOWEST)
public void playerPortalCheck(PlayerPortalEvent event) {
if (event.isCancelled() || event.getFrom() == null) {
if (event.isCancelled()) {
return;
}
// REMEMBER! getTo MAY be NULL HERE!!!
// If the player was actually outside of the portal, adjust the from location
if (event.getFrom().getWorld().getBlockAt(event.getFrom()).getType() != Material.NETHER_PORTAL) {
Location newloc = this.safeTTeleporter.findPortalBlockNextTo(event.getFrom());
Location newloc = safeTTeleporter.findPortalBlockNextTo(event.getFrom());
// TODO: Fix this. Currently, we only check for PORTAL blocks. I'll have to figure out what
// TODO: we want to do here.
if (newloc != null) {
event.setFrom(newloc);
}
}
// Wait for the adjust, then return!
if (event.getTo() == null) {
return;
}
}
/**
* This method is called when a player actually portals via a vanilla style portal.
* @param event The Event that was fired.
*/
@EventHandler(priority = EventPriority.HIGH)
public void playerPortal(PlayerPortalEvent event) {
if (event.isCancelled() || (event.getFrom() == null)) {
return;
}
// The adjust should have happened much earlier.
if (event.getTo() == null) {
return;
}
MVWorld fromWorld = getWorldManager().getMVWorld(event.getFrom().getWorld().getName());
MVWorld toWorld = getWorldManager().getMVWorld(event.getTo().getWorld().getName());
if (event.getFrom().getWorld().equals(event.getTo().getWorld())) {
// The player is Portaling to the same world.
Logging.finer("Player '" + event.getPlayer().getName() + "' is portaling to the same world.");
return;
}
event.setCancelled(!pt.playerHasMoneyToEnter(fromWorld, toWorld, event.getPlayer(), event.getPlayer(), true));
if (event.isCancelled()) {
Logging.fine("Player '" + event.getPlayer().getName()
+ "' was DENIED ACCESS to '" + event.getTo().getWorld().getName()
+ "' because they don't have the FUNDS required to enter.");
// We don't want to do anything if the event is already cancelled.
return;
}
if (config.getEnforceAccess()) {
event.setCancelled(!pt.playerCanGoFromTo(fromWorld, toWorld, event.getPlayer(), event.getPlayer()));
if (event.isCancelled()) {
Logging.fine("Player '" + event.getPlayer().getName()
+ "' was DENIED ACCESS to '" + event.getTo().getWorld().getName()
+ "' because they don't have: multiverse.access." + event.getTo().getWorld().getName());
}
} else {
Logging.fine("Player '" + event.getPlayer().getName()
+ "' was allowed to go to '" + event.getTo().getWorld().getName()
+ "' because enforceaccess is off.");
Location toLocation = event.getTo();
if (toLocation == null) {
// We don't want to do anything if the destination is null.
Logging.fine("Player '%s' entering a portal with null destination location.", event.getPlayer().getName());
return;
}
if (!config.isUsingCustomPortalSearch()) {
event.setSearchRadius(config.getCustomPortalSearchRadius());
Player player = event.getPlayer();
MVWorld fromWorld = getWorldManager().getMVWorld(event.getFrom().getWorld());
MVWorld toWorld = getWorldManager().getMVWorld(toLocation.getWorld());
if (toWorld == null) {
// We don't want to do anything if the destination world is not managed by MV.
Logging.fine("Player '%s' is teleporting to world '%s' which is not managed by Multiverse-Core. No further actions will be taken by Multiverse-Core.",
player.getName(), toLocation.getWorld());
return;
}
}
private void sendPlayerToDefaultWorld(final Player player) {
// Remove the player 1 tick after the login. I'm sure there's GOT to be a better way to do this...
this.server.getScheduler().scheduleSyncDelayedTask(this.plugin,
new Runnable() {
@Override
public void run() {
player.teleport(getWorldManager().getFirstSpawnWorld().getSpawnLocation());
}
}, 1L);
}
// FOLLOWING 2 Methods and Private class handle Per Player GameModes.
private void handleGameModeAndFlight(Player player, World world) {
MVWorld mvWorld = getWorldManager().getMVWorld(world.getName());
if (mvWorld != null) {
this.handleGameModeAndFlight(player, mvWorld);
} else {
Logging.finer("Not handling gamemode and flight for world '" + world.getName()
+ "' not managed by Multiverse.");
if (toWorld.equals(fromWorld)) {
// We don't want to do anything if the destination world is the same as the origin world.
Logging.fine("Player '%s' is teleporting to the same world.", player.getName());
return;
}
}
/**
* Handles the gamemode for the specified {@link Player}.
* @param player The {@link Player}.
* @param world The world the player is in.
*/
public void handleGameModeAndFlight(final Player player, final MVWorld world) {
// We perform this task one tick later to MAKE SURE that the player actually reaches the
// destination world, otherwise we'd be changing the player mode if they havent moved anywhere.
this.server.getScheduler().scheduleSyncDelayedTask(this.plugin,
new Runnable() {
@Override
public void run() {
if (!MVPlayerListener.this.pt.playerCanIgnoreGameModeRestriction(world, player)) {
// Check that the player is in the new world and they haven't been teleported elsewhere or the event cancelled.
if (player.getWorld() == world.getCBWorld()) {
Logging.fine("Handling gamemode for player: %s, Changing to %s", player.getName(), world.getGameMode().toString());
Logging.finest("From World: %s", player.getWorld());
Logging.finest("To World: %s", world);
player.setGameMode(world.getGameMode());
// Check if their flight mode should change
// TODO need a override permission for this
if (player.getAllowFlight() && !world.getAllowFlight() && player.getGameMode() != GameMode.CREATIVE) {
player.setAllowFlight(false);
if (player.isFlying()) {
player.setFlying(false);
}
} else if (world.getAllowFlight()) {
if (player.getGameMode() == GameMode.CREATIVE) {
player.setAllowFlight(true);
}
}
} else {
Logging.fine("The gamemode/allowfly was NOT changed for player '%s' because he is now in world '%s' instead of world '%s'",
player.getName(), player.getWorld().getName(), world.getName());
}
} else {
Logging.fine("Player: " + player.getName() + " is IMMUNE to gamemode changes!");
}
ResultGroup worldEntryResult = worldEntryCheckerProvider.forWorld(player, toWorld).canEnterWorld(fromWorld)
.onSuccess(() -> {
Logging.fine("Player '%s' is allowed to use portals to enter world '%s'.", player.getName(), toWorld.getName());
if (!config.isUsingCustomPortalSearch()) {
event.setSearchRadius(config.getCustomPortalSearchRadius());
}
}, 1L);
})
.onFailure(() -> {
event.setCancelled(true);
Logging.fine("Player '%s' is not allowed to use portals to enter world '%s'.", player.getName(), toWorld.getName());
});
Logging.finer("Portal entry result for player '%s', from '%s' to '%s': %s",
player.getName(), fromWorld == null ? "null" : fromWorld.getName(), toWorld.getName(), worldEntryResult);
sendWorldEntryMessage(player, player, fromWorld, toWorld, worldEntryResult);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void playerTeleport(PlayerTeleportEvent event) {
if (event.isCancelled()) {
// We don't want to do anything if the event is already cancelled.
return;
}
Player teleportee = event.getPlayer();
Option<String> teleporterName = teleportQueue.popFromQueue(teleportee.getName());
if (teleporterName.isEmpty() && !config.getTeleportIntercept()) {
// We don't want to do anything if teleport interception is disabled, and teleport is not by MV.
return;
}
CommandSender teleporter = teleporterName.map(name -> name.equals("CONSOLE")
? server.getConsoleSender()
: server.getPlayerExact(name))
.getOrElse(teleportee);
Logging.fine("Inferred teleporter '%s' for teleportee '%s'.", teleporter.getName(), teleportee.getName());
Option<MVWorld> fromWorld = Option.of(getWorldManager().getMVWorld(event.getFrom().getWorld()));
MVWorld toWorld = Option.of(event.getTo()).map(to -> getWorldManager().getMVWorld(to.getWorld())).getOrNull();
if (toWorld == null) {
// We don't want to do anything if the destination world is not managed by MV.
Logging.fine("Player '%s' is teleporting to world '%s' which is not managed by Multiverse-Core. No further actions will be taken by Multiverse-Core.",
teleportee.getName(), event.getTo().getWorld());
return;
}
if (fromWorld.filter(world -> world.equals(toWorld)).isDefined()) {
// We don't want to do anything if the destination world is the same as the origin world.
Logging.fine("Player '%s' is teleporting to the same world.", teleportee.getName());
return;
}
ResultGroup worldEntryResult = worldEntryCheckerProvider.forWorld(teleportee, toWorld)
.canEnterWorld(fromWorld.getOrNull())
.onSuccess(() -> Logging.fine("MV-Core is allowing '%s' to go to '%s'.", teleportee.getName(), toWorld.getName()))
.onSuccessReason(EntryFeeResult.Success.ENOUGH_MONEY, () -> {
economist.payEntryFee((Player) teleporter, toWorld);
//TODO send payment message
})
.onFailure(() -> {
event.setCancelled(true);
Logging.fine("MV-Core is denying '%s' from going to '%s'.", teleportee.getName(), toWorld.getName());
});
Logging.fine("World entry result for player '%s', from '%s' to '%s': %s",
teleportee.getName(), fromWorld.map(MVWorld::getName).getOrNull(), toWorld.getName(), worldEntryResult);
sendWorldEntryMessage(teleporter, teleportee, fromWorld.getOrNull(), toWorld, worldEntryResult);
}
private void sendWorldEntryMessage(CommandSender teleporter, Player teleportee, MVWorld fromWorld, MVWorld toWorld, ResultGroup worldEntryResult) {
if (worldEntryResult.isSuccess()) {
return;
}
if (teleportee.equals(teleporter)) {
teleporter.sendMessage("You are unable to teleport to world '%s'".formatted(toWorld.getName()));
} else {
teleporter.sendMessage("You are unable to teleport '%s' to world '%s'".formatted(teleportee.getName(), toWorld.getName()));
}
worldEntryResult
.onFailureReason(WorldAccessResult.Failure.class, reason -> {
teleporter.sendMessage("You do not have permission to access world '%s'".formatted(toWorld.getName()));
})
.onFailureReason(PlayerLimitResult.Failure.class, reason -> {
teleporter.sendMessage("World '%s' is full".formatted(toWorld.getName()));
})
.onFailureReason(EntryFeeResult.Failure.class, reason -> {
teleporter.sendMessage("You do not have enough money to pay world '%s' entry fee.".formatted(toWorld.getName()));
//TODO Formatted entry fee amount
})
.onFailureReason(BlacklistResult.Failure.class, reason -> {
teleporter.sendMessage("World '%s' is blacklisted by world '%s'".formatted(fromWorld.getName(), toWorld.getName()));
});
}
@EventHandler(priority = EventPriority.MONITOR)
public void playerChangedWorld(PlayerChangedWorldEvent event) {
MVWorld toWorld = getWorldManager().getMVWorld(event.getPlayer().getWorld());
if (toWorld == null) {
// We don't want to do anything if the destination world is not managed by MV.
Logging.fine("Player '%s' is changing to world '%s' which is not managed by Multiverse-Core. No further actions will be taken by Multiverse-Core.",
event.getPlayer().getName(), event.getPlayer().getWorld());
return;
}
this.handleGameModeAndFlight(event.getPlayer(), toWorld);
}
public void handleGameModeAndFlight(Player player, MVWorld world) {
if (!config.getEnforceGameMode()) {
Logging.fine("GameMode enforcement is disabled. Not changing game mode.");
return;
}
if (!player.getWorld().equals(world.getCBWorld())) {
Logging.fine("Player '%s' is not in world '%s'. Not changing game mode or flight.", player.getName(), world.getName());
return;
}
if (permissionsChecker.hasGameModeBypassPermission(player, world)) {
Logging.fine("Player '%s' has bypass permission. Not changing game mode or flight.", player.getName());
return;
}
GameMode targetGameMode = world.getGameMode();
Logging.fine("Handling gamemode for player %s: Changing to %s", player.getName(), targetGameMode.toString());
player.setGameMode(targetGameMode);
// TODO need a override permission for this
if (player.getAllowFlight() && !world.getAllowFlight() && player.getGameMode() != GameMode.CREATIVE) {
player.setAllowFlight(false);
if (player.isFlying()) {
player.setFlying(false);
}
} else if (world.getAllowFlight()) {
if (player.getGameMode() == GameMode.CREATIVE) {
player.setAllowFlight(true);
}
}
}
private void oneTickLater(Runnable runnable) {
server.getScheduler().scheduleSyncDelayedTask(plugin, runnable, 1L);
}
private MVWorldManager getWorldManager() {
return worldManagerProvider.get();
}
}
@@ -5,6 +5,7 @@ import java.util.Map;
import java.util.Optional;
import com.dumptruckman.minecraft.util.Logging;
import io.vavr.control.Option;
import org.jvnet.hk2.annotations.Service;
@Service
@@ -32,12 +33,12 @@ public class TeleportQueue {
* @param playerName The teleported player (the teleportee).
* @return The player that teleported the other one (the teleporter).
*/
public Optional<String> popFromQueue(String playerName) {
public Option<String> popFromQueue(String playerName) {
if (teleportQueue.containsKey(playerName)) {
String teleportee = teleportQueue.get(playerName);
teleportQueue.remove(playerName);
return Optional.of(teleportee);
return Option.of(teleportee);
}
return Optional.empty();
return Option.none();
}
}
@@ -0,0 +1,53 @@
package com.onarandombox.MultiverseCore.utils.permissions;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
public class ChildPermission extends Permission {
protected final Permission wildcard = new Permission(this.getName() + ".*", this.getDescription(), this.getDefault());
public ChildPermission(@NotNull String name) {
super(name);
}
public ChildPermission(@NotNull String name, @Nullable String description) {
super(name, description);
}
public ChildPermission(@NotNull String name, @Nullable PermissionDefault defaultValue) {
super(name, defaultValue);
}
public ChildPermission(@NotNull String name, @Nullable String description, @Nullable PermissionDefault defaultValue) {
super(name, description, defaultValue);
}
public ChildPermission(@NotNull String name, @Nullable Map<String, Boolean> children) {
super(name, children);
}
public ChildPermission(@NotNull String name, @Nullable String description, @Nullable Map<String, Boolean> children) {
super(name, description, children);
}
public ChildPermission(@NotNull String name, @Nullable PermissionDefault defaultValue, @Nullable Map<String, Boolean> children) {
super(name, defaultValue, children);
}
public ChildPermission(@NotNull String name, @Nullable String description, @Nullable PermissionDefault defaultValue, @Nullable Map<String, Boolean> children) {
super(name, description, defaultValue, children);
}
public ChildPermission child(@NotNull String name) {
return new ChildPermission(
this.getName() + "." + name,
this.getDescription(),
this.getDefault()
);
}
}
@@ -0,0 +1,13 @@
package com.onarandombox.MultiverseCore.utils.permissions;
import org.jvnet.hk2.annotations.Service;
@Service
public class MVCorePermissions {
public final ChildPermission WORLD_ACCESS = new ChildPermission("multiverse.access");
public final ChildPermission WORLD_EXEMPT = new ChildPermission("multiverse.exempt");
public final ChildPermission GAMEMODE_BYPASS = new ChildPermission("mv.bypass.gamemode");
public final ChildPermission PLAYERLIMIT_BYPASS = new ChildPermission("mv.bypass.playerlimit");
public final ChildPermission TELEPORT_SELF = new ChildPermission("multiverse.teleport.self");
public final ChildPermission TELEPORT_OTHER = new ChildPermission("multiverse.teleport.other");
}
@@ -0,0 +1,57 @@
package com.onarandombox.MultiverseCore.utils.permissions;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.destination.ParsedDestination;
import jakarta.inject.Inject;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.Permission;
import org.jetbrains.annotations.NotNull;
import org.jvnet.hk2.annotations.Service;
@Service
public class PermissionsChecker {
private final MVCorePermissions permissions;
@Inject
PermissionsChecker(MVCorePermissions permissions) {
this.permissions = permissions;
}
public boolean hasWorldAccessPermission(@NotNull CommandSender sender, @NotNull MVWorld world) {
return hasPermission(sender, permissions.WORLD_ACCESS.child(world.getName()));
}
public boolean hasWorldExemptPermission(@NotNull CommandSender sender, @NotNull MVWorld world) {
return hasPermission(sender, permissions.WORLD_EXEMPT.child(world.getName()));
}
public boolean hasPlayerLimitBypassPermission(@NotNull CommandSender sender, @NotNull MVWorld world) {
return hasPermission(sender, permissions.PLAYERLIMIT_BYPASS.child(world.getName()));
}
public boolean hasGameModeBypassPermission(@NotNull CommandSender sender, @NotNull MVWorld world) {
return hasPermission(sender, permissions.GAMEMODE_BYPASS.child(world.getName()));
}
public boolean hasTeleportPermission(@NotNull CommandSender sender, @NotNull ParsedDestination<?> destination, boolean self) {
ChildPermission permission = self ? permissions.TELEPORT_SELF : permissions.TELEPORT_OTHER;
if (!hasPermission(sender, permission.child(destination.getIdentifier()))) {
return false;
}
if (destination.getFinerPermissionSuffix() == null) {
return true;
}
return hasPermission(sender, permission.child(destination.getIdentifier()).child(destination.getFinerPermissionSuffix()));
}
private boolean hasPermission(CommandSender sender, Permission permission) {
if (sender.hasPermission(permission)) {
Logging.finer("Checking to see if sender [%s] has permission [%s]... YES", sender.getName(), permission.getName());
return true;
}
Logging.finer("Checking to see if sender [%s] has permission [%s]... NO", sender.getName(), permission.getName());
return false;
}
}
@@ -0,0 +1,4 @@
package com.onarandombox.MultiverseCore.utils.result;
public interface FailureReason {
}
@@ -0,0 +1,84 @@
package com.onarandombox.MultiverseCore.utils.result;
import java.util.NoSuchElementException;
import java.util.function.Consumer;
public sealed interface Result<S extends SuccessReason, F extends FailureReason> permits Result.Success, Result.Failure {
static <F extends FailureReason, S extends SuccessReason> Result<S, F> success(S successReason) {
return new Success<>(successReason);
}
static <F extends FailureReason, S extends SuccessReason> Result<S, F> failure(F failureReason) {
return new Failure<>(failureReason);
}
boolean isSuccess();
boolean isFailure();
S getSuccessReason();
F getFailureReason();
default Result<S, F> onSuccess(Consumer<S> consumer) {
if (this.isSuccess()) {
consumer.accept(this.getSuccessReason());
}
return this;
}
default Result<S, F> onFailure(Consumer<F> consumer) {
if (this.isFailure()) {
consumer.accept(this.getFailureReason());
}
return this;
}
default Result<S, F> onSuccessReason(S successReason, Consumer<S> consumer) {
if (this.isSuccess() && this.getSuccessReason() == successReason) {
consumer.accept(this.getSuccessReason());
}
return this;
}
default Result<S, F> onFailureReason(F failureReason, Consumer<F> consumer) {
if (this.isFailure() && this.getFailureReason() == failureReason) {
consumer.accept(this.getFailureReason());
}
return this;
}
record Success<F extends FailureReason, S extends SuccessReason>(S getSuccessReason) implements Result<S, F> {
@Override
public boolean isSuccess() {
return true;
}
@Override
public boolean isFailure() {
return false;
}
@Override
public F getFailureReason() {
throw new NoSuchElementException("No failure reason for success");
}
}
record Failure<S extends SuccessReason, F extends FailureReason>(F getFailureReason) implements Result<S, F> {
@Override
public boolean isSuccess() {
return false;
}
@Override
public boolean isFailure() {
return true;
}
@Override
public S getSuccessReason() {
throw new NoSuchElementException("No success reason for failure");
}
}
}
@@ -0,0 +1,124 @@
package com.onarandombox.MultiverseCore.utils.result;
import io.vavr.control.Option;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class ResultGroup {
public static Builder builder() {
return new Builder(true);
}
public static Builder builder(boolean stopOnFailure) {
return new Builder(stopOnFailure);
}
private final boolean isSuccess;
private final List<Result<?, ?>> results;
ResultGroup(boolean isSuccess, List<Result<?, ?>> results) {
this.isSuccess = isSuccess;
this.results = results;
}
public boolean isSuccess() {
return isSuccess;
}
public boolean isFailure() {
return !isSuccess;
}
public ResultGroup onSuccess(Runnable successRunnable) {
if (isSuccess) {
successRunnable.run();
}
return this;
}
public ResultGroup onFailure(Runnable failureRunnable) {
if (isFailure()) {
failureRunnable.run();
}
return this;
}
public <S extends SuccessReason> ResultGroup onSuccessReason(Class<S> successReasonClass, Consumer<S> successConsumer) {
getSuccessReason(successReasonClass).peek(successConsumer);
return this;
}
public <F extends FailureReason> ResultGroup onFailureReason(Class<F> failureReasonClass, Consumer<F> failureConsumer) {
getFailureReason(failureReasonClass).peek(failureConsumer);
return this;
}
public <S extends SuccessReason> ResultGroup onSuccessReason(S successReason, Runnable successRunnable) {
getSuccessReason(successReason.getClass()).filter(successReason::equals).peek(reason -> successRunnable.run());
return this;
}
public <S extends SuccessReason> Option<S> getSuccessReason(Class<S> successReasonClass) {
if (isFailure()) {
return Option.none();
}
return Option.ofOptional(results.stream()
.map(Result::getSuccessReason)
.filter(successReasonClass::isInstance)
.map(successReasonClass::cast)
.findFirst());
}
public <F extends FailureReason> Option<F> getFailureReason(Class<F> failureReasonClass) {
if (isSuccess()) {
return Option.none();
}
return Option.ofOptional(results.stream()
.map(Result::getFailureReason)
.filter(failureReasonClass::isInstance)
.map(failureReasonClass::cast)
.findFirst());
}
@Override
public String toString() {
return "ResultGroup{" +
"isSuccess=" + isSuccess +
", results={" + results.stream().map(Objects::toString).collect(Collectors.joining(", ")) + "}" +
'}';
}
public static class Builder {
private final boolean stopOnFailure;
private final List<Result<?, ?>> results;
private boolean isSuccess = true;
public Builder(boolean stopOnFailure) {
this.stopOnFailure = stopOnFailure;
this.results = new ArrayList<>();
}
public Builder then(Supplier<Result<?, ?>> resultSupplier) {
if (!isSuccess && stopOnFailure) {
return this;
}
Result<?, ?> result = resultSupplier.get();
if (result.isFailure()) {
isSuccess = false;
}
results.add(result);
return this;
}
public ResultGroup build() {
return new ResultGroup(isSuccess, results);
}
}
}
@@ -0,0 +1,4 @@
package com.onarandombox.MultiverseCore.utils.result;
public interface SuccessReason {
}
@@ -8,7 +8,6 @@
package com.onarandombox.MultiverseCore.world;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -22,7 +22,7 @@ public class EntryFee extends SerializationConfig {
@Nullable
private Material currency;
private final Material DISABLED_MATERIAL = Material.AIR;
public static final Material DISABLED_MATERIAL = Material.AIR;
public EntryFee() {
super();
@@ -0,0 +1,16 @@
package com.onarandombox.MultiverseCore.world.entrycheck;
import com.onarandombox.MultiverseCore.utils.result.FailureReason;
import com.onarandombox.MultiverseCore.utils.result.SuccessReason;
public class BlacklistResult {
public enum Success implements SuccessReason {
UNKNOWN_FROM_WORLD,
BYPASSED_BLACKLISTED,
NOT_BLACKLISTED
}
public enum Failure implements FailureReason {
BLACKLISTED
}
}
@@ -0,0 +1,18 @@
package com.onarandombox.MultiverseCore.world.entrycheck;
import com.onarandombox.MultiverseCore.utils.result.FailureReason;
import com.onarandombox.MultiverseCore.utils.result.SuccessReason;
public class EntryFeeResult {
public enum Success implements SuccessReason {
FREE_ENTRY,
ENOUGH_MONEY,
EXEMPT_FROM_ENTRY_FEE,
CONSOLE_OR_BLOCK_COMMAND_SENDER
}
public enum Failure implements FailureReason {
NOT_ENOUGH_MONEY,
CANNOT_PAY_ENTRY_FEE
}
}
@@ -0,0 +1,16 @@
package com.onarandombox.MultiverseCore.world.entrycheck;
import com.onarandombox.MultiverseCore.utils.result.FailureReason;
import com.onarandombox.MultiverseCore.utils.result.SuccessReason;
public class PlayerLimitResult {
public enum Success implements SuccessReason {
NO_PLAYERLIMIT,
WITHIN_PLAYERLIMIT,
BYPASS_PLAYERLIMIT
}
public enum Failure implements FailureReason {
EXCEED_PLAYERLIMIT
}
}
@@ -0,0 +1,15 @@
package com.onarandombox.MultiverseCore.world.entrycheck;
import com.onarandombox.MultiverseCore.utils.result.FailureReason;
import com.onarandombox.MultiverseCore.utils.result.SuccessReason;
public class WorldAccessResult {
public enum Success implements SuccessReason {
NO_ENFORCE_WORLD_ACCESS,
HAS_WORLD_ACCESS
}
public enum Failure implements FailureReason {
NO_WORLD_ACCESS
}
}
@@ -0,0 +1,114 @@
package com.onarandombox.MultiverseCore.world.entrycheck;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.economy.MVEconomist;
import com.onarandombox.MultiverseCore.utils.permissions.PermissionsChecker;
import com.onarandombox.MultiverseCore.utils.result.Result;
import com.onarandombox.MultiverseCore.utils.result.ResultGroup;
import com.onarandombox.MultiverseCore.world.configuration.EntryFee;
import org.bukkit.Material;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class WorldEntryChecker {
private final @NotNull CommandSender sender;
private final @NotNull MVWorld toWorld;
private final @NotNull MVCoreConfig config;
private final @NotNull MVEconomist economist;
private final @NotNull PermissionsChecker permissionsChecker;
public WorldEntryChecker(
@NotNull CommandSender sender,
@NotNull MVWorld toWorld,
@NotNull MVCoreConfig config,
@NotNull PermissionsChecker permissionsChecker,
@NotNull MVEconomist economist
) {
this.sender = sender;
this.toWorld = toWorld;
this.config = config;
this.permissionsChecker = permissionsChecker;
this.economist = economist;
}
public ResultGroup canStayInWorld() {
return canStayInWorld(true);
}
public ResultGroup canStayInWorld(boolean stopOnFailure) {
return ResultGroup.builder(stopOnFailure)
.then(this::canAccessWorld)
.then(this::isWithinPlayerLimit)
.build();
}
public ResultGroup canEnterWorld(@Nullable MVWorld fromWorld) {
return canEnterWorld(fromWorld, true);
}
public ResultGroup canEnterWorld(@Nullable MVWorld fromWorld, boolean stopOnFailure) {
return ResultGroup.builder(stopOnFailure)
.then(this::canAccessWorld)
.then(this::isWithinPlayerLimit)
.then(() -> isNotBlacklisted(fromWorld))
.then(this::canPayEntryFee)
.build();
}
public Result<WorldAccessResult.Success, WorldAccessResult.Failure> canAccessWorld() {
if (!config.getEnforceAccess()) {
return Result.success(WorldAccessResult.Success.NO_ENFORCE_WORLD_ACCESS);
}
return permissionsChecker.hasWorldAccessPermission(this.sender, this.toWorld)
? Result.success(WorldAccessResult.Success.HAS_WORLD_ACCESS)
: Result.failure(WorldAccessResult.Failure.NO_WORLD_ACCESS);
}
public Result<PlayerLimitResult.Success, PlayerLimitResult.Failure> isWithinPlayerLimit() {
final int playerLimit = toWorld.getPlayerLimit();
if (playerLimit <= -1) {
return Result.success(PlayerLimitResult.Success.NO_PLAYERLIMIT);
}
if (permissionsChecker.hasPlayerLimitBypassPermission(sender, toWorld)) {
return Result.success(PlayerLimitResult.Success.BYPASS_PLAYERLIMIT);
}
return playerLimit > toWorld.getCBWorld().getPlayers().size()
? Result.success(PlayerLimitResult.Success.WITHIN_PLAYERLIMIT)
: Result.failure(PlayerLimitResult.Failure.EXCEED_PLAYERLIMIT);
}
public Result<BlacklistResult.Success, BlacklistResult.Failure> isNotBlacklisted(@Nullable MVWorld fromWorld) {
if (fromWorld == null) {
return Result.success(BlacklistResult.Success.UNKNOWN_FROM_WORLD);
}
return toWorld.getWorldBlacklist().contains(fromWorld.getName())
? Result.failure(BlacklistResult.Failure.BLACKLISTED)
: Result.success(BlacklistResult.Success.NOT_BLACKLISTED);
}
public Result<EntryFeeResult.Success, EntryFeeResult.Failure> canPayEntryFee() {
double price = toWorld.getPrice();
Material currency = toWorld.getCurrency();
if (price == 0D && (currency == null || currency == EntryFee.DISABLED_MATERIAL)) {
return Result.success(EntryFeeResult.Success.FREE_ENTRY);
}
if (sender instanceof ConsoleCommandSender || sender instanceof BlockCommandSender) {
return Result.success(EntryFeeResult.Success.CONSOLE_OR_BLOCK_COMMAND_SENDER);
}
if (permissionsChecker.hasWorldExemptPermission(sender, toWorld)) {
return Result.success(EntryFeeResult.Success.EXEMPT_FROM_ENTRY_FEE);
}
if (!(sender instanceof Player player)) {
return Result.failure(EntryFeeResult.Failure.CANNOT_PAY_ENTRY_FEE);
}
return economist.isPlayerWealthyEnough(player, price, currency)
? Result.success(EntryFeeResult.Success.ENOUGH_MONEY)
: Result.failure(EntryFeeResult.Failure.NOT_ENOUGH_MONEY);
}
}
@@ -0,0 +1,35 @@
package com.onarandombox.MultiverseCore.world.entrycheck;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.config.MVCoreConfig;
import com.onarandombox.MultiverseCore.economy.MVEconomist;
import com.onarandombox.MultiverseCore.utils.permissions.PermissionsChecker;
import jakarta.inject.Inject;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
@Service
public class WorldEntryCheckerProvider {
private final @NotNull MVCoreConfig config;
private final @NotNull MVEconomist economist;
private final @NotNull PermissionsChecker permissionsChecker;
@Inject
WorldEntryCheckerProvider(
@NotNull MVCoreConfig config,
@NotNull MVEconomist economist,
@NotNull PermissionsChecker permissionsChecker
) {
this.config = config;
this.economist = economist;
this.permissionsChecker = permissionsChecker;
}
public @NotNull WorldEntryChecker forWorld(@NotNull CommandSender sender, @NotNull MVWorld toWorld) {
return new WorldEntryChecker(sender, toWorld, config, permissionsChecker, economist);
}
}
@@ -16,12 +16,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.onarandombox.MultiverseCore.MultiverseCore;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.listeners.MVEntityListener;
import com.onarandombox.MultiverseCore.listeners.MVPlayerListener;
import com.onarandombox.MultiverseCore.listeners.MVWeatherListener;
import com.onarandombox.MultiverseCore.utils.file.FileUtils;
import com.onarandombox.MultiverseCore.world.SimpleMVWorldManager;
import junit.framework.Assert;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@@ -4,7 +4,6 @@ import com.onarandombox.MultiverseCore.anchor.AnchorManager
import com.onarandombox.MultiverseCore.api.BlockSafety
import com.onarandombox.MultiverseCore.api.Destination
import com.onarandombox.MultiverseCore.api.LocationManipulation
import com.onarandombox.MultiverseCore.api.MVConfig
import com.onarandombox.MultiverseCore.api.MVWorldManager
import com.onarandombox.MultiverseCore.api.SafeTTeleporter
import com.onarandombox.MultiverseCore.commandtools.MVCommandManager
@@ -14,11 +13,11 @@ import com.onarandombox.MultiverseCore.config.MVCoreConfig
import com.onarandombox.MultiverseCore.economy.MVEconomist
import com.onarandombox.MultiverseCore.listeners.MVChatListener
import com.onarandombox.MultiverseCore.listeners.MVEntityListener
import com.onarandombox.MultiverseCore.listeners.MVPlayerListener
import com.onarandombox.MultiverseCore.listeners.MVPortalListener
import com.onarandombox.MultiverseCore.listeners.MVWeatherListener
import com.onarandombox.MultiverseCore.listeners.MVWorldInitListener
import com.onarandombox.MultiverseCore.listeners.MVWorldListener
import com.onarandombox.MultiverseCore.listeners.MVPlayerListener
import com.onarandombox.MultiverseCore.teleportation.SimpleBlockSafety
import com.onarandombox.MultiverseCore.teleportation.SimpleLocationManipulation
import com.onarandombox.MultiverseCore.teleportation.SimpleSafeTTeleporter
@@ -27,9 +26,9 @@ import com.onarandombox.MultiverseCore.utils.UnsafeCallWrapper
import com.onarandombox.MultiverseCore.utils.metrics.MetricsConfigurator
import com.onarandombox.MultiverseCore.world.SimpleMVWorldManager
import org.mvplugins.multiverse.core.TestWithMockBukkit
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.Test
import kotlin.test.assertNull
class InjectionTest : TestWithMockBukkit() {
@@ -89,7 +88,7 @@ class InjectionTest : TestWithMockBukkit() {
}
@Test
fun `MVPlayerListener is available as a service`() {
fun `NewMVPlayerListener is available as a service`() {
assertNotNull(multiverseCore.getService(MVPlayerListener::class.java))
}