/* * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT). * * Copyright (c) JCThePants (www.jcwhatever.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.jcwhatever.nucleus.utils.player; import com.jcwhatever.nucleus.storage.serialize.DeserializeException; import com.jcwhatever.nucleus.storage.IDataNode; import com.jcwhatever.nucleus.storage.serialize.IDataNodeSerializable; import com.jcwhatever.nucleus.utils.PreCon; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.UUID; import javax.annotation.Nullable; /** * A snapshot of a players state. * * <p>The players state consists of chest items, armor, applied enchantments, * game mode, flight, health, food level, exp, fire ticks, fall distance, * and location.</p> */ public class PlayerStateSnapshot implements IDataNodeSerializable { private UUID _playerId; private ItemStack[] _items; private ItemStack[] _armor; private Location _location; private GameMode _gameMode; private Collection<PotionEffect> _potions; private float _exp; private int _food; private int _level; private double _health; private boolean _flight; private boolean _allowFlight; private int _fireTicks; private double _fallDistance; /** * Constructor. * * @param player The player to take a state snapshot from. */ public PlayerStateSnapshot(Player player) { _playerId = player.getUniqueId(); _items = player.getInventory().getContents().clone(); _armor = player.getInventory().getArmorContents().clone(); _location = player.getLocation(); _gameMode = player.getGameMode(); _potions = new ArrayList<PotionEffect>(player.getActivePotionEffects()); _health = player.getHealth(); _food = player.getFoodLevel(); _level = player.getLevel(); _exp = player.getExp(); _flight = player.isFlying(); _allowFlight = player.getAllowFlight(); _fireTicks = player.getFireTicks(); _fallDistance = player.getFallDistance(); } /** * Private Constructor. * * <p>Used for serialization.</p> */ private PlayerStateSnapshot() {} /** * Get the ID of the player the snapshot was * taken from. */ public UUID getPlayerId() { return _playerId; } /** * Get the player chest items. */ public ItemStack[] getItems() { return _items.clone(); } /** * Get the player armor chest. */ public ItemStack[] getArmor() { return _armor.clone(); } /** * Get the player location. */ public Location getLocation() { return _location; } /** * Get the players {@link org.bukkit.GameMode}. */ public GameMode getGameMode() { return _gameMode; } /** * Get the players active potion effects. */ public List<PotionEffect> getPotionEffects() { return new ArrayList<>(_potions); } /** * Get the players health. */ public double getHealth() { return _health; } /** * Get the players food level. */ public int getFoodLevel() { return _food; } /** * Get the players food level. */ public int getLevel() { return _level; } /** * Get the players Experience. */ public double getExp() { return _exp; } /** * Determine if the player is flying. */ public boolean isFlying() { return _flight; } /** * Determine if flight is allowed for the player. */ public boolean isFlightAllowed() { return _allowFlight; } /** * Get the players fire ticks. */ public int getFireTicks() { return _fireTicks; } /** * Get the fall distance. */ public double getFallDistance() { return _fallDistance; } @Override public void serialize(IDataNode dataNode) { dataNode.set("player-id", _playerId); dataNode.set("items", _items); dataNode.set("armor", _armor); dataNode.set("location", _location); dataNode.set("gamemode", _gameMode); dataNode.set("health", _health); dataNode.set("food", _food); dataNode.set("levels", _level); dataNode.set("exp", _exp); dataNode.set("flight", _flight); dataNode.set("allow-flight", _allowFlight); dataNode.set("fall-distance", _fallDistance); dataNode.set("fire-ticks", _fireTicks); IDataNode potionNode = dataNode.getNode("potions"); potionNode.remove(); // clear node for (PotionEffect effect : _potions) { IDataNode effectNode = potionNode.getNode(UUID.randomUUID().toString()); setEffectToNode(effect, effectNode); } } @Override public void deserialize(IDataNode dataNode) throws DeserializeException { if ((_playerId = dataNode.getUUID("player-id")) == null) throw new DeserializeException("player-id not found."); if ((_items = dataNode.getItemStacks("items")) == null) throw new DeserializeException("items not found."); if ((_armor = dataNode.getItemStacks("armor")) == null) throw new DeserializeException("armor not found."); if ((_location = dataNode.getLocation("location")) == null) throw new DeserializeException("location not found."); if ((_gameMode = dataNode.getEnum("gamemode", GameMode.class)) == null) throw new DeserializeException("gamemode not found."); _health = dataNode.getDouble("health", 20); _food = dataNode.getInteger("food", 20); _level = dataNode.getInteger("levels", 0); _exp = (float)dataNode.getDouble("exp", 0); _flight = dataNode.getBoolean("flight", false); _allowFlight = dataNode.getBoolean("allow-flight", false); _fireTicks = dataNode.getInteger("fire-ticks", 0); _fallDistance = (float)dataNode.getDouble("fall-distance", 0); try { IDataNode potionsNode = dataNode.getNode("potions"); _potions = new ArrayList<>(potionsNode.size()); for (IDataNode potionNode : potionsNode) { PotionEffect effect = getEffectFromNode(potionNode); if (effect == null) continue; _potions.add(effect); } } catch (Exception ex) { ex.printStackTrace(); throw new DeserializeException("Exception while reading potions."); } } /* * Load a new potion effect from effect data on the specified data node. */ @Nullable private static PotionEffect getEffectFromNode(IDataNode dataNode) { PreCon.notNull(dataNode); int amplifier = dataNode.getInteger("amplifier"); int duration = dataNode.getInteger("duration"); boolean isAmbient = dataNode.getBoolean("ambient"); String typeName = dataNode.getString("effect-name"); if (typeName == null) return null; PotionEffectType type = PotionEffectType.getByName(typeName); if (type == null) return null; return new PotionEffect(type, duration, amplifier, isAmbient); } /* * Sets potion effect data to the specified node. Does not save the node. */ private static void setEffectToNode(PotionEffect effect, IDataNode dataNode) { PreCon.notNull(effect); PreCon.notNull(dataNode); dataNode.set("amplifier", effect.getAmplifier()); dataNode.set("duration", effect.getDuration()); dataNode.set("ambient", effect.isAmbient()); dataNode.set("effect-name", effect.getType().getName()); } }