Mega-Stapel-Aggregationsmechanik (MC 26.1.2)
Dieses Dokument liefert eine technische und mathematische Aufschlüsselung der Item-Aggregation am Boden, der Suchradius-Mathematik und der Entitätsverschmelzung in Item Clumps für Minecraft 26.1.2.
📊 Feature-Infobox
| Eigenschaft | Spezifikation |
|---|---|
| Systemname | Mega-Stapel-Aggregator für Boden-Items |
| Zielklasse | net.minecraft.world.entity.item.ItemEntity |
| Standard-Verschmelzungslimit | 9.999 Items (Konfigurierbar bis $2.147.483.647$) |
| Suchradius ($r$) | Horizontal $1\text{ bis }10\text{ Blöcke}$ (Standard: $1\text{ Block}$) |
| Radius-Injektion | @ModifyArgs auf AABB.inflate(DDD) |
| Steuernde GameRules | item_clumps:enable_clumping, item_clumps:max_clump_size, item_clumps:merge_radius |
⚙️ Funktionsweise der Mega-Stapel-Aggregation
In Vanilla Minecraft suchen gedroppte Items jeden Tick via mergeWithNeighbours() nach gleichen Items. Vanilla untersagt das Verschmelzen jedoch, wenn die Anzahl itemStack.getMaxStackSize() (meist 64) überschreiten würde.
Item Clumps hebt diese Beschränkung über ItemEntityMixin.java auf, während die Datenkomponentenintegrität strikt gewahrt bleibt.
┌──────────────────────────────┐
│ 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.│
└───────────────────┘ └───────────────────┘📐 Mathematische Formeln & Präzisionsberechnungen
1. Horizontale Bounding-Box-Vergrößerung (@ModifyArgs)
$$\text{args.set}(0, r), \quad \text{args.set}(2, r)$$
Wobei:
- $r = \text{DynamicGameRuleManager}.\text{getInt}(\text{level}, \text{MERGE_RADIUS}) \in [1, 10]$ Blöcke.
- Der vertikale Höhenindex ($1$) bleibt unverändert, wodurch die Trennung zwischen verschiedenen Stockwerken gewahrt bleibt.
2. Mathematik des Itemmengen-Transfers
- Vollständige Absorption ($S \le \text{maxClumpSize}$): $$\text{count}_{\text{merged}} = \text{thisCount} + \text{otherCount}$$
- Partielle Absorption ($S > \text{maxClumpSize}$): $$\Delta = \text{maxClumpSize} - \text{thisCount}$$ $$\text{thisCount}' = \text{maxClumpSize}, \quad \text{otherCount}' = \text{otherCount} - \Delta$$
💻 Reale Java-Quellcode-Implementierung
Aus ItemEntityMixin.java in 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();
}