Skip to content

Mecánicas de agrupación en mega-stacks (MC 26.1.2)

Este documento proporciona un desglose técnico y matemático de la agregación de objetos en el suelo, el cálculo del radio de búsqueda y la fusión de entidades en Item Clumps para Minecraft 26.1.2.


📊 Ficha técnica de características

PropiedadEspecificación
Nombre del sistemaAgregador de mega-stacks de objetos en suelo
Clase objetivonet.minecraft.world.entity.item.ItemEntity
Límite de fusión predeterminado9,999 objetos (Configurable hasta $2,147,483,647$)
Radio de búsqueda ($r$)Horizontal $1\text{ a }10\text{ bloques}$ (Predeterminado: $1\text{ bloque}$)
Inyección de radio@ModifyArgs en AABB.inflate(DDD)
GameRules de controlitem_clumps:enable_clumping, item_clumps:max_clump_size, item_clumps:merge_radius

⚙️ Cómo funciona la agregación en mega-stacks

En Minecraft Vanilla, los objetos caídos llaman a mergeWithNeighbours() durante su ciclo de ticks, buscando objetos cercanos del mismo tipo. Sin embargo, Vanilla prohíbe estrictamente la fusión si el recuento de objetos de la entidad de destino excediera itemStack.getMaxStackSize() (normalmente 64).

Item Clumps intercepta esta comprobación mediante ItemEntityMixin.java para eliminar esta restricción mientras preserva una rigurosa seguridad de componentes de datos.

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

📐 Fórmulas matemáticas y cálculo de precisión

1. Expansión horizontal del cuadro delimitador (@ModifyArgs)

$$\text{args.set}(0, r), \quad \text{args.set}(2, r)$$

Donde:

  • $r = \text{DynamicGameRuleManager}.\text{getInt}(\text{level}, \text{MERGE_RADIUS}) \in [1, 10]$ bloques.
  • El índice de altura vertical ($1$) no se modifica, preservando la separación vertical entre los diferentes niveles de piso.

2. Cálculo de transferencia de recuento de objetos

  • Absorción completa ($S \le \text{maxClumpSize}$): $$\text{count}_{\text{merged}} = \text{thisCount} + \text{otherCount}$$
  • Absorción parcial ($S > \text{maxClumpSize}$): $$\Delta = \text{maxClumpSize} - \text{thisCount}$$ $$\text{thisCount}' = \text{maxClumpSize}, \quad \text{otherCount}' = \text{otherCount} - \Delta$$

💻 Implementación del código fuente Java real

De ItemEntityMixin.java en 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();
}

🔗 Documentación relacionada (MC 26.1.2)

Official documentation & web portal for Dasik Igaijinn mods.