diff --git a/core/src/main/java/de/erethon/dungeonsxl/player/DGlobalPlayer.java b/core/src/main/java/de/erethon/dungeonsxl/player/DGlobalPlayer.java index 95db5010..fda06b51 100644 --- a/core/src/main/java/de/erethon/dungeonsxl/player/DGlobalPlayer.java +++ b/core/src/main/java/de/erethon/dungeonsxl/player/DGlobalPlayer.java @@ -42,6 +42,8 @@ import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; +import org.bukkit.attribute.AttributeModifier; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; @@ -474,23 +476,30 @@ public class DGlobalPlayer implements GlobalPlayer { } player.setLevel(data.getOldLevel()); player.setExp(data.getOldExp()); - if (is1_9) { - player.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(data.getOldMaxHealth()); - player.setHealth(data.getOldHealth() <= data.getOldMaxHealth() ? data.getOldHealth() : data.getOldMaxHealth()); - } else { - player.setHealth(player.getMaxHealth()); - } player.setFoodLevel(data.getOldFoodLevel()); player.setFireTicks(data.getOldFireTicks()); + for (PotionEffect effect : player.getActivePotionEffects()) { player.removePotionEffect(effect.getType()); } - player.addPotionEffects(data.getOldPotionEffects()); if (is1_9) { player.setCollidable(data.getOldCollidabilityState()); player.setInvulnerable(data.getOldInvulnerabilityState()); + for (Attribute attribute : Attribute.values()) { + AttributeInstance instance = player.getAttribute(attribute); + if (instance == null) { + continue; + } + instance.setBaseValue((double) data.getOldAttributeBases().get(attribute)); + for (AttributeModifier mod : instance.getModifiers()) { + instance.removeModifier(mod); + } + for (/*AttributeModifier*/Object mod : data.getOldAttributeMods().get(attribute)) { // TODO Remove casts when 1.8 is dropped + instance.addModifier((AttributeModifier) mod); + } + } } player.setAllowFlight(data.getOldFlyingState()); diff --git a/core/src/main/java/de/erethon/dungeonsxl/player/DInstancePlayer.java b/core/src/main/java/de/erethon/dungeonsxl/player/DInstancePlayer.java index e6b73135..d929c56d 100644 --- a/core/src/main/java/de/erethon/dungeonsxl/player/DInstancePlayer.java +++ b/core/src/main/java/de/erethon/dungeonsxl/player/DInstancePlayer.java @@ -22,6 +22,7 @@ import de.erethon.dungeonsxl.api.player.InstancePlayer; import de.erethon.dungeonsxl.api.world.GameWorld; import de.erethon.dungeonsxl.api.world.InstanceWorld; import de.erethon.dungeonsxl.config.MainConfig; +import de.erethon.dungeonsxl.util.AttributeUtil; import de.erethon.dungeonsxl.util.ParsingUtil; import org.bukkit.World; import org.bukkit.attribute.Attribute; @@ -80,6 +81,7 @@ public abstract class DInstancePlayer extends DGlobalPlayer implements InstanceP player.setLevel(0); double maxHealth; if (is1_9) { + AttributeUtil.resetPlayerAttributes(player); maxHealth = player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue(); } else { maxHealth = player.getMaxHealth(); diff --git a/core/src/main/java/de/erethon/dungeonsxl/player/DPlayerData.java b/core/src/main/java/de/erethon/dungeonsxl/player/DPlayerData.java index ee12ec8a..83649747 100644 --- a/core/src/main/java/de/erethon/dungeonsxl/player/DPlayerData.java +++ b/core/src/main/java/de/erethon/dungeonsxl/player/DPlayerData.java @@ -16,8 +16,11 @@ */ package de.erethon.dungeonsxl.player; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import de.erethon.commons.chat.MessageUtil; import de.erethon.commons.compatibility.Internals; +import de.erethon.commons.config.ConfigUtil; import de.erethon.commons.config.DREConfig; import de.erethon.commons.javaplugin.DREPlugin; import de.erethon.commons.misc.EnumUtil; @@ -29,10 +32,13 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; +import org.bukkit.attribute.AttributeModifier; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; @@ -59,12 +65,13 @@ public class DPlayerData extends DREConfig { private ItemStack oldOffHand; private int oldLvl; private float oldExp; - private double oldMaxHealth; private double oldHealth; private int oldFoodLevel; private int oldFireTicks; private GameMode oldGameMode; private Collection oldPotionEffects; + private Map/**/ oldAttributeBases; + private Multimap/**/ oldAttributeMods; private boolean oldCollidabilityState; private boolean oldFlyingState; private boolean oldInvulnerabilityState; @@ -195,20 +202,6 @@ public class DPlayerData extends DREConfig { oldExp = exp; } - /** - * @return the old max health - */ - public double getOldMaxHealth() { - return oldMaxHealth; - } - - /** - * @param maxHealth the maximum health to set - */ - public void setOldMaxHealth(double maxHealth) { - oldMaxHealth = maxHealth; - } - /** * @return the old health */ @@ -279,6 +272,34 @@ public class DPlayerData extends DREConfig { oldPotionEffects = potionEffects; } + /** + * @return the old attribute bases + */ + public Map/**/ getOldAttributeBases() { + return oldAttributeBases; + } + + /** + * @param attributeBases the old attribute bases to set + */ + public void setOldAttributeBases(Map/**/ attributeBases) { + oldAttributeBases = attributeBases; + } + + /** + * @return the old attribute modifiers + */ + public Multimap/**/ getOldAttributeMods() { + return oldAttributeMods; + } + + /** + * @param attributeMods the old attribute modifiers to set + */ + public void setOldAttributeMods(Multimap/**/ attributeMods) { + oldAttributeMods = attributeMods; + } + /** * @return if the player was collidable */ @@ -503,7 +524,6 @@ public class DPlayerData extends DREConfig { oldLvl = config.getInt(PREFIX_STATE_PERSISTENCE + "oldLvl"); oldExp = config.getInt(PREFIX_STATE_PERSISTENCE + "oldExp"); - oldMaxHealth = config.getDouble(PREFIX_STATE_PERSISTENCE + "oldMaxHealth"); oldHealth = config.getDouble(PREFIX_STATE_PERSISTENCE + "oldHealth"); oldFoodLevel = config.getInt(PREFIX_STATE_PERSISTENCE + "oldFoodLevel"); oldFireTicks = config.getInt(PREFIX_STATE_PERSISTENCE + "oldFireTicks"); @@ -515,6 +535,34 @@ public class DPlayerData extends DREConfig { } oldPotionEffects = (Collection) config.get(PREFIX_STATE_PERSISTENCE + "oldPotionEffects"); + if (is1_9) { + Map basesMap = ConfigUtil.getMap(config, PREFIX_STATE_PERSISTENCE + "oldAttributeBases", false); + if (basesMap != null) { + oldAttributeBases = new HashMap<>(); + for (Entry entry : basesMap.entrySet()) { + if (!(entry.getValue() instanceof Double)) { + continue; + } + Attribute attribute = EnumUtil.getEnum(Attribute.class, entry.getKey()); + Double base = (Double) entry.getValue(); + oldAttributeBases.put(attribute, base); + } + } + + Map modsMap = ConfigUtil.getMap(config, PREFIX_STATE_PERSISTENCE + "oldAttributeModifiers", false); + if (modsMap != null) { + oldAttributeMods = HashMultimap.create(); + for (Entry entry : modsMap.entrySet()) { + if (!(entry.getValue() instanceof Collection)) { + continue; + } + Attribute attribute = EnumUtil.getEnum(Attribute.class, entry.getKey()); + Collection mods = (Collection) entry.getValue(); + oldAttributeMods.putAll(attribute, mods); + } + } + } + try { oldLocation = (Location) config.get(PREFIX_STATE_PERSISTENCE + "oldLocation"); } catch (IllegalArgumentException exception) { @@ -544,9 +592,6 @@ public class DPlayerData extends DREConfig { oldGameMode = player.getGameMode(); oldFireTicks = player.getFireTicks(); oldFoodLevel = player.getFoodLevel(); - if (is1_9) { - oldMaxHealth = player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue(); - } oldHealth = player.getHealth(); oldExp = player.getExp(); oldLvl = player.getLevel(); @@ -558,6 +603,18 @@ public class DPlayerData extends DREConfig { oldLocation = player.getLocation(); oldPotionEffects = player.getActivePotionEffects(); if (is1_9) { + oldAttributeBases = new HashMap<>(); + oldAttributeMods = HashMultimap.create(); + for (Attribute attribute : Attribute.values()) { + AttributeInstance instance = player.getAttribute(attribute); + if (instance == null) { + continue; + } + oldAttributeBases.put(attribute, instance.getBaseValue()); + for (AttributeModifier mod : instance.getModifiers()) { + oldAttributeMods.put(attribute, mod); + } + } oldCollidabilityState = player.isCollidable(); oldInvulnerabilityState = player.isInvulnerable(); } @@ -566,7 +623,6 @@ public class DPlayerData extends DREConfig { config.set(PREFIX_STATE_PERSISTENCE + "oldGameMode", oldGameMode.toString()); config.set(PREFIX_STATE_PERSISTENCE + "oldFireTicks", oldFireTicks); config.set(PREFIX_STATE_PERSISTENCE + "oldFoodLevel", oldFoodLevel); - config.set(PREFIX_STATE_PERSISTENCE + "oldMaxHealth", oldMaxHealth); config.set(PREFIX_STATE_PERSISTENCE + "oldHealth", oldHealth); config.set(PREFIX_STATE_PERSISTENCE + "oldExp", oldExp); config.set(PREFIX_STATE_PERSISTENCE + "oldLvl", oldLvl); @@ -575,6 +631,10 @@ public class DPlayerData extends DREConfig { config.set(PREFIX_STATE_PERSISTENCE + "oldOffHand", oldOffHand); config.set(PREFIX_STATE_PERSISTENCE + "oldLocation", oldLocation); config.set(PREFIX_STATE_PERSISTENCE + "oldPotionEffects", oldPotionEffects); + if (is1_9) { + config.set(PREFIX_STATE_PERSISTENCE + "oldAttributeBases", oldAttributeBases); + config.set(PREFIX_STATE_PERSISTENCE + "oldAttributeMods", oldAttributeMods.asMap()); + } config.set(PREFIX_STATE_PERSISTENCE + "oldCollidabilityState", oldCollidabilityState); config.set(PREFIX_STATE_PERSISTENCE + "oldFlyingState", oldFlyingState); config.set(PREFIX_STATE_PERSISTENCE + "oldInvulnerabilityState", oldInvulnerabilityState); @@ -589,7 +649,6 @@ public class DPlayerData extends DREConfig { oldGameMode = null; oldFireTicks = 0; oldFoodLevel = 0; - oldMaxHealth = 20; oldHealth = 0; oldExp = 0; oldLvl = 0; @@ -598,6 +657,8 @@ public class DPlayerData extends DREConfig { oldOffHand = null; oldLocation = null; oldPotionEffects = null; + oldAttributeBases = null; + oldAttributeMods = null; oldCollidabilityState = true; oldFlyingState = false; oldInvulnerabilityState = false; diff --git a/core/src/main/java/de/erethon/dungeonsxl/util/AttributeUtil.java b/core/src/main/java/de/erethon/dungeonsxl/util/AttributeUtil.java new file mode 100644 index 00000000..5c57ddc7 --- /dev/null +++ b/core/src/main/java/de/erethon/dungeonsxl/util/AttributeUtil.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012-2020 Frank Baumann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.erethon.dungeonsxl.util; + +import com.google.common.collect.ImmutableMap; +import java.util.Map; +import org.bukkit.attribute.Attribute; +import static org.bukkit.attribute.Attribute.*; +import org.bukkit.attribute.AttributeInstance; +import org.bukkit.entity.Player; + +/** + * @author Daniel Saukel + */ +public class AttributeUtil { + + private static final Map DEFAULT_PLAYER_VALUES = ImmutableMap.of( + GENERIC_MOVEMENT_SPEED, .1, // .7 + GENERIC_ATTACK_DAMAGE, 1.0 // 2.0 + ); + + /** + * Returns the default value that a player entity has. + * + * @param attribute the attribute instance to check + * @return the default value that a player entity has + */ + public static final Double getDefaultPlayerValue(AttributeInstance attribute) { + return DEFAULT_PLAYER_VALUES.getOrDefault(attribute.getAttribute(), attribute.getDefaultValue()); + } + + /** + * Resets a player's attributes. + * + * @param player the player + */ + public static void resetPlayerAttributes(Player player) { + for (Attribute attribute : Attribute.values()) { + AttributeInstance instance = player.getAttribute(attribute); + if (instance == null) { + continue; + } + instance.setBaseValue(getDefaultPlayerValue(instance)); + instance.getModifiers().forEach(instance::removeModifier); + } + } + +}