9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-25 18:09:27 +00:00

添加attribute-modifiers

This commit is contained in:
XiaoMoMi
2025-07-06 05:21:25 +08:00
parent ace2ff8259
commit d165d83d9b
34 changed files with 474 additions and 36 deletions

View File

@@ -72,8 +72,18 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
return getComponentInternal(type, MRegistryOps.NBT);
}
@SuppressWarnings({"rawtypes", "unchecked"})
public Optional<Tag> getSparrowNBTComponent(Object type) {
return getComponentInternal(type, MRegistryOps.SPARROW_NBT);
Object componentType = ensureDataComponentType(type);
Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType);
try {
Object componentData = FastNMS.INSTANCE.method$ItemStack$getComponent(getLiteralObject(), componentType);
if (componentData == null) return Optional.empty();
DataResult<Tag> result = codec.encodeStart(MRegistryOps.SPARROW_NBT, componentData);
return result.result().map(Tag::copy);
} catch (Throwable t) {
throw new RuntimeException("Cannot read component " + type.toString(), t);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})

View File

@@ -29,7 +29,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
@Override
public Optional<Item<ItemStack>> c2s(Item<ItemStack> wrapped) {
Tag customData = wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA);
Tag customData = wrapped.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA);
if (!(customData instanceof CompoundTag compoundTag)) return Optional.empty();
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
boolean hasDifferentMaterial = false;
@@ -75,7 +75,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
if (!Config.interceptItem() && !hasDifferentMaterial) return Optional.empty();
return new OtherItem(wrapped, hasDifferentMaterial).process();
} else {
CompoundTag customData = Optional.ofNullable(wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag());
CompoundTag customData = Optional.ofNullable(wrapped.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag());
CompoundTag arguments = customData.getCompound(ArgumentModifier.ARGUMENTS_TAG);
ItemBuildContext context;
if (arguments == null) {
@@ -176,7 +176,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
}
public static boolean processModernItemName(Item<ItemStack> item, Supplier<CompoundTag> tag) {
Tag nameTag = item.getNBTComponent(ComponentTypes.ITEM_NAME);
Tag nameTag = item.getSparrowNBTComponent(ComponentTypes.ITEM_NAME);
if (nameTag == null) return false;
String tagStr = nameTag.getAsString();
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(tagStr);
@@ -189,7 +189,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
}
public static boolean processModernCustomName(Item<ItemStack> item, Supplier<CompoundTag> tag) {
Tag nameTag = item.getNBTComponent(ComponentTypes.CUSTOM_NAME);
Tag nameTag = item.getSparrowNBTComponent(ComponentTypes.CUSTOM_NAME);
if (nameTag == null) return false;
String tagStr = nameTag.getAsString();
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(tagStr);
@@ -202,7 +202,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
}
public static boolean processModernLore(Item<ItemStack> item, Supplier<CompoundTag> tagSupplier) {
Tag loreTag = item.getNBTComponent(ComponentTypes.LORE);
Tag loreTag = item.getSparrowNBTComponent(ComponentTypes.LORE);
boolean changed = false;
if (!(loreTag instanceof ListTag listTag)) {
return false;
@@ -254,7 +254,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
this.globalChanged = true;
}
if (this.globalChanged) {
CompoundTag customData = Optional.ofNullable(this.item.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag());
CompoundTag customData = Optional.ofNullable(this.item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag());
customData.put(NETWORK_ITEM_TAG, getOrCreateTag());
this.item.setNBTComponent(ComponentKeys.CUSTOM_DATA, customData);
return Optional.of(this.item);

View File

@@ -111,7 +111,12 @@ public abstract class BukkitItemFactory<W extends ItemWrapper<ItemStack>> extend
}
@Override
protected Tag getNBTComponent(W item, Object type) {
public Object getNBTComponent(W item, Object type) {
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");
}
@Override
protected Tag getSparrowNBTComponent(W item, Object type) {
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");
}

View File

@@ -227,7 +227,12 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
}
@Override
protected Tag getNBTComponent(ComponentItemWrapper item, Object type) {
public Object getNBTComponent(ComponentItemWrapper item, Object type) {
return item.getNBTComponent(type).orElse(null);
}
@Override
protected Tag getSparrowNBTComponent(ComponentItemWrapper item, Object type) {
return item.getSparrowNBTComponent(type).orElse(null);
}

View File

@@ -12,10 +12,8 @@ import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import org.bukkit.inventory.ItemStack;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public class CommonItemPacketHandler implements EntityPacketHandler {
public static final CommonItemPacketHandler INSTANCE = new CommonItemPacketHandler();

View File

@@ -160,6 +160,11 @@ warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>Issue
warning.config.item.settings.equipment.missing_asset_id: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'asset-id' argument for 'equipment' settings.</yellow>"
warning.config.item.settings.equipment.invalid_asset_id: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an invalid 'asset-id' argument for 'equipment' settings. This might be because you haven't created this equipment configuration or misspelled the asset-id.</yellow>"
warning.config.item.settings.projectile.missing_item: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'item' argument for 'projectile' settings.</yellow>"
warning.config.item.data.attribute_modifiers.missing_type: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'type' argument for 'attribute-modifiers' data.</yellow>"
warning.config.item.data.attribute_modifiers.missing_amount: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'amount' argument for 'attribute-modifiers' data.</yellow>"
warning.config.item.data.attribute_modifiers.missing_operation: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'operation' argument for 'attribute-modifiers' data.</yellow>"
warning.config.item.data.attribute_modifiers.display.missing_type: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'type' argument for 'attribute-modifiers' display data.</yellow>"
warning.config.item.data.attribute_modifiers.display.missing_value: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'value' argument for 'attribute-modifiers' display data.</yellow>"
warning.config.item.missing_material: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'material' argument.</yellow>"
warning.config.item.invalid_material: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an invalid material type '<arg:2>'.</yellow>"
warning.config.item.invalid_custom_model_data: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using a negative custom model data '<arg:2>' which is invalid.</yellow>"

View File

@@ -160,6 +160,11 @@ warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>在文
warning.config.item.settings.equipment.missing_asset_id: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'equipment' 设置所需的 'asset-id' 参数.</yellow>"
warning.config.item.settings.equipment.invalid_asset_id: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 为 'equipment' 设置配置了无效的 'asset-id'. 这可能是因为你没有创建装备配置或是错误地拼写了 asset-id.</yellow>"
warning.config.item.settings.projectile.missing_item: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'projectile' 设置所需的 'item' 参数.</yellow>"
warning.config.item.data.attribute_modifiers.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 数据所需的 'type' 参数.</yellow>"
warning.config.item.data.attribute_modifiers.missing_amount: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 数据所需的 'amount' 参数.</yellow>"
warning.config.item.data.attribute_modifiers.missing_operation: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 数据所需的 'operation' 参数.</yellow>"
warning.config.item.data.attribute_modifiers.display.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 显示数据所需的 'type' 参数。</yellow>"
warning.config.item.data.attribute_modifiers.display.missing_value: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少 'attribute-modifiers' 显示数据所需的 'value' 参数。</yellow>"
warning.config.item.missing_material: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少必需的 'material' 参数</yellow>"
warning.config.item.invalid_material: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了无效的材料类型 '<arg:2>'</yellow>"
warning.config.item.invalid_custom_model_data: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了无效的负数模型值 '<arg:2>'.</yellow>"

View File

@@ -0,0 +1,81 @@
package net.momirealms.craftengine.core.attribute;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.Nullable;
public class AttributeModifier {
private final String type;
private final Slot slot;
private final Key id;
private final double amount;
private final Operation operation;
@Nullable
private final Display display;
public AttributeModifier(String type, Slot slot, Key id, double amount, Operation operation, @Nullable Display display) {
this.amount = amount;
this.display = display;
this.id = id;
this.operation = operation;
this.slot = slot;
this.type = type;
}
public double amount() {
return amount;
}
public @Nullable Display display() {
return display;
}
public Key id() {
return id;
}
public Operation operation() {
return operation;
}
public Slot slot() {
return slot;
}
public String type() {
return type;
}
public enum Slot {
ANY,
HAND,
ARMOR,
MAINHAND,
OFFHAND,
HEAD,
CHEST,
LEGS,
FEET,
BODY
}
public enum Operation {
ADD_VALUE("add_value"), ADD_MULTIPLIED_BASE("add_multiplied_base"), ADD_MULTIPLIED_TOTAL("add_multiplied_total");
private final String id;
Operation(String id) {
this.id = id;
}
public String id() {
return id;
}
}
public record Display(AttributeModifier.Display.Type type, String value) {
public enum Type {
DEFAULT, HIDDEN, OVERRIDE
}
}
}

View File

@@ -0,0 +1,43 @@
package net.momirealms.craftengine.core.attribute;
import net.momirealms.craftengine.core.util.Key;
public final class Attributes {
private Attributes() {}
// latest version
public static final Key ARMOR = Key.from("armor");
public static final Key ARMOR_TOUGHNESS = Key.from("armor_toughness");
public static final Key ATTACK_DAMAGE = Key.from("attack_damage");
public static final Key ATTACK_KNOCKBACK = Key.from("attack_knockback");
public static final Key ATTACK_SPEED = Key.from("attack_speed");
public static final Key BLOCK_BREAK_SPEED = Key.from("block_break_speed");
public static final Key BLOCK_INTERACTION_RANGE = Key.from("block_interaction_range");
public static final Key BURNING_TIME = Key.from("burning_time");
public static final Key CAMERA_DISTANCE = Key.from("camera_distance");
public static final Key ENTITY_INTERACTION_RANGE = Key.from("entity_interaction_range");
public static final Key EXPLOSION_KNOCKBACK_RESISTANCE = Key.from("explosion_knockback_resistance");
public static final Key FALL_DAMAGE_MULTIPLIER = Key.from("fall_damage_multiplier");
public static final Key FLYING_SPEED = Key.from("flying_speed");
public static final Key FOLLOW_RANGE = Key.from("follow_range");
public static final Key GRAVITY = Key.from("gravity");
public static final Key JUMP_STRENGTH = Key.from("jump_strength");
public static final Key KNOCKBACK_RESISTANCE = Key.from("knockback_resistance");
public static final Key LUCK = Key.from("luck");
public static final Key MAX_ABSORPTION = Key.from("max_absorption");
public static final Key MAX_HEALTH = Key.from("max_health");
public static final Key MINING_EFFICIENCY = Key.from("mining_efficiency");
public static final Key MOVEMENT_EFFICIENCY = Key.from("movement_efficiency");
public static final Key MOVEMENT_SPEED = Key.from("movement_speed");
public static final Key OXYGEN_BONUS = Key.from("oxygen_bonus");
public static final Key SAFE_FALL_DISTANCE = Key.from("safe_fall_distance");
public static final Key SCALE = Key.from("scale");
public static final Key SPAWN_REINFORCEMENT = Key.from("spawn_reinforcements");
public static final Key SNEAKING_SPEED = Key.from("sneaking_speed");
public static final Key STEP_HEIGHT = Key.from("step_height");
public static final Key SUBMERGED_MINING_SPEED = Key.from("submerged_mining_speed");
public static final Key SWEEPING_DAMAGE_RATIO = Key.from("sweeping_damage_ratio");
public static final Key TEMPT_RANGE = Key.from("tempt_range");
public static final Key WATER_MOVEMENT_EFFICIENCY = Key.from("water_movement_efficiency");
public static final Key WAYPOINT_RECEIVE_RANGE = Key.from("waypoint_receive_range");
public static final Key WAYPOINT_TRANSMIT_RANGE = Key.from("waypoint_transmit_range");
}

View File

@@ -0,0 +1,37 @@
package net.momirealms.craftengine.core.attribute;
import net.momirealms.craftengine.core.util.Key;
public final class Attributes1_21 {
private Attributes1_21() {}
public static final Key ARMOR = Key.from("generic.armor");
public static final Key ARMOR_TOUGHNESS = Key.from("generic.armor_toughness");
public static final Key ATTACK_DAMAGE = Key.from("generic.attack_damage");
public static final Key ATTACK_KNOCKBACK = Key.from("generic.attack_knockback");
public static final Key ATTACK_SPEED = Key.from("generic.attack_speed");
public static final Key FLYING_SPEED = Key.from("generic.flying_speed");
public static final Key FOLLOW_RANGE = Key.from("generic.follow_range");
public static final Key KNOCKBACK_RESISTANCE = Key.from("generic.knockback_resistance");
public static final Key LUCK = Key.from("generic.luck");
public static final Key MAX_ABSORPTION = Key.from("generic.max_absorption");
public static final Key MAX_HEALTH = Key.from("generic.max_health");
public static final Key MOVEMENT_EFFICIENCY = Key.from("generic.movement_efficiency");
public static final Key SCALE = Key.from("generic.scale");
public static final Key STEP_HEIGHT = Key.from("generic.step_height");
public static final Key JUMP_STRENGTH = Key.from("generic.jump_strength");
public static final Key ENTITY_INTERACTION_RANGE = Key.from("player.entity_interaction_range");
public static final Key BLOCK_INTERACTION_RANGE = Key.from("player.block_interaction_range");
public static final Key SPAWN_REINFORCEMENT = Key.from("zombie.spawn_reinforcements");
public static final Key BLOCK_BREAK_SPEED = Key.from("player.block_break_speed");
public static final Key GRAVITY = Key.from("generic.gravity");
public static final Key SAFE_FALL_DISTANCE = Key.from("generic.safe_fall_distance");
public static final Key FALL_DAMAGE_MULTIPLIER = Key.from("generic.fall_damage_multiplier");
public static final Key BURNING_TIME = Key.from("generic.burning_time");
public static final Key EXPLOSION_KNOCKBACK_RESISTANCE = Key.from("generic.explosion_knockback_resistance");
public static final Key MINING_EFFICIENCY = Key.from("player.mining_efficiency");
public static final Key OXYGEN_BONUS = Key.from("generic.oxygen_bonus");
public static final Key SNEAKING_SPEED = Key.from("player.sneaking_speed");
public static final Key SUBMERGED_MINING_SPEED = Key.from("player.submerged_mining_speed");
public static final Key SWEEPING_DAMAGE_RATIO = Key.from("player.sweeping_damage_ratio");
public static final Key WATER_MOVEMENT_EFFICIENCY = Key.from("generic.water_movement_efficiency");
}

View File

@@ -366,7 +366,12 @@ public class AbstractItem<W extends ItemWrapper<I>, I> implements Item<I> {
}
@Override
public Tag getNBTComponent(Object type) {
public Tag getSparrowNBTComponent(Object type) {
return this.factory.getSparrowNBTComponent(this.item, type);
}
@Override
public Object getNBTComponent(Object type) {
return this.factory.getNBTComponent(this.item, type);
}

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.core.item;
import net.momirealms.craftengine.core.attribute.AttributeModifier;
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviors;
import net.momirealms.craftengine.core.item.data.Enchantment;
@@ -532,6 +533,38 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
return new TagsModifier<>(data);
}, "tags", "tag", "nbt");
}
registerDataType((object -> {
MutableInt mutableInt = new MutableInt(0);
List<AttributeModifier> attributeModifiers = ResourceConfigUtils.parseConfigAsList(object, (map) -> {
String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.item.data.attribute_modifiers.missing_type");
Key nativeType = AttributeModifiersModifier.getNativeAttributeName(Key.of(type));
AttributeModifier.Slot slot = AttributeModifier.Slot.valueOf(map.getOrDefault("slot", "any").toString().toUpperCase(Locale.ENGLISH));
Key id = Optional.ofNullable(map.get("id")).map(String::valueOf).map(Key::of).orElseGet(() -> {
mutableInt.add(1);
return Key.of("craftengine", "modifier_" + mutableInt.intValue());
});
double amount = ResourceConfigUtils.getAsDouble(
ResourceConfigUtils.requireNonNullOrThrow(map.get("amount"), "warning.config.item.data.attribute_modifiers.missing_amount"), "amount"
);
AttributeModifier.Operation operation = AttributeModifier.Operation.valueOf(
ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("operation"), "warning.config.item.data.attribute_modifiers.missing_operation").toUpperCase(Locale.ENGLISH)
);
AttributeModifier.Display display = null;
if (VersionHelper.isOrAbove1_21_6() && map.containsKey("display")) {
Map<String, Object> displayMap = MiscUtils.castToMap(map.get("display"), false);
AttributeModifier.Display.Type displayType = AttributeModifier.Display.Type.valueOf(ResourceConfigUtils.requireNonEmptyStringOrThrow(displayMap.get("type"), "warning.config.item.data.attribute_modifiers.display.missing_type").toUpperCase(Locale.ENGLISH));
if (displayType == AttributeModifier.Display.Type.OVERRIDE) {
String miniMessageValue = ResourceConfigUtils.requireNonEmptyStringOrThrow(displayMap.get("value"), "warning.config.item.data.attribute_modifiers.display.missing_value");
display = new AttributeModifier.Display(displayType, miniMessageValue);
} else {
display = new AttributeModifier.Display(displayType, null);
}
}
return new AttributeModifier(nativeType.value(), slot, id,
amount, operation, display);
});
return new AttributeModifiersModifier<>(attributeModifiers);
}), "attributes", "attribute-modifiers", "attribute-modifier");
registerDataType((obj) -> {
boolean value = TypeUtils.checkType(obj, Boolean.class);
return new UnbreakableModifier<>(value);

View File

@@ -154,7 +154,9 @@ public interface Item<I> {
JsonElement getJsonComponent(Object type);
Tag getNBTComponent(Object type);
Tag getSparrowNBTComponent(Object type);
Object getNBTComponent(Object type);
void setComponent(Object type, Object value);

View File

@@ -53,7 +53,9 @@ public abstract class ItemFactory<W extends ItemWrapper<I>, I> {
protected abstract JsonElement getJsonComponent(W item, Object type);
protected abstract Tag getNBTComponent(W item, Object type);
protected abstract Tag getSparrowNBTComponent(W item, Object type);
protected abstract Object getNBTComponent(W item, Object type);
protected abstract boolean hasComponent(W item, Object type);

View File

@@ -28,7 +28,7 @@ public class ArgumentModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> apply(Item<I> item, ItemBuildContext context) {
if (VersionHelper.isOrAbove1_20_5()) {
CompoundTag customData = (CompoundTag) Optional.ofNullable(item.getNBTComponent(ComponentKeys.CUSTOM_DATA)).orElse(new CompoundTag());
CompoundTag customData = (CompoundTag) Optional.ofNullable(item.getSparrowNBTComponent(ComponentKeys.CUSTOM_DATA)).orElse(new CompoundTag());
CompoundTag argumentTag = new CompoundTag();
for (Map.Entry<String, TextProvider> entry : this.arguments.entrySet()) {
argumentTag.put(entry.getKey(), new StringTag(entry.getValue().get(context)));

View File

@@ -0,0 +1,193 @@
package net.momirealms.craftengine.core.item.modifier;
import net.momirealms.craftengine.core.attribute.AttributeModifier;
import net.momirealms.craftengine.core.attribute.Attributes;
import net.momirealms.craftengine.core.attribute.Attributes1_21;
import net.momirealms.craftengine.core.item.ComponentKeys;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.NetworkItemHandler;
import net.momirealms.craftengine.core.util.AdventureHelper;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.UUIDUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.ListTag;
import net.momirealms.sparrow.nbt.Tag;
import java.nio.charset.StandardCharsets;
import java.util.*;
public class AttributeModifiersModifier<I> implements ItemDataModifier<I> {
public static final Map<Key, Key> CONVERTOR = new HashMap<>();
static {
if (VersionHelper.isOrAbove1_20_2()) {
CONVERTOR.put(Attributes1_21.BURNING_TIME, Attributes.BURNING_TIME);
CONVERTOR.put(Attributes1_21.ARMOR, Attributes.ARMOR);
CONVERTOR.put(Attributes1_21.ARMOR_TOUGHNESS, Attributes.ARMOR_TOUGHNESS);
CONVERTOR.put(Attributes1_21.ATTACK_KNOCKBACK, Attributes.ATTACK_KNOCKBACK);
CONVERTOR.put(Attributes1_21.ATTACK_DAMAGE, Attributes.ATTACK_DAMAGE);
CONVERTOR.put(Attributes1_21.ATTACK_SPEED, Attributes.ATTACK_SPEED);
CONVERTOR.put(Attributes1_21.FLYING_SPEED, Attributes.FLYING_SPEED);
CONVERTOR.put(Attributes1_21.FOLLOW_RANGE, Attributes.FOLLOW_RANGE);
CONVERTOR.put(Attributes1_21.KNOCKBACK_RESISTANCE, Attributes.KNOCKBACK_RESISTANCE);
CONVERTOR.put(Attributes1_21.LUCK, Attributes.LUCK);
CONVERTOR.put(Attributes1_21.MAX_ABSORPTION, Attributes.MAX_ABSORPTION);
CONVERTOR.put(Attributes1_21.MAX_HEALTH, Attributes.MAX_HEALTH);
CONVERTOR.put(Attributes1_21.MOVEMENT_EFFICIENCY, Attributes.MOVEMENT_EFFICIENCY);
CONVERTOR.put(Attributes1_21.SCALE, Attributes.SCALE);
CONVERTOR.put(Attributes1_21.STEP_HEIGHT, Attributes.STEP_HEIGHT);
CONVERTOR.put(Attributes1_21.JUMP_STRENGTH, Attributes.JUMP_STRENGTH);
CONVERTOR.put(Attributes1_21.ENTITY_INTERACTION_RANGE, Attributes.ENTITY_INTERACTION_RANGE);
CONVERTOR.put(Attributes1_21.BLOCK_INTERACTION_RANGE, Attributes.BLOCK_INTERACTION_RANGE);
CONVERTOR.put(Attributes1_21.SPAWN_REINFORCEMENT, Attributes.SPAWN_REINFORCEMENT);
CONVERTOR.put(Attributes1_21.BLOCK_BREAK_SPEED, Attributes.BLOCK_BREAK_SPEED);
CONVERTOR.put(Attributes1_21.GRAVITY, Attributes.GRAVITY);
CONVERTOR.put(Attributes1_21.SAFE_FALL_DISTANCE, Attributes.SAFE_FALL_DISTANCE);
CONVERTOR.put(Attributes1_21.FALL_DAMAGE_MULTIPLIER, Attributes.FALL_DAMAGE_MULTIPLIER);
CONVERTOR.put(Attributes1_21.EXPLOSION_KNOCKBACK_RESISTANCE, Attributes.EXPLOSION_KNOCKBACK_RESISTANCE);
CONVERTOR.put(Attributes1_21.MINING_EFFICIENCY, Attributes.MINING_EFFICIENCY);
CONVERTOR.put(Attributes1_21.OXYGEN_BONUS, Attributes.OXYGEN_BONUS);
CONVERTOR.put(Attributes1_21.SNEAKING_SPEED, Attributes.SNEAKING_SPEED);
CONVERTOR.put(Attributes1_21.SUBMERGED_MINING_SPEED, Attributes.SUBMERGED_MINING_SPEED);
CONVERTOR.put(Attributes1_21.SWEEPING_DAMAGE_RATIO, Attributes.SWEEPING_DAMAGE_RATIO);
CONVERTOR.put(Attributes1_21.WATER_MOVEMENT_EFFICIENCY, Attributes.WATER_MOVEMENT_EFFICIENCY);
} else {
CONVERTOR.put(Attributes.BURNING_TIME, Attributes1_21.BURNING_TIME);
CONVERTOR.put(Attributes.ARMOR, Attributes1_21.ARMOR);
CONVERTOR.put(Attributes.ARMOR_TOUGHNESS, Attributes1_21.ARMOR_TOUGHNESS);
CONVERTOR.put(Attributes.ATTACK_KNOCKBACK, Attributes1_21.ATTACK_KNOCKBACK);
CONVERTOR.put(Attributes.ATTACK_DAMAGE, Attributes1_21.ATTACK_DAMAGE);
CONVERTOR.put(Attributes.ATTACK_SPEED, Attributes1_21.ATTACK_SPEED);
CONVERTOR.put(Attributes.FLYING_SPEED, Attributes1_21.FLYING_SPEED);
CONVERTOR.put(Attributes.FOLLOW_RANGE, Attributes1_21.FOLLOW_RANGE);
CONVERTOR.put(Attributes.KNOCKBACK_RESISTANCE, Attributes1_21.KNOCKBACK_RESISTANCE);
CONVERTOR.put(Attributes.LUCK, Attributes1_21.LUCK);
CONVERTOR.put(Attributes.MAX_ABSORPTION, Attributes1_21.MAX_ABSORPTION);
CONVERTOR.put(Attributes.MAX_HEALTH, Attributes1_21.MAX_HEALTH);
CONVERTOR.put(Attributes.MOVEMENT_EFFICIENCY, Attributes1_21.MOVEMENT_EFFICIENCY);
CONVERTOR.put(Attributes.SCALE, Attributes1_21.SCALE);
CONVERTOR.put(Attributes.STEP_HEIGHT, Attributes1_21.STEP_HEIGHT);
CONVERTOR.put(Attributes.JUMP_STRENGTH, Attributes1_21.JUMP_STRENGTH);
CONVERTOR.put(Attributes.ENTITY_INTERACTION_RANGE, Attributes1_21.ENTITY_INTERACTION_RANGE);
CONVERTOR.put(Attributes.BLOCK_INTERACTION_RANGE, Attributes1_21.BLOCK_INTERACTION_RANGE);
CONVERTOR.put(Attributes.SPAWN_REINFORCEMENT, Attributes1_21.SPAWN_REINFORCEMENT);
CONVERTOR.put(Attributes.BLOCK_BREAK_SPEED, Attributes1_21.BLOCK_BREAK_SPEED);
CONVERTOR.put(Attributes.GRAVITY, Attributes1_21.GRAVITY);
CONVERTOR.put(Attributes.SAFE_FALL_DISTANCE, Attributes1_21.SAFE_FALL_DISTANCE);
CONVERTOR.put(Attributes.FALL_DAMAGE_MULTIPLIER, Attributes1_21.FALL_DAMAGE_MULTIPLIER);
CONVERTOR.put(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE, Attributes1_21.EXPLOSION_KNOCKBACK_RESISTANCE);
CONVERTOR.put(Attributes.MINING_EFFICIENCY, Attributes1_21.MINING_EFFICIENCY);
CONVERTOR.put(Attributes.OXYGEN_BONUS, Attributes1_21.OXYGEN_BONUS);
CONVERTOR.put(Attributes.SNEAKING_SPEED, Attributes1_21.SNEAKING_SPEED);
CONVERTOR.put(Attributes.SUBMERGED_MINING_SPEED, Attributes1_21.SUBMERGED_MINING_SPEED);
CONVERTOR.put(Attributes.SWEEPING_DAMAGE_RATIO, Attributes1_21.SWEEPING_DAMAGE_RATIO);
CONVERTOR.put(Attributes.WATER_MOVEMENT_EFFICIENCY, Attributes1_21.WATER_MOVEMENT_EFFICIENCY);
}
}
public static Key getNativeAttributeName(final Key attributeName) {
return CONVERTOR.getOrDefault(attributeName, attributeName);
}
private final List<AttributeModifier> modifiers;
public AttributeModifiersModifier(List<AttributeModifier> modifiers) {
this.modifiers = modifiers;
}
public List<AttributeModifier> modifiers() {
return this.modifiers;
}
@Override
public String name() {
return "attribute-modifiers";
}
private static Object previous;
@Override
public Item<I> apply(Item<I> item, ItemBuildContext context) {
if (VersionHelper.isOrAbove1_21_5()) {
ListTag modifiers = (ListTag) Optional.ofNullable(item.getSparrowNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS)).orElseGet(ListTag::new);
for (AttributeModifier modifier : this.modifiers) {
CompoundTag modifierTag = new CompoundTag();
modifierTag.putString("type", modifier.type());
modifierTag.putString("slot", modifier.slot().name().toLowerCase(Locale.ENGLISH));
modifierTag.putString("id", modifier.id().toString());
modifierTag.putDouble("amount", modifier.amount());
modifierTag.putString("operation", modifier.operation().id());
AttributeModifier.Display display = modifier.display();
if (VersionHelper.isOrAbove1_21_6() && display != null) {
CompoundTag displayTag = new CompoundTag();
AttributeModifier.Display.Type displayType = display.type();
displayTag.putString("type", displayType.name().toLowerCase(Locale.ENGLISH));
if (displayType == AttributeModifier.Display.Type.OVERRIDE) {
displayTag.put("value", AdventureHelper.componentToTag(AdventureHelper.miniMessage().deserialize(display.value(), context.tagResolvers())));
}
modifierTag.put("display", displayTag);
}
modifiers.add(modifierTag);
}
item.setNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS, modifiers);
} else if (VersionHelper.isOrAbove1_20_5()) {
CompoundTag compoundTag = (CompoundTag) Optional.ofNullable(item.getSparrowNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS)).orElseGet(CompoundTag::new);
ListTag modifiers = compoundTag.getList("modifiers");
if (modifiers == null) {
modifiers = new ListTag();
compoundTag.put("modifiers", modifiers);
}
for (AttributeModifier modifier : this.modifiers) {
CompoundTag modifierTag = new CompoundTag();
modifierTag.putString("type", modifier.type());
modifierTag.putString("slot", modifier.slot().name().toLowerCase(Locale.ENGLISH));
if (VersionHelper.isOrAbove1_21()) {
modifierTag.putString("id", modifier.id().toString());
} else {
modifierTag.putIntArray("uuid", UUIDUtils.uuidToIntArray(UUID.nameUUIDFromBytes(modifier.id().toString().getBytes(StandardCharsets.UTF_8))));
modifierTag.putString("name", modifier.id().toString());
}
modifierTag.putDouble("amount", modifier.amount());
modifierTag.putString("operation", modifier.operation().id());
modifiers.add(modifierTag);
}
item.setNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS, compoundTag);
} else {
ListTag listTag = (ListTag) Optional.ofNullable(item.getNBTTag("AttributeModifiers")).orElseGet(ListTag::new);
for (AttributeModifier modifier : this.modifiers) {
CompoundTag modifierTag = new CompoundTag();
modifierTag.putString("AttributeName", modifier.type());
modifierTag.putString("Name", modifier.id().toString());
modifierTag.putString("Slot", modifier.slot().name().toLowerCase(Locale.ENGLISH));
modifierTag.putInt("Operation", modifier.operation().ordinal());
modifierTag.putDouble("Amount", modifier.amount());
modifierTag.putIntArray("UUID", UUIDUtils.uuidToIntArray(UUID.nameUUIDFromBytes(modifier.id().toString().getBytes(StandardCharsets.UTF_8))));
listTag.add(modifierTag);
}
item.setTag(listTag, "AttributeModifiers");
}
return item;
}
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getSparrowNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS);
if (previous != null) {
networkData.put(ComponentKeys.ATTRIBUTE_MODIFIERS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {
networkData.put(ComponentKeys.ATTRIBUTE_MODIFIERS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
} else {
Tag previous = item.getNBTTag("AttributeModifiers");
if (previous != null) {
networkData.put("AttributeModifiers", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {
networkData.put("AttributeModifiers", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
}
}
return item;
}
}

View File

@@ -75,7 +75,7 @@ public class ComponentModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
for (Pair<Key, Tag> entry : this.arguments) {
Tag previous = item.getNBTComponent(entry.left());
Tag previous = item.getSparrowNBTComponent(entry.left());
if (previous != null) {
networkData.put(entry.left().asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -29,7 +29,7 @@ public class CustomModelDataModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.CUSTOM_MODEL_DATA);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.CUSTOM_MODEL_DATA);
if (previous != null) {
networkData.put(ComponentKeys.CUSTOM_MODEL_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -30,7 +30,7 @@ public class CustomNameModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.CUSTOM_NAME);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.CUSTOM_NAME);
if (previous != null) {
networkData.put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -29,7 +29,7 @@ public class DyedColorModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.DYED_COLOR);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.DYED_COLOR);
if (previous != null) {
networkData.put(ComponentKeys.DYED_COLOR.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -47,7 +47,7 @@ public class DynamicLoreModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.LORE);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.LORE);
if (previous != null) {
networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -34,7 +34,7 @@ public class EnchantmentModifier<I> implements ItemDataModifier<I> {
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.STORED_ENCHANTMENTS);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.STORED_ENCHANTMENTS);
if (previous != null) {
networkData.put(ComponentKeys.STORED_ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {
@@ -50,7 +50,7 @@ public class EnchantmentModifier<I> implements ItemDataModifier<I> {
}
} else {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.ENCHANTMENTS);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.ENCHANTMENTS);
if (previous != null) {
networkData.put(ComponentKeys.ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -40,7 +40,7 @@ public class EquippableAssetIdModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
Tag previous = item.getNBTComponent(ComponentKeys.EQUIPPABLE);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.EQUIPPABLE);
if (previous != null) {
networkData.put(ComponentKeys.EQUIPPABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -37,7 +37,7 @@ public class FoodModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
Tag previous = item.getNBTComponent(ComponentKeys.FOOD);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.FOOD);
if (previous != null) {
networkData.put(ComponentKeys.FOOD.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -78,7 +78,7 @@ public class HideTooltipModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (VersionHelper.isOrAbove1_21_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.TOOLTIP_DISPLAY);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.TOOLTIP_DISPLAY);
if (previous != null) {
networkData.put(ComponentKeys.TOOLTIP_DISPLAY.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {
@@ -86,7 +86,7 @@ public class HideTooltipModifier<I> implements ItemDataModifier<I> {
}
} else if (VersionHelper.isOrAbove1_20_5()) {
for (Key component : this.components) {
Tag previous = item.getNBTComponent(component);
Tag previous = item.getSparrowNBTComponent(component);
if (previous != null) {
networkData.put(component.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {
@@ -130,7 +130,7 @@ public class HideTooltipModifier<I> implements ItemDataModifier<I> {
@Override
public void apply(Item<I> item) {
Tag previous = item.getNBTComponent(this.component);
Tag previous = item.getSparrowNBTComponent(this.component);
if (previous instanceof CompoundTag compoundTag) {
compoundTag.putBoolean("show_in_tooltip", false);
item.setNBTComponent(this.component, compoundTag);

View File

@@ -28,7 +28,7 @@ public class ItemModelModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
Tag previous = item.getNBTComponent(ComponentKeys.ITEM_MODEL);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.ITEM_MODEL);
if (previous != null) {
networkData.put(ComponentKeys.ITEM_MODEL.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -30,7 +30,7 @@ public class ItemNameModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.ITEM_NAME);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.ITEM_NAME);
if (previous != null) {
networkData.put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -32,7 +32,7 @@ public class LoreModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.LORE);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.LORE);
if (previous != null) {
networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -36,7 +36,7 @@ public class RemoveComponentModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
for (String component : this.arguments) {
Tag previous = item.getNBTComponent(component);
Tag previous = item.getSparrowNBTComponent(component);
if (previous != null) {
networkData.put(component, NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
}

View File

@@ -28,7 +28,7 @@ public class TooltipStyleModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
Tag previous = item.getNBTComponent(ComponentKeys.TOOLTIP_STYLE);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.TOOLTIP_STYLE);
if (previous != null) {
networkData.put(ComponentKeys.TOOLTIP_STYLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -32,7 +32,7 @@ public class TrimModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.TRIM);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.TRIM);
if (previous != null) {
networkData.put(ComponentKeys.TRIM.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -29,7 +29,7 @@ public class UnbreakableModifier<I> implements ItemDataModifier<I> {
@Override
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
if (VersionHelper.isOrAbove1_20_5()) {
Tag previous = item.getNBTComponent(ComponentKeys.UNBREAKABLE);
Tag previous = item.getSparrowNBTComponent(ComponentKeys.UNBREAKABLE);
if (previous != null) {
networkData.put(ComponentKeys.UNBREAKABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
} else {

View File

@@ -6,4 +6,18 @@ public final class UUIDUtils {
public static final UUID EMPTY = new UUID(0, 0);
private UUIDUtils() {}
public static UUID uuidFromIntArray(int[] array) {
return new UUID((long) array[0] << 32 | (long) array[1] & 4294967295L, (long) array[2] << 32 | (long) array[3] & 4294967295L);
}
public static int[] uuidToIntArray(UUID uuid) {
long l = uuid.getMostSignificantBits();
long m = uuid.getLeastSignificantBits();
return leastMostToIntArray(l, m);
}
private static int[] leastMostToIntArray(long uuidMost, long uuidLeast) {
return new int[]{(int) (uuidMost >> 32), (int) uuidMost, (int) (uuidLeast >> 32), (int) uuidLeast};
}
}

View File

@@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G
# Project settings
# Rule: [major update].[feature update].[bug fix]
project_version=0.0.59.4
project_version=0.0.59.5
config_version=41
lang_version=21
project_group=net.momirealms
@@ -39,7 +39,7 @@ zstd_version=1.5.7-2
commons_io_version=2.18.0
commons_imaging_version=1.0.0-alpha6
commons_lang3_version=3.17.0
sparrow_nbt_version=0.9.1
sparrow_nbt_version=0.9.4
sparrow_util_version=0.50.6
fastutil_version=8.5.15
netty_version=4.1.121.Final