9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-26 18:39:20 +00:00

客户端侧material

This commit is contained in:
XiaoMoMi
2025-06-12 05:35:07 +08:00
parent 8b7383762a
commit 963e8e2c22
37 changed files with 211 additions and 71 deletions

View File

@@ -21,12 +21,12 @@ import java.util.Map;
public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
private final Material material;
public BukkitCustomItem(Holder<Key> id, Key materialKey, Material material,
public BukkitCustomItem(Holder<Key> id, Material material, Key materialKey, Key clientBoundMaterialKey,
List<ItemBehavior> behaviors,
List<ItemDataModifier<ItemStack>> modifiers, List<ItemDataModifier<ItemStack>> clientBoundModifiers,
ItemSettings settings,
Map<EventTrigger, List<Function<PlayerOptionalContext>>> events) {
super(id, materialKey, behaviors, modifiers, clientBoundModifiers, settings, events);
super(id, materialKey, clientBoundMaterialKey, behaviors, modifiers, clientBoundModifiers, settings, events);
this.material = material;
}
@@ -57,8 +57,9 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
public static class BuilderImpl implements Builder<ItemStack> {
private Holder<Key> id;
private Key materialKey;
private final Key materialKey;
private final Material material;
private Key clientBoundMaterialKey;
private final Map<EventTrigger, List<Function<PlayerOptionalContext>>> events = new EnumMap<>(EventTrigger.class);
private final List<ItemBehavior> behaviors = new ArrayList<>(4);
private final List<ItemDataModifier<ItemStack>> modifiers = new ArrayList<>(4);
@@ -77,8 +78,8 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
}
@Override
public Builder<ItemStack> material(Key material) {
this.materialKey = material;
public Builder<ItemStack> clientBoundMaterial(Key clientBoundMaterialKey) {
this.clientBoundMaterialKey = clientBoundMaterialKey;
return this;
}
@@ -133,7 +134,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
@Override
public CustomItem<ItemStack> build() {
this.modifiers.addAll(this.settings.modifiers());
return new BukkitCustomItem(this.id, this.materialKey, this.material, List.copyOf(this.behaviors),
return new BukkitCustomItem(this.id, this.material, this.materialKey, this.clientBoundMaterialKey, List.copyOf(this.behaviors),
List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), this.settings, this.events);
}
}

View File

@@ -200,9 +200,12 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
}
@Override
protected CustomItem.Builder<ItemStack> createPlatformItemBuilder(Holder<Key> id, Key materialId) {
protected CustomItem.Builder<ItemStack> createPlatformItemBuilder(Holder<Key> id, Key materialId, Key clientBoundMaterialId) {
Material material = ResourceConfigUtils.requireNonNullOrThrow(Registry.MATERIAL.get(KeyUtils.toNamespacedKey(materialId)), () -> new LocalizedResourceConfigException("warning.config.item.invalid_material", materialId.toString()));
return BukkitCustomItem.builder(material).material(materialId).id(id);
if (!clientBoundMaterialId.equals(materialId)) {
ResourceConfigUtils.requireNonNullOrThrow(Registry.MATERIAL.get(KeyUtils.toNamespacedKey(clientBoundMaterialId)), () -> new LocalizedResourceConfigException("warning.config.item.invalid_material", clientBoundMaterialId.toString()));
}
return BukkitCustomItem.builder(material).id(id).clientBoundMaterial(clientBoundMaterialId);
}
@SuppressWarnings("unchecked")

View File

@@ -29,7 +29,20 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
@Override
public Optional<Item<ItemStack>> c2s(Item<ItemStack> wrapped) {
if (!wrapped.hasTag(NETWORK_ITEM_TAG)) return Optional.empty();
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
boolean hasDifferentMaterial = false;
if (optionalCustomItem.isPresent()) {
CustomItem<ItemStack> customItem = optionalCustomItem.get();
if (!customItem.material().equals(wrapped.vanillaId())) {
wrapped = wrapped.transmuteCopy(customItem.material());
hasDifferentMaterial = true;
}
}
if (!wrapped.hasTag(NETWORK_ITEM_TAG)) {
if (hasDifferentMaterial) {
return Optional.of(wrapped);
}
}
CompoundTag networkData = (CompoundTag) wrapped.getNBTTag(NETWORK_ITEM_TAG);
if (networkData == null) return Optional.empty();
wrapped.removeTag(NETWORK_ITEM_TAG);
@@ -46,12 +59,16 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
if (optionalCustomItem.isEmpty()) {
if (!Config.interceptItem()) return Optional.empty();
return new OtherItem(wrapped).process();
return new OtherItem(wrapped, false).process();
} else {
CustomItem<ItemStack> customItem = optionalCustomItem.get();
boolean hasDifferentMaterial = !wrapped.vanillaId().equals(customItem.clientBoundMaterial());
if (hasDifferentMaterial) {
wrapped = wrapped.transmuteCopy(customItem.clientBoundMaterial());
}
if (!customItem.hasClientBoundDataModifier()) {
if (!Config.interceptItem()) return Optional.empty();
return new OtherItem(wrapped).process();
if (!Config.interceptItem() && !hasDifferentMaterial) return Optional.empty();
return new OtherItem(wrapped, hasDifferentMaterial).process();
} else {
CompoundTag tag = new CompoundTag();
Tag argumentTag = wrapped.getNBTTag(ArgumentModifier.ARGUMENTS_TAG);
@@ -77,7 +94,12 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
processLore(wrapped, tag::put);
}
}
if (tag.isEmpty()) return Optional.empty();
if (tag.isEmpty()) {
if (hasDifferentMaterial) {
return Optional.of(wrapped);
}
return Optional.empty();
}
wrapped.setTag(tag, NETWORK_ITEM_TAG);
return Optional.of(wrapped);
}
@@ -130,9 +152,11 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
private final Item<ItemStack> item;
private boolean globalChanged = false;
private CompoundTag networkTag;
private final boolean forceReturn;
public OtherItem(Item<ItemStack> item) {
public OtherItem(Item<ItemStack> item, boolean forceReturn) {
this.item = item;
this.forceReturn = forceReturn;
}
public Optional<Item<ItemStack>> process() {
@@ -145,6 +169,8 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
if (this.globalChanged) {
this.item.setTag(this.networkTag, NETWORK_ITEM_TAG);
return Optional.of(this.item);
} else if (this.forceReturn) {
return Optional.of(this.item);
} else {
return Optional.empty();
}

View File

@@ -30,8 +30,22 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
public Optional<Item<ItemStack>> c2s(Item<ItemStack> wrapped) {
Tag customData = wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA);
if (!(customData instanceof CompoundTag compoundTag)) return Optional.empty();
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
boolean hasDifferentMaterial = false;
if (optionalCustomItem.isPresent()) {
CustomItem<ItemStack> customItem = optionalCustomItem.get();
if (!customItem.material().equals(wrapped.vanillaId())) {
wrapped = wrapped.transmuteCopy(customItem.material());
hasDifferentMaterial = true;
}
}
CompoundTag networkData = compoundTag.getCompound(NETWORK_ITEM_TAG);
if (networkData == null) return Optional.empty();
if (networkData == null) {
if (hasDifferentMaterial) {
return Optional.of(wrapped);
}
return Optional.empty();
}
compoundTag.remove(NETWORK_ITEM_TAG);
for (Map.Entry<String, Tag> entry : networkData.entrySet()) {
if (entry.getValue() instanceof CompoundTag tag) {
@@ -48,12 +62,16 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
if (optionalCustomItem.isEmpty()) {
if (!Config.interceptItem()) return Optional.empty();
return new OtherItem(wrapped).process();
return new OtherItem(wrapped, false).process();
} else {
CustomItem<ItemStack> customItem = optionalCustomItem.get();
boolean hasDifferentMaterial = !wrapped.vanillaId().equals(customItem.clientBoundMaterial());
if (hasDifferentMaterial) {
wrapped = wrapped.transmuteCopy(customItem.clientBoundMaterial());
}
if (!customItem.hasClientBoundDataModifier()) {
if (!Config.interceptItem()) return Optional.empty();
return new OtherItem(wrapped).process();
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 arguments = customData.getCompound(ArgumentModifier.ARGUMENTS_TAG);
@@ -86,7 +104,10 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
else processLegacyLore(wrapped, () -> tag);
}
}
if (tag.isEmpty()) return Optional.empty();
if (tag.isEmpty()) {
if (hasDifferentMaterial) return Optional.of(wrapped);
return Optional.empty();
}
customData.put(NETWORK_ITEM_TAG, tag);
wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, customData);
return Optional.of(wrapped);
@@ -203,11 +224,13 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
static class OtherItem {
private final Item<ItemStack> item;
private final boolean forceReturn;
private boolean globalChanged = false;
private CompoundTag tag;
public OtherItem(Item<ItemStack> item) {
public OtherItem(Item<ItemStack> item, boolean forceReturn) {
this.item = item;
this.forceReturn = forceReturn;
}
public Optional<Item<ItemStack>> process() {
@@ -231,6 +254,8 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
customData.put(NETWORK_ITEM_TAG, getOrCreateTag());
this.item.setNBTComponent(ComponentKeys.CUSTOM_DATA, customData);
return Optional.of(this.item);
} else if (this.forceReturn) {
return Optional.of(this.item);
} else {
return Optional.empty();
}

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item.factory;
import com.google.gson.JsonElement;
import com.saicone.rtag.item.ItemTagStream;
import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.util.ItemTags;
import net.momirealms.craftengine.core.item.ItemFactory;

View File

@@ -5,8 +5,10 @@ import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper;
import net.momirealms.craftengine.bukkit.item.ComponentTypes;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
import net.momirealms.craftengine.bukkit.util.EnchantmentUtils;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.item.Enchantment;
import net.momirealms.craftengine.core.item.Trim;
import net.momirealms.craftengine.core.plugin.CraftEngine;
@@ -507,9 +509,9 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
protected ComponentItemWrapper mergeCopy(ComponentItemWrapper item1, ComponentItemWrapper item2) {
Object itemStack1 = item1.getLiteralObject();
Object itemStack2 = item2.getLiteralObject();
Object itemStack3 = FastNMS.INSTANCE.method$ItemStack$transmuteCopy(itemStack1, itemStack2);
Object itemStack3 = FastNMS.INSTANCE.method$ItemStack$transmuteCopy(itemStack1, FastNMS.INSTANCE.method$ItemStack$getItem(itemStack2), item2.count());
FastNMS.INSTANCE.method$ItemStack$applyComponents(itemStack3, FastNMS.INSTANCE.method$ItemStack$getComponentsPatch(itemStack2));
return new ComponentItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack3), item2.count());
return new ComponentItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack3));
}
@Override
@@ -519,7 +521,14 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
try {
FastNMS.INSTANCE.method$ItemStack$applyComponents(itemStack1, FastNMS.INSTANCE.method$ItemStack$getComponentsPatch(itemStack2));
} catch (Exception e) {
plugin.logger().warn("Failed to merge item", e);
this.plugin.logger().warn("Failed to merge item", e);
}
}
@Override
protected ComponentItemWrapper transmuteCopy(ComponentItemWrapper item1, Key item, int amount) {
Object itemStack1 = item1.getLiteralObject();
Object itemStack2 = FastNMS.INSTANCE.method$ItemStack$transmuteCopy(itemStack1, FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(item)), amount);
return new ComponentItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack2));
}
}

View File

@@ -6,6 +6,9 @@ import com.saicone.rtag.tag.TagBase;
import com.saicone.rtag.tag.TagCompound;
import com.saicone.rtag.tag.TagList;
import net.momirealms.craftengine.bukkit.item.LegacyItemWrapper;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.item.Enchantment;
import net.momirealms.craftengine.core.item.Trim;
import net.momirealms.craftengine.core.item.modifier.IdModifier;
@@ -319,4 +322,11 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
// update wrapped item
item1.update();
}
@Override
protected LegacyItemWrapper transmuteCopy(LegacyItemWrapper item, Key newItem, int amount) {
Object newItemStack = FastNMS.INSTANCE.constructor$ItemStack(FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(newItem)), amount);
ItemObject.setCustomDataTag(newItemStack, TagCompound.clone(ItemObject.getCustomDataTag(item.getLiteralObject())));
return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(newItemStack)), amount);
}
}

View File

@@ -791,6 +791,7 @@ public class RecipeEventListener implements Listener {
return new Pair<>(first, second);
}
// 不是完美的解决方案,仍然需要更多的探讨
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onCraft(CraftItemEvent event) {
org.bukkit.inventory.Recipe recipe = event.getRecipe();