2013-07-28 02:02:27 +02:00
|
|
|
package com.comphenix.protocol.wrappers;
|
|
|
|
|
|
|
|
import java.lang.reflect.Constructor;
|
2020-06-28 21:59:30 +02:00
|
|
|
import java.util.*;
|
2013-07-28 02:02:27 +02:00
|
|
|
import javax.annotation.Nonnull;
|
2021-06-20 18:08:47 +02:00
|
|
|
import javax.annotation.Nullable;
|
2013-07-28 02:02:27 +02:00
|
|
|
|
2013-12-05 06:52:20 +01:00
|
|
|
import com.comphenix.protocol.PacketType;
|
2013-07-28 02:02:27 +02:00
|
|
|
import com.comphenix.protocol.events.PacketContainer;
|
|
|
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
|
|
|
import com.comphenix.protocol.reflect.StructureModifier;
|
|
|
|
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
|
|
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
2020-06-28 21:59:30 +02:00
|
|
|
import com.comphenix.protocol.utility.MinecraftVersion;
|
2013-07-28 02:02:27 +02:00
|
|
|
import com.comphenix.protocol.wrappers.collection.CachedSet;
|
|
|
|
import com.comphenix.protocol.wrappers.collection.ConvertedSet;
|
|
|
|
import com.google.common.base.Objects;
|
|
|
|
import com.google.common.base.Preconditions;
|
2020-06-28 21:59:30 +02:00
|
|
|
import com.google.common.collect.ImmutableMap;
|
2013-07-28 02:02:27 +02:00
|
|
|
import com.google.common.collect.Sets;
|
|
|
|
|
2020-06-28 21:59:30 +02:00
|
|
|
|
2013-07-28 02:02:27 +02:00
|
|
|
/**
|
|
|
|
* Represents a single attribute sent in packet 44.
|
|
|
|
* @author Kristian
|
|
|
|
*/
|
2013-12-09 13:46:41 +01:00
|
|
|
public class WrappedAttribute extends AbstractWrapper {
|
2020-06-28 21:59:30 +02:00
|
|
|
public static boolean KEY_WRAPPED = MinecraftVersion.NETHER_UPDATE.atOrAbove();
|
|
|
|
|
2013-07-28 02:02:27 +02:00
|
|
|
// Shared structure modifier
|
|
|
|
private static StructureModifier<Object> ATTRIBUTE_MODIFIER;
|
|
|
|
|
|
|
|
// The one constructor
|
|
|
|
private static Constructor<?> ATTRIBUTE_CONSTRUCTOR;
|
2020-06-28 21:59:30 +02:00
|
|
|
|
|
|
|
private static final Map<String, String> REMAP;
|
|
|
|
|
|
|
|
static {
|
|
|
|
Map<String, String> remap = new HashMap<>();
|
|
|
|
remap.put("generic.maxHealth", "generic.max_health");
|
|
|
|
remap.put("generic.followRange", "generic.follow_range");
|
|
|
|
remap.put("generic.knockbackResistance", "generic.knockback_resistance");
|
|
|
|
remap.put("generic.movementSpeed", "generic.movement_speed");
|
|
|
|
remap.put("generic.attackDamage", "generic.attack_damage");
|
|
|
|
remap.put("generic.attackSpeed", "generic.attack_speed");
|
|
|
|
remap.put("generic.armorToughness", "generic.armor_toughness");
|
|
|
|
remap.put("generic.attackKnockback", "generic.attack_knockback");
|
|
|
|
remap.put("horse.jumpStrength", "horse.jump_strength");
|
|
|
|
remap.put("zombie.spawnReinforcements", "zombie.spawn_reinforcements");
|
|
|
|
REMAP = ImmutableMap.copyOf(remap);
|
|
|
|
}
|
2013-07-28 02:02:27 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reference to the underlying attribute snapshot.
|
|
|
|
*/
|
|
|
|
protected Object handle;
|
|
|
|
protected StructureModifier<Object> modifier;
|
|
|
|
|
|
|
|
// Cached computed value
|
|
|
|
private double computedValue = Double.NaN;
|
|
|
|
|
|
|
|
// Cached modifiers list
|
|
|
|
private Set<WrappedAttributeModifier> attributeModifiers;
|
|
|
|
|
2013-12-09 13:46:41 +01:00
|
|
|
/**
|
|
|
|
* Construct a wrapper around a specific NMS instance.
|
|
|
|
* @param handle - the NMS instance.
|
|
|
|
*/
|
|
|
|
private WrappedAttribute(@Nonnull Object handle) {
|
|
|
|
super(MinecraftReflection.getAttributeSnapshotClass());
|
|
|
|
setHandle(handle);
|
|
|
|
|
|
|
|
// Initialize modifier
|
|
|
|
if (ATTRIBUTE_MODIFIER == null) {
|
2021-06-20 18:08:47 +02:00
|
|
|
ATTRIBUTE_MODIFIER = new StructureModifier<>(MinecraftReflection.getAttributeSnapshotClass());
|
2013-12-09 13:46:41 +01:00
|
|
|
}
|
|
|
|
this.modifier = ATTRIBUTE_MODIFIER.withTarget(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-28 02:02:27 +02:00
|
|
|
/**
|
|
|
|
* Construct a new wrapped attribute around a specific NMS instance.
|
|
|
|
* @param handle - handle to a NMS AttributeSnapshot.
|
|
|
|
* @return The attribute wrapper.
|
|
|
|
* @throws IllegalArgumentException If the handle is not a AttributeSnapshot.
|
|
|
|
*/
|
|
|
|
public static WrappedAttribute fromHandle(@Nonnull Object handle) {
|
|
|
|
return new WrappedAttribute(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct a new wrapped attribute builder.
|
|
|
|
* @return The new builder.
|
|
|
|
*/
|
|
|
|
public static Builder newBuilder() {
|
|
|
|
return new Builder(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct a new wrapped attribute builder initialized to the values from a template.
|
|
|
|
* @param template - the attribute template.
|
|
|
|
* @return The new builder.
|
|
|
|
*/
|
|
|
|
public static Builder newBuilder(@Nonnull WrappedAttribute template) {
|
|
|
|
return new Builder(Preconditions.checkNotNull(template, "template cannot be NULL."));
|
|
|
|
}
|
2020-06-28 21:59:30 +02:00
|
|
|
|
|
|
|
public static class WrappedAttributeBase {
|
|
|
|
public double defaultValue;
|
|
|
|
public boolean unknown;
|
|
|
|
public String key;
|
|
|
|
}
|
|
|
|
|
2021-06-13 17:36:44 +02:00
|
|
|
private static final Class<?> ATTRIBUTE_BASE_CLASS = MinecraftReflection.getNullableNMS(
|
2022-08-24 02:44:48 +02:00
|
|
|
"world.entity.ai.attributes.AttributeBase", "world.entity.ai.attributes.Attribute", "AttributeBase"
|
2021-06-13 17:36:44 +02:00
|
|
|
);
|
2020-06-28 21:59:30 +02:00
|
|
|
|
|
|
|
private static final AutoWrapper<WrappedAttributeBase> ATTRIBUTE_BASE = AutoWrapper.wrap(
|
|
|
|
WrappedAttributeBase.class, ATTRIBUTE_BASE_CLASS
|
|
|
|
);
|
|
|
|
|
2013-07-28 02:02:27 +02:00
|
|
|
/**
|
|
|
|
* Retrieve the unique attribute key that identifies its function.
|
|
|
|
* <p>
|
|
|
|
* Example: "generic.maxHealth"
|
|
|
|
* @return The attribute key.
|
|
|
|
*/
|
|
|
|
public String getAttributeKey() {
|
2020-06-28 21:59:30 +02:00
|
|
|
if (KEY_WRAPPED) {
|
|
|
|
WrappedAttributeBase base = modifier.withType(ATTRIBUTE_BASE_CLASS, ATTRIBUTE_BASE).read(0);
|
|
|
|
return base.key.replace("attribute.name.", ""); // TODO not entirely sure why this happens
|
|
|
|
} else {
|
|
|
|
return (String) modifier.withType(String.class).read(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the attribute base instance. New in 1.16.
|
|
|
|
*
|
|
|
|
* @return The attribute base
|
|
|
|
*/
|
|
|
|
public WrappedAttributeBase getBase() {
|
|
|
|
return modifier.withType(WrappedAttributeBase.class, ATTRIBUTE_BASE).readSafely(0);
|
2013-07-28 02:02:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the base value of this attribute, before any of the modifiers have been taken into account.
|
|
|
|
* @return The base value.
|
|
|
|
*/
|
|
|
|
public double getBaseValue() {
|
|
|
|
return (Double) modifier.withType(double.class).read(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the final computed value.
|
|
|
|
* @return The final value.
|
|
|
|
*/
|
|
|
|
public double getFinalValue() {
|
|
|
|
if (Double.isNaN(computedValue)) {
|
|
|
|
computedValue = computeValue();
|
|
|
|
}
|
|
|
|
return computedValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the parent update attributes packet.
|
|
|
|
* @return The parent packet.
|
2021-06-20 18:08:47 +02:00
|
|
|
* @deprecated Removed in 1.17
|
2013-07-28 02:02:27 +02:00
|
|
|
*/
|
2021-06-20 18:08:47 +02:00
|
|
|
@Nullable
|
2023-04-15 23:09:15 +02:00
|
|
|
@Deprecated
|
2013-07-28 02:02:27 +02:00
|
|
|
public PacketContainer getParentPacket() {
|
2021-06-20 18:08:47 +02:00
|
|
|
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-07-28 02:02:27 +02:00
|
|
|
return new PacketContainer(
|
2015-06-17 21:08:58 +02:00
|
|
|
PacketType.Play.Server.UPDATE_ATTRIBUTES,
|
2013-07-28 02:02:27 +02:00
|
|
|
modifier.withType(MinecraftReflection.getPacketClass()).read(0)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determine if the attribute has a given attribute modifier, identified by UUID.
|
2015-06-17 21:08:58 +02:00
|
|
|
* @param id - the id to check for.
|
2013-07-28 02:02:27 +02:00
|
|
|
* @return TRUE if it does, FALSE otherwise.
|
|
|
|
*/
|
|
|
|
public boolean hasModifier(UUID id) {
|
|
|
|
return getModifiers().contains(WrappedAttributeModifier.newBuilder(id).build());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve an attribute modifier by UUID.
|
|
|
|
* @param id - the id to look for.
|
|
|
|
* @return The single attribute modifier with the given ID.
|
|
|
|
*/
|
|
|
|
public WrappedAttributeModifier getModifierByUUID(UUID id) {
|
|
|
|
if (hasModifier(id)) {
|
|
|
|
for (WrappedAttributeModifier modifier : getModifiers()) {
|
|
|
|
if (Objects.equal(modifier.getUUID(), id)) {
|
|
|
|
return modifier;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve an immutable set of all the attribute modifiers that will compute the final value of this attribute.
|
|
|
|
* @return Every attribute modifier.
|
|
|
|
*/
|
2015-06-17 21:08:58 +02:00
|
|
|
public Set<WrappedAttributeModifier> getModifiers() {
|
2013-07-28 02:02:27 +02:00
|
|
|
if (attributeModifiers == null) {
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
Collection<Object> collection = (Collection<Object>) modifier.withType(Collection.class).read(0);
|
|
|
|
|
|
|
|
// Convert to an equivalent wrapper
|
2015-06-17 21:08:58 +02:00
|
|
|
ConvertedSet<Object, WrappedAttributeModifier> converted =
|
2013-07-28 02:02:27 +02:00
|
|
|
new ConvertedSet<Object, WrappedAttributeModifier>(getSetSafely(collection)) {
|
|
|
|
@Override
|
|
|
|
protected Object toInner(WrappedAttributeModifier outer) {
|
|
|
|
return outer.getHandle();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected WrappedAttributeModifier toOuter(Object inner) {
|
|
|
|
return WrappedAttributeModifier.fromHandle(inner);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-06-20 18:08:47 +02:00
|
|
|
attributeModifiers = new CachedSet<>(converted);
|
2013-07-28 02:02:27 +02:00
|
|
|
}
|
|
|
|
return Collections.unmodifiableSet(attributeModifiers);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct an attribute with the same key and name, but a different list of modifiers.
|
|
|
|
* @param modifiers - attribute modifiers.
|
|
|
|
* @return The new attribute.
|
|
|
|
*/
|
|
|
|
public WrappedAttribute withModifiers(Collection<WrappedAttributeModifier> modifiers) {
|
|
|
|
return newBuilder(this).modifiers(modifiers).build();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object obj) {
|
|
|
|
if (this == obj)
|
|
|
|
return true;
|
|
|
|
if (obj instanceof WrappedAttribute) {
|
|
|
|
WrappedAttribute other = (WrappedAttribute) obj;
|
|
|
|
|
2017-05-14 20:28:56 +02:00
|
|
|
if (getBaseValue() == other.getBaseValue() &&
|
|
|
|
Objects.equal(getAttributeKey(), other.getAttributeKey())) {
|
2021-06-20 18:08:47 +02:00
|
|
|
return other.getModifiers().containsAll(getModifiers());
|
2017-05-14 20:28:56 +02:00
|
|
|
}
|
2013-07-28 02:02:27 +02:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2017-05-14 20:28:56 +02:00
|
|
|
|
2013-07-28 02:02:27 +02:00
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
if (attributeModifiers == null)
|
|
|
|
getModifiers();
|
|
|
|
return Objects.hashCode(getAttributeKey(), getBaseValue(), attributeModifiers);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compute the final value from the current attribute modifers.
|
|
|
|
* @return The final value.
|
|
|
|
*/
|
|
|
|
private double computeValue() {
|
|
|
|
Collection<WrappedAttributeModifier> modifiers = getModifiers();
|
|
|
|
double x = getBaseValue();
|
|
|
|
double y = 0;
|
|
|
|
|
|
|
|
// Compute each phase
|
|
|
|
for (int phase = 0; phase < 3; phase++) {
|
|
|
|
for (WrappedAttributeModifier modifier : modifiers) {
|
|
|
|
if (modifier.getOperation().getId() == phase) {
|
|
|
|
switch (phase) {
|
|
|
|
case 0: // Adding phase
|
|
|
|
x += modifier.getAmount();
|
|
|
|
break;
|
|
|
|
case 1: // Multiply percentage
|
2015-06-17 21:08:58 +02:00
|
|
|
y += x * modifier.getAmount();
|
2013-07-28 02:02:27 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
y *= 1 + modifier.getAmount();
|
|
|
|
break;
|
|
|
|
default :
|
|
|
|
throw new IllegalStateException("Unknown phase: " + phase);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The additive phase is finished
|
|
|
|
if (phase == 0) {
|
|
|
|
y = x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return y;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
2017-05-14 20:28:56 +02:00
|
|
|
return "WrappedAttribute[key=" + getAttributeKey() + ", base=" + getBaseValue() + ", final=" + getFinalValue() + ", modifiers=" + getModifiers() + "]";
|
2013-07-28 02:02:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If the collection is a set, retrieve it - otherwise, create a new set with the same elements.
|
|
|
|
* @param collection - the collection.
|
|
|
|
* @return A set with the same elements.
|
|
|
|
*/
|
|
|
|
private static <U> Set<U> getSetSafely(Collection<U> collection) {
|
|
|
|
return collection instanceof Set ? (Set<U>) collection : Sets.newHashSet(collection);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ensure that the given double is not infinite nor NaN.
|
|
|
|
* @param value - the value to check.
|
|
|
|
*/
|
|
|
|
static double checkDouble(double value) {
|
|
|
|
if (Double.isInfinite(value))
|
|
|
|
throw new IllegalArgumentException("value cannot be infinite.");
|
|
|
|
if (Double.isNaN(value))
|
|
|
|
throw new IllegalArgumentException("value cannot be NaN.");
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-06-17 21:08:58 +02:00
|
|
|
* Represents a builder for wrapped attributes.
|
2013-07-28 02:02:27 +02:00
|
|
|
* <p>
|
|
|
|
* Use {@link WrappedAttribute#newBuilder()} to construct it.
|
|
|
|
* @author Kristian
|
|
|
|
*/
|
|
|
|
public static class Builder {
|
|
|
|
private double baseValue = Double.NaN;
|
|
|
|
private String attributeKey;
|
|
|
|
private PacketContainer packet;
|
|
|
|
private Collection<WrappedAttributeModifier> modifiers = Collections.emptyList();
|
|
|
|
|
|
|
|
private Builder(WrappedAttribute template) {
|
|
|
|
if (template != null) {
|
|
|
|
baseValue = template.getBaseValue();
|
|
|
|
attributeKey = template.getAttributeKey();
|
|
|
|
packet = template.getParentPacket();
|
|
|
|
modifiers = template.getModifiers();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change the base value of the attribute.
|
|
|
|
* <p>
|
|
|
|
* The modifiers will automatically supply a value if this is unset.
|
2013-10-05 21:42:19 +02:00
|
|
|
* @param baseValue - the base value value.
|
2013-07-28 02:02:27 +02:00
|
|
|
* @return This builder, for chaining.
|
|
|
|
*/
|
|
|
|
public Builder baseValue(double baseValue) {
|
|
|
|
this.baseValue = checkDouble(baseValue);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the unique attribute key that identifies its function.
|
|
|
|
* <p>
|
|
|
|
* This is required.
|
|
|
|
* @param attributeKey - the unique attribute key.
|
|
|
|
* @return This builder, for chaining.
|
|
|
|
*/
|
|
|
|
public Builder attributeKey(String attributeKey) {
|
|
|
|
this.attributeKey = Preconditions.checkNotNull(attributeKey, "attributeKey cannot be NULL.");
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the modifers that will be supplied to the client, and used to compute the final value.
|
|
|
|
* @param modifiers - the attribute modifiers.
|
|
|
|
* @return This builder, for chaining.
|
|
|
|
*/
|
|
|
|
public Builder modifiers(Collection<WrappedAttributeModifier> modifiers) {
|
|
|
|
this.modifiers = Preconditions.checkNotNull(modifiers, "modifiers cannot be NULL - use an empty list instead.");
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the parent update attributes packet (44).
|
|
|
|
* @param packet - the parent packet.
|
|
|
|
* @return This builder, for chaining.
|
|
|
|
*/
|
|
|
|
public Builder packet(PacketContainer packet) {
|
2013-12-05 06:52:20 +01:00
|
|
|
if (Preconditions.checkNotNull(packet, "packet cannot be NULL").getType() != PacketType.Play.Server.UPDATE_ATTRIBUTES) {
|
2013-07-28 02:02:27 +02:00
|
|
|
throw new IllegalArgumentException("Packet must be UPDATE_ATTRIBUTES (44)");
|
|
|
|
}
|
|
|
|
this.packet = packet;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the unwrapped modifiers.
|
|
|
|
* @return Unwrapped modifiers.
|
|
|
|
*/
|
|
|
|
private Set<Object> getUnwrappedModifiers() {
|
2022-05-26 05:30:08 +02:00
|
|
|
final Set<Object> output = new HashSet<>();
|
2013-07-28 02:02:27 +02:00
|
|
|
|
|
|
|
for (WrappedAttributeModifier modifier : modifiers) {
|
|
|
|
output.add(modifier.getHandle());
|
|
|
|
}
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a new wrapped attribute with the values of this builder.
|
|
|
|
* @return The wrapped attribute.
|
|
|
|
* @throws RuntimeException If anything went wrong with the reflection.
|
|
|
|
*/
|
|
|
|
public WrappedAttribute build() {
|
|
|
|
Preconditions.checkNotNull(attributeKey, "attributeKey cannot be NULL.");
|
|
|
|
|
|
|
|
// Remember to set the base value
|
|
|
|
if (Double.isNaN(baseValue)) {
|
|
|
|
throw new IllegalStateException("Base value has not been set.");
|
|
|
|
}
|
2021-06-13 17:36:44 +02:00
|
|
|
|
|
|
|
boolean isStatic = MinecraftVersion.CAVES_CLIFFS_1.atOrAbove();
|
|
|
|
|
2013-07-28 02:02:27 +02:00
|
|
|
if (ATTRIBUTE_CONSTRUCTOR == null) {
|
2021-06-13 17:36:44 +02:00
|
|
|
FuzzyReflection ref = FuzzyReflection.fromClass(MinecraftReflection.getAttributeSnapshotClass(), true);
|
|
|
|
FuzzyMethodContract.Builder contract = FuzzyMethodContract.newBuilder().parameterCount(isStatic ? 3 : 4);
|
|
|
|
if (!isStatic) {
|
|
|
|
contract.parameterDerivedOf(MinecraftReflection.getPacketClass(), 0);
|
|
|
|
}
|
|
|
|
contract.parameterExactType(double.class).parameterDerivedOf(Collection.class);
|
|
|
|
ATTRIBUTE_CONSTRUCTOR = ref.getConstructor(contract.build());
|
|
|
|
|
2013-07-28 02:02:27 +02:00
|
|
|
// Just in case
|
|
|
|
ATTRIBUTE_CONSTRUCTOR.setAccessible(true);
|
|
|
|
}
|
|
|
|
|
2020-06-28 21:59:30 +02:00
|
|
|
Object attributeKey;
|
|
|
|
if (KEY_WRAPPED) {
|
2021-06-13 21:57:23 +02:00
|
|
|
WrappedRegistry registry = WrappedRegistry.getAttributeRegistry();
|
2020-06-28 21:59:30 +02:00
|
|
|
String strKey = REMAP.getOrDefault(this.attributeKey, this.attributeKey);
|
2021-06-13 21:57:23 +02:00
|
|
|
attributeKey = registry.get(strKey);
|
2020-06-28 21:59:30 +02:00
|
|
|
|
|
|
|
if (attributeKey == null) {
|
|
|
|
throw new IllegalArgumentException("Invalid attribute name: " + this.attributeKey);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
attributeKey = this.attributeKey;
|
|
|
|
}
|
|
|
|
|
2013-07-28 02:02:27 +02:00
|
|
|
try {
|
2021-06-13 17:36:44 +02:00
|
|
|
Object handle;
|
|
|
|
if (isStatic) {
|
|
|
|
handle = ATTRIBUTE_CONSTRUCTOR.newInstance(attributeKey, baseValue, getUnwrappedModifiers());
|
|
|
|
} else {
|
|
|
|
handle = ATTRIBUTE_CONSTRUCTOR.newInstance(packet.getHandle(), attributeKey, baseValue, getUnwrappedModifiers());
|
|
|
|
}
|
2013-07-28 02:02:27 +02:00
|
|
|
|
|
|
|
return new WrappedAttribute(handle);
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw new RuntimeException("Cannot construct AttributeSnapshot.", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|