Minigame support
This commit is contained in:
1 parent
5fbe850a14
commit
b7da0a1628
2 files changed
+138
-1
No files matched your search
@@ -66,7 +66,14 @@ public final class LoginMigrationService {
|
||||
boolean normalizeGamemode = managedWorld && !mayKeepGamemode
|
||||
&& plugin.getConfig().getBoolean("login-safety.normalize-non-staff-gamemode", true);
|
||||
// A sanctioned spectator is working, not an abandoned autopsy state.
|
||||
boolean autopsyMigration = managedWorld && !staff && !mayKeepGamemode && originalGamemode == GameMode.SPECTATOR
|
||||
// A minigame puts its own players into spectator legitimately, so a disconnect
|
||||
// from an arena looks exactly
|
||||
// like the abandoned season 1 state this migration exists to rescue. Migrating
|
||||
// one of those would burn the
|
||||
// player's one-shot flag and record the arena as their /spawnback location.
|
||||
boolean minigameArena = MinigameArenas.contains(player);
|
||||
boolean autopsyMigration = managedWorld && !staff && !mayKeepGamemode && !minigameArena
|
||||
&& originalGamemode == GameMode.SPECTATOR
|
||||
&& plugin.getConfig().getBoolean("login-safety.autopsy-migration.enabled", true)
|
||||
&& !migrationStore.hasMigrated(player.getUniqueId());
|
||||
boolean vulnerableAfterLogin = normalizeGamemode || originalGamemode == GameMode.SURVIVAL
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package spawnog.login;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
// Reports whether a player is inside a minigame arena.
|
||||
//
|
||||
// Autopsy migration exists for OG:SMP season 1 players who were left in spectator mode on the SMP. A minigame puts
|
||||
// its own players into spectator legitimately -- Spleef does it to everyone it eliminates, and Splegg runs whole
|
||||
// matches in worlds it owns -- so without this check a routine minigame disconnect looks identical to the state the
|
||||
// migration is meant to rescue. Migrating one of those players burns their one-shot migration flag and records the
|
||||
// arena as their /spawnback location.
|
||||
//
|
||||
// Every lookup is reflective and optional: no minigame is a dependency, and an absent one simply answers "no".
|
||||
public final class MinigameArenas {
|
||||
|
||||
private static final String SPLEEF_PLUGIN = "Spleef-OG";
|
||||
private static final String SPLEEF_API = "net.trueog.spleefog.api.SpleefAPI";
|
||||
private static final String SPLEGG_PLUGIN = "Splegg-OG";
|
||||
private static final String DUELS_PLUGIN = "Duels-OG";
|
||||
|
||||
private MinigameArenas() {
|
||||
|
||||
}
|
||||
|
||||
public static boolean contains(Player player) {
|
||||
|
||||
return player != null && (inSpleef(player) || inSplegg(player) || inDuel(player));
|
||||
|
||||
}
|
||||
|
||||
private static boolean inSpleef(Player player) {
|
||||
|
||||
Plugin plugin = enabled(SPLEEF_PLUGIN);
|
||||
if (plugin == null)
|
||||
return false;
|
||||
|
||||
try {
|
||||
|
||||
Class<?> api = Class.forName(SPLEEF_API, true, plugin.getClass().getClassLoader());
|
||||
if (Boolean.TRUE.equals(api.getMethod("isInSpleef", Player.class).invoke(null, player)))
|
||||
return true;
|
||||
|
||||
// Survives a crash, where the live session is gone but the saved pre-match
|
||||
// state is not. That is
|
||||
// exactly the login on which a minigame casualty would otherwise be mistaken
|
||||
// for an SMP one.
|
||||
Method pending = api.getMethod("hasPendingRecovery", java.util.UUID.class);
|
||||
return Boolean.TRUE.equals(pending.invoke(null, player.getUniqueId()));
|
||||
|
||||
} catch (ReflectiveOperationException | RuntimeException ex) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Splegg owns the worlds its games run in, so the player's world answers this
|
||||
// even after the game has ended.
|
||||
private static boolean inSplegg(Player player) {
|
||||
|
||||
Plugin plugin = enabled(SPLEGG_PLUGIN);
|
||||
if (plugin == null)
|
||||
return false;
|
||||
|
||||
String world = player.getWorld().getName();
|
||||
try {
|
||||
|
||||
Object configured = plugin.getClass().getMethod("getInGameWorlds").invoke(plugin);
|
||||
if (configured instanceof List<?> worlds) {
|
||||
|
||||
for (Object name : worlds) {
|
||||
|
||||
if (name != null && world.equalsIgnoreCase(name.toString()))
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object prefix = plugin.getClass().getMethod("getGameWorldPrefix").invoke(plugin);
|
||||
// Per-game worlds are named <prefix><gameId>-<map>.
|
||||
return prefix != null && !prefix.toString().isEmpty()
|
||||
&& world.toLowerCase(Locale.ROOT).startsWith(prefix.toString().toLowerCase(Locale.ROOT));
|
||||
|
||||
} catch (ReflectiveOperationException | RuntimeException ex) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean inDuel(Player player) {
|
||||
|
||||
Plugin plugin = enabled(DUELS_PLUGIN);
|
||||
if (plugin == null)
|
||||
return false;
|
||||
|
||||
try {
|
||||
|
||||
Object arenaManager = plugin.getClass().getMethod("getArenaManager").invoke(plugin);
|
||||
if (arenaManager == null)
|
||||
return false;
|
||||
|
||||
Method query = arenaManager.getClass().getMethod("isInMatch", Player.class);
|
||||
query.setAccessible(true);
|
||||
return Boolean.TRUE.equals(query.invoke(arenaManager, player));
|
||||
|
||||
} catch (ReflectiveOperationException | RuntimeException ex) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Plugin enabled(String name) {
|
||||
|
||||
Plugin plugin = Bukkit.getPluginManager().getPlugin(name);
|
||||
return plugin != null && plugin.isEnabled() ? plugin : null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user