mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-13 17:04:25 +00:00
refactor: port inventory tile trait to java
Keep TIInventoryTile as AE2's public rebuild API and JInventoryTile as the registered mixin input, preserving both generated interfaces and flattened sided-slot behavior.
This commit is contained in:
1 parent
48cbb7ff3e
commit
4e8d238b57
6 files changed
+391
-144
No files matched your search
+6
-5
@@ -25,10 +25,11 @@ No trustworthy tool will produce a maintainable Java port automatically. A decom
|
||||
|
||||
The binary and source-level consumer audits, low-coupling Phase 3 queue, audit-derived immediate compatibility gate,
|
||||
focused profile, first traversal optimization, complete redstone interaction helper unit, `MicroRecipe` port, and the
|
||||
first five Java-trait ports are complete. `TPartialOcclusionTile` proved the no-field path, `TSlottedTile` proved state
|
||||
first six Java-trait ports are complete. `TPartialOcclusionTile` proved the no-field path, `TSlottedTile` proved state
|
||||
and lifecycle rewriting, `TRedstoneTile` removed the measured redstone allocation, `TTileChangeTile` exercised mutable
|
||||
state plus inherited access, and `TFluidHandlerTile` preserved ordered Forge fluid distribution. All retain their exact
|
||||
runtime interfaces. See `JAVA_MIGRATION_PROFILE.md`.
|
||||
state plus inherited access, `TFluidHandlerTile` preserved ordered Forge fluid distribution, and
|
||||
`TIInventoryTile`/`JInventoryTile` preserved AE2's direct rebuild linkage plus flattened sided inventory routing. All
|
||||
retain their exact runtime interfaces. See `JAVA_MIGRATION_PROFILE.md`.
|
||||
|
||||
That audit found and this branch has now repaired one existing regression: Schematica 1.12.6 reflects the original private
|
||||
`MultiPartRegistry$` field `codechicken$multipart$MultiPartRegistry$$typeMap` and casts it to a Scala mutable map. The
|
||||
@@ -360,7 +361,7 @@ Exit condition: identified steady-state Scala allocation sites are removed with
|
||||
- [ ] Preserve pass-through interface behavior.
|
||||
- [x] Keep the completed OpenComputers `TSlottedTile.v_partMap` mutation/rebinding case green and cover ProjectRed/
|
||||
Extra Utilities behavior before `TRedstoneTile`.
|
||||
- [ ] Explicitly cover AE2's `TIInventoryTile.rebuildSlotMap` before the inventory trait.
|
||||
- [x] Explicitly cover AE2's `TIInventoryTile.rebuildSlotMap` before the inventory trait.
|
||||
|
||||
Exit condition: built-in behavior is implemented in Java while the established runtime composition mechanism remains stable.
|
||||
|
||||
@@ -416,7 +417,7 @@ The work should move from low to high risk while keeping a buildable mixed-langu
|
||||
Extensive tests are both possible and recommended here. Their purpose is not to prove that the current Scala behavior is ideal; it is to make its observable behavior explicit before translation, so every later difference is intentional.
|
||||
|
||||
The repository now has a Java-8-compatible JUnit Jupiter suite and a small Forge integration runner. The current
|
||||
baseline is 141 plain-JVM tests and 37 Forge server tests. Minecraft 1.7.10 does not provide the modern GameTest
|
||||
baseline is 153 plain-JVM tests and 70 Forge server tests. Minecraft 1.7.10 does not provide the modern GameTest
|
||||
framework, so game-dependent coverage continues through the existing narrow Forge harness rather than a second test
|
||||
framework.
|
||||
|
||||
|
||||
@@ -1640,3 +1640,56 @@ multipart fluid distribution. This is a structural removal, not a throughput or
|
||||
- Complete plain-JVM suite: 153 tests, 0 failures, 0 errors.
|
||||
- Java 8 Forge dedicated-server suite: 62 tests, 0 failures, 0 errors.
|
||||
- The frozen consumer inventory and audited source consumers contain no `TFluidHandlerTile` reference.
|
||||
|
||||
## 2026-08-30 — TIInventoryTile/JInventoryTile Java-trait port
|
||||
|
||||
AE2 is the load-bearing consumer for this port. `CableBusPart.notifyNeighbors` checks a generated tile with
|
||||
`instanceof TIInventoryTile` and directly invokes `rebuildSlotMap()`. The registered trait input is separately named
|
||||
`JInventoryTile`; preserving only one of those types would break either registration or AE2 linkage.
|
||||
|
||||
### Observable behavior
|
||||
|
||||
No known runtime divergence. Each generated tile starts with distinct empty inventory-list and slot-map instances.
|
||||
Binding appends only `IInventory` parts in order, removal deletes the matching inventory, and clear empties both the
|
||||
superclass part list and inventory state. Copying from another inventory tile shares its inventory list by identity and
|
||||
rebuilds a distinct slot map; copying from a plain tile leaves both current references untouched.
|
||||
|
||||
The slot map still flattens every inventory in list order and routes each global slot to its original inventory and
|
||||
local index. The fixed name, custom-name flag, stack limit, usability and no-op open/close behavior are unchanged.
|
||||
Sided access still exposes only `ISidedInventory` slots, while its global base advances across every inventory;
|
||||
insert/extract checks still delegate to sided inventories and return true for ordinary inventories.
|
||||
|
||||
### Generated ABI and raw input divergence
|
||||
|
||||
At Forge runtime `TIInventoryTile` remains a public interface extending exactly `ISidedInventory`, with no fields and
|
||||
the exact same 28 methods: 20 behavior/inventory methods, four public state accessors, and four super accessors.
|
||||
`JInventoryTile` remains a public child interface with no fields and the exact same 36 methods, adding four private-
|
||||
field accessors and four `JInventoryTile` super bridges. The generated composite still owns the two private fields
|
||||
`codechicken$multipart$scalatraits$JInventoryTile$$invList` and
|
||||
`codechicken$multipart$scalatraits$JInventoryTile$$slotMap`, with `LinkedList` and `scala.Tuple2[]` descriptors.
|
||||
|
||||
The raw dev artifact now contains a Java interface `TIInventoryTile`, a concrete Java `JInventoryTile` mixin input,
|
||||
and package-private `JInventoryTileAccess` instead of the Scala interface, `$class` helper and concrete forwarding
|
||||
class. No frozen consumer references `TIInventoryTile$class` or names `JInventoryTile`; AE2's load-bearing
|
||||
`TIInventoryTile.rebuildSlotMap()` descriptor is unchanged. As with the other Java-trait ports, consumers compiling
|
||||
against the untransformed dev jar should use a transformed compile stub when they name the registered mixin type.
|
||||
|
||||
### Transformer constraint
|
||||
|
||||
The Java-trait stack analyzer has no case for JVM opcode `NEWARRAY` (`188`). Creating the primitive result array in
|
||||
`getAccessibleSlotsFromSide` initially failed trait registration with `scala.MatchError: 188`. The method now collects
|
||||
the same ordered boxed slots and delegates only the final `int[]` allocation/copy to package-private
|
||||
`JInventoryTileAccess`. Reference-array allocation remains inside the trait because its `ANEWARRAY` opcode is already
|
||||
supported. The helper adds no public surface.
|
||||
|
||||
### Validation
|
||||
|
||||
- `TIInventoryTileFunctionalTest`: 7 Forge tests covering list/map lifecycle and identity, flattened routing, the
|
||||
direct AE2-shaped rebuild call, fixed metadata, sided global offsets, and insert/extract delegation.
|
||||
- `ForgeEnvironmentSmokeTest.generatesAndCachesInventoryTileClassWithBothPublicTraitInterfaces`: exact 28- and
|
||||
36-method runtime interfaces, inheritance, generated private fields, distinct initialization, setter rebinding, and
|
||||
generated-class reuse.
|
||||
- All eight tests passed against the untouched Scala implementation first and pass unchanged after the port.
|
||||
- Complete plain-JVM suite: 153 tests, 0 failures, 0 errors.
|
||||
- Java 8 Forge dedicated-server suite: 70 tests, 0 failures, 0 errors.
|
||||
- Raw `javap` descriptors for both public types match the reference, including `scala.Tuple2[]` state accessors.
|
||||
+21
-13
@@ -12,8 +12,8 @@ what breaks, and what is left. The other documents hold the reasoning.
|
||||
| `JAVA_MIGRATION_MANUAL_CHECKS.md` | What no automated test can cover, and must be checked by hand in a client |
|
||||
| `JAVA_MIGRATION_PROFILE.md` | The focused baseline, first measured result, findings, and exact rerun command |
|
||||
|
||||
Branch: `algent/java`. Base: `master`. 81 commits including separate characterization and port commits for
|
||||
`TFluidHandlerTile`.
|
||||
Branch: `algent/java`. Base: `master`. 83 commits including separate characterization and port commits for
|
||||
`TIInventoryTile`/`JInventoryTile`.
|
||||
|
||||
## The one rule that matters
|
||||
|
||||
@@ -67,7 +67,7 @@ awk -F'"' '/<testsuite /{t+=$4;f+=$8;e+=$10} END{print "tests="t" failures="f" e
|
||||
grep -o 'tests="[0-9]*" skipped="[0-9]*" failures="[0-9]*" errors="[0-9]*"' run/server/junit-out/TEST-*.xml
|
||||
```
|
||||
|
||||
Current baseline: **153 plain-JVM tests, 62 Forge server tests, all passing at their last completed runs.**
|
||||
Current baseline: **153 plain-JVM tests, 70 Forge server tests, all passing at their last completed runs.**
|
||||
|
||||
### ABI diff against the reference
|
||||
|
||||
@@ -193,6 +193,10 @@ as trait-owned state without checking its owner. `TFluidHandlerTile` therefore k
|
||||
writes in package-private `TFluidHandlerTileAccess`. A static helper outside the transformed class is enough when no
|
||||
trait-to-superclass cast is involved.
|
||||
|
||||
**Java traits cannot allocate primitive arrays.** The stack analyzer has no case for JVM opcode `NEWARRAY` and throws
|
||||
`MatchError: 188` while registering the trait. `JInventoryTile` therefore converts its collected sided slots to
|
||||
`int[]` in package-private `JInventoryTileAccess`. Reference arrays use `ANEWARRAY` and remain safe inside traits.
|
||||
|
||||
**Type the access shim's parameters `Object`.** `TTileChangeTileAccess` first typed them as the trait itself and cast
|
||||
to `TileMultipart` inside. Because the untransformed trait extends `TileMultipart`, javac elided the cast, and once
|
||||
Forge rewrote the trait to an interface the verifier rejected the `getfield`. `TRedstoneTileAccess` only escapes this
|
||||
@@ -210,7 +214,7 @@ All eight load-bearing `$class` helpers from the inventory, both registries, and
|
||||
`TFacePart`, the `TIconHitEffects` unit, `TItemMultiPart`/`JItemMultiPart`, `TEdgePart`, `Saw`, `MicroMaterialRegistry`,
|
||||
`MultiPartRegistry`, `TileMultipart`, `TMultiPart`, `TickScheduler`, `BlockMultipart`, the complete
|
||||
`IRedstonePart`/`RedstoneInteractions` unit, `MicroRecipe`, and the `TPartialOcclusionTile`, `TSlottedTile`, and
|
||||
`TRedstoneTile`, `TTileChangeTile`, and `TFluidHandlerTile` Java-trait ports.
|
||||
`TRedstoneTile`, `TTileChangeTile`, `TFluidHandlerTile`, and `TIInventoryTile`/`JInventoryTile` Java-trait ports.
|
||||
|
||||
Plus the six marker interfaces: `TSlottedPart`, `IRandomDisplayTick`, `INeighborTileChange`, `TRandomUpdateTick`,
|
||||
`ISidedHollowConnect`, `IMicroMaterialRender`, plus `MultipartHelper`, `TileCache`, `PacketScheduler` and the `ControlKeyModifer` pair.
|
||||
@@ -225,7 +229,7 @@ across the port. It is also where the two shim constraints in the gotchas list w
|
||||
`rayTraceAll`'s index production is now characterized, closing the gap the read-path cleanup left: the index written
|
||||
into `ExtendedMOP.data` is what `reduceMOP` hands back to every click, activate, harvest and pick block.
|
||||
|
||||
87 Java files, 41 Scala files, ~5,556 Scala lines left (non-blank; that is the metric this figure has always used).
|
||||
89 Java files, 40 Scala files, ~5,453 Scala lines left (non-blank; that is the metric this figure has always used).
|
||||
|
||||
## What is left, and in what order
|
||||
|
||||
@@ -294,6 +298,13 @@ field initialization, setter rebinding, and class-cache behavior. No shipping co
|
||||
`$class` or closure classes. A narrow access helper is required for `FluidStack.amount` because the transformer treats
|
||||
all direct field reads inside a Java trait as trait-owned state.
|
||||
|
||||
`TIInventoryTile` and `JInventoryTile` are now Java without collapsing their distinct roles. AE2 still casts generated
|
||||
tiles to the public 28-method `TIInventoryTile` interface and calls `rebuildSlotMap`; the registered `JInventoryTile`
|
||||
still rewrites to a 36-method child interface carrying its private-state accessors and both super-bridge layers. Seven
|
||||
behavior tests freeze inventory-list sharing, flattened routing, sided offsets and the direct rebuild call. The
|
||||
generated composite retains its two private prefixed fields and per-tile initialization. Primitive `int[]` creation is
|
||||
isolated in `JInventoryTileAccess` because the transformer cannot analyze `NEWARRAY`.
|
||||
|
||||
**Medium.** The `handler` packages on both sides, `ItemMicroPart`,
|
||||
`MicroblockPlacement`, `PlacementGrids`, `BlockMicroMaterial`, `MissingMicroMaterial`, `ConfigContent`,
|
||||
`DefaultContent`.
|
||||
@@ -302,13 +313,10 @@ all direct field reads inside a Java trait as trait-owned state.
|
||||
`multipart/scalatraits/`. The no-field, stateful, measured hot-query, and inherited-member cases are all complete
|
||||
without a generator change.
|
||||
|
||||
Take `TIInventoryTile` next. AE2's `CableBusPart.notifyNeighbors` does `tile() instanceof TIInventoryTile` then
|
||||
calls `rebuildSlotMap()`, so the runtime interface must keep that method public; freeze that plus the inventory-field
|
||||
behavior first. Note it is `JInventoryTile`, the concrete class, that is registered — do not collapse the two, because
|
||||
AE2 casts to the trait.
|
||||
|
||||
`TRandomDisplayTickTile` is registered client-only and reads inherited `partList`, so it needs both a shim and the
|
||||
client-side test work. It also extends `TileMultipartClient`, which is still Scala.
|
||||
Take the client tile pair next: `TileMultipartClient` and `TRandomDisplayTickTile`. The latter is the only Scala file
|
||||
left in `multipart/scalatraits/`, is registered client-only, and reads inherited `partList`, so it needs both an access
|
||||
shim and client-side characterization rather than relying on the dedicated-server harness. Audit the base trait's
|
||||
consumer-visible shape before deciding whether to port them together.
|
||||
|
||||
**Phase 6/7, last.** `Microblock` and the microblock shape hierarchy, `MicroblockGenerator`, `MultipartGenerator`, and
|
||||
all of `multipart/asm/`. The ASM subsystem should be last; freeze generated-class fixtures before touching it.
|
||||
@@ -322,7 +330,7 @@ all of `multipart/asm/`. The ASM subsystem should be last; freeze generated-clas
|
||||
work and is required before release claims about real TPS.
|
||||
- The server side of flag-sensitive pass-through registration is automated; client-side exclusion still belongs to
|
||||
the packaged-client/manual compatibility run.
|
||||
- Shipping consumers compiled against the old `TSlottedTile` and `TRedstoneTile` interfaces remain binary-compatible
|
||||
- Shipping consumers compiled against the old `TSlottedTile`, `TRedstoneTile`, and `TIInventoryTile` interfaces remain binary-compatible
|
||||
because Forge still exposes those exact interfaces at runtime. A consumer recompiled against the untransformed dev
|
||||
jar instead sees concrete Java mixin inputs and can emit class/field opcodes that are invalid after Forge rewrites
|
||||
them to interfaces. Provide a transformed compile stub or downstream source guidance before claiming
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
package codechicken.multipart.scalatraits;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.ISidedInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.multipart.TMultiPart;
|
||||
import codechicken.multipart.TileMultipart;
|
||||
import scala.Tuple2;
|
||||
|
||||
/** Registered Java trait input that distributes inventory access among multipart inventories. */
|
||||
public class JInventoryTile extends TileMultipart implements TIInventoryTile {
|
||||
|
||||
private LinkedList<IInventory> invList = new LinkedList<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Tuple2<IInventory, Object>[] slotMap = (Tuple2<IInventory, Object>[]) new Tuple2[0];
|
||||
|
||||
@Override
|
||||
public LinkedList<IInventory> invList() {
|
||||
return invList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invList_$eq(LinkedList<IInventory> inventories) {
|
||||
invList = inventories;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tuple2<IInventory, Object>[] slotMap() {
|
||||
return slotMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void slotMap_$eq(Tuple2<IInventory, Object>[] slots) {
|
||||
slotMap = slots;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codechicken$multipart$scalatraits$TIInventoryTile$$super$copyFrom(TileMultipart that) {
|
||||
super.copyFrom(that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codechicken$multipart$scalatraits$TIInventoryTile$$super$bindPart(TMultiPart part) {
|
||||
super.bindPart(part);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codechicken$multipart$scalatraits$TIInventoryTile$$super$partRemoved(TMultiPart part, int position) {
|
||||
super.partRemoved(part, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void codechicken$multipart$scalatraits$TIInventoryTile$$super$clearParts() {
|
||||
super.clearParts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyFrom(TileMultipart that) {
|
||||
codechicken$multipart$scalatraits$TIInventoryTile$$super$copyFrom(that);
|
||||
if (that instanceof TIInventoryTile) {
|
||||
invList = ((TIInventoryTile) that).invList();
|
||||
rebuildSlotMap();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindPart(TMultiPart part) {
|
||||
codechicken$multipart$scalatraits$TIInventoryTile$$super$bindPart(part);
|
||||
if (part instanceof IInventory) {
|
||||
invList.add((IInventory) part);
|
||||
rebuildSlotMap();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partRemoved(TMultiPart part, int position) {
|
||||
codechicken$multipart$scalatraits$TIInventoryTile$$super$partRemoved(part, position);
|
||||
if (part instanceof IInventory) {
|
||||
invList.remove(part);
|
||||
rebuildSlotMap();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void clearParts() {
|
||||
codechicken$multipart$scalatraits$TIInventoryTile$$super$clearParts();
|
||||
invList.clear();
|
||||
slotMap = (Tuple2<IInventory, Object>[]) new Tuple2[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void rebuildSlotMap() {
|
||||
int totalSlots = 0;
|
||||
for (IInventory inventory : invList) {
|
||||
totalSlots += inventory.getSizeInventory();
|
||||
}
|
||||
|
||||
Tuple2<IInventory, Object>[] rebuilt = (Tuple2<IInventory, Object>[]) new Tuple2[totalSlots];
|
||||
int index = 0;
|
||||
for (IInventory inventory : invList) {
|
||||
for (int slot = 0; slot < inventory.getSizeInventory(); slot++) {
|
||||
rebuilt[index++] = new Tuple2<IInventory, Object>(inventory, Integer.valueOf(slot));
|
||||
}
|
||||
}
|
||||
slotMap = rebuilt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSizeInventory() {
|
||||
return slotMap.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlot(int slot) {
|
||||
Tuple2<IInventory, Object> entry = slotMap[slot];
|
||||
return entry._1().getStackInSlot(((Number) entry._2()).intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack decrStackSize(int slot, int amount) {
|
||||
Tuple2<IInventory, Object> entry = slotMap[slot];
|
||||
return entry._1().decrStackSize(((Number) entry._2()).intValue(), amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStackInSlotOnClosing(int slot) {
|
||||
Tuple2<IInventory, Object> entry = slotMap[slot];
|
||||
return entry._1().getStackInSlotOnClosing(((Number) entry._2()).intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInventorySlotContents(int slot, ItemStack stack) {
|
||||
Tuple2<IInventory, Object> entry = slotMap[slot];
|
||||
entry._1().setInventorySlotContents(((Number) entry._2()).intValue(), stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInventoryName() {
|
||||
return "Multipart Inventory";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInventoryName() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInventoryStackLimit() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseableByPlayer(EntityPlayer player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openInventory() {}
|
||||
|
||||
@Override
|
||||
public void closeInventory() {}
|
||||
|
||||
@Override
|
||||
public boolean isItemValidForSlot(int slot, ItemStack stack) {
|
||||
Tuple2<IInventory, Object> entry = slotMap[slot];
|
||||
return entry._1().isItemValidForSlot(((Number) entry._2()).intValue(), stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getAccessibleSlotsFromSide(int side) {
|
||||
List<Integer> accessibleSlots = new ArrayList<>();
|
||||
int base = 0;
|
||||
for (IInventory inventory : invList) {
|
||||
if (inventory instanceof ISidedInventory) {
|
||||
int[] localSlots = ((ISidedInventory) inventory).getAccessibleSlotsFromSide(side);
|
||||
for (int localSlot : localSlots) {
|
||||
accessibleSlots.add(Integer.valueOf(localSlot + base));
|
||||
}
|
||||
}
|
||||
base += inventory.getSizeInventory();
|
||||
}
|
||||
|
||||
return JInventoryTileAccess.toIntArray(accessibleSlots);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInsertItem(int slot, ItemStack stack, int side) {
|
||||
Tuple2<IInventory, Object> entry = slotMap[slot];
|
||||
IInventory inventory = entry._1();
|
||||
return !(inventory instanceof ISidedInventory)
|
||||
|| ((ISidedInventory) inventory).canInsertItem(((Number) entry._2()).intValue(), stack, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExtractItem(int slot, ItemStack stack, int side) {
|
||||
Tuple2<IInventory, Object> entry = slotMap[slot];
|
||||
IInventory inventory = entry._1();
|
||||
return !(inventory instanceof ISidedInventory)
|
||||
|| ((ISidedInventory) inventory).canExtractItem(((Number) entry._2()).intValue(), stack, side);
|
||||
}
|
||||
}
|
||||
|
||||
/** Keeps primitive-array allocation outside the generated trait transformer. */
|
||||
final class JInventoryTileAccess {
|
||||
|
||||
private JInventoryTileAccess() {}
|
||||
|
||||
static int[] toIntArray(List<Integer> values) {
|
||||
int[] result = new int[values.size()];
|
||||
for (int index = 0; index < result.length; index++) {
|
||||
result[index] = values.get(index).intValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package codechicken.multipart.scalatraits;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.ISidedInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import codechicken.multipart.TMultiPart;
|
||||
import codechicken.multipart.TileMultipart;
|
||||
import scala.Tuple2;
|
||||
|
||||
/** Consumer-facing inventory contract implemented by the generated multipart tile. */
|
||||
public interface TIInventoryTile extends ISidedInventory {
|
||||
|
||||
void codechicken$multipart$scalatraits$TIInventoryTile$$super$copyFrom(TileMultipart that);
|
||||
|
||||
void codechicken$multipart$scalatraits$TIInventoryTile$$super$bindPart(TMultiPart part);
|
||||
|
||||
void codechicken$multipart$scalatraits$TIInventoryTile$$super$partRemoved(TMultiPart part, int position);
|
||||
|
||||
void codechicken$multipart$scalatraits$TIInventoryTile$$super$clearParts();
|
||||
|
||||
LinkedList<IInventory> invList();
|
||||
|
||||
void invList_$eq(LinkedList<IInventory> inventories);
|
||||
|
||||
Tuple2<IInventory, Object>[] slotMap();
|
||||
|
||||
void slotMap_$eq(Tuple2<IInventory, Object>[] slots);
|
||||
|
||||
void copyFrom(TileMultipart that);
|
||||
|
||||
void bindPart(TMultiPart part);
|
||||
|
||||
void partRemoved(TMultiPart part, int position);
|
||||
|
||||
void clearParts();
|
||||
|
||||
void rebuildSlotMap();
|
||||
|
||||
@Override
|
||||
int getSizeInventory();
|
||||
|
||||
@Override
|
||||
ItemStack getStackInSlot(int slot);
|
||||
|
||||
@Override
|
||||
ItemStack decrStackSize(int slot, int amount);
|
||||
|
||||
@Override
|
||||
ItemStack getStackInSlotOnClosing(int slot);
|
||||
|
||||
@Override
|
||||
void setInventorySlotContents(int slot, ItemStack stack);
|
||||
|
||||
@Override
|
||||
String getInventoryName();
|
||||
|
||||
@Override
|
||||
boolean hasCustomInventoryName();
|
||||
|
||||
@Override
|
||||
int getInventoryStackLimit();
|
||||
|
||||
@Override
|
||||
boolean isUseableByPlayer(EntityPlayer player);
|
||||
|
||||
@Override
|
||||
void openInventory();
|
||||
|
||||
@Override
|
||||
void closeInventory();
|
||||
|
||||
@Override
|
||||
boolean isItemValidForSlot(int slot, ItemStack stack);
|
||||
|
||||
@Override
|
||||
int[] getAccessibleSlotsFromSide(int side);
|
||||
|
||||
@Override
|
||||
boolean canInsertItem(int slot, ItemStack stack, int side);
|
||||
|
||||
@Override
|
||||
boolean canExtractItem(int slot, ItemStack stack, int side);
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
package codechicken.multipart.scalatraits
|
||||
|
||||
import net.minecraft.inventory.{IInventory, ISidedInventory}
|
||||
import codechicken.multipart.{TMultiPart, TileMultipart}
|
||||
import java.util.LinkedList
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import scala.collection.JavaConversions._
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
trait TIInventoryTile extends TileMultipart with ISidedInventory {
|
||||
var invList = new LinkedList[IInventory]()
|
||||
var slotMap = Array[(IInventory, Int)]()
|
||||
|
||||
override def copyFrom(that: TileMultipart) {
|
||||
super.copyFrom(that)
|
||||
if (that.isInstanceOf[TIInventoryTile]) {
|
||||
invList = that.asInstanceOf[TIInventoryTile].invList
|
||||
rebuildSlotMap()
|
||||
}
|
||||
}
|
||||
|
||||
override def bindPart(part: TMultiPart) {
|
||||
super.bindPart(part)
|
||||
if (part.isInstanceOf[IInventory]) {
|
||||
invList += part.asInstanceOf[IInventory]
|
||||
rebuildSlotMap()
|
||||
}
|
||||
}
|
||||
|
||||
override def partRemoved(part: TMultiPart, p: Int) {
|
||||
super.partRemoved(part, p)
|
||||
if (part.isInstanceOf[IInventory]) {
|
||||
invList -= part.asInstanceOf[IInventory]
|
||||
rebuildSlotMap()
|
||||
}
|
||||
}
|
||||
|
||||
override def clearParts() {
|
||||
super.clearParts()
|
||||
invList.clear()
|
||||
slotMap = Array()
|
||||
}
|
||||
|
||||
def rebuildSlotMap() {
|
||||
slotMap = Array.ofDim(invList.map(_.getSizeInventory).sum)
|
||||
var i = 0
|
||||
for (inv <- invList; s <- 0 until inv.getSizeInventory) {
|
||||
slotMap(i) = (inv, s)
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
def getSizeInventory: Int = slotMap.length
|
||||
|
||||
def getStackInSlot(i: Int) = {
|
||||
val (inv, slot) = slotMap(i)
|
||||
inv.getStackInSlot(slot)
|
||||
}
|
||||
|
||||
def decrStackSize(i: Int, j: Int) = {
|
||||
val (inv, slot) = slotMap(i)
|
||||
inv.decrStackSize(slot, j)
|
||||
}
|
||||
|
||||
def getStackInSlotOnClosing(i: Int) = {
|
||||
val (inv, slot) = slotMap(i)
|
||||
inv.getStackInSlotOnClosing(slot)
|
||||
}
|
||||
|
||||
def setInventorySlotContents(i: Int, itemstack: ItemStack) = {
|
||||
val (inv, slot) = slotMap(i)
|
||||
inv.setInventorySlotContents(slot, itemstack)
|
||||
}
|
||||
|
||||
def getInventoryName = "Multipart Inventory"
|
||||
|
||||
def hasCustomInventoryName = false
|
||||
|
||||
def getInventoryStackLimit = 64
|
||||
|
||||
def isUseableByPlayer(entityplayer: EntityPlayer) = true
|
||||
|
||||
def openInventory() {}
|
||||
|
||||
def closeInventory() {}
|
||||
|
||||
def isItemValidForSlot(i: Int, itemstack: ItemStack) = {
|
||||
val (inv, slot) = slotMap(i)
|
||||
inv.isItemValidForSlot(slot, itemstack)
|
||||
}
|
||||
|
||||
def getAccessibleSlotsFromSide(side: Int) = {
|
||||
val buf = new ArrayBuffer[Int]()
|
||||
var base = 0
|
||||
for (inv <- invList) {
|
||||
inv match {
|
||||
case isided: ISidedInventory =>
|
||||
buf ++= isided.getAccessibleSlotsFromSide(side).map(_ + base)
|
||||
case _ =>
|
||||
}
|
||||
base += inv.getSizeInventory
|
||||
}
|
||||
buf.toArray
|
||||
}
|
||||
|
||||
def canInsertItem(i: Int, itemstack: ItemStack, j: Int) = {
|
||||
val (inv, slot) = slotMap(i)
|
||||
inv match {
|
||||
case isided: ISidedInventory => isided.canInsertItem(slot, itemstack, j)
|
||||
case _ => true
|
||||
}
|
||||
}
|
||||
|
||||
def canExtractItem(i: Int, itemstack: ItemStack, j: Int) = {
|
||||
val (inv, slot) = slotMap(i)
|
||||
inv match {
|
||||
case isided: ISidedInventory => isided.canExtractItem(slot, itemstack, j)
|
||||
case _ => true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** To handle obfuscation issues, this is registered as a java trait.
|
||||
*/
|
||||
class JInventoryTile extends TileMultipart with TIInventoryTile {}
|
||||
Reference in new issue
Block a user