mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-12 08:27:50 +00:00
refactor: port Saw to Java
Extracts the Saw trait out of ItemSaw.scala into a Java interface and retains the Saw$class bridge for ProjRed. ItemSaw itself stays Scala. The interface is descriptor-identical to the reference, the bridge adds only a private constructor, and the emitted class-file set for this area is unchanged. Item does not declare getMaxCuttingStrength, so it becomes a real default method. One consequence is worth noting: ItemSaw previously carried a Scala trait forwarder for it and now inherits the default instead, so it no longer declares that method. Three jars reference the ItemSaw type but none reference its members, and an invokevirtual would still resolve through the interface default. This is the first port that changed the declared members of a class it did not touch. Unlike TFacePart$class and TEdgePart$class, which hold constants and ignore overrides, this bridge dispatches getCuttingStrength back through the interface so an implementor's override is honoured. Both behaviors are preserved as found and asserted separately. First port outside codechicken.multipart. Validated with 65 plain-JVM tests, a clean build, and the Java 8 Forge dedicated-server suite.
This commit is contained in:
1 parent
844efac5a2
commit
52ff8ff460
4 files changed
+87
-14
No files matched your search
@@ -443,3 +443,49 @@ No in-repo Scala needed changing.
|
||||
- Complete plain-JVM suite: 61 tests, 0 failures, 0 errors.
|
||||
- Clean `spotlessApply checkstyleTest build`: passing.
|
||||
- Java 8 Forge dedicated-server suite: 3 tests, 0 failures, 0 errors.
|
||||
|
||||
## 2026-08-14 — Saw Java port
|
||||
|
||||
The first port outside `codechicken.multipart`. `Saw` was declared in `ItemSaw.scala`; only the trait is extracted,
|
||||
and `ItemSaw` itself stays Scala.
|
||||
|
||||
### Observable behavior
|
||||
|
||||
No known divergence. `getMaxCuttingStrength` still asks the saw about a stack of itself, so the stack handed to
|
||||
`getCuttingStrength` wraps the saw and has size 1, and the result still follows an implementor's
|
||||
`getCuttingStrength` override.
|
||||
|
||||
### Default method, and a shape change on ItemSaw
|
||||
|
||||
`Item` does not declare `getMaxCuttingStrength`, so it becomes a real Java `default`.
|
||||
|
||||
Consequence worth recording: `ItemSaw` previously carried a Scala trait forwarder for `getMaxCuttingStrength` and now
|
||||
inherits the default instead, so it no longer declares that method. Three jars reference the `ItemSaw` type
|
||||
(IguanaTweaksTConstruct, ProjectBlue, endercore) but none reference any of its members, and an `invokevirtual` against
|
||||
`ItemSaw.getMaxCuttingStrength` would still resolve through the interface default. `harvestLevel` and
|
||||
`getCuttingStrength` are unchanged.
|
||||
|
||||
This is the first time a port changed the declared members of a class it did not touch. Watch for it whenever a trait
|
||||
default is introduced on a type with concrete Scala implementors.
|
||||
|
||||
### Unlike the other constant bridges
|
||||
|
||||
`Saw$class.getMaxCuttingStrength` dispatches `getCuttingStrength` back through the interface, so an implementor's
|
||||
override is honoured even when the bridge is called directly. `TFacePart$class` and `TEdgePart$class` hold constants
|
||||
and deliberately ignore overrides. Both behaviors are preserved as found and are asserted separately.
|
||||
|
||||
### Supported JVM API
|
||||
|
||||
- `Saw` is descriptor-identical to the reference.
|
||||
- `Saw$class` keeps both statics for ProjRed and adds only a private constructor. Its body casts to `Item` to build
|
||||
the stack, exactly as the reference bytecode did.
|
||||
- The emitted class-file set for this area is unchanged.
|
||||
|
||||
### Validation
|
||||
|
||||
- `SawCharacterizationTest`: 3 tests, 0 failures, 0 errors, unchanged from the Scala baseline.
|
||||
- `SawBinaryCompatibilityTest`: 1 test, 0 failures, 0 errors, where the fixture reports its strength only if handed a
|
||||
stack that wraps itself.
|
||||
- Complete plain-JVM suite: 65 tests, 0 failures, 0 errors.
|
||||
- Clean `spotlessApply checkstyleTest build`: passing.
|
||||
- Java 8 Forge dedicated-server suite: 3 tests, 0 failures, 0 errors.
|
||||
@@ -21,20 +21,6 @@ import net.minecraft.client.renderer.texture.{TextureMap, IIconRegister}
|
||||
import codechicken.lib.render.uv.UVTranslation
|
||||
import codechicken.microblock.handler.MicroblockProxy
|
||||
|
||||
/** Interface for items that are 'saws'
|
||||
*/
|
||||
trait Saw extends Item {
|
||||
|
||||
/** The maximum harvest level that some version of this saw is capable of
|
||||
* cutting
|
||||
*/
|
||||
def getMaxCuttingStrength: Int = getCuttingStrength(new ItemStack(this))
|
||||
|
||||
/** The harvest level this saw is capable of cutting
|
||||
*/
|
||||
def getCuttingStrength(item: ItemStack): Int
|
||||
}
|
||||
|
||||
class ItemSaw(sawTag: ConfigTag, val harvestLevel: Int) extends Item with Saw {
|
||||
{
|
||||
val maxDamage =
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package codechicken.microblock;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* Binary bridge for Scala implementations compiled against the original trait. Their forwarders call this static
|
||||
* directly, so the body cannot delegate back to the instance method without recursing.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class Saw$class {
|
||||
|
||||
private Saw$class() {}
|
||||
|
||||
public static int getMaxCuttingStrength(Saw saw) {
|
||||
return saw.getCuttingStrength(new ItemStack((Item) saw));
|
||||
}
|
||||
|
||||
public static void $init$(Saw saw) {}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package codechicken.microblock;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* Interface for items that are 'saws'.
|
||||
* <p>
|
||||
* Item does not declare getMaxCuttingStrength, so it can safely be a default method. Implementors must extend
|
||||
* {@link Item}; the default casts to it in order to build a stack of itself, exactly as the reference did.
|
||||
*/
|
||||
public interface Saw {
|
||||
|
||||
/** The maximum harvest level that some version of this saw is capable of cutting. */
|
||||
default int getMaxCuttingStrength() {
|
||||
return getCuttingStrength(new ItemStack((Item) this));
|
||||
}
|
||||
|
||||
/** The harvest level this saw is capable of cutting. */
|
||||
int getCuttingStrength(ItemStack item);
|
||||
}
|
||||
Reference in new issue
Block a user