Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Reimplement] Hide specified item components [for 1.21.4] #215

Merged
merged 2 commits into from
Feb 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: TheFloodDragon <[email protected]>
Date: Fri, 7 Feb 2025 18:41:55 +0800
Subject: [PATCH] Hide specified item components


diff --git a/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java b/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java
index 828fbe03e7beb860cd0816c7ac8adbffe196533b..f602c4c55483a189f973929b982f1834ca7e9952 100644
--- a/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java
+++ b/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java
@@ -53,8 +53,8 @@ public class ClientboundContainerSetContentPacket implements Packet<ClientGamePa
private void write(RegistryFriendlyByteBuf buffer) {
buffer.writeContainerId(this.containerId);
buffer.writeVarInt(this.stateId);
- ItemStack.OPTIONAL_LIST_STREAM_CODEC.encode(buffer, this.items);
- ItemStack.OPTIONAL_STREAM_CODEC.encode(buffer, this.carriedItem);
+ ItemStack.OPTIONAL_LIST_STREAM_CODEC.encode(buffer, org.dreeam.leaf.util.item.ItemStackStripper.strip(this.items, true)); // Leaf - Hide specified item components
+ ItemStack.OPTIONAL_STREAM_CODEC.encode(buffer, org.dreeam.leaf.util.item.ItemStackStripper.strip(this.carriedItem, true)); // Leaf - Hide specified item components
}

@Override
diff --git a/net/minecraft/network/protocol/game/ClientboundContainerSetSlotPacket.java b/net/minecraft/network/protocol/game/ClientboundContainerSetSlotPacket.java
index c1130f596cf3443eeb62eb1b12587172fe0859ee..18590e0b1d94ee3266637c5f3ab65ead4f8fb394 100644
--- a/net/minecraft/network/protocol/game/ClientboundContainerSetSlotPacket.java
+++ b/net/minecraft/network/protocol/game/ClientboundContainerSetSlotPacket.java
@@ -33,7 +33,7 @@ public class ClientboundContainerSetSlotPacket implements Packet<ClientGamePacke
buffer.writeContainerId(this.containerId);
buffer.writeVarInt(this.stateId);
buffer.writeShort(this.slot);
- ItemStack.OPTIONAL_STREAM_CODEC.encode(buffer, this.itemStack);
+ ItemStack.OPTIONAL_STREAM_CODEC.encode(buffer, org.dreeam.leaf.util.item.ItemStackStripper.strip(this.itemStack, true)); // Leaf - Hide specified item components
}

@Override
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
index 3dcd8df0b395a8fed8bc0cbe0ff78f4ae0056fd3..6033f629ac457472ad10f8e346732a596aea52d9 100644
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -306,7 +306,7 @@ public abstract class AbstractContainerMenu {

private void synchronizeCarriedToRemote() {
if (!this.suppressRemoteUpdates) {
- if (!ItemStack.matches(this.getCarried(), this.remoteCarried)) {
+ if (!org.dreeam.leaf.util.item.ItemStackStripper.matchesStripped(this.getCarried(), this.remoteCarried)) { // Leaf - Hide specified item components - Avoid some frequent client animations
this.remoteCarried = this.getCarried().copy();
if (this.synchronizer != null) {
this.synchronizer.sendCarriedChange(this, this.remoteCarried);
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.dreeam.leaf.config.modules.gameplay;

import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import org.dreeam.leaf.config.ConfigModules;
import org.dreeam.leaf.config.EnumConfigCategory;
import org.dreeam.leaf.config.LeafConfig;

import java.util.ArrayList;
import java.util.List;

/**
* HideItemComponent
*
* @author TheFloodDragon
* @since 2025/2/4 18:30
*/
public class HideItemComponent extends ConfigModules {

public String getBasePath() {
return EnumConfigCategory.GAMEPLAY.getBaseKeyName() + ".hide-item-component";
}

public static boolean enabled = false;
public static List<DataComponentType<?>> hiddenTypes = List.of();

@Override
public void onLoaded() {
config.addCommentRegionBased(getBasePath(), """
Controls whether specified component information would be sent to clients.
It may break resource packs and mods that rely on the information.
Also, it can avoid some frequent client animations.
Attention: This is not same as Paper's item-obfuscation, we only hide specified component information from player's inventory.""",
"""
控制哪些物品组件信息会被发送至客户端.
可能会导致依赖物品组件的资源包/模组无法正常工作.
可以避免一些客户端动画效果.
注意: 此项与 Paper 的 item-obfuscation 不同, 我们只从玩家背包中隐藏物品指定的组件信息.""");
List<String> list = config.getList(getBasePath() + ".hidden-types", new ArrayList<>(), config.pickStringRegionBased("""
Which type of components will be hidden from clients.
It needs a component type list, incorrect things will not work.""",
"""
被隐藏的物品组件类型列表.
该配置项接受一个物品组件列表, 格式不正确将不会启用."""));
enabled = config.getBoolean(getBasePath() + ".enabled", enabled, config.pickStringRegionBased(
"If enabled, specified item component information from player's inventory will be hided.",
"启用后, 玩家背包内物品的指定组件信息会被隐藏."
));

final List<DataComponentType<?>> types = new ArrayList<>(list.size());

for (String componentType : list) {
BuiltInRegistries.DATA_COMPONENT_TYPE.get(ResourceLocation.parse(componentType)).ifPresentOrElse(
optional -> types.add(optional.value()),
() -> LeafConfig.LOGGER.warn("Unknown component type: {}", componentType)
);
}

hiddenTypes = types;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.dreeam.leaf.util.item;

import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.world.item.ItemStack;
import org.dreeam.leaf.config.modules.gameplay.HideItemComponent;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
* ItemStackStripper
*
* @author TheFloodDragon
* @since 2025/2/4 19:04
*/
public class ItemStackStripper {

public static ItemStack strip(final ItemStack itemStack, final boolean copy) {
if (!HideItemComponent.enabled || itemStack.isEmpty() || itemStack.getComponentsPatch().isEmpty())
return itemStack;

final ItemStack copied = copy ? itemStack.copy() : itemStack;

// Remove specified types
for (DataComponentType<?> type : HideItemComponent.hiddenTypes) {
// Only remove, no others
copied.remove(type);
}

return copied;
}

public static List<ItemStack> strip(final List<ItemStack> itemStacks, final boolean copy) {
if (!HideItemComponent.enabled) return itemStacks;

final List<ItemStack> copiedItems = new ArrayList<>();

for (ItemStack itemStack : itemStacks) {
if (itemStack.isEmpty() || itemStack.getComponentsPatch().isEmpty()) {
copiedItems.add(itemStack);
continue;
}

final ItemStack copied = copy ? itemStack.copy() : itemStack;

// Remove specified types
for (DataComponentType<?> type : HideItemComponent.hiddenTypes) {
// Only remove, no others
copied.remove(type);
}

copiedItems.add(copied);
}

return copiedItems;
}

/**
* Check if two ItemStacks are the same after stripping components
*/
public static boolean matchesStripped(ItemStack left, ItemStack right) {
if (HideItemComponent.enabled) {
return left == right || (
left.is(right.getItem()) && left.getCount() == right.getCount() &&
(left.isEmpty() && right.isEmpty() || Objects.equals(strip(left.getComponents()), strip(right.getComponents())))
);
}

return ItemStack.matches(left, right);
}

/**
* @return a new DataComponentMap with all hidden components removed
*/
private static DataComponentMap strip(final DataComponentMap map) {
return map.filter(c -> !HideItemComponent.hiddenTypes.contains(c));
}
}