mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-13 17:04:25 +00:00
refactor: port slotted tile trait to java
This commit is contained in:
1 parent
7894c98352
commit
39e0858006
7 files changed
+177
-87
No files matched your search
+24
-12
@@ -24,10 +24,10 @@ No trustworthy tool will produce a maintainable Java port automatically. A decom
|
||||
## Current status
|
||||
|
||||
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
|
||||
no-field `TPartialOcclusionTile` Java-trait pilot are complete. Direct Java source now survives the existing
|
||||
`registerJavaTrait` rewrite with its generated interface, super accessor, behavior, and class caching intact. The next
|
||||
checkpoint is the stateful `TSlottedTile`; see `JAVA_MIGRATION_PROFILE.md`.
|
||||
focused profile, first traversal optimization, complete redstone interaction helper unit, `MicroRecipe` port, and both
|
||||
Java-trait checkpoints are complete. `TPartialOcclusionTile` proved the no-field path; `TSlottedTile` now proves field
|
||||
accessors, per-instance initialization, rebinding/copying, callbacks, super bridges, and class caching. The next
|
||||
measured target is `TRedstoneTile`; 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
|
||||
@@ -329,7 +329,7 @@ and the already-ported registry again supports Schematica.
|
||||
- [x] Rewrite `TileMultipart` update/operate traversal without per-call collection allocation.
|
||||
- [ ] Rewrite redstone queries without closure allocation or `IntRef` boxing.
|
||||
- [x] Replace non-local returns in recipe scans with ordinary Java control flow.
|
||||
- [ ] Replace the remaining non-local return in the generated `TSlottedTile` slot scan.
|
||||
- [x] Replace the remaining non-local return in the generated `TSlottedTile` slot scan.
|
||||
- [x] Keep fastutil out of these paths because profiling did not justify another dependency or data structure.
|
||||
- [x] Re-profile the same scenarios and record both improvements and regressions.
|
||||
|
||||
@@ -337,9 +337,10 @@ Status: active. `operate` now preserves its captured-sequence mutation semantics
|
||||
and the six-interface `IRedstonePart`/`RedstoneInteractions$` unit is ported with its class list and descriptors intact.
|
||||
The comparison proves its allocation is owned by `scalatraits/TRedstoneTile.scala`, so that part waits for Phase 5.
|
||||
`MicroRecipe` is also Java: all five recipe forms and precedence are characterized, its published Scala façade remains,
|
||||
and its closure-backed scans and non-local returns are gone. `TPartialOcclusionTile` has completed the simple no-field
|
||||
Java-trait pilot. The remaining two hot-path items are stateful generated traits: port `TSlottedTile` as the field and
|
||||
lifecycle checkpoint before changing `TRedstoneTile` and re-running the redstone profile.
|
||||
and its closure-backed scans and non-local returns are gone. `TPartialOcclusionTile` completed the simple no-field
|
||||
Java-trait pilot, and `TSlottedTile` completed the stateful field/lifecycle checkpoint while removing the remaining
|
||||
slot-scan closures and exception-backed return. The remaining measured item is `TRedstoneTile`; characterize its exact
|
||||
generated surface and real consumers, then re-profile immediately before and after its Java port.
|
||||
|
||||
Exit condition: identified steady-state Scala allocation sites are removed with compatible results.
|
||||
|
||||
@@ -348,13 +349,13 @@ Exit condition: identified steady-state Scala allocation sites are removed with
|
||||
- [x] Characterize the direct class shape, generated interface, super dispatch, behavior, and class caching of a
|
||||
no-field pilot.
|
||||
- [x] Port one simple built-in trait as a pilot using `registerJavaTrait`.
|
||||
- [ ] Verify generated field accessors, initialization, copying, lifecycle callbacks, and class caching on the
|
||||
stateful `TSlottedTile` checkpoint. The no-field pilot proves methods/interfaces/caching but cannot prove state.
|
||||
- [x] Verify generated field accessors, initialization, copying, lifecycle callbacks, super bridges, and class caching
|
||||
on the stateful `TSlottedTile` checkpoint.
|
||||
- [ ] Convert remaining traits in small related groups.
|
||||
- [ ] Document or deliberately relax the Java trait restrictions only when a real trait requires it.
|
||||
- [ ] Preserve pass-through interface behavior.
|
||||
- [ ] Explicitly cover OpenComputers' `TSlottedTile.v_partMap` mutation/rebinding before that port, AE2's
|
||||
`TIInventoryTile.rebuildSlotMap` before the inventory trait, and ProjectRed/Extra Utilities behavior before
|
||||
- [ ] Keep the completed OpenComputers `TSlottedTile.v_partMap` mutation/rebinding case green; explicitly cover AE2's
|
||||
`TIInventoryTile.rebuildSlotMap` before the inventory trait and ProjectRed/Extra Utilities behavior before
|
||||
`TRedstoneTile`.
|
||||
|
||||
Exit condition: built-in behavior is implemented in Java while the established runtime composition mechanism remains stable.
|
||||
@@ -680,3 +681,14 @@ generated-trait compatibility work. Scala-runtime removal remains a later projec
|
||||
two behavior methods plus its super accessor, caches the generated class, and passes all 37 server tests.
|
||||
- The pilot raises the plain-JVM baseline to 145 tests. It deliberately proves no field or lifecycle behavior, so the
|
||||
next checkpoint is `TSlottedTile`, not a bulk conversion of the remaining traits.
|
||||
- Characterized `TSlottedTile` against untouched Scala with six focused Forge cases plus the existing live-world
|
||||
lifecycle fixture. The gate freezes its exact 13-method runtime interface, 27-slot per-instance initialization,
|
||||
getter/setter rebinding, copy identity, clear/remove/bind behavior, occupied-slot rejection, Scala value equality,
|
||||
generated field, super accessors, and class cache.
|
||||
- Ported `TSlottedTile` to a concrete Java mixin input with one public array field and ordinary loops. The runtime
|
||||
rewrite remains interface- and behavior-identical, while the four Scala range closures, `$class` artifact in the raw
|
||||
jar, and `NonLocalReturnControl` slot rejection disappear. All 145 plain-JVM and 43 Forge tests pass.
|
||||
- Found a Phase 5 source-build constraint: shipping binaries still see the same runtime interface, but a consumer
|
||||
recompiled directly against the untransformed dev jar sees the Java mixin input as a class. Consumers that name a
|
||||
generated trait therefore need a transformed compile stub or must avoid direct trait invocations; record this before
|
||||
claiming source-compatible downstream rebuilds.
|
||||
@@ -501,9 +501,10 @@ behavior:
|
||||
converting microblocks or Minecraft part implementations.
|
||||
6. Treat Scala runtime removal as downstream coordination work after the Java port, not as a requirement of it.
|
||||
|
||||
Current-branch generator verification: `ForgeEnvironmentSmokeTest` pins cached built-in `TSlottedTile` generation,
|
||||
an external Scala microblock trait registered by name like ProjectRed's `LightMicroblock`, direct-Java-source
|
||||
`TPartialOcclusionTile` rewriting and override dispatch, and server-only pass-through forwarding, overloading,
|
||||
Current-branch generator verification: `ForgeEnvironmentSmokeTest` pins exact direct-Java-source `TSlottedTile`
|
||||
interface/field generation, initialization, rebinding and caching, an external Scala microblock trait registered by
|
||||
name like ProjectRed's `LightMicroblock`, direct-Java-source `TPartialOcclusionTile` rewriting and override dispatch,
|
||||
and server-only pass-through forwarding, overloading,
|
||||
single-implementor selection, copying/rebinding, and removal cleanup. Full downstream mixed tiles and client-side
|
||||
selection remain Phase 7 integration cases.
|
||||
|
||||
|
||||
@@ -1407,3 +1407,55 @@ assumed safe from this result; `TSlottedTile` is the explicit stateful checkpoin
|
||||
- Complete plain-JVM suite: 145 tests, 0 failures, 0 errors.
|
||||
- Java 8 Forge dedicated-server suite: 37 tests, 0 failures, 0 errors.
|
||||
- Runtime reflection verifies the exact generated interface methods, no fields, override behavior, and class reuse.
|
||||
|
||||
## 2026-08-28 — TSlottedTile Java-trait port
|
||||
|
||||
This is the stateful `registerJavaTrait` checkpoint. OpenComputers casts generated tiles to this type, retrieves the
|
||||
public `v_partMap()` array, mutates matching entries in place, and calls `bindPart` to rebuild them. The frozen binary
|
||||
inventory contains that exact getter descriptor and no reference to `TSlottedTile$class`.
|
||||
|
||||
### Observable behavior
|
||||
|
||||
No known runtime divergence. Every generated tile receives its own 27-entry array. `copyFrom` still calls its super
|
||||
implementation first and then shares the source array by identity only when the source is slotted. `partMap` preserves
|
||||
normal array indexing. `clearParts` still clears both the superclass part list and every entry in the current array.
|
||||
|
||||
`partRemoved` still calls super first, acts only on `TSlottedPart`, scans exactly 27 slots, and uses Scala-style
|
||||
null-safe value equality; Java uses `Objects.equals` to preserve the last detail. `canAddPart` still rejects the first
|
||||
occupied masked slot before delegating to the base tile, while non-slotted and conflict-free parts delegate normally.
|
||||
`bindPart` still calls super first and fills each of the 27 positive masked slots. OpenComputers' external mutation and
|
||||
rebind pattern is exercised directly.
|
||||
|
||||
### Generated ABI and raw input divergence
|
||||
|
||||
At Forge runtime `TSlottedTile` remains a public interface with no fields and the exact same 13 abstract methods: six
|
||||
behavior methods, `v_partMap` getter/setter, and five super accessors. The generated composite still owns a
|
||||
`TMultiPart[] v_partMap` field, runs the 27-entry initializer for every instance, and reuses its class for equal trait
|
||||
sets. All 27 shipping consumer jars therefore retain their binary linkage.
|
||||
|
||||
The untransformed artifact necessarily changes shape. Scala emitted an interface, a static `$class` implementation
|
||||
helper, and four `$$anonfun$` range classes. Java emits one concrete `TileMultipart` subclass with a public array field,
|
||||
one no-arg constructor, and six overrides; `registerJavaTrait` creates the interface/helper at class-load time. No
|
||||
shipping consumer references the removed raw helper or closure classes.
|
||||
|
||||
This produces an accepted source-build limitation: code recompiled directly against the raw dev jar sees a class and
|
||||
public field, so it may emit `invokevirtual` or `getfield`; Forge later rewrites that owner to an interface, for which
|
||||
those opcodes are invalid. Existing binaries such as OpenComputers use `invokeinterface` and remain valid. A future
|
||||
downstream-source release needs either a transformed compile stub/API artifact or explicit avoidance of direct
|
||||
generated-trait calls; runtime binary compatibility does not by itself solve that development artifact problem.
|
||||
|
||||
### Performance boundary
|
||||
|
||||
Ordinary loops remove the four Scala `Range.foreach` closure classes and the `NonLocalReturnControl` used for occupied
|
||||
slot rejection. The retained focused profiler does not perform slotted placement, so this is a structural removal, not
|
||||
a numeric performance claim. No new dependency or generator change was needed.
|
||||
|
||||
### Validation
|
||||
|
||||
- `TSlottedTileFunctionalTest`: 6 Forge tests covering copy identity, non-slotted copy, external mutation/rebinding,
|
||||
bind/remove/clear semantics, value equality, and occupied/free/non-slotted placement.
|
||||
- `ForgeEnvironmentSmokeTest` verifies the exact 13-method runtime interface, generated field, distinct initialized
|
||||
arrays, setter rebinding, and class-cache identity.
|
||||
- Existing live-world lifecycle tests continue to cover add/remove slot caches and relocation of the generated tile.
|
||||
- Complete plain-JVM suite: 145 tests, 0 failures, 0 errors.
|
||||
- Java 8 Forge dedicated-server suite: 43 tests, 0 failures, 0 errors.
|
||||
+19
-12
@@ -12,7 +12,7 @@ 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`. 70 commits including the `TPartialOcclusionTile` characterization and Java port.
|
||||
Branch: `algent/java`. Base: `master`. 72 commits including both `TSlottedTile` commits.
|
||||
|
||||
## The one rule that matters
|
||||
|
||||
@@ -66,7 +66,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: **145 plain-JVM tests, 37 Forge server tests, all passing at their last completed runs.**
|
||||
Current baseline: **145 plain-JVM tests, 43 Forge server tests, all passing at their last completed runs.**
|
||||
|
||||
### ABI diff against the reference
|
||||
|
||||
@@ -189,14 +189,15 @@ All eight load-bearing `$class` helpers from the inventory, both registries, and
|
||||
`IDWriter`, `PartialOcclusionTest`/`JPartialOcclusion`, `TCuboidPart`/`JCuboidPart`, the `TNormalOcclusion` unit,
|
||||
`TFacePart`, the `TIconHitEffects` unit, `TItemMultiPart`/`JItemMultiPart`, `TEdgePart`, `Saw`, `MicroMaterialRegistry`,
|
||||
`MultiPartRegistry`, `TileMultipart`, `TMultiPart`, `TickScheduler`, `BlockMultipart`, the complete
|
||||
`IRedstonePart`/`RedstoneInteractions` unit, `MicroRecipe`, and the no-field `TPartialOcclusionTile` Java-trait pilot.
|
||||
`IRedstonePart`/`RedstoneInteractions` unit, `MicroRecipe`, and the `TPartialOcclusionTile` and `TSlottedTile`
|
||||
Java-trait checkpoints.
|
||||
|
||||
Plus the six marker interfaces: `TSlottedPart`, `IRandomDisplayTick`, `INeighborTileChange`, `TRandomUpdateTick`,
|
||||
`ISidedHollowConnect`, `IMicroMaterialRender`, plus `MultipartHelper`, `TileCache`, `PacketScheduler` and the `ControlKeyModifer` pair.
|
||||
|
||||
Both `package.scala` objects are gone, removed rather than ported. `MultipartRenderer` is done.
|
||||
|
||||
83 Java files, 45 Scala files, ~5,852 Scala lines left (non-blank; that is the metric this figure has always used).
|
||||
84 Java files, 44 Scala files, ~5,806 Scala lines left (non-blank; that is the metric this figure has always used).
|
||||
|
||||
## What is left, and in what order
|
||||
|
||||
@@ -243,16 +244,21 @@ plain-JVM tests freeze its input class and behavior. The Forge harness proves th
|
||||
to the exact three-method runtime interface, preserves override/super dispatch, and reuses the generated composite
|
||||
class. It has no fields or lifecycle callbacks, so this is not evidence for stateful traits.
|
||||
|
||||
`TSlottedTile` is now Java and supplies that stateful evidence. The generated runtime interface still has the exact 13
|
||||
methods, including public array getter/setter and five super accessors. Each tile receives a distinct 27-entry array;
|
||||
copying shares the source array exactly as before; external array mutation plus `bindPart`, clear/removal behavior,
|
||||
occupied-slot rejection, value equality, actual add/remove/move lifecycle, and generated-class caching are all green.
|
||||
|
||||
**Medium.** The `handler` packages on both sides, `ItemMicroPart`,
|
||||
`MicroblockPlacement`, `PlacementGrids`, `BlockMicroMaterial`, `MissingMicroMaterial`, `ConfigContent`,
|
||||
`DefaultContent`.
|
||||
|
||||
**Phase 5, needs the `registerJavaTrait` path.** `TileMultipartClient` and everything in `multipart/scalatraits/`.
|
||||
These are registered with the ASM generator; converting them is a different mechanism with documented restrictions.
|
||||
The no-field `TPartialOcclusionTile` pilot is complete without a generator change. Next characterize and port
|
||||
`TSlottedTile` as the stateful checkpoint. Freeze the generated getter/setter and 27-entry initialization, array identity
|
||||
through `copyFrom`, clearing/removal/binding, occupied-slot rejection, super-call order, class caching, and
|
||||
OpenComputers' direct `v_partMap()` mutation pattern before changing its source. Only then proceed to `TRedstoneTile`.
|
||||
The no-field and stateful checkpoints are complete without a generator change. Next characterize `TRedstoneTile`'s
|
||||
exact generated interface and every ProjectRed/Extra Utilities call, capture a fresh allocation baseline, port its
|
||||
queries with ordinary loops, and immediately rerun the same profile. Keep `TIInventoryTile` separate until AE2's
|
||||
`rebuildSlotMap` and inventory-field behavior are frozen.
|
||||
|
||||
**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.
|
||||
@@ -266,15 +272,16 @@ 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.
|
||||
- The completed `TPartialOcclusionTile` pilot is stateless. It does not prove the generator's field-to-accessor rewrite,
|
||||
constructor initialization injection, setter rebinding, or lifecycle ordering; `TSlottedTile` is the required
|
||||
checkpoint for those mechanisms.
|
||||
- A shipping consumer compiled against the old `TSlottedTile` interface remains binary-compatible because Forge still
|
||||
exposes that exact interface at runtime. A consumer recompiled against the untransformed dev jar instead sees the
|
||||
concrete Java mixin input and can emit class/field opcodes that are invalid after Forge rewrites it to an interface.
|
||||
Provide a transformed compile stub or downstream source guidance before claiming source-compatible rebuilds.
|
||||
- Microblock-specific NBT and packet payloads still need characterization immediately before that subsystem changes;
|
||||
the compact core tile/part fixture is complete.
|
||||
- `TileMultipart`'s `partList` still republishes an immutable Scala `Seq` on every mutation. `operate` no longer calls
|
||||
the Java port's copying `parts()` helper, but less frequent read and mutation paths still do. Optimize those only if
|
||||
a representative profile identifies them; their mutable snapshots are intentional at mutation sites.
|
||||
- The focused redstone allocation remains 80.5 B per three-query iteration. It is generated by
|
||||
`scalatraits/TRedstoneTile.scala`, not `RedstoneInteractions`; address it after the stateful `TSlottedTile` checkpoint.
|
||||
`scalatraits/TRedstoneTile.scala`, not `RedstoneInteractions`; it is now the next measured target.
|
||||
- Phase 1 never properly started. GTNHLib is currently commented out in `dependencies.gradle`; it had been added at
|
||||
`api` scope to satisfy a test compile rather than because a migration change needed it.
|
||||
@@ -122,8 +122,10 @@ requires the Phase 5 `registerJavaTrait` path and must not be smuggled into this
|
||||
characterized, and ordinary loops replaced its range/closure scans and exception-backed non-local returns. The focused
|
||||
server workload does not craft recipes, so no timing claim is made for that structural removal.
|
||||
|
||||
The remaining measured redstone allocation and slot-scan non-local return live in generated traits. The simpler
|
||||
`TPartialOcclusionTile` Java-source pilot is complete and has no profile claim because this workload does not exercise
|
||||
partial-occlusion placement. It proves direct Java input, generated method/super dispatch, and class caching, but has no
|
||||
fields or lifecycle callbacks. Use `TSlottedTile` as the stateful generator checkpoint, then port `TRedstoneTile` and
|
||||
re-run this workload immediately before and after that change.
|
||||
The generated-trait checkpoints are complete. `TPartialOcclusionTile` proved the no-field path; `TSlottedTile` proved
|
||||
field/accessor generation, initialization, copying, lifecycle behavior, and caching. Its ordinary loops remove four
|
||||
Scala range closures and the exception-backed slot-scan return structurally, but the focused workload has no slotted
|
||||
placement phase, so no numeric performance claim is made for that port.
|
||||
|
||||
The remaining measured redstone allocation lives in `TRedstoneTile`. Capture a fresh baseline with this exact workload,
|
||||
characterize ProjectRed and Extra Utilities behavior, port the queries, and rerun immediately afterward.
|
||||
@@ -0,0 +1,71 @@
|
||||
package codechicken.multipart.scalatraits;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import codechicken.multipart.TMultiPart;
|
||||
import codechicken.multipart.TSlottedPart;
|
||||
import codechicken.multipart.TileMultipart;
|
||||
|
||||
/** Mixin implementation for slotted parts. */
|
||||
public class TSlottedTile extends TileMultipart {
|
||||
|
||||
public TMultiPart[] v_partMap = new TMultiPart[27];
|
||||
|
||||
@Override
|
||||
public void copyFrom(TileMultipart that) {
|
||||
super.copyFrom(that);
|
||||
if (that instanceof TSlottedTile) {
|
||||
v_partMap = ((TSlottedTile) that).v_partMap;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TMultiPart partMap(int slot) {
|
||||
return v_partMap[slot];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearParts() {
|
||||
super.clearParts();
|
||||
Arrays.fill(v_partMap, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partRemoved(TMultiPart part, int position) {
|
||||
super.partRemoved(part, position);
|
||||
if (part instanceof TSlottedPart) {
|
||||
for (int index = 0; index < 27; index++) {
|
||||
if (Objects.equals(partMap(index), part)) {
|
||||
v_partMap[index] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAddPart(TMultiPart part) {
|
||||
if (part instanceof TSlottedPart) {
|
||||
int slotMask = ((TSlottedPart) part).getSlotMask();
|
||||
for (int index = 0; index < v_partMap.length; index++) {
|
||||
if ((slotMask & (1 << index)) != 0 && partMap(index) != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.canAddPart(part);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindPart(TMultiPart part) {
|
||||
super.bindPart(part);
|
||||
if (part instanceof TSlottedPart) {
|
||||
int slotMask = ((TSlottedPart) part).getSlotMask();
|
||||
for (int index = 0; index < 27; index++) {
|
||||
if ((slotMask & (1 << index)) > 0) {
|
||||
v_partMap[index] = part;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package codechicken.multipart.scalatraits
|
||||
|
||||
import codechicken.multipart.TileMultipart
|
||||
import codechicken.multipart.TMultiPart
|
||||
import codechicken.multipart.TSlottedPart
|
||||
|
||||
/** Mixin implementation for TSlottedPart. Puts parts into a slot array for
|
||||
* quick access at the cost of memory consumption
|
||||
*/
|
||||
trait TSlottedTile extends TileMultipart {
|
||||
var v_partMap = new Array[TMultiPart](27)
|
||||
|
||||
override def copyFrom(that: TileMultipart) {
|
||||
super.copyFrom(that)
|
||||
if (that.isInstanceOf[TSlottedTile])
|
||||
v_partMap = that.asInstanceOf[TSlottedTile].v_partMap
|
||||
}
|
||||
|
||||
override def partMap(slot: Int) = v_partMap(slot)
|
||||
|
||||
override def clearParts() {
|
||||
super.clearParts()
|
||||
for (i <- 0 until v_partMap.length)
|
||||
v_partMap(i) = null
|
||||
}
|
||||
|
||||
override def partRemoved(part: TMultiPart, p: Int) {
|
||||
super.partRemoved(part, p)
|
||||
if (part.isInstanceOf[TSlottedPart])
|
||||
for (i <- 0 until 27)
|
||||
if (partMap(i) == part)
|
||||
v_partMap(i) = null
|
||||
}
|
||||
|
||||
override def canAddPart(part: TMultiPart): Boolean = {
|
||||
if (part.isInstanceOf[TSlottedPart]) {
|
||||
val slotMask = part.asInstanceOf[TSlottedPart].getSlotMask
|
||||
for (i <- 0 until v_partMap.length)
|
||||
if ((slotMask & 1 << i) != 0 && partMap(i) != null)
|
||||
return false
|
||||
}
|
||||
|
||||
return super.canAddPart(part)
|
||||
}
|
||||
|
||||
override def bindPart(part: TMultiPart) {
|
||||
super.bindPart(part)
|
||||
if (part.isInstanceOf[TSlottedPart]) {
|
||||
val mask = part.asInstanceOf[TSlottedPart].getSlotMask
|
||||
for (i <- 0 until 27)
|
||||
if ((mask & 1 << i) > 0)
|
||||
v_partMap(i) = part
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user