Skip to content

Mekanisme Pengelompokan Mega-Stack (MC 26.2)

Dokumen ini menyajikan rincian teknis dan matematis yang mendalam tentang agregasi item di tanah, perhitungan radius pencarian, pencegahan overflow 64-bit, dan pengoptimalan alokasi heap dalam Item Clumps untuk Minecraft 26.2.


📊 Kotak Info Fitur

PropertiSpesifikasi
Nama SistemAgregator Mega-Stack Item Tanah
Kelas Targetnet.minecraft.world.entity.item.ItemEntity
Batas Penggabungan Bawaan9.999 item (Dapat dikonfigurasi hingga $2.147.483.647$)
Radius Pencarian ($r$)Horisontal $1$ hingga $10$ blok (Bawaan: $1$ blok)
Beban Tick$0.00\text{ ms}$ pada item diam (hanya dijalankan saat setItem())
Alokasi MemoriNol alokasi objek saat pencarian & penyerapan (copyWithCount(int))
GameRules Pengendaliitem_clumps:enable_clumping, item_clumps:max_clump_size, item_clumps:merge_radius

⚙️ Cara Kerja Agregasi Mega-Stack

Dalam vanilla Minecraft, item yang terjatuh memanggil mergeWithNeighbours() selama siklus tick-nya, mencari item serupa di sekitar. Namun, vanilla melarang keras penggabungan jika jumlah item entitas target melebihi itemStack.getMaxStackSize() (biasanya 64, atau 16 untuk mutiara ender / telur).

Item Clumps memotong pemeriksaan ini melalui ItemEntityMixin.java untuk menghapus batasan buatan ini sambil tetap menjaga keamanan komponen data secara ketat.

                  ┌──────────────────────────────┐
                  │    ItemEntity A Ticks In     │
                  └──────────────┬───────────────┘


                  ┌──────────────────────────────┐
                  │     Fast-Path Validation     │
                  │  - Matching player target?   │
                  │  - Identical DataComponents? │
                  └──────────────┬───────────────┘
                                 │ (Pass)

                  ┌──────────────────────────────┐
                  │   In-Flight Magnet Check     │
                  │ (Is either item magnetized?) │
                  └──────────────┬───────────────┘
                                 │ (No)

                  ┌──────────────────────────────┐
                  │    64-Bit Arithmetic Sum     │
                  │   S = (long) A + (long) B    │
                  └──────────────┬───────────────┘

                 ┌───────────────┴───────────────┐
                 │                               │
        S <= maxClumpSize                S > maxClumpSize
                 │                               │
                 ▼                               ▼
       ┌───────────────────┐           ┌───────────────────┐
       │   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 (Bounding Box) Horisontal

Vanilla mencari dalam kotak batas yang sangat sempit: $\text{AABB}_{\text{vanilla}} = \text{AABB}.\text{inflate}(0.5, 0.0, 0.5)$.

Item Clumps memperluas kotak batas horisontal secara dinamis menggunakan injeksi @Redirect tanpa alokasi memori tambahan:

$$\text{AABB}_{\text{clump}} = \text{boundingBox}.\text{inflate}(r, y, r)$$

Di mana:

  • $r = \text{DynamicGameRuleManager}.\text{getInt}(\text{level}, \text{MERGE_RADIUS}) \in [1, 10]$ blok.
  • $y = 0.0$ (ketinggian pencarian vertikal tetap dipertahankan secara ketat untuk mencegah item di lantai atau corong yang berbeda bertingkat saling bergabung).

2. Penjumlahan Integer 64-Bit & Keamanan Overflow Aritmatika

Ketika dua kelompok item raksasa bergabung di konfigurasi server besar (misalnya batas maksimum disetel ke 2 miliar), penjumlahan int 32-bit biasa dapat mengalami overflow menjadi bilangan negatif ($\text{Integer.MAX_VALUE} + 1 = -2,147,483,648$), merusak status entitas.

Item Clumps menghitung penjumlahan dalam presisi 64-bit:

$$S = (\text{long}),\text{thisCount} + (\text{long}),\text{otherCount}$$

  • Penyerapan Penuh ($S \le \text{maxClumpSize}$): $$\text{count}_{\text{merged}} = (\text{int}),S$$
  • Penyerapan Sebagian ($S > \text{maxClumpSize}$): $$\Delta = \text{maxClumpSize} - \text{thisCount}$$ $$\text{thisCount}' = \text{maxClumpSize}, \quad \text{otherCount}' = \text{otherCount} - \Delta$$

3. Ketelitian Komponen & Status

Item tidak akan pernah bergabung kecuali semua Komponen Data (sihir/enchantment, kerusakan durabilitas, nama kustom, trim zirah, efek ramuan) 100% identik bit-demi-bit:

$$\text{ItemStack}.\text{isSameItemSameComponents}(\text{stack}_A, \text{stack}_B) == \text{true}$$


💻 Implementasi Kode Sumber Java Asli

Dari ItemEntityMixin.java di Minecraft 26.2:

java
@Inject(method = "tryToMerge", at = @At("HEAD"), cancellable = true)
private void item_clumps$customMerge(ItemEntity other, CallbackInfo ci) {
    ItemStack thisStack = this.getItem();
    ItemStack otherStack = other.getItem();

    // Fast-path exit before GameRule lookups
    if (!Objects.equals(this.target, ((ItemEntityMixin)(Object)other).target) || 
        !ItemStack.isSameItemSameComponents(thisStack, otherStack)) {
        return;
    }

    if (!DynamicGameRuleManager.getBoolean(this.level(), ItemClumpsFabric.ENABLE_CLUMPING)) return;

    // Magnet mod in-flight protection
    if (net.fabricmc.loader.api.FabricLoader.getInstance().isModLoaded("magnet")) {
        try {
            java.lang.reflect.Method isMagnetizedMethod;
            try {
                isMagnetizedMethod = this.getClass().getMethod("ig_magnet$isMagnetized");
            } catch (NoSuchMethodException e) {
                isMagnetizedMethod = this.getClass().getMethod("ig$isMagnetized");
            }
            if ((boolean) isMagnetizedMethod.invoke(this) || (boolean) isMagnetizedMethod.invoke(other)) {
                ci.cancel();
                return;
            }
        } catch (Throwable ignored) {}
    }

    int thisCount = thisStack.getCount();
    int otherCount = otherStack.getCount();
    int maxClump = (ItemClumpsFabric.MAX_CLUMP_SIZE == null) 
        ? thisStack.getMaxStackSize() 
        : DynamicGameRuleManager.getInt(this.level(), ItemClumpsFabric.MAX_CLUMP_SIZE);

    long sum = (long) thisCount + (long) otherCount;
    if (sum > (long) maxClump) {
        int spaceLeft = maxClump - thisCount;
        if (spaceLeft > 0) {
            ItemStack thisCopy = thisStack.copyWithCount(maxClump);
            this.setItem(thisCopy);
            
            ItemStack otherCopy = otherStack.copyWithCount(otherCount - spaceLeft);
            other.setItem(otherCopy);

            this.pickupDelay = Math.max(this.pickupDelay, ((ItemEntityMixin)(Object)other).pickupDelay);
            this.age = Math.min(this.age, ((ItemEntityMixin)(Object)other).age);
        }
        ci.cancel();
        return;
    }

    // Full Merge: larger stack absorbs the smaller stack
    if (otherCount < thisCount) {
        ItemStack thisCopy = thisStack.copyWithCount((int) sum);
        this.setItem(thisCopy);
        this.pickupDelay = Math.max(this.pickupDelay, ((ItemEntityMixin)(Object)other).pickupDelay);
        this.age = Math.min(this.age, ((ItemEntityMixin)(Object)other).age);
        other.discard();
    } else {
        ItemStack otherCopy = otherStack.copyWithCount((int) sum);
        other.setItem(otherCopy);
        ((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();
}

🔗 Dokumentasi Terkait (MC 26.2)

Official documentation & web portal for Dasik Igaijinn mods.