From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: JellySquid Date: Sun, 24 Jan 2021 16:57:03 +0100 Subject: [PATCH] lithium block Co-authored-by: Hugo Planque diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/tuples/FinalObject.java b/src/main/java/me/jellysquid/mods/lithium/common/util/tuples/FinalObject.java new file mode 100644 index 0000000000000000000000000000000000000000..f78927e71258e859154cca8ba78d17130b0d82c1 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/lithium/common/util/tuples/FinalObject.java @@ -0,0 +1,20 @@ +package me.jellysquid.mods.lithium.common.util.tuples; + +/** + * The purpose of this class is safe publication of the wrapped value. (JLS 17.5) + */ +public class FinalObject { + private final T value; + + public FinalObject(T value) { + this.value = value; + } + + public FinalObject of(T value) { + return new FinalObject<>(value); + } + + public T getValue() { + return value; + } +} diff --git a/src/main/java/net/minecraft/core/EnumDirection.java b/src/main/java/net/minecraft/core/EnumDirection.java index b8fe75b8c37ef1968519e69e078444b1a3c5c359..a825b17e454138e181926df3f2faa6d9d7af4055 100644 --- a/src/main/java/net/minecraft/core/EnumDirection.java +++ b/src/main/java/net/minecraft/core/EnumDirection.java @@ -100,6 +100,7 @@ public enum EnumDirection implements INamable { return new EnumDirection[]{enumdirection, enumdirection1, enumdirection2, enumdirection2.opposite(), enumdirection1.opposite(), enumdirection.opposite()}; } + public int get3DDataValue(){ return c(); } // Yatopia - OBFHELPER public int c() { return this.g; } diff --git a/src/main/java/net/minecraft/world/level/block/piston/TileEntityPiston.java b/src/main/java/net/minecraft/world/level/block/piston/TileEntityPiston.java index 58c7a52612fe0f5c1e4ddacc0bf93cd81f1286b8..af2a8fdcaf5962334dcc20717f3a1ad14aebcbcb 100644 --- a/src/main/java/net/minecraft/world/level/block/piston/TileEntityPiston.java +++ b/src/main/java/net/minecraft/world/level/block/piston/TileEntityPiston.java @@ -29,9 +29,9 @@ import net.minecraft.world.phys.shapes.VoxelShapes; public class TileEntityPiston extends TileEntity implements ITickable { private IBlockData a; - private EnumDirection b; - private boolean c; - private boolean g; + private EnumDirection b; public EnumDirection getFacing() { return b; } // Yatopia - OBFHELPER + private boolean c; public boolean isExtending() { return c; } // Yatopia - OBFHELPER + private boolean g; public boolean isSource() { return g; } // Yatopia - OBFHELPER private static final ThreadLocal h = ThreadLocal.withInitial(() -> { return null; }); @@ -40,6 +40,74 @@ public class TileEntityPiston extends TileEntity implements ITickable { private long k; private int l; + // Yatopia start - Port Lithium + private static final VoxelShape[] PISTON_BASE_WITH_MOVING_HEAD_SHAPES = precomputePistonBaseWithMovingHeadShapes(); + /** + * We cache the offset and simplified VoxelShapes that are otherwise constructed on every call of getCollisionShape. + * For each offset direction and distance (6 directions, 2 distances each, and no direction with 0 distance) we + * store the offset and simplified VoxelShapes in the original VoxelShape when they are accessed the first time. + * We use safe publication, because both the Render and Server thread are using the cache. + * + * @param blockShape the original shape, must not be modified after passing it as an argument to this method + * @param offset the offset distance + * @param direction the offset direction + * @return blockShape offset and simplified + */ + private static VoxelShape getOffsetAndSimplified(VoxelShape blockShape, float offset, EnumDirection direction) { + VoxelShape offsetSimplifiedShape = blockShape.getOffsetSimplifiedShape(offset, direction); + if (offsetSimplifiedShape == null) { + //create the offset shape and store it for later use + offsetSimplifiedShape = blockShape.offset(direction.getAdjacentX() * offset, direction.getAdjacentY() * offset, direction.getAdjacentZ() * offset).simplify(); + blockShape.setShape(offset, direction, offsetSimplifiedShape); + } + return offsetSimplifiedShape; + } + + /** + * Precompute all 18 possible configurations for the merged piston base and head shape. + * + * @return The array of the merged VoxelShapes, indexed by {@link TileEntityPiston#getIndexForMergedShape(float, EnumDirection)} + */ + private static VoxelShape[] precomputePistonBaseWithMovingHeadShapes() { + float[] offsets = {0f, 0.5f, 1f}; + EnumDirection[] directions = EnumDirection.values(); + + VoxelShape[] mergedShapes = new VoxelShape[offsets.length * directions.length]; + + for (EnumDirection facing : directions) { + VoxelShape baseShape = Blocks.PISTON.getBlockData().set(BlockPiston.EXTENDED, true) + .set(BlockPiston.FACING, facing).getCollisionShape(null, null); + for (float offset : offsets) { + //this cache is only required for the merged piston head + base shape. + //this shape is only used when !this.extending + //here: isShort = this.extending != 1.0F - this.progress < 0.25F can be simplified to: + //isShort = f < 0.25F , because f = getAmountExtended(this.progress) can be simplified to f == 1.0F - this.progress + //therefore isShort is dependent on the offset: + boolean isShort = offset < 0.25f; + + VoxelShape headShape = (Blocks.PISTON_HEAD.getBlockData().set(BlockPistonExtension.FACING, facing)) + .set(BlockPistonExtension.SHORT, isShort).getCollisionShape(null, null); + + VoxelShape offsetHead = headShape.offset(facing.getAdjacentX() * offset, + facing.getAdjacentY() * offset, + facing.getAdjacentZ() * offset); + mergedShapes[getIndexForMergedShape(offset, facing)] = VoxelShapes.union(baseShape, offsetHead); + } + + } + + return mergedShapes; + } + + private static int getIndexForMergedShape(float offset, EnumDirection direction) { + if (offset != 0f && offset != 0.5f && offset != 1f) { + return -1; + } + //shape of offset 0 is still dependent on the direction, due to piston head and base being directional blocks + return (int) (2 * offset) + (3 * direction.get3DDataValue()); + } + // Yatopia End + public TileEntityPiston() { super(TileEntityTypes.PISTON); } @@ -350,13 +418,21 @@ public class TileEntityPiston extends TileEntity implements ITickable { } else { iblockdata = this.a; } + float f = this.e(this.i); // Yatopia Start - Port Lithium + if (this.isExtending() || !this.isSource()) { + //here voxelShape2.isEmpty() is guaranteed, vanilla code would call union() which calls simplify() + VoxelShape blockShape = iblockdata.getCollisionShape(iblockaccess, blockposition); + + //we cache the simplified shapes, as the simplify() method costs a lot of CPU time and allocates several objects + VoxelShape offsetAndSimplified = getOffsetAndSimplified(blockShape, Math.abs(f), f < 0f ? this.getFacing().opposite() : this.getFacing()); + return offsetAndSimplified; + } else { + //retracting piston heads have to act like their base as well, as the base block is replaced with the moving block + //f >= 0f is guaranteed (assuming no other mod interferes) + int index = getIndexForMergedShape(f, this.getFacing()); + return PISTON_BASE_WITH_MOVING_HEAD_SHAPES[index]; + } // Yatopia End - float f = this.e(this.i); - double d0 = (double) ((float) this.b.getAdjacentX() * f); - double d1 = (double) ((float) this.b.getAdjacentY() * f); - double d2 = (double) ((float) this.b.getAdjacentZ() * f); - - return VoxelShapes.a(voxelshape, iblockdata.getCollisionShape(iblockaccess, blockposition).a(d0, d1, d2)); } } diff --git a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java index 9567630593da7c77a0173b93c9a57ceb7887a59b..fbc5fab9946b6f9233f3014f0e69f2576b2138d7 100644 --- a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java +++ b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java @@ -13,9 +13,50 @@ import net.minecraft.util.MathHelper; import net.minecraft.world.phys.AxisAlignedBB; import net.minecraft.world.phys.MovingObjectPositionBlock; import net.minecraft.world.phys.Vec3D; +import me.jellysquid.mods.lithium.common.util.tuples.FinalObject; // Yatopia public abstract class VoxelShape { + // Yatopia - Port Lithium + private FinalObject[] offsetAndSimplified; + + public void setShape(float offset, EnumDirection direction, VoxelShape offsetShape) { + if (offsetShape == null) { + throw new IllegalArgumentException("offsetShape must not be null!"); + } + int index = getIndexForOffsetSimplifiedShapes(offset, direction); + FinalObject[] offsetAndSimplified = this.offsetAndSimplified; + if (offsetAndSimplified == null) { + //noinspection unchecked + this.offsetAndSimplified = (offsetAndSimplified = new FinalObject[1 + (2 * 6)]); + } + //using FinalObject as it stores the value in a final field, which guarantees safe publication + offsetAndSimplified[index] = new FinalObject<>(offsetShape); + } + + public VoxelShape getOffsetSimplifiedShape(float offset, EnumDirection direction) { + FinalObject[] offsetAndSimplified = this.offsetAndSimplified; + if (offsetAndSimplified == null) { + return null; + } + int index = getIndexForOffsetSimplifiedShapes(offset, direction); + //usage of FinalObject guarantees that we are seeing a fully initialized VoxelShape here, even when it was created on a different thread + FinalObject wrappedShape = offsetAndSimplified[index]; + //noinspection FinalObjectAssignedToNull,FinalObjectGetWithoutIsPresent + return wrappedShape == null ? null : wrappedShape.getValue(); + } + + private static int getIndexForOffsetSimplifiedShapes(float offset, EnumDirection direction) { + if (offset != 0f && offset != 0.5f && offset != 1f) { + throw new IllegalArgumentException("offset must be one of {0f, 0.5f, 1f}"); + } + if (offset == 0f) { + return 0; //can treat offsetting by 0 in all directions the same + } + return (int) (2 * offset) + 2 * direction.get3DDataValue(); + } + // Yatopia End + protected final VoxelShapeDiscrete a; public final VoxelShapeDiscrete getShape() { return this.a; } // Tuinity - OBFHELPER @Nullable private VoxelShape[] b; diff --git a/src/main/java/net/minecraft/world/phys/shapes/VoxelShapes.java b/src/main/java/net/minecraft/world/phys/shapes/VoxelShapes.java index 98e787e6383a39de1708428137fd7f9e057ff153..049aa5f51e7517744b25f8c2c4b5e7a7de24a73e 100644 --- a/src/main/java/net/minecraft/world/phys/shapes/VoxelShapes.java +++ b/src/main/java/net/minecraft/world/phys/shapes/VoxelShapes.java @@ -187,6 +187,7 @@ public final class VoxelShapes { return (long) i * (long) (j / IntMath.gcd(i, j)); } + public static VoxelShape union(VoxelShape voxelshape, VoxelShape voxelshape1) { return a(voxelshape, voxelshape1); } // Yatopia - OBFHELPER public static VoxelShape a(VoxelShape voxelshape, VoxelShape voxelshape1) { return a(voxelshape, voxelshape1, OperatorBoolean.OR); }