Mekanisme Pengelompokan Mega-Stack (MC 26.1.2)
Dokumen ini menyajikan rincian teknis dan matematis tentang agregasi item di tanah, perhitungan radius pencarian, dan penggabungan entitas dalam Item Clumps untuk Minecraft 26.1.2.
📊 Kotak Info Fitur
| Properti | Spesifikasi |
|---|---|
| Nama Sistem | Agregator Mega-Stack Item Tanah |
| Kelas Target | net.minecraft.world.entity.item.ItemEntity |
| Batas Penggabungan Bawaan | 9.999 item (Dapat dikonfigurasi hingga $2.147.483.647$) |
| Radius Pencarian ($r$) | Horisontal $1$ hingga $10$ blok (Bawaan: $1$ blok) |
| Injeksi Radius | @ModifyArgs pada AABB.inflate(DDD) |
| GameRules Pengendali | item_clumps:enable_clumping, item_clumps:max_clump_size, item_clumps:merge_radius |
⚙️ Cara Kerja Agregasi Mega-Stack
Dalam vanilla Minecraft, item yang dijatuhkan memanggil mergeWithNeighbours() setiap tick, tetapi vanilla melarang penggabungan jika jumlah item melebihi itemStack.getMaxStackSize() (biasanya 64).
Item Clumps mencegat pemeriksaan ini melalui ItemEntityMixin.java untuk membuka batasan tersebut sembari mempertahankan keamanan komponen data.
┌──────────────────────────────┐
│ ItemEntity A Ticks In │
└──────────────┬───────────────┘
│
▼
┌──────────────────────────────┐
│ Feasibility Check │
│ - Matching player target? │
│ - Identical DataComponents? │
└──────────────┬───────────────┘
│ (Pass)
▼
┌──────────────────────────────┐
│ Combine Stacks Math Check │
└──────────────┬───────────────┘
│
┌───────────────┴───────────────┐
│ │
thisCount + otherCount <= maxClump thisCount + otherCount > maxClump
│ │
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Complete Merge │ │ Partial Merge │
│ Larger absorbs │ │ Fill entity A to │
│ smaller entity; │ │ maxClumpSize; │
│ Younger age kept. │ │ B keeps remainder.│
└───────────────────┘ └───────────────────┘📐 Rumus Matematika & Perhitungan Presisi
1. Pelebaran Kotak Batas Horisontal (@ModifyArgs)
$$\text{args.set}(0, r), \quad \text{args.set}(2, r)$$
Di mana:
- $r = \text{DynamicGameRuleManager}.\text{getInt}(\text{level}, \text{MERGE_RADIUS}) \in [1, 10]$ blok.
- Indeks ketinggian vertikal ($1$) tidak disentuh, menjaga pemisahan vertikal antar lantai yang berbeda.
2. Matematika Transfer Jumlah Item
- Penyerapan Penuh ($S \le \text{maxClumpSize}$): $$\text{count}_{\text{merged}} = \text{thisCount} + \text{otherCount}$$
- Penyerapan Sebagian ($S > \text{maxClumpSize}$): $$\Delta = \text{maxClumpSize} - \text{thisCount}$$ $$\text{thisCount}' = \text{maxClumpSize}, \quad \text{otherCount}' = \text{otherCount} - \Delta$$
💻 Implementasi Kode Sumber Java Asli
Dari ItemEntityMixin.java di Minecraft 26.1.2:
java
@ModifyArgs(method = "mergeWithNeighbours", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/phys/AABB;inflate(DDD)Lnet/minecraft/world/phys/AABB;"))
private void item_clumps$modifySearchRadius(Args args) {
if (DynamicGameRuleManager.getBoolean(this.level(), ItemClumpsFabric.ENABLE_CLUMPING)) {
double radius = DynamicGameRuleManager.getInt(this.level(), ItemClumpsFabric.MERGE_RADIUS);
args.set(0, radius);
args.set(2, radius);
}
}
@Inject(method = "tryToMerge", at = @At("HEAD"), cancellable = true)
private void item_clumps$customMerge(ItemEntity other, CallbackInfo ci) {
if (!DynamicGameRuleManager.getBoolean(this.level(), ItemClumpsFabric.ENABLE_CLUMPING)) return;
ItemStack thisStack = this.getItem();
ItemStack otherStack = other.getItem();
if (!Objects.equals(this.target, ((ItemEntityMixin)(Object)other).target) ||
!ItemStack.isSameItemSameComponents(thisStack, otherStack)) {
return;
}
int thisCount = thisStack.getCount();
int otherCount = otherStack.getCount();
int maxClump = DynamicGameRuleManager.getInt(this.level(), ItemClumpsFabric.MAX_CLUMP_SIZE);
if (thisCount + otherCount > maxClump) {
int spaceLeft = maxClump - thisCount;
if (spaceLeft > 0) {
thisStack.setCount(maxClump);
this.setItem(thisStack);
otherStack.setCount(otherCount - spaceLeft);
other.setItem(otherStack);
}
ci.cancel();
return;
}
// Full Merge: larger stack absorbs the smaller stack
if (otherCount < thisCount) {
thisStack.setCount(thisCount + otherCount);
this.setItem(thisStack);
this.pickupDelay = Math.max(this.pickupDelay, ((ItemEntityMixin)(Object)other).pickupDelay);
this.age = Math.min(this.age, ((ItemEntityMixin)(Object)other).age);
other.discard();
} else {
otherStack.setCount(thisCount + otherCount);
other.setItem(otherStack);
((ItemEntityMixin)(Object)other).pickupDelay = Math.max(((ItemEntityMixin)(Object)other).pickupDelay, this.pickupDelay);
((ItemEntityMixin)(Object)other).age = Math.min(((ItemEntityMixin)(Object)other).age, this.age);
this.discard();
}
ci.cancel();
}