Create FilterBreaker 是一个 Minecraft 1.21.1 NeoForge 客户端模组,用于复现和回归测试 Create 物流网络数据包中的服务端验证问题。
主要功能:
/gainfilter:构造并发送StockKeeperCategoryRefundPacket;
此模组会改变服务端库存状态。测试前建议备份世界,并使用可回滚的测试存档。
| 项目 | 版本 |
|---|---|
| Minecraft | 1.21.1 |
| Java | 21 |
| NeoForge | 21.1.235 |
| Create | 6.0.10 |
| FilterBreaker | 0.1.0 |
| 加载端 | Client |
上述组合已经完成本地构建验证。反射调用依赖 Create 对应类和构造器签名,其他 Create 版本可能表现不同。
- 从 Releases 下载
create-filter-breaker-0.1.0.jar。 - 准备 Minecraft 1.21.1、Java 21、NeoForge 21.1.235 和 Create 6.0.10。
- 把 FilterBreaker JAR 放入客户端实例的
mods目录。 - 启动游戏并确认模组列表中出现 Create FilterBreaker。
FilterBreaker 自身只在客户端加载。连接世界时,服务端需要安装协议兼容的 Create。
StockKeeperCategoryRefundPacket 继承 Create 的 BlockEntityConfigurationPacket。服务端仍会检查:
- 玩家模式;
- 目标区块是否已加载;
- 玩家与目标方块的距离;
- 坐标处是否存在对应的同步方块实体。
因此需要在附近放置或找到一个已加载的 Stock Ticker。
/gainfilter create:filter 1成功后客户端会显示发送位置、数量和物品 ID。
使用准星指向的方块坐标:
/gainfilter <item> [count]手动指定 Stock Ticker 坐标:
/gainfilter <x> <y> <z> <item> [count]参数:
| 参数 | 说明 |
|---|---|
<x> <y> <z> |
Stock Ticker 方块坐标 |
<item> |
Minecraft 1.21.1 /give 风格物品参数 |
[count] |
可选,范围 1–99,默认 1 |
/gainfilter create:filter 1
/gainfilter create:attribute_filter 1
/gainfilter create:package_filter 1显式指定坐标:
/gainfilter 12 64 -8 create:filter[minecraft:custom_name='{"text":"Ticker Test","italic":false}'] 1<item> 由原版 ItemArgument 解析,所以组件 ID 和组件内容必须已经注册,并通过对应 Codec 的格式检查。
退款处理使用:
filter.getItem() instanceof FilterItemCreate 6.0.10 中常见的匹配物品包括:
create:filtercreate:attribute_filtercreate:package_filter
退款包直接产生的根物品仍是 FilterItem。嵌套组件中的物品是否进一步形成独立物品,取决于后续读取、转换、打开或提取该组件的游戏逻辑。
Create 的 Stock Ticker 分类界面在删除分类时执行:
if (!entry.isEmpty())
CatnipServices.NETWORK.sendToServer(
new StockKeeperCategoryRefundPacket(
menu.contentHolder.getBlockPos(),
entry
)
);
entries.remove(entry);这里的 entry 是客户端内存中的完整 ItemStack。
源码:StockKeeperCategoryScreen.java
public static final StreamCodec<RegistryFriendlyByteBuf,
StockKeeperCategoryRefundPacket> STREAM_CODEC = StreamCodec.composite(
BlockPos.STREAM_CODEC, p -> p.pos,
ItemStack.STREAM_CODEC, p -> p.filter,
StockKeeperCategoryRefundPacket::new
);ItemStack.STREAM_CODEC 会传输:
- 数量;
- 物品注册 ID;
- 完整
DataComponentPatch; - 组件中的有效嵌套数据。
@Override
protected void applySettings(ServerPlayer player, StockTickerBlockEntity be) {
if (!filter.isEmpty() && filter.getItem() instanceof FilterItem)
player.getInventory()
.placeItemBackInInventory(filter);
}源码:StockKeeperCategoryRefundPacket.java
关键点:
filter来自客户端数据包;be是真实服务端 Stock Ticker;- 退款函数没有读取
be.categories; - 没有验证该 Filter 是否存在于服务端分类;
- 没有从服务端分类中删除条目;
- 没有把数量固定为 1;
- 没有核对客户端组件与服务端条目;
- 没有把退款绑定到菜单会话或一次性删除事务。
因此,服务器只确认根物品属于 FilterItem,随后把客户端提交的完整栈放进玩家库存。
/gainfilter
→ 客户端 ItemArgument 解析 ID 与数据组件
→ ItemInput.createItemStack(count, false)
→ 反射构造 StockKeeperCategoryRefundPacket
→ PacketDistributor.sendToServer
→ 服务端 ItemStack.STREAM_CODEC 重建完整栈
→ instanceof FilterItem
→ placeItemBackInInventory(filter)
/gainfilter 注册为客户端指令,命令文本通常不会进入服务端命令日志。服务端接收的是 Create 自定义 serverbound payload:
REFUND_STOCK_KEEPER_CATEGORY
BlockPos + ItemStack
服务端网络审计、数据包处理日志或对 StockKeeperCategoryRefundPacket 的埋点可以记录该请求。
需要 Java 21。
Windows:
.\gradlew.bat clean buildLinux/macOS:
chmod +x gradlew
./gradlew clean build构建产物:
build/libs/create-filter-breaker-0.1.0.jar
src/main/java/io/github/adnermo/filterbreaker/
├── FilterBreaker.java
├── FilterBreakerClient.java
├── ChatLimitBreakerClient.java
└── mixin/ChatScreenMixin.java
参见 CHANGELOG.md 与 GitHub Releases。
MIT © 2026 Adnermo