Yatopia/patches/server/0065-lithium-block.patch
2021-04-22 11:50:26 -04:00

233 lines
12 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: JellySquid <jellysquid+atwork@protonmail.com>
Date: Sun, 24 Jan 2021 16:57:03 +0100
Subject: [PATCH] lithium block
Co-authored-by: Hugo Planque <hookwood01@gmail.com>
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<T> {
+ private final T value;
+
+ public FinalObject(T value) {
+ this.value = value;
+ }
+
+ public FinalObject<T> 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<EnumDirection> 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<VoxelShape>[] 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<VoxelShape>[] 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<VoxelShape>[] 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<VoxelShape> 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);
}