mirror of
https://github.com/garbagemule/MobArena.git
synced 2025-02-16 20:41:56 +01:00
Refactor the join/leave process.
Note that this commit makes breaking changes to the Arena interface and completely changes the responsibility of the InventoryManager. The join/leave process is replaced with an implementation of the Command Pattern, where every step of the process (e.g. teleport to lobby, change gamemode to survival, reset health, etc.) is realized as an implementation of the new Step interface, which has "run" and "undo" operations. The "run" operation takes a snapshot of a specific part of the player's state and then resets it. The "undo" operation restores the snapshot. Step groupings are arranged in two factory classes, PlayerJoinArena and PlayerSpecArena, which realize, respectively, the join and spectate processes. Each instance of ArenaImpl instantiates groupings for its own context, and a grouping is invoked as one unit when a player joins or spectates an arena, and rolled back when a player leaves. As a result of a more stringent process, some things are now a little different than before: - Setting spectate-on-death to true effectively results in /ma leave followed by /ma spec. This makes the player/arena state a little more predictable and well-defined. - Using exit warps will result in the player leaving to their entry point and then being teleported to the exit warp. This means the exit warp doesn't have any effect on the rest of the restoration process, as it effectively happens "post leave". This finally fixes #423.
This commit is contained in:
parent
208a43262e
commit
b1c6b61827
@ -351,7 +351,7 @@ public class ArenaClass
|
||||
Arena arena = am.getArenaWithPlayer(p);
|
||||
if (arena != null) {
|
||||
try {
|
||||
arena.getInventoryManager().restoreInv(p);
|
||||
arena.getInventoryManager().equip(p);
|
||||
removeBannedItems(p.getInventory());
|
||||
} catch (Exception e) {
|
||||
am.getPlugin().getLogger().severe("Failed to give " + p.getName() + " their own items: " + e.getMessage());
|
||||
|
@ -4,6 +4,10 @@ import static com.garbagemule.MobArena.util.config.ConfigUtils.makeSection;
|
||||
|
||||
import com.garbagemule.MobArena.ArenaClass.ArmorType;
|
||||
import com.garbagemule.MobArena.ScoreboardManager.NullScoreboardManager;
|
||||
import com.garbagemule.MobArena.steps.Step;
|
||||
import com.garbagemule.MobArena.steps.StepFactory;
|
||||
import com.garbagemule.MobArena.steps.PlayerJoinArena;
|
||||
import com.garbagemule.MobArena.steps.PlayerSpecArena;
|
||||
import com.garbagemule.MobArena.events.ArenaEndEvent;
|
||||
import com.garbagemule.MobArena.events.ArenaPlayerDeathEvent;
|
||||
import com.garbagemule.MobArena.events.ArenaPlayerJoinEvent;
|
||||
@ -17,16 +21,8 @@ import com.garbagemule.MobArena.repairable.Repairable;
|
||||
import com.garbagemule.MobArena.repairable.RepairableComparator;
|
||||
import com.garbagemule.MobArena.repairable.RepairableContainer;
|
||||
import com.garbagemule.MobArena.things.Thing;
|
||||
import com.garbagemule.MobArena.time.Time;
|
||||
import com.garbagemule.MobArena.time.TimeStrategy;
|
||||
import com.garbagemule.MobArena.time.TimeStrategyLocked;
|
||||
import com.garbagemule.MobArena.time.TimeStrategyNull;
|
||||
import com.garbagemule.MobArena.util.ClassChests;
|
||||
import com.garbagemule.MobArena.util.Delays;
|
||||
import com.garbagemule.MobArena.util.Enums;
|
||||
import com.garbagemule.MobArena.util.ItemParser;
|
||||
import com.garbagemule.MobArena.util.inventory.InventoryManager;
|
||||
import com.garbagemule.MobArena.util.inventory.InventoryUtils;
|
||||
import com.garbagemule.MobArena.util.timer.AutoStartTimer;
|
||||
import com.garbagemule.MobArena.util.timer.StartDelayTimer;
|
||||
import com.garbagemule.MobArena.waves.SheepBouncer;
|
||||
@ -34,7 +30,6 @@ import com.garbagemule.MobArena.waves.WaveManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
@ -65,6 +60,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.PriorityBlockingQueue;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ArenaImpl implements Arena
|
||||
@ -94,7 +90,6 @@ public class ArenaImpl implements Arena
|
||||
private RewardManager rewardManager;
|
||||
private ClassLimitManager limitManager;
|
||||
private Map<Player,ArenaPlayer> arenaPlayerMap;
|
||||
private Map<Player,PlayerData> playerData = new HashMap<>();
|
||||
|
||||
private Set<Player> arenaPlayers, lobbyPlayers, readyPlayers, specPlayers, deadPlayers;
|
||||
private Set<Player> movingPlayers;
|
||||
@ -123,7 +118,6 @@ public class ArenaImpl implements Arena
|
||||
// Misc
|
||||
private ArenaListener eventListener;
|
||||
private List<Thing> entryFee;
|
||||
private TimeStrategy timeStrategy;
|
||||
private AutoStartTimer autoStartTimer;
|
||||
private StartDelayTimer startDelayTimer;
|
||||
private boolean isolatedChat;
|
||||
@ -134,6 +128,11 @@ public class ArenaImpl implements Arena
|
||||
// Last player standing
|
||||
private Player lastStanding;
|
||||
|
||||
// Actions
|
||||
private Map<Player, Step> histories;
|
||||
private StepFactory playerJoinArena;
|
||||
private StepFactory playerSpecArena;
|
||||
|
||||
/**
|
||||
* Primary constructor. Requires a name and a world.
|
||||
*/
|
||||
@ -152,7 +151,7 @@ public class ArenaImpl implements Arena
|
||||
this.running = false;
|
||||
this.edit = false;
|
||||
|
||||
this.inventoryManager = new InventoryManager(this);
|
||||
this.inventoryManager = new InventoryManager();
|
||||
this.rewardManager = new RewardManager(this);
|
||||
|
||||
// Warps, points and locations
|
||||
@ -220,16 +219,17 @@ public class ArenaImpl implements Arena
|
||||
|
||||
this.isolatedChat = settings.getBoolean("isolated-chat", false);
|
||||
|
||||
String timeString = settings.getString("player-time-in-arena", "world");
|
||||
Time time = Enums.getEnumFromString(Time.class, timeString);
|
||||
this.timeStrategy = (time != null ? new TimeStrategyLocked(time) : new TimeStrategyNull());
|
||||
|
||||
// Scoreboards
|
||||
this.scoreboard = (settings.getBoolean("use-scoreboards", true) ? new ScoreboardManager(this) : new NullScoreboardManager(this));
|
||||
|
||||
// Messenger
|
||||
String prefix = settings.getString("prefix", "");
|
||||
this.messenger = !prefix.isEmpty() ? new Messenger(prefix) : plugin.getGlobalMessenger();
|
||||
|
||||
// Actions
|
||||
this.histories = new HashMap<>();
|
||||
this.playerJoinArena = PlayerJoinArena.create(this);
|
||||
this.playerSpecArena = PlayerSpecArena.create(this);
|
||||
}
|
||||
|
||||
|
||||
@ -354,12 +354,6 @@ public class ArenaImpl implements Arena
|
||||
return waveManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getPlayerEntry(Player p) {
|
||||
PlayerData mp = playerData.get(p);
|
||||
return (mp != null ? mp.entry() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArenaListener getEventListener() {
|
||||
return eventListener;
|
||||
@ -523,15 +517,7 @@ public class ArenaImpl implements Arena
|
||||
movingPlayers.add(p);
|
||||
p.teleport(region.getArenaWarp());
|
||||
movingPlayers.remove(p);
|
||||
p.setAllowFlight(false);
|
||||
p.setFlying(false);
|
||||
//movePlayerToLocation(p, region.getArenaWarp());
|
||||
setHealth(p, p.getMaxHealth());
|
||||
p.setFoodLevel(20);
|
||||
if (settings.getBoolean("display-waves-as-level", false)) {
|
||||
p.setLevel(0);
|
||||
p.setExp(0.0f);
|
||||
}
|
||||
|
||||
assignClassPermissions(p);
|
||||
arenaPlayerMap.get(p).resetStats();
|
||||
|
||||
@ -678,6 +664,10 @@ public class ArenaImpl implements Arena
|
||||
}
|
||||
movingPlayers.add(p);
|
||||
|
||||
rollback(p);
|
||||
|
||||
specPlayers.remove(p);
|
||||
|
||||
// Announce globally (must happen before moving player)
|
||||
if (settings.getBoolean("global-join-announce", false)) {
|
||||
if (lobbyPlayers.isEmpty()) {
|
||||
@ -687,18 +677,17 @@ public class ArenaImpl implements Arena
|
||||
}
|
||||
}
|
||||
|
||||
MAUtils.sitPets(p);
|
||||
movePlayerToLobby(p);
|
||||
takeFee(p);
|
||||
storePlayerData(p, loc);
|
||||
removePotionEffects(p);
|
||||
setHealth(p, p.getMaxHealth());
|
||||
p.setFoodLevel(20);
|
||||
if (settings.getBoolean("display-timer-as-level", false)) {
|
||||
p.setLevel(0);
|
||||
p.setExp(0.0f);
|
||||
Step step = playerJoinArena.create(p);
|
||||
try {
|
||||
step.run();
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, () -> "Player " + p.getName() + " couldn't join arena " + name);
|
||||
return false;
|
||||
}
|
||||
p.setGameMode(GameMode.SURVIVAL);
|
||||
histories.put(p, step);
|
||||
|
||||
lobbyPlayers.add(p);
|
||||
plugin.getArenaMaster().addPlayer(p, this);
|
||||
|
||||
arenaPlayerMap.put(p, new ArenaPlayer(p, this, plugin));
|
||||
|
||||
@ -775,7 +764,6 @@ public class ArenaImpl implements Arena
|
||||
removeClassPermissions(p);
|
||||
removePotionEffects(p);
|
||||
|
||||
restoreInvAndExp(p);
|
||||
if (inLobby(p) || inArena(p)) {
|
||||
refund(p);
|
||||
}
|
||||
@ -792,7 +780,6 @@ public class ArenaImpl implements Arena
|
||||
}
|
||||
}
|
||||
|
||||
movePlayerToEntry(p);
|
||||
discardPlayer(p);
|
||||
|
||||
endArena();
|
||||
@ -834,8 +821,9 @@ public class ArenaImpl implements Arena
|
||||
return;
|
||||
}
|
||||
|
||||
setHealth(p, p.getMaxHealth());
|
||||
Delays.revivePlayer(plugin, this, p);
|
||||
p.setHealth(20.0);
|
||||
plugin.getServer().getScheduler()
|
||||
.scheduleSyncDelayedTask(plugin, () -> revivePlayer(p));
|
||||
endArena();
|
||||
}
|
||||
|
||||
@ -864,37 +852,25 @@ public class ArenaImpl implements Arena
|
||||
}
|
||||
|
||||
deadPlayers.remove(p);
|
||||
revivePlayer(p);
|
||||
plugin.getServer().getScheduler()
|
||||
.scheduleSyncDelayedTask(plugin, () -> revivePlayer(p));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void revivePlayer(Player p) {
|
||||
Delays.douse(plugin, p, 1);
|
||||
removeClassPermissions(p);
|
||||
removePotionEffects(p);
|
||||
|
||||
discardPlayer(p);
|
||||
if (settings.getBoolean("spectate-on-death", true)) {
|
||||
movePlayerToSpec(p);
|
||||
messenger.tell(p, Msg.SPEC_FROM_ARENA);
|
||||
messenger.tell(p, Msg.MISC_MA_LEAVE_REMINDER);
|
||||
} else {
|
||||
restoreInvAndExp(p);
|
||||
movePlayerToEntry(p);
|
||||
discardPlayer(p);
|
||||
playerSpec(p, null);
|
||||
}
|
||||
p.updateInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getRespawnLocation(Player p) {
|
||||
Location l = null;
|
||||
if (settings.getBoolean("spectate-on-death", true)) {
|
||||
l = region.getSpecWarp();
|
||||
} else {
|
||||
l = playerData.get(p).entry();
|
||||
}
|
||||
return l;
|
||||
return region.getSpecWarp();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -904,14 +880,37 @@ public class ArenaImpl implements Arena
|
||||
}
|
||||
movingPlayers.add(p);
|
||||
|
||||
storePlayerData(p, loc);
|
||||
MAUtils.sitPets(p);
|
||||
movePlayerToSpec(p);
|
||||
|
||||
rollback(p);
|
||||
|
||||
Step step = playerSpecArena.create(p);
|
||||
try {
|
||||
step.run();
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, () -> "Player " + p.getName() + " couldn't spec arena " + name);
|
||||
return;
|
||||
}
|
||||
histories.put(p, step);
|
||||
|
||||
specPlayers.add(p);
|
||||
plugin.getArenaMaster().addPlayer(p, this);
|
||||
|
||||
messenger.tell(p, Msg.SPEC_PLAYER_SPECTATE);
|
||||
movingPlayers.remove(p);
|
||||
}
|
||||
|
||||
private void rollback(Player p) {
|
||||
Step step = histories.remove(p);
|
||||
if (step == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
step.undo();
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, () -> "Failed to revert player " + p.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnPets() {
|
||||
for (Player p : arenaPlayers) {
|
||||
// Skip players who are either null or offline
|
||||
@ -1078,33 +1077,6 @@ public class ArenaImpl implements Arena
|
||||
scheduleTask(sheepBouncer, settings.getInt("first-wave-delay", 5) * 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePlayerData(Player p, Location loc)
|
||||
{
|
||||
plugin.getArenaMaster().addPlayer(p, this);
|
||||
|
||||
PlayerData mp = playerData.get(p);
|
||||
|
||||
// If there's no player stored, create a new one!
|
||||
if (mp == null) {
|
||||
if (region.getExitWarp() != null) loc = region.getExitWarp();
|
||||
mp = new PlayerData(p, loc);
|
||||
playerData.put(p, mp);
|
||||
}
|
||||
|
||||
// At any rate, update the data.
|
||||
mp.update();
|
||||
|
||||
// And update the inventory as well.
|
||||
try {
|
||||
inventoryManager.storeInv(p);
|
||||
inventoryManager.clearInventory(p);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
plugin.getLogger().severe("Failed to store inventory for player " + p.getName() + "!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeContainerContents()
|
||||
{
|
||||
@ -1124,80 +1096,16 @@ public class ArenaImpl implements Arena
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void movePlayerToLobby(Player p)
|
||||
{
|
||||
specPlayers.remove(p); // If joining from spec area
|
||||
lobbyPlayers.add(p);
|
||||
p.teleport(region.getLobbyWarp());
|
||||
p.setAllowFlight(false);
|
||||
p.setFlying(false);
|
||||
timeStrategy.setPlayerTime(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void movePlayerToSpec(Player p)
|
||||
{
|
||||
specPlayers.add(p);
|
||||
p.teleport(region.getSpecWarp());
|
||||
timeStrategy.setPlayerTime(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void movePlayerToEntry(Player p)
|
||||
{
|
||||
Location entry = playerData.get(p).entry();
|
||||
if (entry == null || p.isDead()) return;
|
||||
|
||||
p.teleport(entry);
|
||||
timeStrategy.resetPlayerTime(p);
|
||||
|
||||
p.setGameMode(playerData.get(p).getMode());
|
||||
p.addPotionEffects(playerData.get(p).getPotionEffects());
|
||||
}
|
||||
|
||||
private void restoreInvAndExp(Player p) {
|
||||
inventoryManager.clearInventory(p);
|
||||
try {
|
||||
inventoryManager.restoreInv(p);
|
||||
inventoryManager.clearCache(p);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
plugin.getLogger().severe("Failed to restore inventory for player " + p.getName() + "!");
|
||||
}
|
||||
rewardManager.grantRewards(p);
|
||||
|
||||
// Try to prevent XP issues
|
||||
if (lobbyPlayers.contains(p)
|
||||
|| !settings.getBoolean("keep-exp")
|
||||
|| settings.getBoolean("display-waves-as-level", false)
|
||||
|| settings.getBoolean("display-timer-as-level", false)) {
|
||||
playerData.get(p).restoreData();
|
||||
}
|
||||
else {
|
||||
p.setFoodLevel(playerData.get(p).food());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void discardPlayer(Player p)
|
||||
{
|
||||
rollback(p);
|
||||
plugin.getArenaMaster().removePlayer(p);
|
||||
clearPlayer(p);
|
||||
}
|
||||
|
||||
private void clearPlayer(Player p)
|
||||
{
|
||||
// Remove the player data completely.
|
||||
PlayerData mp = playerData.remove(p);
|
||||
|
||||
// Health must be handled in a certain way because of Heroes
|
||||
// Math.min to guard for ItemLoreStats weirdness
|
||||
setHealth(p, Math.min(p.getMaxHealth(), mp.health()));
|
||||
|
||||
// Put out fire.
|
||||
Delays.douse(plugin, p, 3);
|
||||
|
||||
// Remove pets.
|
||||
monsterManager.removePets(p);
|
||||
|
||||
@ -1211,10 +1119,6 @@ public class ArenaImpl implements Arena
|
||||
scoreboard.removePlayer(p);
|
||||
}
|
||||
|
||||
private void setHealth(Player p, double health) {
|
||||
p.setHealth(health);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repairBlocks()
|
||||
{
|
||||
@ -1245,7 +1149,7 @@ public class ArenaImpl implements Arena
|
||||
return;
|
||||
}
|
||||
|
||||
inventoryManager.clearInventory(p);
|
||||
InventoryManager.clearInventory(p);
|
||||
|
||||
arenaPlayer.setArenaClass(arenaClass);
|
||||
arenaClass.grantItems(p);
|
||||
@ -1265,7 +1169,7 @@ public class ArenaImpl implements Arena
|
||||
return;
|
||||
}
|
||||
|
||||
inventoryManager.clearInventory(p);
|
||||
InventoryManager.clearInventory(p);
|
||||
arenaPlayer.setArenaClass(arenaClass);
|
||||
|
||||
PlayerInventory inv = p.getInventory();
|
||||
|
@ -8,14 +8,12 @@ import com.garbagemule.MobArena.listeners.MagicSpellsListener;
|
||||
import com.garbagemule.MobArena.things.ThingManager;
|
||||
import com.garbagemule.MobArena.util.VersionChecker;
|
||||
import com.garbagemule.MobArena.util.config.ConfigUtils;
|
||||
import com.garbagemule.MobArena.util.inventory.InventoryManager;
|
||||
import com.garbagemule.MobArena.waves.ability.AbilityManager;
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
@ -26,10 +24,8 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* MobArena
|
||||
@ -40,9 +36,6 @@ public class MobArena extends JavaPlugin
|
||||
private ArenaMaster arenaMaster;
|
||||
private CommandHandler commandHandler;
|
||||
|
||||
// Inventories from disconnects
|
||||
private Set<String> inventoriesToRestore;
|
||||
|
||||
// Vault
|
||||
private Economy economy;
|
||||
|
||||
@ -91,9 +84,6 @@ public class MobArena extends JavaPlugin
|
||||
arenaMaster = new ArenaMasterImpl(this);
|
||||
arenaMaster.initialize();
|
||||
|
||||
// Register any inventories to restore.
|
||||
registerInventories();
|
||||
|
||||
// Register event listeners
|
||||
registerListeners();
|
||||
|
||||
@ -258,32 +248,6 @@ public class MobArena extends JavaPlugin
|
||||
"Note: You -must- use spaces instead of tabs!";
|
||||
}
|
||||
|
||||
private void registerInventories() {
|
||||
this.inventoriesToRestore = new HashSet<>();
|
||||
|
||||
File dir = new File(getDataFolder(), "inventories");
|
||||
if (!dir.exists()) {
|
||||
dir.mkdir();
|
||||
return;
|
||||
}
|
||||
|
||||
for (File f : dir.listFiles()) {
|
||||
if (f.getName().endsWith(".inv")) {
|
||||
inventoriesToRestore.add(f.getName().substring(0, f.getName().indexOf(".")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void restoreInventory(Player p) {
|
||||
if (!inventoriesToRestore.contains(p.getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (InventoryManager.restoreFromFile(this, p)) {
|
||||
inventoriesToRestore.remove(p.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public Economy getEconomy() {
|
||||
return economy;
|
||||
}
|
||||
|
@ -1,109 +0,0 @@
|
||||
package com.garbagemule.MobArena;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class PlayerData
|
||||
{
|
||||
private Player player;
|
||||
|
||||
private double health;
|
||||
private int food, level;
|
||||
private float exp;
|
||||
private GameMode mode = null;
|
||||
private Location entry = null;
|
||||
private Collection<PotionEffect> potions;
|
||||
|
||||
public PlayerData(Player player, Location loc) {
|
||||
this.player = player;
|
||||
this.mode = player.getGameMode();
|
||||
this.potions = player.getActivePotionEffects();
|
||||
this.entry = loc;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the information that is restored, when a player
|
||||
* dies in the arena, that is, health, food level, and
|
||||
* experience. Used when a player re-joins an arena while
|
||||
* already being a spectator.
|
||||
*/
|
||||
public void update() {
|
||||
this.health = player.getHealth();
|
||||
this.food = player.getFoodLevel();
|
||||
this.level = player.getLevel();
|
||||
this.exp = player.getExp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores health, food level, and experience as per the
|
||||
* currently stored values of this object. Used when a
|
||||
* player leaves the arena.
|
||||
*/
|
||||
public void restoreData() {
|
||||
player.setFoodLevel(food);
|
||||
player.setLevel(level);
|
||||
player.setExp(exp);
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public double health() {
|
||||
return health;
|
||||
}
|
||||
|
||||
public void setHealth(int health) {
|
||||
this.health = health;
|
||||
}
|
||||
|
||||
public int food() {
|
||||
return food;
|
||||
}
|
||||
|
||||
public void setFood(int food) {
|
||||
this.food = food;
|
||||
}
|
||||
|
||||
public int level() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public float exp() {
|
||||
return exp;
|
||||
}
|
||||
|
||||
public void setExp(int exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public GameMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public Collection<PotionEffect> getPotionEffects() {
|
||||
return potions;
|
||||
}
|
||||
|
||||
public void setMode(GameMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public Location entry() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void setEntry(Location entry) {
|
||||
this.entry = entry;
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import com.garbagemule.MobArena.commands.CommandInfo;
|
||||
import com.garbagemule.MobArena.framework.ArenaMaster;
|
||||
import com.garbagemule.MobArena.util.inventory.InventoryManager;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@CommandInfo(
|
||||
name = "restore",
|
||||
@ -20,12 +21,17 @@ public class RestoreCommand implements Command
|
||||
// Require a player name
|
||||
if (args.length != 1) return false;
|
||||
|
||||
if (am.getArenaWithPlayer(args[0]) != null) {
|
||||
Player player = am.getPlugin().getServer().getPlayer(args[0]);
|
||||
if (player == null) {
|
||||
am.getGlobalMessenger().tell(sender, "Player not found.");
|
||||
return true;
|
||||
}
|
||||
if (am.getArenaWithPlayer(player) != null) {
|
||||
am.getGlobalMessenger().tell(sender, "Player is currently in an arena.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (InventoryManager.restoreFromFile(am.getPlugin(), am.getPlugin().getServer().getPlayer(args[0]))) {
|
||||
if (InventoryManager.restoreFromFile(am.getPlugin(), player)) {
|
||||
am.getGlobalMessenger().tell(sender, "Restored " + args[0] + "'s inventory!");
|
||||
} else {
|
||||
am.getGlobalMessenger().tell(sender, "Failed to restore " + args[0] + "'s inventory.");
|
||||
|
@ -81,8 +81,6 @@ public interface Arena
|
||||
|
||||
WaveManager getWaveManager();
|
||||
|
||||
Location getPlayerEntry(Player p);
|
||||
|
||||
ArenaListener getEventListener();
|
||||
|
||||
void setLeaderboard(Leaderboard leaderboard);
|
||||
@ -168,18 +166,10 @@ public interface Arena
|
||||
|
||||
void playerSpec(Player p, Location loc);
|
||||
|
||||
void storePlayerData(Player p, Location loc);
|
||||
|
||||
void storeContainerContents();
|
||||
|
||||
void restoreContainerContents();
|
||||
|
||||
void movePlayerToLobby(Player p);
|
||||
|
||||
void movePlayerToSpec(Player p);
|
||||
|
||||
void movePlayerToEntry(Player p);
|
||||
|
||||
void discardPlayer(Player p);
|
||||
|
||||
void repairBlocks();
|
||||
|
@ -322,8 +322,6 @@ public class MAGlobalListener implements Listener
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
plugin.restoreInventory(event.getPlayer());
|
||||
}
|
||||
|
||||
public enum TeleportResponse {
|
||||
|
@ -0,0 +1,66 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import com.garbagemule.MobArena.framework.Arena;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.logging.Level;
|
||||
|
||||
class ClearInventory extends PlayerStep {
|
||||
private final File inventories;
|
||||
private final Arena arena;
|
||||
|
||||
private ItemStack[] contents;
|
||||
private File backup;
|
||||
|
||||
private ClearInventory(Player player, Arena arena) {
|
||||
super(player);
|
||||
this.inventories = new File(arena.getPlugin().getDataFolder(), "inventories");
|
||||
this.arena = arena;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
contents = player.getInventory().getContents();
|
||||
createBackup();
|
||||
|
||||
player.getInventory().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
player.getInventory().setContents(contents);
|
||||
|
||||
arena.getInventoryManager().remove(player);
|
||||
deleteBackup();
|
||||
}
|
||||
|
||||
private void createBackup() {
|
||||
YamlConfiguration yaml = new YamlConfiguration();
|
||||
yaml.set("contents", contents);
|
||||
|
||||
backup = new File(inventories, player.getUniqueId().toString());
|
||||
try {
|
||||
yaml.save(backup);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to store inventory for " + player.getName(), e);
|
||||
}
|
||||
arena.getInventoryManager().put(player, contents);
|
||||
}
|
||||
|
||||
private void deleteBackup() {
|
||||
try {
|
||||
Files.delete(backup.toPath());
|
||||
} catch (IOException e) {
|
||||
arena.getPlugin().getLogger().log(Level.WARNING, "Couldn't delete backup inventory file for " + player.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
static StepFactory create(Arena arena) {
|
||||
return player -> new ClearInventory(player, arena);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
class ClearPotionEffects extends PlayerStep {
|
||||
private Collection<PotionEffect> effects;
|
||||
|
||||
private ClearPotionEffects(Player player) {
|
||||
super(player);
|
||||
effects = Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
effects = player.getActivePotionEffects();
|
||||
|
||||
effects.stream()
|
||||
.map(PotionEffect::getType)
|
||||
.forEach(player::removePotionEffect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
player.addPotionEffects(effects);
|
||||
}
|
||||
|
||||
static StepFactory create() {
|
||||
return ClearPotionEffects::new;
|
||||
}
|
||||
}
|
36
src/main/java/com/garbagemule/MobArena/steps/Defer.java
Normal file
36
src/main/java/com/garbagemule/MobArena/steps/Defer.java
Normal file
@ -0,0 +1,36 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
/**
|
||||
* This wrapper allows a delegate {@link Step}'s {@link Step#run() run()}
|
||||
* operation to be deferred until this wrapper's {@link Step#undo() undo()}
|
||||
* operation is invoked. This is useful when a Step should only be invoked
|
||||
* during rollback, but not during the initial procedure.
|
||||
*
|
||||
* @see GrantRewards
|
||||
*/
|
||||
class Defer implements Step {
|
||||
private Step step;
|
||||
|
||||
private Defer(Step step) {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// OK BOSS
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
step.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "deferred(" + step + ")";
|
||||
}
|
||||
|
||||
static StepFactory it(StepFactory factory) {
|
||||
return player -> new Defer(factory.create(player));
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import com.garbagemule.MobArena.framework.Arena;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class GrantRewards extends PlayerStep {
|
||||
private final Arena arena;
|
||||
|
||||
private GrantRewards(Player player, Arena arena) {
|
||||
super(player);
|
||||
this.arena = arena;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
arena.getRewardManager().grantRewards(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
// OK BOSS
|
||||
}
|
||||
|
||||
static StepFactory create(Arena arena) {
|
||||
return player -> new GrantRewards(player, arena);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
abstract class MovePlayerStep extends PlayerStep {
|
||||
private final Supplier<Location> destination;
|
||||
|
||||
private Location location;
|
||||
|
||||
MovePlayerStep(Player player, Supplier<Location> destination) {
|
||||
super(player);
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
location = player.getLocation();
|
||||
|
||||
player.teleport(destination.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
player.teleport(location);
|
||||
}
|
||||
}
|
14
src/main/java/com/garbagemule/MobArena/steps/MoveToExit.java
Normal file
14
src/main/java/com/garbagemule/MobArena/steps/MoveToExit.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import com.garbagemule.MobArena.framework.Arena;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class MoveToExit extends MovePlayerStep {
|
||||
private MoveToExit(Player player, Arena arena) {
|
||||
super(player, () -> arena.getRegion().getExitWarp());
|
||||
}
|
||||
|
||||
static StepFactory create(Arena arena) {
|
||||
return player -> new MoveToExit(player, arena);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import com.garbagemule.MobArena.framework.Arena;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class MoveToLobby extends MovePlayerStep {
|
||||
private MoveToLobby(Player player, Arena arena) {
|
||||
super(player, () -> arena.getRegion().getLobbyWarp());
|
||||
}
|
||||
|
||||
static StepFactory create(Arena arena) {
|
||||
return player -> new MoveToLobby(player, arena);
|
||||
}
|
||||
}
|
14
src/main/java/com/garbagemule/MobArena/steps/MoveToSpec.java
Normal file
14
src/main/java/com/garbagemule/MobArena/steps/MoveToSpec.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import com.garbagemule.MobArena.framework.Arena;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class MoveToSpec extends MovePlayerStep {
|
||||
private MoveToSpec(Player player, Arena arena) {
|
||||
super(player, () -> arena.getRegion().getSpecWarp());
|
||||
}
|
||||
|
||||
static StepFactory create(Arena arena) {
|
||||
return player -> new MoveToSpec(player, arena);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import com.garbagemule.MobArena.framework.Arena;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PlayerJoinArena {
|
||||
public static StepFactory create(Arena arena) {
|
||||
ConfigurationSection settings = arena.getSettings();
|
||||
|
||||
List<StepFactory> factories = new ArrayList<>();
|
||||
|
||||
if (arena.getRegion().getExitWarp() != null) {
|
||||
factories.add(Defer.it(MoveToExit.create(arena)));
|
||||
}
|
||||
factories.add(SitPets.create());
|
||||
factories.add(MoveToLobby.create(arena));
|
||||
factories.add(SetGameMode.create());
|
||||
factories.add(Defer.it(GrantRewards.create(arena)));
|
||||
factories.add(ClearInventory.create(arena));
|
||||
factories.add(ClearPotionEffects.create());
|
||||
factories.add(SetFlying.create());
|
||||
factories.add(SetHealth.create());
|
||||
factories.add(SetHunger.create());
|
||||
factories.add(SetExperience.create());
|
||||
factories.add(SetPlayerTime.create(settings));
|
||||
|
||||
return PlayerMultiStep.create(factories, arena.getPlugin().getLogger());
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* PlayerMultiSteps group lists of {@link StepFactory StepFactories} into a
|
||||
* single unit, effectively realizing the Composite Pattern.
|
||||
* <p>
|
||||
* Each factory is invoked to create a given {@link Step}, which is executed
|
||||
* right away. If the Step succeeds, it is pushed to a history stack. The undo
|
||||
* operation pops the successful Steps off the history stack one by one and
|
||||
* runs the undo operation on each one in reverse order.
|
||||
* <p>
|
||||
* If one Step fails, any previous successful Steps are rolled back by running
|
||||
* their undo operations.
|
||||
*/
|
||||
class PlayerMultiStep extends PlayerStep {
|
||||
private final List<StepFactory> factories;
|
||||
private final Logger logger;
|
||||
|
||||
private Deque<Step> history;
|
||||
|
||||
private PlayerMultiStep(Player player, List<StepFactory> factories, Logger logger) {
|
||||
super(player);
|
||||
this.factories = factories;
|
||||
this.logger = logger;
|
||||
this.history = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
history.clear();
|
||||
|
||||
factories.forEach(factory -> {
|
||||
Step step = factory.create(player);
|
||||
try {
|
||||
step.run();
|
||||
history.push(step);
|
||||
logger.info("Step " + step + " OK");
|
||||
} catch (RuntimeException up) {
|
||||
logger.log(Level.SEVERE, up, () -> "Failed to run step " + step);
|
||||
undo();
|
||||
throw up;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
while (!history.isEmpty()) {
|
||||
Step step = history.pop();
|
||||
try {
|
||||
step.undo();
|
||||
logger.info("Rollback " + step + " OK");
|
||||
} catch (RuntimeException e) {
|
||||
logger.log(Level.SEVERE, e, () -> "Failed to undo step " + step);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static StepFactory create(List<StepFactory> factories, Logger logger) {
|
||||
return player -> new PlayerMultiStep(player, factories, logger);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import com.garbagemule.MobArena.framework.Arena;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PlayerSpecArena {
|
||||
public static StepFactory create(Arena arena) {
|
||||
ConfigurationSection settings = arena.getSettings();
|
||||
|
||||
List<StepFactory> factories = new ArrayList<>();
|
||||
|
||||
if (arena.getRegion().getExitWarp() != null) {
|
||||
factories.add(Defer.it(MoveToExit.create(arena)));
|
||||
}
|
||||
factories.add(SitPets.create());
|
||||
factories.add(MoveToSpec.create(arena));
|
||||
factories.add(SetGameMode.create());
|
||||
factories.add(ClearInventory.create(arena));
|
||||
factories.add(ClearPotionEffects.create());
|
||||
factories.add(SetFlying.create());
|
||||
factories.add(SetHealth.create());
|
||||
factories.add(SetHunger.create());
|
||||
factories.add(SetExperience.create());
|
||||
factories.add(SetPlayerTime.create(settings));
|
||||
|
||||
return PlayerMultiStep.create(factories, arena.getPlugin().getLogger());
|
||||
}
|
||||
}
|
18
src/main/java/com/garbagemule/MobArena/steps/PlayerStep.java
Normal file
18
src/main/java/com/garbagemule/MobArena/steps/PlayerStep.java
Normal file
@ -0,0 +1,18 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
abstract class PlayerStep implements Step {
|
||||
protected final Player player;
|
||||
|
||||
protected PlayerStep(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String step = getClass().getSimpleName();
|
||||
String target = player.getName();
|
||||
return step + "(" + target + ")";
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class SetExperience extends PlayerStep {
|
||||
private int level;
|
||||
private float exp;
|
||||
|
||||
private SetExperience(Player player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
level = player.getLevel();
|
||||
exp = player.getExp();
|
||||
|
||||
player.setExp(0);
|
||||
player.setLevel(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
player.setLevel(level);
|
||||
player.setExp(exp);
|
||||
}
|
||||
|
||||
static StepFactory create() {
|
||||
return SetExperience::new;
|
||||
}
|
||||
}
|
35
src/main/java/com/garbagemule/MobArena/steps/SetFlying.java
Normal file
35
src/main/java/com/garbagemule/MobArena/steps/SetFlying.java
Normal file
@ -0,0 +1,35 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class SetFlying extends PlayerStep {
|
||||
private boolean allow;
|
||||
private boolean flying;
|
||||
private float speed;
|
||||
|
||||
private SetFlying(Player player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
allow = player.getAllowFlight();
|
||||
flying = player.isFlying();
|
||||
speed = player.getFlySpeed();
|
||||
|
||||
player.setFlySpeed(0);
|
||||
player.setFlying(false);
|
||||
player.setAllowFlight(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
player.setAllowFlight(allow);
|
||||
player.setFlying(flying);
|
||||
player.setFlySpeed(speed);
|
||||
}
|
||||
|
||||
static StepFactory create() {
|
||||
return SetFlying::new;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class SetGameMode extends PlayerStep {
|
||||
private GameMode mode;
|
||||
|
||||
private SetGameMode(Player player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mode = player.getGameMode();
|
||||
|
||||
player.setGameMode(GameMode.SURVIVAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
player.setGameMode(mode);
|
||||
}
|
||||
|
||||
static StepFactory create() {
|
||||
return SetGameMode::new;
|
||||
}
|
||||
}
|
39
src/main/java/com/garbagemule/MobArena/steps/SetHealth.java
Normal file
39
src/main/java/com/garbagemule/MobArena/steps/SetHealth.java
Normal file
@ -0,0 +1,39 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class SetHealth extends PlayerStep {
|
||||
private static final double FULL_HEALTH = 20.0;
|
||||
private static final int NORMAL_FIRE = -20;
|
||||
private static final int NORMAL_AIR = 300;
|
||||
|
||||
private double health;
|
||||
private int fire;
|
||||
private int air;
|
||||
|
||||
private SetHealth(Player player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
health = player.getHealth();
|
||||
fire = player.getFireTicks();
|
||||
air = player.getRemainingAir();
|
||||
|
||||
player.setRemainingAir(NORMAL_AIR);
|
||||
player.setFireTicks(NORMAL_FIRE);
|
||||
player.setHealth(FULL_HEALTH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
player.setHealth(health);
|
||||
player.setFireTicks(fire);
|
||||
player.setRemainingAir(air);
|
||||
}
|
||||
|
||||
static StepFactory create() {
|
||||
return SetHealth::new;
|
||||
}
|
||||
}
|
39
src/main/java/com/garbagemule/MobArena/steps/SetHunger.java
Normal file
39
src/main/java/com/garbagemule/MobArena/steps/SetHunger.java
Normal file
@ -0,0 +1,39 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class SetHunger extends PlayerStep {
|
||||
private static final int FULL_FOOD = 20;
|
||||
private static final float NORMAL_SATURATION = 5f;
|
||||
private static final float NORMAL_EXHAUSTION = 0f;
|
||||
|
||||
private int food;
|
||||
private float saturation;
|
||||
private float exhaustion;
|
||||
|
||||
private SetHunger(Player player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
food = player.getFoodLevel();
|
||||
saturation = player.getSaturation();
|
||||
exhaustion = player.getExhaustion();
|
||||
|
||||
player.setExhaustion(NORMAL_EXHAUSTION);
|
||||
player.setSaturation(NORMAL_SATURATION);
|
||||
player.setFoodLevel(FULL_FOOD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
player.setFoodLevel(food);
|
||||
player.setSaturation(saturation);
|
||||
player.setExhaustion(exhaustion);
|
||||
}
|
||||
|
||||
static StepFactory create() {
|
||||
return SetHunger::new;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import com.garbagemule.MobArena.time.Time;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
class SetPlayerTime extends PlayerStep {
|
||||
private final Time time;
|
||||
|
||||
private SetPlayerTime(Player player, Time time) {
|
||||
super(player);
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (time != null) {
|
||||
player.setPlayerTime(time.getTime(), false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
if (time != null) {
|
||||
player.resetPlayerTime();
|
||||
}
|
||||
}
|
||||
|
||||
static StepFactory create(ConfigurationSection settings) {
|
||||
Time time = parseTime(settings);
|
||||
return player -> new SetPlayerTime(player, time);
|
||||
}
|
||||
|
||||
private static Time parseTime(ConfigurationSection settings) {
|
||||
String value = settings.getString("player-time-in-arena", "world");
|
||||
try {
|
||||
return Time.valueOf(value.toLowerCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
79
src/main/java/com/garbagemule/MobArena/steps/SitPets.java
Normal file
79
src/main/java/com/garbagemule/MobArena/steps/SitPets.java
Normal file
@ -0,0 +1,79 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Ocelot;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Tameable;
|
||||
import org.bukkit.entity.Wolf;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class SitPets extends PlayerStep {
|
||||
private List<Entity> pets;
|
||||
|
||||
private SitPets(Player player) {
|
||||
super(player);
|
||||
pets = Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
pets = findNearbyPets(player);
|
||||
|
||||
pets.forEach(SitPets.setSitting(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
pets.forEach(SitPets.setSitting(false));
|
||||
}
|
||||
|
||||
static StepFactory create() {
|
||||
return SitPets::new;
|
||||
}
|
||||
|
||||
private static List<Entity> findNearbyPets(Player player) {
|
||||
return player.getNearbyEntities(80, 40, 80).stream()
|
||||
.filter(SitPets.isPetOwnedBy(player))
|
||||
.filter(SitPets::isFollowing)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static Predicate<Entity> isPetOwnedBy(Player player) {
|
||||
return entity -> {
|
||||
switch (entity.getType()) {
|
||||
case WOLF:
|
||||
case OCELOT:
|
||||
return player.equals(((Tameable) entity).getOwner());
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isFollowing(Entity entity) {
|
||||
switch (entity.getType()) {
|
||||
case WOLF:
|
||||
return !((Wolf) entity).isSitting();
|
||||
case OCELOT:
|
||||
return !((Ocelot) entity).isSitting();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Consumer<Entity> setSitting(boolean sitting) {
|
||||
return entity -> {
|
||||
switch (entity.getType()) {
|
||||
case WOLF:
|
||||
((Wolf) entity).setSitting(sitting);
|
||||
break;
|
||||
case OCELOT:
|
||||
((Ocelot) entity).setSitting(sitting);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
28
src/main/java/com/garbagemule/MobArena/steps/Step.java
Normal file
28
src/main/java/com/garbagemule/MobArena/steps/Step.java
Normal file
@ -0,0 +1,28 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
/**
|
||||
* Steps are small, self-contained pieces of behavior.
|
||||
* <p>
|
||||
* The {@link #run()} method of a Step executes its behavior. This could be
|
||||
* anything, but it usually involves a change in state, <em>somewhere</em>,
|
||||
* and some Steps support the optional {@link #undo()} operation that attempts
|
||||
* to revert the state back to what it was before the Step was executed.
|
||||
* <p>
|
||||
* Steps realize the Command role of the Command Pattern.
|
||||
*
|
||||
* @see StepFactory
|
||||
*/
|
||||
public interface Step {
|
||||
/**
|
||||
* Execute the behavior of this Step.
|
||||
*/
|
||||
void run();
|
||||
|
||||
/**
|
||||
* Undo a previous execution of this Step (optional operation).
|
||||
* <p>
|
||||
* This method can be called without first invoking the {@link #run()}
|
||||
* method. Doing so is silly.
|
||||
*/
|
||||
void undo();
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* StepFactories create closures over {@link Player Players} and return
|
||||
* {@link Step Steps} that operate on the given Player.
|
||||
*/
|
||||
public interface StepFactory {
|
||||
Step create(Player player);
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package com.garbagemule.MobArena.time;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface TimeStrategy
|
||||
{
|
||||
/**
|
||||
* Set the time enum used by setPlayerTime()
|
||||
* @param time a Time enum
|
||||
*/
|
||||
void setTime(Time time);
|
||||
|
||||
/**
|
||||
* Set the local client time for the player.
|
||||
* @param p a player
|
||||
*/
|
||||
void setPlayerTime(Player p);
|
||||
|
||||
/**
|
||||
* Reset the local client time for the player to the server time
|
||||
* @param p a player
|
||||
*/
|
||||
void resetPlayerTime(Player p);
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package com.garbagemule.MobArena.time;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class TimeStrategyLocked implements TimeStrategy
|
||||
{
|
||||
private Time time;
|
||||
|
||||
public TimeStrategyLocked(Time time) {
|
||||
setTime(time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(Time time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerTime(Player p) {
|
||||
p.setPlayerTime(time.getTime(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPlayerTime(Player p) {
|
||||
p.resetPlayerTime();
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package com.garbagemule.MobArena.time;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class TimeStrategyNull implements TimeStrategy
|
||||
{
|
||||
@Override
|
||||
public void setTime(Time time) {}
|
||||
|
||||
@Override
|
||||
public void setPlayerTime(Player p) {}
|
||||
|
||||
@Override
|
||||
public void resetPlayerTime(Player p) {}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package com.garbagemule.MobArena.util;
|
||||
|
||||
import com.garbagemule.MobArena.MobArena;
|
||||
import com.garbagemule.MobArena.framework.Arena;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class Delays
|
||||
{
|
||||
public static void douse(MobArena plugin, final Player p, long delay) {
|
||||
if (!plugin.isEnabled()) return;
|
||||
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
|
||||
public void run() {
|
||||
if (p.isOnline()) {
|
||||
p.setFireTicks(0);
|
||||
}
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
|
||||
public static void revivePlayer(MobArena plugin, final Arena arena, final Player p) {
|
||||
if (!plugin.isEnabled()) return;
|
||||
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
|
||||
public void run() {
|
||||
if (p.isOnline()) {
|
||||
arena.revivePlayer(p);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
package com.garbagemule.MobArena.util.inventory;
|
||||
|
||||
import com.garbagemule.MobArena.MobArena;
|
||||
import com.garbagemule.MobArena.framework.Arena;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
@ -12,88 +10,39 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class InventoryManager
|
||||
{
|
||||
private File dir;
|
||||
private Map<Player,ItemStack[]> items, armor;
|
||||
private Map<Player, ItemStack[]> inventories;
|
||||
|
||||
public InventoryManager(Arena arena) {
|
||||
this.dir = new File(arena.getPlugin().getDataFolder(), "inventories");
|
||||
this.dir.mkdir();
|
||||
|
||||
this.items = new HashMap<>();
|
||||
this.armor = new HashMap<>();
|
||||
public InventoryManager() {
|
||||
this.inventories = new HashMap<>();
|
||||
}
|
||||
|
||||
public void storeInv(Player p) throws IOException {
|
||||
// Avoid overwrites
|
||||
if (items.containsKey(p)) return;
|
||||
|
||||
// Fetch the player's items and armor
|
||||
ItemStack[] items = p.getInventory().getContents();
|
||||
ItemStack[] armor = p.getInventory().getArmorContents();
|
||||
|
||||
// Store them in memory
|
||||
this.items.put(p, items);
|
||||
this.armor.put(p, armor);
|
||||
|
||||
// And on disk
|
||||
File file = new File(dir, p.getName());
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
config.set("items", items);
|
||||
config.set("armor", armor);
|
||||
config.save(file);
|
||||
|
||||
p.updateInventory();
|
||||
public void put(Player p, ItemStack[] contents) {
|
||||
inventories.put(p, contents);
|
||||
}
|
||||
|
||||
public void restoreInv(Player p) throws IOException, InvalidConfigurationException {
|
||||
// Try to grab the items from memory first
|
||||
ItemStack[] items = this.items.get(p);
|
||||
ItemStack[] armor = this.armor.get(p);
|
||||
|
||||
// If we can't restore from memory, restore from file
|
||||
if (items == null || armor == null) {
|
||||
File file = new File(dir, p.getName());
|
||||
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
config.load(file);
|
||||
|
||||
// Get the items and armor lists
|
||||
List<?> itemsList = config.getList("items");
|
||||
List<?> armorList = config.getList("armor");
|
||||
|
||||
// Turn the lists into arrays
|
||||
items = itemsList.toArray(new ItemStack[itemsList.size()]);
|
||||
armor = armorList.toArray(new ItemStack[armorList.size()]);
|
||||
public void equip(Player p) {
|
||||
ItemStack[] contents = inventories.get(p);
|
||||
if (contents == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the player inventory contents
|
||||
p.getInventory().setContents(items);
|
||||
p.getInventory().setArmorContents(armor);
|
||||
p.getInventory().setContents(contents);
|
||||
}
|
||||
|
||||
public void clearCache(Player p) {
|
||||
items.remove(p);
|
||||
armor.remove(p);
|
||||
|
||||
File file = new File(dir, p.getName());
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
public void remove(Player p) {
|
||||
inventories.remove(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a player's inventory completely.
|
||||
* @param p a player
|
||||
*/
|
||||
public void clearInventory(Player p) {
|
||||
public static void clearInventory(Player p) {
|
||||
PlayerInventory inv = p.getInventory();
|
||||
inv.clear();
|
||||
inv.setHelmet(null);
|
||||
@ -131,29 +80,23 @@ public class InventoryManager
|
||||
|
||||
public static boolean restoreFromFile(MobArena plugin, Player p) {
|
||||
try {
|
||||
// Grab the file and load the config
|
||||
File dir = new File(plugin.getDataFolder(), "inventories");
|
||||
File file = new File(dir, p.getName());
|
||||
File inventories = new File(plugin.getDataFolder(), "inventories");
|
||||
File file = new File(inventories, p.getUniqueId().toString());
|
||||
|
||||
if (!file.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
config.load(file);
|
||||
|
||||
// Get the items and armor lists
|
||||
List<?> itemsList = config.getList("items");
|
||||
List<?> armorList = config.getList("armor");
|
||||
ItemStack[] contents = config.getList("contents").toArray(new ItemStack[0]);
|
||||
p.getInventory().setContents(contents);
|
||||
|
||||
// Turn the lists into arrays
|
||||
ItemStack[] items = itemsList.toArray(new ItemStack[itemsList.size()]);
|
||||
ItemStack[] armor = armorList.toArray(new ItemStack[armorList.size()]);
|
||||
|
||||
// Set the player inventory contents
|
||||
p.getInventory().setContents(items);
|
||||
p.getInventory().setArmorContents(armor);
|
||||
|
||||
// Delete files
|
||||
file.delete();
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to restore inventory for " + p.getName(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user