|
@@ -4,42 +4,194 @@ import com.gmail.nossr50.mcMMO;
|
|
import org.bukkit.Registry;
|
|
import org.bukkit.Registry;
|
|
import org.bukkit.attribute.Attribute;
|
|
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 {
|
|
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");
|
|
|
|
+ */
|
|
}
|
|
}
|