ホログラフィックラベルとしきい値 (MC 26.2)
本書では、Minecraft 26.2 における浮遊数量ラベルシステム、label_min_count しきい値制御、バニラクライアントでのネームタグ描画について解説します。
📊 機能情報ボックス
| 項目 | 仕様 |
|---|---|
| システム名 | サーバーサイド・ホログラフィックネームタグ表示 |
| 描画方式 | バニラ標準のカスタムネームタグ (setCustomName / setCustomNameVisible) |
| クライアントMOD必要? | 不要 (バニラクライアントで100%表示可能) |
| ラベルの形式 | <アイテム名> x<数量> (例: ダイヤモンド x128, オークの原木 x500) |
| しきい値GameRule | item_clumps:label_min_count (初期値: -1, スタック上限を使用) |
| 表示切替GameRule | item_clumps:render_labels (初期値: true) |
| Tick処理負荷 | $0.00\text{ ms}$ (setItem() 変更時のみ厳格に実行) |
🏷️ バニラクライアントでの浮遊ラベル描画の仕組み
Item Clumps はクライアントMODや独自のOpenGL描画パケットを必要とせず、Minecraftバニラに組み込まれているエンティティのカスタムネームタグ描画機能をそのまま利用します:
┌───────────────────────────────┐
│ Ground Item Stack Size Changes│
│ (ItemEntity.setItem) │
└───────────────┬───────────────┘
│
▼
┌───────────────────────────────┐
│ Is render_labels Enabled? │
│ Does count > maxStack? │
└───────────────┬───────────────┘
│
┌────────────────┴────────────────┐
│ (Yes) │ (No)
▼ ▼
┌───────────────────────────┐ ┌───────────────────────────┐
│ Set Entity Custom Name │ │ Clear Entity Custom Name │
│ setCustomName(name xCount)│ │ setCustomName(null) │
│ setCustomNameVisible(true)│ │ setCustomNameVisible(false│
└─────────────┬─────────────┘ └───────────────────────────┘
│
▼
┌───────────────────────────┐
│ SyncedEntityData Packet │
│ Sent to all nearby clients│
└─────────────┬─────────────┘
│
▼
┌───────────────────────────┐
│ Vanilla Client Renders │
│ Clean Floating Name Tag! │
└───────────────────────────┘⚙️ しきい値のカスタマイズ (label_min_count)
Minecraft 26.2 では、管理者は item_clumps:label_min_count ゲームルールを使用してラベルが表示される条件を自在に設定できます:
label_min_count の値 | しきい値の挙動 |
|---|---|
-1 (初期値) | バニラスタック上限: スタック上限を超えた場合にのみラベル表示 (丸石なら $> 64$、パールなら $> 16$、剣なら $> 1$)。 |
0 | 常時表示: 地上のすべてのドロップアイテムに数量ラベルを表示 (例: 土 x1)。 |
100 | メガスタックフィルター: 数量が $101$ 個以上になるまでラベルを非表示。 |
1000 | 超大規模ストレージモード: 巨大な集約アイテムにのみラベルを表示。 |
💻 実際のJavaソースコード実装
Minecraft 26.2 の ItemEntityMixin.java より:
java
private void item_clumps$updateVanillaNameTag() {
if (this.level() == null || this.level().isClientSide()) return;
ItemStack stack = this.getItem();
if (stack.isEmpty()) {
this.setCustomName(null);
this.setCustomNameVisible(false);
return;
}
int count = stack.getCount();
int labelMin = DynamicGameRuleManager.getInt(this.level(), ItemClumpsFabric.LABEL_MIN_COUNT);
int maxStack = (labelMin == -1) ? stack.getOrDefault(DataComponents.MAX_STACK_SIZE, 1) : labelMin;
if (DynamicGameRuleManager.getBoolean(this.level(), ItemClumpsFabric.RENDER_LABELS) && count > maxStack) {
Component name = stack.getItemName().copy().append(" x" + count);
if (!this.hasCustomName() || !this.getCustomName().getString().equals(name.getString())) {
this.setCustomName(name);
this.setCustomNameVisible(true);
}
} else {
if (this.hasCustomName()) {
this.setCustomName(null);
this.setCustomNameVisible(false);
}
}
}
@Inject(method = "setItem", at = @At("TAIL"))
private void item_clumps$onSetItem(ItemStack itemStack, CallbackInfo ci) {
if (!this.level().isClientSide()) {
this.item_clumps$updateVanillaNameTag();
}
}