mirror of
https://github.com/Multiverse/Multiverse-Core.git
synced 2024-11-25 12:05:14 +01:00
feat: Re-implement spawn location override and gamemode enforcement
This commit is contained in:
parent
4bfcd0d907
commit
de16e97d88
@ -1,50 +1,93 @@
|
||||
package com.onarandombox.MultiverseCore.listeners;
|
||||
|
||||
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.config.MVCoreConfig;
|
||||
import com.onarandombox.MultiverseCore.economy.MVEconomist;
|
||||
import com.onarandombox.MultiverseCore.inject.InjectableListener;
|
||||
import com.onarandombox.MultiverseCore.teleportation.TeleportQueue;
|
||||
import com.onarandombox.MultiverseCore.utils.permissions.PermissionsChecker;
|
||||
import com.onarandombox.MultiverseCore.utils.result.ResultGroup;
|
||||
import com.onarandombox.MultiverseCore.world.entrycheck.EntryFeeResult;
|
||||
import com.onarandombox.MultiverseCore.world.entrycheck.WorldEntryCheckerProvider;
|
||||
import io.vavr.control.Option;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
@Service
|
||||
public class NewMVPlayerListener implements InjectableListener {
|
||||
private final @NotNull MultiverseCore plugin;
|
||||
private final @NotNull MVCoreConfig config;
|
||||
private final @NotNull Server server;
|
||||
private final @NotNull TeleportQueue teleportQueue;
|
||||
private final @NotNull MVWorldManager worldManager;
|
||||
private final @NotNull WorldEntryCheckerProvider worldEntryCheckerProvider;
|
||||
private final @NotNull MVEconomist economist;
|
||||
private final @NotNull PermissionsChecker permissionsChecker;
|
||||
|
||||
@Inject
|
||||
NewMVPlayerListener(
|
||||
@NotNull MultiverseCore plugin,
|
||||
@NotNull MVCoreConfig config,
|
||||
@NotNull Server server,
|
||||
@NotNull TeleportQueue teleportQueue,
|
||||
@NotNull MVWorldManager worldManager,
|
||||
@NotNull WorldEntryCheckerProvider worldEntryCheckerProvider,
|
||||
@NotNull MVEconomist economist
|
||||
@NotNull MVEconomist economist,
|
||||
@NotNull PermissionsChecker permissionsChecker
|
||||
) {
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.server = server;
|
||||
this.teleportQueue = teleportQueue;
|
||||
this.worldManager = worldManager;
|
||||
this.worldEntryCheckerProvider = worldEntryCheckerProvider;
|
||||
this.economist = economist;
|
||||
this.permissionsChecker = permissionsChecker;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void playerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
Location spawnLocation = worldManager.getFirstSpawnWorld().getSpawnLocation();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Logging.finer("Player joined AGAIN!");
|
||||
MVWorld world = worldManager.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()
|
||||
.success(() -> oneTickLater(() -> handleGameModeAndFlight(player, world)))
|
||||
.failure(() -> {
|
||||
player.sendMessage("[MV] - Sorry you can't be in this world anymore!");
|
||||
oneTickLater(() -> player.teleport(spawnLocation));
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
@ -67,6 +110,8 @@ public class NewMVPlayerListener implements InjectableListener {
|
||||
: server.getPlayerExact(name))
|
||||
.getOrElse(teleportee);
|
||||
|
||||
Logging.fine("Inferred teleporter '%s' for teleportee '%s'.", teleporter.getName(), teleportee.getName());
|
||||
|
||||
Option<MVWorld> fromWorld = Option.of(this.worldManager.getMVWorld(event.getFrom().getWorld()));
|
||||
MVWorld toWorld = Option.of(event.getTo()).map(to -> this.worldManager.getMVWorld(to.getWorld())).getOrNull();
|
||||
|
||||
@ -82,7 +127,8 @@ public class NewMVPlayerListener implements InjectableListener {
|
||||
return;
|
||||
}
|
||||
|
||||
ResultGroup worldEntryResult = worldEntryCheckerProvider.forWorld(teleportee, fromWorld.getOrNull(), toWorld).canEnterWorld()
|
||||
ResultGroup worldEntryResult = worldEntryCheckerProvider.forWorld(teleportee, toWorld)
|
||||
.canEnterWorld(fromWorld.getOrNull())
|
||||
.success(() -> Logging.fine("MV-Core is allowing '%s' to go to '%s'.", teleportee.getName(), toWorld.getName()))
|
||||
.successWithReason(EntryFeeResult.Success.ENOUGH_MONEY, () -> {
|
||||
economist.payEntryFee((Player) teleporter, toWorld);
|
||||
@ -97,4 +143,51 @@ public class NewMVPlayerListener implements InjectableListener {
|
||||
Logging.fine("World entry result for player '%s', from '%s' to '%s': %s",
|
||||
teleportee.getName(), fromWorld.map(MVWorld::getName).getOrNull(), toWorld.getName(), worldEntryResult);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void playerChangedWorld(PlayerChangedWorldEvent event) {
|
||||
MVWorld toWorld = worldManager.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);
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
}
|
||||
|
@ -48,10 +48,10 @@ public class PermissionsChecker {
|
||||
|
||||
private boolean hasPermission(CommandSender sender, Permission permission) {
|
||||
if (sender.hasPermission(permission)) {
|
||||
Logging.finer("Checking to see if sender [" + sender.getName() + "] has permission [" + permission + "]... YES");
|
||||
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 [" + sender.getName() + "] has permission [" + permission + "]... NO");
|
||||
Logging.finer("Checking to see if sender [%s] has permission [%s]... NO", sender.getName(), permission.getName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
package com.onarandombox.MultiverseCore.world.entrycheck;
|
||||
|
||||
import com.onarandombox.MultiverseCore.utils.result.FailureReason;
|
||||
import com.onarandombox.MultiverseCore.utils.result.SuccessReason;
|
||||
|
||||
public class GameModeResult {
|
||||
public enum Success implements SuccessReason {
|
||||
ENFORCE_GAME_MODE
|
||||
}
|
||||
|
||||
public enum Failure implements FailureReason {
|
||||
NO_ENFORCE_GAME_MODE,
|
||||
BYPASS_ENFORCE_GAME_MODE
|
||||
}
|
||||
}
|
@ -20,7 +20,6 @@ import java.util.Objects;
|
||||
|
||||
public class WorldEntryChecker {
|
||||
private final @NotNull CommandSender sender;
|
||||
private final @Nullable MVWorld fromWorld;
|
||||
private final @NotNull MVWorld toWorld;
|
||||
|
||||
private final @NotNull MVCoreConfig config;
|
||||
@ -29,29 +28,38 @@ public class WorldEntryChecker {
|
||||
|
||||
public WorldEntryChecker(
|
||||
@NotNull CommandSender sender,
|
||||
@Nullable MVWorld fromWorld,
|
||||
@NotNull MVWorld toWorld,
|
||||
@NotNull MVCoreConfig config,
|
||||
@NotNull PermissionsChecker permissionsChecker,
|
||||
@NotNull MVEconomist economist
|
||||
) {
|
||||
this.sender = sender;
|
||||
this.fromWorld = fromWorld;
|
||||
this.toWorld = toWorld;
|
||||
this.config = config;
|
||||
this.permissionsChecker = permissionsChecker;
|
||||
this.economist = economist;
|
||||
}
|
||||
|
||||
public ResultGroup canEnterWorld() {
|
||||
return canEnterWorld(true);
|
||||
public ResultGroup canStayInWorld() {
|
||||
return canStayInWorld(true);
|
||||
}
|
||||
|
||||
public ResultGroup canEnterWorld(boolean stopOnFailure) {
|
||||
public ResultGroup canStayInWorld(boolean stopOnFailure) {
|
||||
return ResultGroup.builder(stopOnFailure)
|
||||
.then(this::canAccessWorld)
|
||||
.then(this::isNotBlacklisted)
|
||||
.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();
|
||||
}
|
||||
@ -65,6 +73,28 @@ public class WorldEntryChecker {
|
||||
: 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();
|
||||
@ -84,26 +114,4 @@ public class WorldEntryChecker {
|
||||
? Result.success(EntryFeeResult.Success.ENOUGH_MONEY)
|
||||
: Result.failure(EntryFeeResult.Failure.NOT_ENOUGH_MONEY);
|
||||
}
|
||||
|
||||
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() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ 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;
|
||||
@ -28,7 +29,7 @@ public class WorldEntryCheckerProvider {
|
||||
this.permissionsChecker = permissionsChecker;
|
||||
}
|
||||
|
||||
public @NotNull WorldEntryChecker forWorld(@NotNull Player player, @Nullable MVWorld fromWorld, @NotNull MVWorld toWorld) {
|
||||
return new WorldEntryChecker(player, fromWorld, toWorld, config, permissionsChecker, economist);
|
||||
public @NotNull WorldEntryChecker forWorld(@NotNull CommandSender sender, @NotNull MVWorld toWorld) {
|
||||
return new WorldEntryChecker(sender, toWorld, config, permissionsChecker, economist);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user