mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-12 08:27:50 +00:00
refactor: port BlockMultipart to Java
Converts the Block face of the API and its companion object. BlockMultipart$ is descriptor-identical to the reference including reduceMOP's Tuple2 return, and the class differs by exactly one descriptor: hasTileEntity$default$1, the accessor Scala emits for a default argument, which Java has no equivalent for. No jar references any member of this class. addCollisionBoxesToList keeps its descriptor; only its generic signature changes from Scala's List<?> to the raw List that vanilla's Block actually declares, which is the more faithful override. getClientTile returns TileMultipartClient, a Scala trait extending TileMultipart, so in bytecode it is a bare interface carrying none of the class's members; addHitEffects casts to reach the part list. Third occurrence of that pattern after JIconHitEffects and TRandomUpdateTick. Four anonfun classes removed, including two nested inner closures. Validated with 90 plain-JVM tests, a clean build, and the Java 8 Forge dedicated-server suite. Most of this class needs a player, a ray trace or a renderer, so breaking, selection, collision, pick block, activation and particles stay on the manual checklist.
This commit is contained in:
1 parent
213ff0c8ea
commit
cd5b801878
4 files changed
+462
-449
No files matched your search
@@ -796,3 +796,53 @@ Accepted divergence: the five `$$anonfun$` classes under `WorldTickScheduler.pos
|
||||
and the `preTick`/`postTick` pair all run for every server tick of the suite.
|
||||
- Scheduled and random tick firing over time, and the chunk NBT round trip, are not asserted by any test and stay on
|
||||
the manual checklist.
|
||||
|
||||
## 2026-08-14 — BlockMultipart Java port
|
||||
|
||||
The Block face of the API. No jar references any member of it; it appears only as the return type of
|
||||
`MultipartProxy.block()`, which ProjRed and buildcraft-compat call, and by name in Waila and guidenh reflection.
|
||||
|
||||
### Observable behavior
|
||||
|
||||
No known divergence. Every override still resolves the tile through `getTile`, which continues to return null both
|
||||
when the tile is not a multipart tile and when its part list is empty, so the null branches and the empty-tile branches
|
||||
stay merged exactly as before. `isAir` still reports true for a missing tile, `getExplosionResistance` still returns 0
|
||||
rather than reaching the throwing max on an empty tile, and the redstone queries still flip the side with `side ^ 1`.
|
||||
|
||||
`reduceMOP` still returns the struck part's index alongside a rebased `ExtendedMOP` carrying that part's own data and
|
||||
the original distance.
|
||||
|
||||
### Supported JVM API
|
||||
|
||||
- `BlockMultipart$` is descriptor-identical to the reference, including `reduceMOP`'s `scala.Tuple2` return.
|
||||
- `BlockMultipart` differs by exactly one descriptor, discussed below. `addCollisionBoxesToList` keeps its descriptor;
|
||||
only its generic signature changes from Scala's `List<?>` to the raw `List` that vanilla's `Block` actually
|
||||
declares, which is the more faithful override.
|
||||
- The four static forwarders `getTile`, `getClientTile`, `reduceMOP` and `drawHighlight` are unchanged.
|
||||
|
||||
### Removed API
|
||||
|
||||
`hasTileEntity$default$1()`, the accessor Scala emits for the default argument on `hasTileEntity(meta: Int = 0)`.
|
||||
Java has no default arguments, so it disappears. It is a compiler artifact of the default parameter, not API, and no
|
||||
jar references any member of this class.
|
||||
|
||||
### TileMultipartClient is a bare interface here
|
||||
|
||||
`getClientTile` returns `TileMultipartClient`, which is a Scala trait extending `TileMultipart`, so in bytecode it is
|
||||
an interface carrying none of the class's members. `addHitEffects` casts to `TileMultipart` to reach the part list.
|
||||
This is the third occurrence of the pattern, after `JIconHitEffects` and `TRandomUpdateTick`.
|
||||
|
||||
### Compiler artifacts
|
||||
|
||||
Accepted divergence: the four `$$anonfun$` classes under `getDrops` and `addCollisionBoxesToList`, including the two
|
||||
nested inner closures, are removed. The Java loops produce no replacement classes.
|
||||
|
||||
### Validation
|
||||
|
||||
- Complete plain-JVM suite: 90 tests, 0 failures, 0 errors.
|
||||
- Clean `spotlessApply checkstyleTest build`: passing.
|
||||
- Java 8 Forge dedicated-server suite: 5 tests, 0 failures, 0 errors. The block is registered during startup and is
|
||||
the block every generated multipart tile is placed against, so registration and `hasTileEntity` run for real.
|
||||
- Almost everything else in this class needs a player, a ray trace or a renderer. Block breaking, selection boxes,
|
||||
collision, pick block, activation, particles and light are all on the manual checklist and are the reason that
|
||||
checklist exists.
|
||||
@@ -0,0 +1,35 @@
|
||||
package codechicken.multipart;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import codechicken.lib.raytracer.ExtendedMOP;
|
||||
import scala.Tuple2;
|
||||
|
||||
/**
|
||||
* Scala companion singleton. Retained because compiled Scala consumers read MODULE$ and call these instance methods.
|
||||
*/
|
||||
public final class BlockMultipart$ {
|
||||
|
||||
public static final BlockMultipart$ MODULE$ = new BlockMultipart$();
|
||||
|
||||
private BlockMultipart$() {}
|
||||
|
||||
public TileMultipart getTile(IBlockAccess world, int x, int y, int z) {
|
||||
return BlockMultipart.getTile(world, x, y, z);
|
||||
}
|
||||
|
||||
public TileMultipartClient getClientTile(IBlockAccess world, int x, int y, int z) {
|
||||
return BlockMultipart.getClientTile(world, x, y, z);
|
||||
}
|
||||
|
||||
public Tuple2<Object, ExtendedMOP> reduceMOP(MovingObjectPosition hit) {
|
||||
return BlockMultipart.reduceMOP(hit);
|
||||
}
|
||||
|
||||
public boolean drawHighlight(World world, EntityPlayer player, MovingObjectPosition hit, float frame) {
|
||||
return BlockMultipart.drawHighlight(world, player, hit, frame);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
package codechicken.multipart;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.MapColor;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.particle.EffectRenderer;
|
||||
import net.minecraft.client.renderer.texture.IIconRegister;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import codechicken.lib.raytracer.ExtendedMOP;
|
||||
import codechicken.lib.raytracer.RayTracer;
|
||||
import codechicken.lib.render.TextureUtils;
|
||||
import codechicken.lib.vec.Cuboid6;
|
||||
import scala.Tuple2;
|
||||
|
||||
/** Block class for all multiparts, should be internal use only. */
|
||||
public class BlockMultipart extends Block {
|
||||
|
||||
public BlockMultipart() {
|
||||
super(new Material(MapColor.stoneColor));
|
||||
}
|
||||
|
||||
public static TileMultipart getTile(IBlockAccess world, int x, int y, int z) {
|
||||
net.minecraft.tileentity.TileEntity t = world.getTileEntity(x, y, z);
|
||||
if (t instanceof TileMultipart && !((TileMultipart) t).jPartList().isEmpty()) {
|
||||
return (TileMultipart) t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static TileMultipartClient getClientTile(IBlockAccess world, int x, int y, int z) {
|
||||
net.minecraft.tileentity.TileEntity t = world.getTileEntity(x, y, z);
|
||||
if (t instanceof TileMultipartClient && !((TileMultipart) t).jPartList().isEmpty()) {
|
||||
return (TileMultipartClient) t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Splits a hit into the index of the part it struck and a MOP rebased onto that part's own data. */
|
||||
public static Tuple2<Object, ExtendedMOP> reduceMOP(MovingObjectPosition hit) {
|
||||
ExtendedMOP ehit = (ExtendedMOP) hit;
|
||||
Tuple2<Object, Object> data = ExtendedMOP.getData(hit);
|
||||
return new Tuple2<>(data._1(), new ExtendedMOP(ehit, data._2(), ehit.dist));
|
||||
}
|
||||
|
||||
public static boolean drawHighlight(World world, EntityPlayer player, MovingObjectPosition hit, float frame) {
|
||||
TileMultipart tile = getTile(world, hit.blockX, hit.blockY, hit.blockZ);
|
||||
if (tile == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Tuple2<Object, ExtendedMOP> reduced = reduceMOP(hit);
|
||||
int index = (Integer) reduced._1();
|
||||
if (tile.jPartList().get(index).drawHighlight(reduced._2(), player, frame)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
tile.jPartList().get(index).collisionRayTrace(RayTracer.getStartVec(player), RayTracer.getEndVec(player));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTileEntity(int meta) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockSolid(IBlockAccess world, int x, int y, int z, int side) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile != null && tile.isSolid(side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideSolid(IBlockAccess world, int x, int y, int z, ForgeDirection side) {
|
||||
return isBlockSolid(world, x, y, z, side.ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceTorchOnTop(World world, int x, int y, int z) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile != null && tile.canPlaceTorchOnTop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighborBlockChange(World world, int x, int y, int z, Block block) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
if (tile != null) {
|
||||
tile.onNeighborBlockChange();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedMOP collisionRayTrace(World world, int x, int y, int z, Vec3 start, Vec3 end) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile == null ? null : tile.collisionRayTrace(start, end);
|
||||
}
|
||||
|
||||
public Iterable<ExtendedMOP> rayTraceAll(World world, int x, int y, int z, Vec3 start, Vec3 end) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile == null ? java.util.Collections.<ExtendedMOP>emptyList() : tile.rayTraceAll(start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z) {
|
||||
MovingObjectPosition hit = RayTracer.retraceBlock(world, player, x, y, z);
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
|
||||
if (hit == null || tile == null) {
|
||||
dropAndDestroy(world, x, y, z);
|
||||
return true;
|
||||
}
|
||||
|
||||
Tuple2<Object, ExtendedMOP> reduced = reduceMOP(hit);
|
||||
int index = (Integer) reduced._1();
|
||||
if (world.isRemote) {
|
||||
tile.jPartList().get(index).addDestroyEffects(reduced._2(), Minecraft.getMinecraft().effectRenderer);
|
||||
return true;
|
||||
}
|
||||
|
||||
tile.harvestPart(index, reduced._2(), player);
|
||||
return world.getTileEntity(x, y, z) == null;
|
||||
}
|
||||
|
||||
public void dropAndDestroy(World world, int x, int y, int z) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
if (tile != null && !world.isRemote) {
|
||||
tile.dropItems(getDrops(world, x, y, z, 0, 0));
|
||||
}
|
||||
|
||||
world.setBlockToAir(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int quantityDropped(int meta, int fortune, Random random) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<ItemStack> getDrops(World world, int x, int y, int z, int meta, int fortune) {
|
||||
ArrayList<ItemStack> ai = new ArrayList<>();
|
||||
if (world.isRemote) {
|
||||
return ai;
|
||||
}
|
||||
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
if (tile != null) {
|
||||
for (TMultiPart part : tile.jPartList()) {
|
||||
for (ItemStack item : part.getDrops()) {
|
||||
ai.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB ebb, List list$,
|
||||
Entity entity) {
|
||||
List<AxisAlignedBB> list = list$;
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
if (tile != null) {
|
||||
for (TMultiPart part : tile.jPartList()) {
|
||||
for (Cuboid6 c : part.getCollisionBoxes()) {
|
||||
AxisAlignedBB aabb = c.toAABB().offset(x, y, z);
|
||||
if (aabb.intersectsWith(ebb)) {
|
||||
list.add(aabb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addHitEffects(World world, MovingObjectPosition hit, EffectRenderer effectRenderer) {
|
||||
TileMultipartClient tile = getClientTile(world, hit.blockX, hit.blockY, hit.blockZ);
|
||||
if (tile != null) {
|
||||
// TileMultipartClient is a Scala trait, so it is a bare interface here and carries no TileMultipart
|
||||
// members.
|
||||
TileMultipart parts = (TileMultipart) tile;
|
||||
Tuple2<Object, ExtendedMOP> reduced = reduceMOP(hit);
|
||||
int index = (Integer) reduced._1();
|
||||
if (index < parts.jPartList().size()) {
|
||||
parts.jPartList().get(index).addHitEffects(reduced._2(), effectRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addDestroyEffects(World world, int x, int y, int z, int s, EffectRenderer effectRenderer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean renderAsNormalBlock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaqueCube() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderType() {
|
||||
return TileMultipart.renderID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir(IBlockAccess world, int x, int y, int z) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile == null || tile.jPartList().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplaceable(IBlockAccess world, int x, int y, int z) {
|
||||
return isAir(world, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderBlockPass() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRenderInPass(int pass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getPickBlock(MovingObjectPosition hit, World world, int x, int y, int z) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
if (tile != null) {
|
||||
if (!(hit instanceof ExtendedMOP)) {
|
||||
return null;
|
||||
}
|
||||
Tuple2<Object, ExtendedMOP> reduced = reduceMOP(hit);
|
||||
return tile.jPartList().get((Integer) reduced._1()).pickItem(reduced._2());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPlayerRelativeBlockHardness(EntityPlayer player, World world, int x, int y, int z) {
|
||||
MovingObjectPosition hit = RayTracer.retraceBlock(world, player, x, y, z);
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
if (hit != null && tile != null) {
|
||||
Tuple2<Object, ExtendedMOP> reduced = reduceMOP(hit);
|
||||
return tile.jPartList().get((Integer) reduced._1()).getStrength(reduced._2(), player) / 30f;
|
||||
}
|
||||
|
||||
return 1 / 100f;
|
||||
}
|
||||
|
||||
/** Kludge to set PROTECTED blockIcon to a blank icon. */
|
||||
@Override
|
||||
public void registerBlockIcons(IIconRegister register) {
|
||||
net.minecraft.util.IIcon icon = TextureUtils.getBlankIcon(16, register);
|
||||
setBlockTextureName(icon.getIconName());
|
||||
super.registerBlockIcons(register);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue(IBlockAccess world, int x, int y, int z) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile == null ? 0 : tile.getLightValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomDisplayTick(World world, int x, int y, int z, Random random) {
|
||||
TileMultipartClient tile = getClientTile(world, x, y, z);
|
||||
if (tile != null) {
|
||||
tile.randomDisplayTick(random);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX,
|
||||
float hitY, float hitZ) {
|
||||
MovingObjectPosition hit = RayTracer.retraceBlock(world, player, x, y, z);
|
||||
if (hit == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
if (tile == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Tuple2<Object, ExtendedMOP> reduced = reduceMOP(hit);
|
||||
return tile.jPartList().get((Integer) reduced._1()).activate(player, reduced._2(), player.getHeldItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockClicked(World world, int x, int y, int z, EntityPlayer player) {
|
||||
MovingObjectPosition hit = RayTracer.retraceBlock(world, player, x, y, z);
|
||||
if (hit == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
if (tile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Tuple2<Object, ExtendedMOP> reduced = reduceMOP(hit);
|
||||
tile.jPartList().get((Integer) reduced._1()).click(player, reduced._2(), player.getHeldItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isProvidingStrongPower(IBlockAccess world, int x, int y, int z, int side) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile == null ? 0 : tile.strongPowerLevel(side ^ 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isProvidingWeakPower(IBlockAccess world, int x, int y, int z, int side) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile == null ? 0 : tile.weakPowerLevel(side ^ 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConnectRedstone(IBlockAccess world, int x, int y, int z, int side) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile != null && tile.canConnectRedstone(side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityCollidedWithBlock(World world, int x, int y, int z, Entity entity) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
if (tile != null) {
|
||||
tile.onEntityCollision(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighborChange(IBlockAccess world, int x, int y, int z, int tileX, int tileY, int tileZ) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
if (tile != null) {
|
||||
tile.onNeighborTileChange(tileX, tileY, tileZ);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getExplosionResistance(Entity entity, World world, int x, int y, int z, double explosionX,
|
||||
double explosionY, double explosionZ) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile == null ? 0 : tile.getExplosionResistance(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getWeakChanges(IBlockAccess world, int x, int y, int z) {
|
||||
TileMultipart tile = getTile(world, x, y, z);
|
||||
return tile != null && tile.getWeakChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canProvidePower() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,449 +0,0 @@
|
||||
package codechicken.multipart
|
||||
|
||||
import java.util.List
|
||||
import java.lang.Iterable
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.material.{MapColor, Material}
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.util.AxisAlignedBB
|
||||
import net.minecraft.world.World
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
import net.minecraft.util.Vec3
|
||||
import net.minecraft.util.MovingObjectPosition
|
||||
import codechicken.lib.raytracer.RayTracer
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
|
||||
import java.util.Random
|
||||
import java.util.ArrayList
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.client.particle.EffectRenderer
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.texture.IIconRegister
|
||||
import codechicken.lib.render.TextureUtils
|
||||
import net.minecraft.world.IBlockAccess
|
||||
import codechicken.lib.raytracer.ExtendedMOP
|
||||
import scala.collection.JavaConversions._
|
||||
|
||||
object BlockMultipart {
|
||||
def getTile(world: IBlockAccess, x: Int, y: Int, z: Int) =
|
||||
world.getTileEntity(x, y, z) match {
|
||||
case t: TileMultipart if !t.partList.isEmpty => t
|
||||
case _ => null
|
||||
}
|
||||
|
||||
def getClientTile(world: IBlockAccess, x: Int, y: Int, z: Int) =
|
||||
world.getTileEntity(x, y, z) match {
|
||||
case t: TileMultipartClient if !t.partList.isEmpty => t
|
||||
case _ => null
|
||||
}
|
||||
|
||||
def reduceMOP(hit: MovingObjectPosition): (Int, ExtendedMOP) = {
|
||||
val ehit = hit.asInstanceOf[ExtendedMOP]
|
||||
val data: (Int, _) = ExtendedMOP.getData(hit)
|
||||
return (data._1, new ExtendedMOP(ehit, data._2, ehit.dist))
|
||||
}
|
||||
|
||||
def drawHighlight(
|
||||
world: World,
|
||||
player: EntityPlayer,
|
||||
hit: MovingObjectPosition,
|
||||
frame: Float
|
||||
): Boolean = {
|
||||
val tile = getTile(world, hit.blockX, hit.blockY, hit.blockZ)
|
||||
if (tile == null)
|
||||
return false
|
||||
|
||||
val (index, mop) = reduceMOP(hit)
|
||||
if (tile.partList.apply(index).drawHighlight(mop, player, frame))
|
||||
return true
|
||||
|
||||
tile.partList
|
||||
.apply(index)
|
||||
.collisionRayTrace(
|
||||
RayTracer.getStartVec(player),
|
||||
RayTracer.getEndVec(player)
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/** Block class for all multiparts, should be internal use only.
|
||||
*/
|
||||
class BlockMultipart extends Block(new Material(MapColor.stoneColor)) {
|
||||
import BlockMultipart._
|
||||
|
||||
override def hasTileEntity(meta: Int = 0) = true
|
||||
|
||||
override def isBlockSolid(
|
||||
world: IBlockAccess,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
side: Int
|
||||
): Boolean =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => false
|
||||
case tile => tile.isSolid(side)
|
||||
}
|
||||
|
||||
override def isSideSolid(
|
||||
world: IBlockAccess,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
side: ForgeDirection
|
||||
): Boolean =
|
||||
isBlockSolid(world, x, y, z, side.ordinal())
|
||||
|
||||
override def canPlaceTorchOnTop(world: World, x: Int, y: Int, z: Int) =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => false
|
||||
case tile => tile.canPlaceTorchOnTop
|
||||
}
|
||||
|
||||
override def onNeighborBlockChange(
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
block: Block
|
||||
) {
|
||||
val tile = getTile(world, x, y, z)
|
||||
if (tile != null)
|
||||
tile.onNeighborBlockChange()
|
||||
}
|
||||
|
||||
override def collisionRayTrace(
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
start: Vec3,
|
||||
end: Vec3
|
||||
): ExtendedMOP =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => null
|
||||
case tile => tile.collisionRayTrace(start, end)
|
||||
}
|
||||
|
||||
def rayTraceAll(
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
start: Vec3,
|
||||
end: Vec3
|
||||
): Iterable[ExtendedMOP] =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => Seq()
|
||||
case tile => tile.rayTraceAll(start, end)
|
||||
}
|
||||
|
||||
override def removedByPlayer(
|
||||
world: World,
|
||||
player: EntityPlayer,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int
|
||||
): Boolean = {
|
||||
val hit = RayTracer.retraceBlock(world, player, x, y, z)
|
||||
val tile = getTile(world, x, y, z)
|
||||
|
||||
if (hit == null || tile == null) {
|
||||
dropAndDestroy(world, x, y, z)
|
||||
return true
|
||||
}
|
||||
|
||||
val (index, mop) = reduceMOP(hit)
|
||||
if (world.isRemote) {
|
||||
tile.partList
|
||||
.apply(index)
|
||||
.addDestroyEffects(mop, Minecraft.getMinecraft.effectRenderer)
|
||||
return true
|
||||
}
|
||||
|
||||
tile.harvestPart(index, mop, player)
|
||||
return world.getTileEntity(x, y, z) == null
|
||||
}
|
||||
|
||||
def dropAndDestroy(world: World, x: Int, y: Int, z: Int) {
|
||||
val tile = getTile(world, x, y, z)
|
||||
if (tile != null && !world.isRemote)
|
||||
tile.dropItems(getDrops(world, x, y, z, 0, 0))
|
||||
|
||||
world.setBlockToAir(x, y, z)
|
||||
}
|
||||
|
||||
override def quantityDropped(meta: Int, fortune: Int, random: Random) = 0
|
||||
|
||||
override def getDrops(
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
meta: Int,
|
||||
fortune: Int
|
||||
): ArrayList[ItemStack] = {
|
||||
val ai = new ArrayList[ItemStack]()
|
||||
if (world.isRemote)
|
||||
return ai
|
||||
|
||||
val tile = getTile(world, x, y, z)
|
||||
if (tile != null)
|
||||
tile.partList.foreach(part => part.getDrops.foreach(item => ai.add(item)))
|
||||
|
||||
return ai
|
||||
}
|
||||
|
||||
override def addCollisionBoxesToList(
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
ebb: AxisAlignedBB,
|
||||
list$ : List[_],
|
||||
entity: Entity
|
||||
) {
|
||||
val list = list$.asInstanceOf[List[AxisAlignedBB]]
|
||||
val tile = getTile(world, x, y, z)
|
||||
if (tile != null)
|
||||
tile.partList.foreach(part =>
|
||||
part.getCollisionBoxes.foreach { c =>
|
||||
val aabb = c.toAABB.offset(x, y, z)
|
||||
if (aabb.intersectsWith(ebb))
|
||||
list.add(aabb)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override def addHitEffects(
|
||||
world: World,
|
||||
hit: MovingObjectPosition,
|
||||
effectRenderer: EffectRenderer
|
||||
): Boolean = {
|
||||
val tile = getClientTile(world, hit.blockX, hit.blockY, hit.blockZ)
|
||||
if (tile != null) {
|
||||
val (index, mop) = reduceMOP(hit)
|
||||
if (index < tile.partList.size)
|
||||
tile.partList.apply(index).addHitEffects(mop, effectRenderer)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override def addDestroyEffects(
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
s: Int,
|
||||
effectRenderer: EffectRenderer
|
||||
) = true
|
||||
|
||||
override def renderAsNormalBlock() = false
|
||||
|
||||
override def isOpaqueCube = false
|
||||
|
||||
override def getRenderType = TileMultipart.renderID
|
||||
|
||||
override def isAir(world: IBlockAccess, x: Int, y: Int, z: Int): Boolean =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => true
|
||||
case tile => tile.partList.isEmpty
|
||||
}
|
||||
|
||||
override def isReplaceable(world: IBlockAccess, x: Int, y: Int, z: Int) =
|
||||
isAir(world, x, y, z)
|
||||
|
||||
override def getRenderBlockPass = 1
|
||||
|
||||
override def canRenderInPass(pass: Int): Boolean = true
|
||||
|
||||
override def getPickBlock(
|
||||
hit: MovingObjectPosition,
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int
|
||||
): ItemStack = {
|
||||
val tile = getTile(world, x, y, z)
|
||||
if (tile != null) {
|
||||
if (!hit.isInstanceOf[ExtendedMOP]) {
|
||||
return null
|
||||
}
|
||||
val (index, mop) = reduceMOP(hit)
|
||||
return tile.partList.apply(index).pickItem(mop)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override def getPlayerRelativeBlockHardness(
|
||||
player: EntityPlayer,
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int
|
||||
): Float = {
|
||||
val hit = RayTracer.retraceBlock(world, player, x, y, z)
|
||||
val tile = getTile(world, x, y, z)
|
||||
if (hit != null && tile != null) {
|
||||
val (index, mop) = reduceMOP(hit)
|
||||
return tile.partList.apply(index).getStrength(mop, player) / 30f
|
||||
}
|
||||
|
||||
return 1 / 100f
|
||||
}
|
||||
|
||||
/** Kludge to set PROTECTED blockIcon to a blank icon
|
||||
*/
|
||||
override def registerBlockIcons(register: IIconRegister) {
|
||||
val icon = TextureUtils.getBlankIcon(16, register)
|
||||
setBlockTextureName(icon.getIconName)
|
||||
super.registerBlockIcons(register)
|
||||
}
|
||||
|
||||
override def getLightValue(world: IBlockAccess, x: Int, y: Int, z: Int): Int =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => 0
|
||||
case tile => tile.getLightValue
|
||||
}
|
||||
|
||||
override def randomDisplayTick(
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
random: Random
|
||||
) {
|
||||
val tile = getClientTile(world, x, y, z)
|
||||
if (tile != null)
|
||||
tile.randomDisplayTick(random)
|
||||
}
|
||||
|
||||
override def onBlockActivated(
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
player: EntityPlayer,
|
||||
side: Int,
|
||||
hitX: Float,
|
||||
hitY: Float,
|
||||
hitZ: Float
|
||||
): Boolean = {
|
||||
val hit = RayTracer.retraceBlock(world, player, x, y, z)
|
||||
if (hit == null)
|
||||
return false
|
||||
|
||||
val tile = getTile(world, x, y, z)
|
||||
if (tile == null)
|
||||
return false
|
||||
|
||||
val (index, mop) = reduceMOP(hit)
|
||||
return tile.partList.apply(index).activate(player, mop, player.getHeldItem)
|
||||
}
|
||||
|
||||
override def onBlockClicked(
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
player: EntityPlayer
|
||||
) {
|
||||
val hit = RayTracer.retraceBlock(world, player, x, y, z)
|
||||
if (hit == null)
|
||||
return
|
||||
|
||||
val tile = getTile(world, x, y, z)
|
||||
if (tile == null)
|
||||
return
|
||||
|
||||
val (index, mop) = reduceMOP(hit)
|
||||
tile.partList.apply(index).click(player, mop, player.getHeldItem)
|
||||
}
|
||||
|
||||
override def isProvidingStrongPower(
|
||||
world: IBlockAccess,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
side: Int
|
||||
): Int =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => 0
|
||||
case tile => tile.strongPowerLevel(side ^ 1)
|
||||
}
|
||||
|
||||
override def isProvidingWeakPower(
|
||||
world: IBlockAccess,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
side: Int
|
||||
): Int =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => 0
|
||||
case tile => tile.weakPowerLevel(side ^ 1)
|
||||
}
|
||||
|
||||
override def canConnectRedstone(
|
||||
world: IBlockAccess,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
side: Int
|
||||
): Boolean =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => false
|
||||
case tile => tile.canConnectRedstone(side)
|
||||
}
|
||||
|
||||
override def onEntityCollidedWithBlock(
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
entity: Entity
|
||||
) {
|
||||
val tile = getTile(world, x, y, z)
|
||||
if (tile != null)
|
||||
tile.onEntityCollision(entity)
|
||||
}
|
||||
|
||||
override def onNeighborChange(
|
||||
world: IBlockAccess,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
tileX: Int,
|
||||
tileY: Int,
|
||||
tileZ: Int
|
||||
) {
|
||||
val tile = getTile(world, x, y, z)
|
||||
if (tile != null)
|
||||
tile.onNeighborTileChange(tileX, tileY, tileZ)
|
||||
}
|
||||
|
||||
override def getExplosionResistance(
|
||||
entity: Entity,
|
||||
world: World,
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
explosionX: Double,
|
||||
explosionY: Double,
|
||||
explosionZ: Double
|
||||
): Float =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => 0
|
||||
case tile => tile.getExplosionResistance(entity)
|
||||
}
|
||||
|
||||
override def getWeakChanges(world: IBlockAccess, x: Int, y: Int, z: Int) =
|
||||
getTile(world, x, y, z) match {
|
||||
case null => false
|
||||
case tile => tile.getWeakChanges
|
||||
}
|
||||
|
||||
override def canProvidePower = true
|
||||
}
|
||||
Reference in new issue
Block a user