Skip to content

Mécaniques d'Agrégation en Méga-Piles (MC 26.2)

Ce document fournit une analyse technique et mathématique approfondie de l'agrégation d'items, du calcul de rayon de recherche, de la prévention de débordement 64 bits et des optimisations de mémoire dans Item Clumps pour Minecraft 26.2.


📊 Fiche Technique de Fonctionnalité

PropriétéSpécification
Nom du SystèmeAgrégateur de Méga-Piles d'Items au Sol
Classe Ciblenet.minecraft.world.entity.item.ItemEntity
Plafond par Défaut9 999 items (Configurable jusqu'à $2,147,483,647$)
Rayon de Recherche ($r$)Horizontal $1\text{ à }10\text{ blocs}$ (Défaut : $1\text{ bloc}$)
Surcharge par Tick$0.00\text{ ms}$ sur items immobiles (appel uniquement sur setItem())
Allocation MémoireZéro allocation d'objets lors de la recherche et absorption (copyWithCount(int))
GameRules de Contrôleitem_clumps:enable_clumping, item_clumps:max_clump_size, item_clumps:merge_radius

⚙️ Fonctionnement de l'Agrégation en Méga-Piles

Dans Minecraft Vanilla, les items au sol appellent mergeWithNeighbours() à chaque tick pour chercher des items identiques à proximité. Vanilla interdit strictement la fusion si la quantité dépasse itemStack.getMaxStackSize() (généralement 64, ou 16 pour les perles de l'Ender et les œufs).

Item Clumps intercepte cette vérification via ItemEntityMixin.java afin de lever cette contrainte artificielle tout en préservant strictement la sécurité des composants de données.

                  ┌──────────────────────────────┐
                  │    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.│
       └───────────────────┘           └───────────────────┘

📐 Formules Mathématiques & Calculs de Précision

1. Élargissement Horizontal de la Boîte Englobante

Vanilla utilise une boîte de collision minuscule : $\text{AABB}_{\text{vanilla}} = \text{AABB}.\text{inflate}(0.5, 0.0, 0.5)$.

Item Clumps élargit dynamiquement la boîte de collision horizontale via une injection @Redirect sans allocation mémoire :

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

Où :

  • $r = \text{DynamicGameRuleManager}.\text{getInt}(\text{level}, \text{MERGE_RADIUS}) \in [1, 10]$ blocs.
  • $y = 0.0$ (la hauteur de recherche verticale est strictement préservée pour éviter que des items sur des étages différents ou au-dessus d'entonnoirs distincts ne fusionnent).

2. Somme Entière 64-Bit & Sécurité Contre le Débordement Arithmétique

Lorsque deux amas massifs fusionnent sur de gros serveurs (ex. plafond à 2 milliards), l'addition classique en entier 32 bits peut déborder en nombres négatifs ($\text{Integer.MAX_VALUE} + 1 = -2,147,483,648$), corrompant les entités.

Item Clumps calcule la somme avec une précision 64 bits :

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

  • Absorption Complète ($S \le \text{maxClumpSize}$) : $$\text{count}_{\text{merged}} = (\text{int}),S$$
  • Absorption Partielle ($S > \text{maxClumpSize}$) : $$\Delta = \text{maxClumpSize} - \text{thisCount}$$ $$\text{thisCount}' = \text{maxClumpSize}, \quad \text{otherCount}' = \text{otherCount} - \Delta$$

3. Rigueur des Composants & de l'État

Les items ne fusionnent jamais à moins que tous leurs composants de données (enchantements, durabilité restante, noms, finitions d'armure, effets de potion) ne soient strictement identiques au bit près :

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


💻 Implémentation du Code Source Java Réel

Depuis ItemEntityMixin.java dans 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();
}

🔗 Documentation Associée (MC 26.2)

Official documentation & web portal for Dasik Igaijinn mods.