소스 검색

update for 1.21.3 compatibility

nossr50 8 달 전
부모
커밋
99bb5857f8

+ 3 - 1
Changelog.txt

@@ -1,9 +1,11 @@
+Version 2.2.023
+    Compatibility with Minecraft 1.21.3
+
 Version 2.2.022
     Fixed a bug where Roll was always reducing damage (thanks Ineusia)
     Fix COTW errors on older versions (thanks Warriorrrr)
     Fixed slimes spawning from slime division not inheriting tags. (thanks Ineusia)
 
-
 Version 2.2.021
     Fixed issue where Roll wasn't reducing as much damage as it should have been (thanks Ineusia)
     Updated locale_es (thanks Devilcasters)

+ 34 - 30
pom.xml

@@ -13,6 +13,8 @@
     </scm>
 
     <properties>
+        <spigot.version>1.21.3-R0.1-SNAPSHOT</spigot.version>
+        <adventure.version>4.3.5-SNAPSHOT</adventure.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <maven.compiler.source>17</maven.compiler.source>
         <maven.compiler.target>17</maven.compiler.target>
@@ -300,7 +302,7 @@
         <dependency>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-text-serializer-bungeecord</artifactId>
-            <version>4.3.2</version>
+            <version>${adventure.version}</version>
         </dependency>
         <dependency>
             <groupId>net.kyori</groupId>
@@ -340,22 +342,22 @@
         <dependency>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-platform-api</artifactId>
-            <version>4.3.3</version>
+            <version>${adventure.version}</version>
         </dependency>
         <dependency>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-platform-bukkit</artifactId>
-            <version>LATEST</version>
+            <version>${adventure.version}</version>
         </dependency>
         <dependency>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-platform-facet</artifactId>
-            <version>4.3.3</version>
+            <version>${adventure.version}</version>
         </dependency>
         <dependency>
             <groupId>net.kyori</groupId>
             <artifactId>adventure-platform-viaversion</artifactId>
-            <version>4.3.3</version>
+            <version>${adventure.version}</version>
         </dependency>
         <dependency>
             <groupId>net.kyori</groupId>
@@ -376,7 +378,7 @@
         <dependency>
             <groupId>org.spigotmc</groupId>
             <artifactId>spigot-api</artifactId>
-            <version>1.21-R0.1-SNAPSHOT</version>
+            <version>${spigot.version}</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -427,6 +429,12 @@
             <version>5.2.0</version>
             <scope>test</scope>
         </dependency>
+<!--        <dependency>-->
+<!--            <groupId>com.github.seeseemelk</groupId>-->
+<!--            <artifactId>MockBukkit-v1.21</artifactId>-->
+<!--            <version>[version]</version>-->
+<!--            <scope>test</scope>-->
+<!--        </dependency>-->
         <dependency>
             <groupId>org.apache.tomcat</groupId>
             <artifactId>tomcat-jdbc</artifactId>
@@ -450,29 +458,25 @@
             <version>0.3.1</version>
             <scope>compile</scope>
         </dependency>
-<!--        <dependency>-->
-<!--            <groupId>org.apache.logging.log4j</groupId>-->
-<!--            <artifactId>log4j-core</artifactId>-->
-<!--            <version>2.22.1</version> &lt;!&ndash; Make sure this version matches the other log4j dependencies &ndash;&gt;-->
-<!--            <scope>test</scope>-->
-<!--        </dependency>-->
-<!--        <dependency>-->
-<!--            <groupId>org.apache.logging.log4j</groupId>-->
-<!--            <artifactId>log4j-api</artifactId>-->
-<!--            <version>2.22.1</version>-->
-<!--            <scope>test</scope>-->
-<!--        </dependency>-->
-<!--        <dependency>-->
-<!--            <groupId>org.apache.logging.log4j</groupId>-->
-<!--            <artifactId>log4j-slf4j-impl</artifactId>-->
-<!--            <version>2.22.1</version>-->
-<!--            <scope>test</scope>-->
-<!--        </dependency>-->
-<!--        <dependency>-->
-<!--            <groupId>com.github.seeseemelk</groupId>-->
-<!--            <artifactId>MockBukkit-v1.19</artifactId>-->
-<!--            <version>LATEST</version>-->
-<!--            <scope>test</scope>-->
-<!--        </dependency>-->
     </dependencies>
+<!--    <profiles>-->
+<!--        <profile>-->
+<!--            <id>spigot-1.18.2</id>-->
+<!--            <properties>-->
+<!--                <spigot.version>1.18.2-R0.1-SNAPSHOT</spigot.version>-->
+<!--            </properties>-->
+<!--        </profile>-->
+<!--        <profile>-->
+<!--            <id>spigot-1.21.1</id>-->
+<!--            <properties>-->
+<!--                <spigot.version>1.21.1-R0.1-SNAPSHOT</spigot.version>-->
+<!--            </properties>-->
+<!--        </profile>-->
+<!--        <profile>-->
+<!--            <id>spigot-1.21.3</id>-->
+<!--            <properties>-->
+<!--                <spigot.version>1.21.3-R0.1-SNAPSHOT</spigot.version>-->
+<!--            </properties>-->
+<!--        </profile>-->
+<!--    </profiles>-->
 </project>

+ 1 - 0
src/main/java/com/gmail/nossr50/chat/ChatManager.java

@@ -14,6 +14,7 @@ import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.text.StringUtils;
 import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.chat.SignedMessage;
 import net.kyori.adventure.text.TextComponent;
 import org.bukkit.command.ConsoleCommandSender;
 import org.jetbrains.annotations.NotNull;

+ 3 - 2
src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -49,6 +49,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
 
+import static com.gmail.nossr50.util.AttributeMapper.MAPPED_MAX_HEALTH;
 import static com.gmail.nossr50.util.MobMetadataUtils.*;
 
 public class EntityListener implements Listener {
@@ -411,7 +412,7 @@ public class EntityListener implements Listener {
                     player.sendMessage(ChatColor.GOLD + "(mmodebug start of combat report) EntityDamageByEntityEvent DEBUG Info:");
                     player.sendMessage("You are being damaged by another player in this event");
                     player.sendMessage("Raw Damage: " + entityDamageEvent.getDamage());
-                    player.sendMessage("Your max health: "+player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
+                    player.sendMessage("Your max health: "+player.getAttribute(MAPPED_MAX_HEALTH).getValue());
                     player.sendMessage("Your current health: "+player.getHealth());
 
                     player.sendMessage(ChatColor.GREEN + "Damage Modifiers (final damage)");
@@ -444,7 +445,7 @@ public class EntityListener implements Listener {
                     }
 
                     player.sendMessage("Final damage: " + entityDamageEvent.getFinalDamage());
-                    player.sendMessage("Target players max health: "+otherPlayer.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
+                    player.sendMessage("Target players max health: "+otherPlayer.getAttribute(MAPPED_MAX_HEALTH).getValue());
                     player.sendMessage("Target players current health: "+otherPlayer.getHealth());
 
                     if (entityDamageEvent.isCancelled()) {

+ 0 - 7
src/main/java/com/gmail/nossr50/mcMMO.java

@@ -138,7 +138,6 @@ public class mcMMO extends JavaPlugin {
     private PotionConfig potionConfig;
     private CustomItemSupportConfig customItemSupportConfig;
     private EnchantmentMapper enchantmentMapper;
-    private AttributeMapper attributeMapper;
 
     private FoliaLib foliaLib;
     private PartyManager partyManager;
@@ -195,8 +194,6 @@ public class mcMMO extends JavaPlugin {
             materialMapStore = new MaterialMapStore();
             // Init compatibility mappers
             enchantmentMapper = new EnchantmentMapper(this);
-            attributeMapper = new AttributeMapper(this);
-
             loadConfigFiles();
 
             if (!noErrorsInConfigFiles) {
@@ -818,10 +815,6 @@ public class mcMMO extends JavaPlugin {
         return enchantmentMapper;
     }
 
-    public AttributeMapper getAttributeMapper() {
-        return attributeMapper;
-    }
-
     public @NotNull FoliaLib getFoliaLib() {
         return foliaLib;
     }

+ 37 - 25
src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java

@@ -13,7 +13,7 @@ import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.Player;
 import org.jetbrains.annotations.NotNull;
 
-import static org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH;
+import static com.gmail.nossr50.util.AttributeMapper.MAPPED_MAX_HEALTH;
 
 public class RuptureTask extends CancellableRunnable {
 
@@ -28,9 +28,16 @@ public class RuptureTask extends CancellableRunnable {
     private int damageTickTracker;
     private int animationTick;
     private final double pureTickDamage;
-    private final double explosionDamage;
 
-    public RuptureTask(@NotNull McMMOPlayer ruptureSource, @NotNull LivingEntity targetEntity, double pureTickDamage, double explosionDamage) {
+    /**
+     * Constructor for the RuptureTask class.
+     *
+     * @param ruptureSource The McMMOPlayer who is the source of the rupture.
+     * @param targetEntity The LivingEntity that is the target of the rupture.
+     * @param pureTickDamage The amount of damage to be applied per tick.
+     */
+    public RuptureTask(@NotNull McMMOPlayer ruptureSource, @NotNull LivingEntity targetEntity,
+                       double pureTickDamage) {
         this.ruptureSource = ruptureSource;
         this.targetEntity = targetEntity;
         this.expireTick = mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(targetEntity instanceof Player) * 20;
@@ -39,7 +46,24 @@ public class RuptureTask extends CancellableRunnable {
         this.damageTickTracker = 0;
         this.animationTick = ANIMATION_TICK_INTERVAL; //Play an animation right away
         this.pureTickDamage = pureTickDamage;
-        this.explosionDamage = explosionDamage;
+    }
+
+    /**
+     * Deprecated constructor for the RuptureTask class.
+     *
+     * @deprecated This constructor is deprecated and will be removed in future versions.
+     * Use {@link #RuptureTask(McMMOPlayer, LivingEntity, double)} instead.
+     *
+     * @param ruptureSource The McMMOPlayer who is the source of the rupture.
+     * @param targetEntity The LivingEntity that is the target of the rupture.
+     * @param pureTickDamage The amount of damage to be applied per tick.
+     * @param ignored This parameter is ignored and should not be used.
+     * @since 2.2.023
+     */
+    @Deprecated(forRemoval = true, since = "2.2.023")
+    public RuptureTask(@NotNull McMMOPlayer ruptureSource, @NotNull LivingEntity targetEntity,
+                       double pureTickDamage, double ignored) {
+        this(ruptureSource, targetEntity, pureTickDamage);
     }
 
     @Override
@@ -100,11 +124,11 @@ public class RuptureTask extends CancellableRunnable {
 
             final double damagedHealth = healthBeforeRuptureIsApplied - damage;
 
-            final AttributeInstance maxHealthAttribute = targetEntity.getAttribute(GENERIC_MAX_HEALTH);
+            final AttributeInstance maxHealthAttribute = targetEntity.getAttribute(MAPPED_MAX_HEALTH);
             if (maxHealthAttribute == null) {
                 // Can't remove health if max health is null
                 mcMMO.p.getLogger().info("RuptureTask: Target entity has an illegal state for its health." +
-                        " Cancelling Rupture. Target has null " + GENERIC_MAX_HEALTH + " attribute.");
+                        " Cancelling Rupture. Target has null " + MAPPED_MAX_HEALTH + " attribute.");
                 return true;
             }
 
@@ -129,18 +153,6 @@ public class RuptureTask extends CancellableRunnable {
     }
 
     public void endRupture() {
-//        targetEntity.setMetadata(mcMMO.EXPLOSION_FROM_RUPTURE, new FixedMetadataValue(mcMMO.p, "null"));
-//
-//        ParticleEffectUtils.playGreaterImpactEffect(targetEntity); //Animate
-//
-//        if (ruptureSource.getPlayer() != null && ruptureSource.getPlayer().isValid()) {
-//            targetEntity.damage(getExplosionDamage(), ruptureSource.getPlayer());
-//        } else {
-//            targetEntity.damage(getExplosionDamage(), null);
-//        }
-//
-//        targetEntity.removeMetadata(mcMMO.RUPTURE_META_KEY, mcMMO.p);
-
         targetEntity.removeMetadata(MetadataConstants.METADATA_KEY_RUPTURE, mcMMO.p);
         this.cancel(); //Task no longer needed
     }
@@ -159,10 +171,6 @@ public class RuptureTask extends CancellableRunnable {
         return tickDamage;
     }
 
-    private double getExplosionDamage() {
-        return explosionDamage;
-    }
-
     @Override
     public String toString() {
         return "RuptureTask{" +
@@ -172,7 +180,6 @@ public class RuptureTask extends CancellableRunnable {
                 ", ruptureTick=" + ruptureTick +
                 ", damageTickTracker=" + damageTickTracker +
                 ", pureTickDamage=" + pureTickDamage +
-                ", explosionDamage=" + explosionDamage +
                 '}';
     }
 
@@ -181,11 +188,16 @@ public class RuptureTask extends CancellableRunnable {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         RuptureTask that = (RuptureTask) o;
-        return expireTick == that.expireTick && ruptureTick == that.ruptureTick && damageTickTracker == that.damageTickTracker && Double.compare(that.pureTickDamage, pureTickDamage) == 0 && Double.compare(that.explosionDamage, explosionDamage) == 0 && Objects.equal(ruptureSource, that.ruptureSource) && Objects.equal(targetEntity, that.targetEntity);
+        return expireTick == that.expireTick
+                && ruptureTick == that.ruptureTick
+                && damageTickTracker == that.damageTickTracker
+                && Double.compare(that.pureTickDamage, pureTickDamage) == 0
+                && Objects.equal(ruptureSource, that.ruptureSource) && Objects.equal(targetEntity, that.targetEntity);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(ruptureSource, targetEntity, expireTick, ruptureTick, damageTickTracker, pureTickDamage, explosionDamage);
+        return Objects.hashCode(ruptureSource, targetEntity, expireTick,
+                ruptureTick, damageTickTracker, pureTickDamage);
     }
 }

+ 1 - 2
src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java

@@ -91,8 +91,7 @@ public class SwordsManager extends SkillManager {
             }
 
             RuptureTask ruptureTask = new RuptureTask(mmoPlayer, target,
-                    mcMMO.p.getAdvancedConfig().getRuptureTickDamage(target instanceof Player, getRuptureRank()),
-                    mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(target instanceof Player, getRuptureRank()));
+                    mcMMO.p.getAdvancedConfig().getRuptureTickDamage(target instanceof Player, getRuptureRank()));
 
             RuptureTaskMeta ruptureTaskMeta = new RuptureTaskMeta(mcMMO.p, ruptureTask);
 

+ 4 - 2
src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java

@@ -31,6 +31,8 @@ import org.jetbrains.annotations.NotNull;
 
 import java.util.HashMap;
 
+import static com.gmail.nossr50.util.AttributeMapper.MAPPED_JUMP_STRENGTH;
+import static com.gmail.nossr50.util.AttributeMapper.MAPPED_MOVEMENT_SPEED;
 import static com.gmail.nossr50.util.MobMetadataUtils.flagMetadata;
 
 public class TamingManager extends SkillManager {
@@ -235,13 +237,13 @@ public class TamingManager extends SkillManager {
 
         // Bred mules & donkeys can actually have horse-like stats, but llamas cannot.
         if (beast instanceof AbstractHorse horseLikeCreature && !(beast instanceof Llama)) {
-            AttributeInstance jumpAttribute = horseLikeCreature.getAttribute(mcMMO.p.getAttributeMapper().getHorseJumpStrength());
+            AttributeInstance jumpAttribute = horseLikeCreature.getAttribute(MAPPED_JUMP_STRENGTH);
 
             if (jumpAttribute != null) {
                 double jumpStrength = jumpAttribute.getValue();
                 // Taken from https://minecraft.wiki/w/Horse#Jump_strength
                 jumpStrength = -0.1817584952 * Math.pow(jumpStrength, 3) + 3.689713992 * Math.pow(jumpStrength, 2) + 2.128599134 * jumpStrength - 0.343930367;
-                message = message.concat("\n" + LocaleLoader.getString("Combat.BeastLoreHorseSpeed", horseLikeCreature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getValue() * 43))
+                message = message.concat("\n" + LocaleLoader.getString("Combat.BeastLoreHorseSpeed", horseLikeCreature.getAttribute(MAPPED_MOVEMENT_SPEED).getValue() * 43))
                         .concat("\n" + LocaleLoader.getString("Combat.BeastLoreHorseJumpStrength", jumpStrength));
             }
         }

+ 183 - 31
src/main/java/com/gmail/nossr50/util/AttributeMapper.java

@@ -4,42 +4,194 @@ import com.gmail.nossr50.mcMMO;
 import org.bukkit.Registry;
 import org.bukkit.attribute.Attribute;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.stream.Stream;
+
 public class AttributeMapper {
-    private final mcMMO pluginRef;
-    private static final String GENERIC_JUMP_STRENGTH = "generic.jump_strength";
-    private static final String HORSE_JUMP_STRENGTH = "horse.jump_strength";
-    private final Attribute horseJumpStrength;
-
-    public AttributeMapper(mcMMO pluginRef) {
-        this.pluginRef = pluginRef;
-        this.horseJumpStrength = initHorseJumpStrength();
+
+    public static final String ATTRIBUTE = "ATTRIBUTE";
+    public static final String ORG_BUKKIT_REGISTRY = "org.bukkit.Registry";
+
+    // Prevent instantiation
+    private AttributeMapper() {
     }
 
-    private Attribute initHorseJumpStrength() {
-        // TODO: Use modern matching?
-//        if (Registry.ATTRIBUTE.match(GENERIC_JUMP_STRENGTH) != null) {
-//            return Registry.ATTRIBUTE.match(GENERIC_JUMP_STRENGTH);
-//        }
-//
-//        if (Registry.ATTRIBUTE.match(HORSE_JUMP_STRENGTH) != null) {
-//            return Registry.ATTRIBUTE.match(HORSE_JUMP_STRENGTH);
-//        }
-
-        for (Attribute attr : Registry.ATTRIBUTE) {
-            if (attr.getKey().getKey().equalsIgnoreCase(HORSE_JUMP_STRENGTH)
-                    || attr.getKey().getKey().equalsIgnoreCase(GENERIC_JUMP_STRENGTH)
-                    || attr.name().equalsIgnoreCase(HORSE_JUMP_STRENGTH)
-                    || attr.name().equalsIgnoreCase(GENERIC_JUMP_STRENGTH)) {
-                return attr;
-            }
-        }
+    // Define constants for attribute keys and their legacy counterparts
+    private static final String MAX_HEALTH_1_21_3_STR = "max_health";
+    private static final String MAX_HEALTH_1_18_2_STR = "generic.max_health";
+    public static final Attribute MAPPED_MAX_HEALTH;
+
+    private static final String JUMP_STRENGTH_1_23_1 = "jump_strength";
+    private static final String JUMP_STRENGTH_1_21_1 = "generic.jump_strength";
+    private static final String JUMP_STR_1_18_2 = "horse.jump_strength";
+    public static final Attribute MAPPED_JUMP_STRENGTH;
 
-        pluginRef.getLogger().severe("Unable to find the Generic Jump Strength or Horse Jump Strength attribute, " +
-                "mcMMO will not function properly.");
-        throw new IllegalStateException("Unable to find the Generic Jump Strength or Horse Jump Strength attribute");
+    public static final Attribute MAPPED_MOVEMENT_SPEED;
+    private static final String MOVEMENT_SPEED_1_18_2 = "generic.movement_speed";
+    private static final String MOVEMENT_SPEED_1_21_1 = "generic.movement_speed";
+    private static final String MOVEMENT_SPEED_1_21_3 = "movement_speed";
+
+    // Add other attributes similarly...
+    // For brevity, only key attributes are shown
+
+    static {
+        MAPPED_MAX_HEALTH = findAttribute(MAX_HEALTH_1_21_3_STR, MAX_HEALTH_1_18_2_STR);
+        MAPPED_JUMP_STRENGTH = findAttribute(JUMP_STRENGTH_1_23_1, JUMP_STRENGTH_1_21_1, JUMP_STR_1_18_2);
+        MAPPED_MOVEMENT_SPEED = findAttribute(MOVEMENT_SPEED_1_18_2, MOVEMENT_SPEED_1_21_1, MOVEMENT_SPEED_1_21_3);
     }
 
-    public Attribute getHorseJumpStrength() {
-        return horseJumpStrength;
+    private static Attribute findAttribute(String... keys) {
+        Stream<?> attributeStream;
+        try {
+            // Try to get Registry.ATTRIBUTE using reflection
+            Class<?> registryClass = Class.forName(ORG_BUKKIT_REGISTRY);
+            Field attributeField = registryClass.getField(ATTRIBUTE);
+            Object attributeRegistry = attributeField.get(null);
+
+            // Get the stream() method of the attribute registry
+            Method streamMethod = attributeRegistry.getClass().getMethod("stream");
+            attributeStream = (Stream<?>) streamMethod.invoke(attributeRegistry);
+        } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException |
+                 InvocationTargetException e) {
+            // Fallback to older versions where Attribute is an enum
+            Object[] enumConstants = Attribute.class.getEnumConstants();
+            attributeStream = Arrays.stream(enumConstants);
+        }
+
+        Optional<?> optionalAttribute = attributeStream
+                .filter(attr -> {
+                    try {
+                        String attrKey = null;
+                        String attrName = null;
+
+                        // Try to get attr.getKey().getKey()
+                        Method getKeyMethod = attr.getClass().getMethod("getKey");
+                        Object namespacedKey = getKeyMethod.invoke(attr);
+
+                        if (namespacedKey != null) {
+                            Method getKeyStringMethod = namespacedKey.getClass().getMethod("getKey");
+                            attrKey = (String) getKeyStringMethod.invoke(namespacedKey);
+                        }
+
+                        // Try to get attr.name()
+                        Method nameMethod;
+                        try {
+                            nameMethod = attr.getClass().getMethod("name");
+                            attrName = (String) nameMethod.invoke(attr);
+                        } catch (NoSuchMethodException e) {
+                            // name() method doesn't exist in newer versions
+                            attrName = null;
+                        }
+
+                        // Compare with provided keys
+                        for (String key : keys) {
+                            if ((attrKey != null && attrKey.equalsIgnoreCase(key)) ||
+                                    (attrName != null && attrName.equalsIgnoreCase(key))) {
+                                return true;
+                            }
+                        }
+                    } catch (Exception e) {
+                        mcMMO.p.getLogger().severe("Unable to find the attribute with possible keys: "
+                                + Arrays.toString(keys) + ", mcMMO will not function properly.");
+                        throw new RuntimeException(e);
+                    }
+                    return false;
+                })
+                .findFirst();
+
+        if (optionalAttribute.isPresent()) {
+            return (Attribute) optionalAttribute.get();
+        } else {
+            mcMMO.p.getLogger().severe("Unable to find the attribute with possible keys: "
+                    + Arrays.toString(keys) + ", mcMMO will not function properly.");
+            throw new IllegalStateException("Unable to find the attribute with possible keys: "
+                    + Arrays.toString(keys));
+        }
     }
+
+    /*
+    For easy reference...
+    List of 1.18 Attributes by name...
+        GENERIC_MAX_HEALTH("generic.max_health"),
+        GENERIC_FOLLOW_RANGE("generic.follow_range"),
+        GENERIC_KNOCKBACK_RESISTANCE("generic.knockback_resistance"),
+        GENERIC_MOVEMENT_SPEED("generic.movement_speed"),
+        GENERIC_FLYING_SPEED("generic.flying_speed"),
+        GENERIC_ATTACK_DAMAGE("generic.attack_damage"),
+        GENERIC_ATTACK_KNOCKBACK("generic.attack_knockback"),
+        GENERIC_ATTACK_SPEED("generic.attack_speed"),
+        GENERIC_ARMOR("generic.armor"),
+        GENERIC_ARMOR_TOUGHNESS("generic.armor_toughness"),
+        GENERIC_LUCK("generic.luck"),
+        HORSE_JUMP_STRENGTH("horse.jump_strength"),
+        ZOMBIE_SPAWN_REINFORCEMENTS("zombie.spawn_reinforcements");
+    List of 1.21.1 Attributes by name...
+        GENERIC_MAX_HEALTH("generic.max_health"),
+        GENERIC_FOLLOW_RANGE("generic.follow_range"),
+        GENERIC_KNOCKBACK_RESISTANCE("generic.knockback_resistance"),
+        GENERIC_MOVEMENT_SPEED("generic.movement_speed"),
+        GENERIC_FLYING_SPEED("generic.flying_speed"),
+        GENERIC_ATTACK_DAMAGE("generic.attack_damage"),
+        GENERIC_ATTACK_KNOCKBACK("generic.attack_knockback"),
+        GENERIC_ATTACK_SPEED("generic.attack_speed"),
+        GENERIC_ARMOR("generic.armor"),
+        GENERIC_ARMOR_TOUGHNESS("generic.armor_toughness"),
+        GENERIC_FALL_DAMAGE_MULTIPLIER("generic.fall_damage_multiplier"),
+        GENERIC_LUCK("generic.luck"),
+        GENERIC_MAX_ABSORPTION("generic.max_absorption"),
+        GENERIC_SAFE_FALL_DISTANCE("generic.safe_fall_distance"),
+        GENERIC_SCALE("generic.scale"),
+        GENERIC_STEP_HEIGHT("generic.step_height"),
+        GENERIC_GRAVITY("generic.gravity"),
+        GENERIC_JUMP_STRENGTH("generic.jump_strength"),
+        GENERIC_EXPLOSION_KNOCKBACK_RESISTANCE("generic.explosion_knockback_resistance"),
+        GENERIC_MOVEMENT_EFFICIENCY("generic.movement_efficiency"),
+        GENERIC_OXYGEN_BONUS("generic.oxygen_bonus"),
+        GENERIC_WATER_MOVEMENT_EFFICIENCY("generic.water_movement_efficiency"),
+        PLAYER_BLOCK_INTERACTION_RANGE("player.block_interaction_range"),
+        PLAYER_ENTITY_INTERACTION_RANGE("player.entity_interaction_range"),
+        PLAYER_BLOCK_BREAK_SPEED("player.block_break_speed"),
+        PLAYER_MINING_EFFICIENCY("player.mining_efficiency"),
+        PLAYER_SNEAKING_SPEED("player.sneaking_speed"),
+        PLAYER_SUBMERGED_MINING_SPEED("player.submerged_mining_speed"),
+        PLAYER_SWEEPING_DAMAGE_RATIO("player.sweeping_damage_ratio"),
+        ZOMBIE_SPAWN_REINFORCEMENTS("zombie.spawn_reinforcements");
+    List of 1.21.3 Attributes...
+        Attribute MAX_HEALTH = getAttribute("max_health");
+        Attribute FOLLOW_RANGE = getAttribute("follow_range");
+        Attribute KNOCKBACK_RESISTANCE = getAttribute("knockback_resistance");
+        Attribute MOVEMENT_SPEED = getAttribute("movement_speed");
+        Attribute FLYING_SPEED = getAttribute("flying_speed");
+        Attribute ATTACK_DAMAGE = getAttribute("attack_damage");
+        Attribute ATTACK_KNOCKBACK = getAttribute("attack_knockback");
+        Attribute ATTACK_SPEED = getAttribute("attack_speed");
+        Attribute ARMOR = getAttribute("armor");
+        Attribute ARMOR_TOUGHNESS = getAttribute("armor_toughness");
+        Attribute FALL_DAMAGE_MULTIPLIER = getAttribute("fall_damage_multiplier");
+        Attribute LUCK = getAttribute("luck");
+        Attribute MAX_ABSORPTION = getAttribute("max_absorption");
+        Attribute SAFE_FALL_DISTANCE = getAttribute("safe_fall_distance");
+        Attribute SCALE = getAttribute("scale");
+        Attribute STEP_HEIGHT = getAttribute("step_height");
+        Attribute GRAVITY = getAttribute("gravity");
+        Attribute JUMP_STRENGTH = getAttribute("jump_strength");
+        Attribute BURNING_TIME = getAttribute("burning_time");
+        Attribute EXPLOSION_KNOCKBACK_RESISTANCE = getAttribute("explosion_knockback_resistance");
+        Attribute MOVEMENT_EFFICIENCY = getAttribute("movement_efficiency");
+        Attribute OXYGEN_BONUS = getAttribute("oxygen_bonus");
+        Attribute WATER_MOVEMENT_EFFICIENCY = getAttribute("water_movement_efficiency");
+        Attribute TEMPT_RANGE = getAttribute("tempt_range");
+        Attribute BLOCK_INTERACTION_RANGE = getAttribute("block_interaction_range");
+        Attribute ENTITY_INTERACTION_RANGE = getAttribute("entity_interaction_range");
+        Attribute BLOCK_BREAK_SPEED = getAttribute("block_break_speed");
+        Attribute MINING_EFFICIENCY = getAttribute("mining_efficiency");
+        Attribute SNEAKING_SPEED = getAttribute("sneaking_speed");
+        Attribute SUBMERGED_MINING_SPEED = getAttribute("submerged_mining_speed");
+        Attribute SWEEPING_DAMAGE_RATIO = getAttribute("sweeping_damage_ratio");
+        Attribute SPAWN_REINFORCEMENTS = getAttribute("spawn_reinforcements");
+    */
 }

+ 22 - 9
src/main/java/com/gmail/nossr50/util/adapter/BiomeAdapter.java

@@ -7,26 +7,39 @@ import java.util.*;
 public class BiomeAdapter {
     public static final Set<Biome> WATER_BIOMES;
     public static final Set<Biome> ICE_BIOMES;
-    
+
     static {
-        List<Biome> allBiomes = Arrays.asList(Biome.values());
-        List<Biome> waterBiomes = new ArrayList<>();
-        List<Biome> iceBiomes = new ArrayList<>();
+        final List<Biome> allBiomes = getAllBiomes();
+        final Set<Biome> waterBiomes = new HashSet<>();
+        final Set<Biome> iceBiomes = new HashSet<>();
         for (Biome biome : allBiomes) {
-            if (isWater(biome.name()) && !isCold(biome.name())) {
+            String biomeName = getBiomeName(biome);
+            if (isWater(biomeName) && !isCold(biomeName)) {
                 waterBiomes.add(biome);
-            } else if (isCold(biome.name())) {
+            } else if (isCold(biomeName)) {
                 iceBiomes.add(biome);
             }
         }
-        WATER_BIOMES = EnumSet.copyOf(waterBiomes);
-        ICE_BIOMES = EnumSet.copyOf(iceBiomes);
+        WATER_BIOMES = Collections.unmodifiableSet(waterBiomes);
+        ICE_BIOMES = Collections.unmodifiableSet(iceBiomes);
+    }
+
+    @SuppressWarnings("deprecation")
+    private static List<Biome> getAllBiomes() {
+        return Arrays.asList(Biome.values());
+    }
+
+    @SuppressWarnings("deprecation")
+    private static String getBiomeName(Biome biome) {
+        return biome.name();
     }
 
     private static boolean isWater(String name) {
         return name.contains("RIVER") || name.contains("OCEAN");
     }
+
     private static boolean isCold(String name) {
-        return (name.contains("COLD") || name.contains("ICE") || name.contains("FROZEN") || name.contains("TAIGA")) && !(name.contains("WARM"));
+        return (name.contains("COLD") || name.contains("ICE")
+                || name.contains("FROZEN") || name.contains("TAIGA")) && !name.contains("WARM");
     }
 }

+ 2 - 1
src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java

@@ -39,6 +39,7 @@ import org.jetbrains.annotations.Nullable;
 import java.util.List;
 
 import static com.gmail.nossr50.datatypes.experience.XPGainReason.PVP;
+import static com.gmail.nossr50.util.AttributeMapper.MAPPED_MOVEMENT_SPEED;
 import static com.gmail.nossr50.util.MobMetadataUtils.hasMobFlag;
 
 public final class CombatUtils {
@@ -1071,7 +1072,7 @@ public final class CombatUtils {
     }
 
     public static void modifyMoveSpeed(@NotNull LivingEntity livingEntity, double multiplier) {
-        AttributeInstance attributeInstance = livingEntity.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
+        AttributeInstance attributeInstance = livingEntity.getAttribute(MAPPED_MOVEMENT_SPEED);
 
         if (attributeInstance != null) {
             double normalSpeed = attributeInstance.getBaseValue();