diff --git a/src/main/java/net/gensokyoreimagined/nitori/access/IThreadedAnvilChunkStorage.java b/src/main/java/net/gensokyoreimagined/nitori/access/IThreadedAnvilChunkStorage.java new file mode 100644 index 0000000..7264911 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/access/IThreadedAnvilChunkStorage.java @@ -0,0 +1,34 @@ +package net.gensokyoreimagined.nitori.access; + +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.PlayerMap; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.util.thread.BlockableEventLoop; +import org.apache.commons.lang3.mutable.MutableObject; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ServerChunkCache.class) +public interface IThreadedAnvilChunkStorage { + + @Invoker + ChunkHolder invokeGetCurrentChunkHolder(long pos); + + @Invoker + ChunkHolder invokeGetChunkHolder(long pos); + + @Accessor + ServerLevel getLevel(); + + @Accessor + PlayerMap getPlayerChunkWatchingManager(); + + @Accessor + BlockableEventLoop getMainThreadExecutor(); + +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/access/ITypeFilterableList.java b/src/main/java/net/gensokyoreimagined/nitori/access/ITypeFilterableList.java new file mode 100644 index 0000000..57583d2 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/access/ITypeFilterableList.java @@ -0,0 +1,8 @@ +package net.gensokyoreimagined.nitori.access; + +public interface ITypeFilterableList { + + Object[] getBackingArray(); + + +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/precompute_shape_arrays/FractionalDoubleListMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/precompute_shape_arrays/FractionalDoubleListMixin.java new file mode 100644 index 0000000..d24dfa9 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/precompute_shape_arrays/FractionalDoubleListMixin.java @@ -0,0 +1,33 @@ +package net.gensokyoreimagined.nitori.mixin.shapes.precompute_shape_arrays; + +import net.minecraft.world.phys.shapes.CubePointRange; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(CubePointRange.class) +public class FractionalDoubleListMixin { + @Shadow + @Final + private int parts; + + private double scale; + + @Inject(method = "(I)V", at = @At("RETURN")) + public void initScale(int sectionCount, CallbackInfo ci) { + this.scale = 1.0D / this.parts; + } + + /** + * @author JellySquid + * @reason Replace division with multiplication + */ + @Overwrite + public double getDouble(int position) { + return position * this.scale; + } +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/precompute_shape_arrays/SimpleVoxelShapeMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/precompute_shape_arrays/SimpleVoxelShapeMixin.java index d940d94..72471be 100644 --- a/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/precompute_shape_arrays/SimpleVoxelShapeMixin.java +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/precompute_shape_arrays/SimpleVoxelShapeMixin.java @@ -1,38 +1,58 @@ package net.gensokyoreimagined.nitori.mixin.shapes.precompute_shape_arrays; -//import it.unimi.dsi.fastutil.doubles.DoubleList; -//import net.minecraft.core.Direction; -//import net.minecraft.world.phys.shapes.CubePointRange; -//import net.minecraft.world.phys.shapes.CubeVoxelShape; -//import net.minecraft.world.phys.shapes.DiscreteVoxelShape; -//import org.spongepowered.asm.mixin.Mixin; -//import org.spongepowered.asm.mixin.Overwrite; -//import org.spongepowered.asm.mixin.injection.At; -//import org.spongepowered.asm.mixin.injection.Inject; -//import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -// -//@Mixin(CubeVoxelShape.class) -//public class SimpleVoxelShapeMixin { -// private static final Direction.Axis[] AXIS = Direction.Axis.values(); -// -// private DoubleList[] parts; -// -// @Inject(method = "", at = @At("RETURN")) -// private void CubeVoxelShape(DiscreteVoxelShape voxels, CallbackInfo ci) { -// this.parts = new DoubleList[AXIS.length]; -// -// for (Direction.Axis axis : AXIS) { -// this.parts[axis.ordinal()] = new CubePointRange(voxels.getSize(axis)); -// } -// } -// -// /** -// * @author JellySquid -// * @reason Use the cached array -// */ -// @Overwrite -// public DoubleList getCoords(Direction.Axis axis) { -// return this.parts[axis.ordinal()]; -// } -// -//} \ No newline at end of file +import it.unimi.dsi.fastutil.doubles.DoubleList; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.shapes.CubePointRange; +import net.minecraft.world.phys.shapes.CubeVoxelShape; +import net.minecraft.world.phys.shapes.DiscreteVoxelShape; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.lang.reflect.Constructor; + +@Mixin(CubeVoxelShape.class) +public class SimpleVoxelShapeMixin { + private static final Direction.Axis[] AXIS = Direction.Axis.values(); + + private DoubleList[] list; + + @Unique + private static Constructor nitori$cubePointRangeConstructor; + + @Unique + private CubePointRange nitori$cubePointRange(int sectionCount) { + try { + if (nitori$cubePointRangeConstructor == null) { + nitori$cubePointRangeConstructor = CubePointRange.class.getDeclaredConstructor(int.class); + nitori$cubePointRangeConstructor.setAccessible(true); + } + + return nitori$cubePointRangeConstructor.newInstance(sectionCount); + } catch (Exception ex) { + throw new AssertionError("Failed to find CubePointRange constructor - " + ex.getMessage(), ex); + } + } + + @Inject(method = "", at = @At("RETURN")) + private void onConstructed(DiscreteVoxelShape voxels, CallbackInfo ci) { + this.list = new DoubleList[AXIS.length]; + + for (Direction.Axis axis : AXIS) { + this.list[axis.ordinal()] = nitori$cubePointRange(voxels.getSize(axis)); + } + } + + /** + * @author JellySquid + * @reason Use the cached array + */ + @Overwrite + public DoubleList getCoords(Direction.Axis axis) { + return this.list[axis.ordinal()]; + } + +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/specialized_shapes/VoxelShapeMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/specialized_shapes/VoxelShapeMixin.java new file mode 100644 index 0000000..e4d726a --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/specialized_shapes/VoxelShapeMixin.java @@ -0,0 +1,151 @@ +package net.gensokyoreimagined.nitori.mixin.shapes.specialized_shapes; + +import it.unimi.dsi.fastutil.doubles.DoubleList; +import net.minecraft.core.AxisCycle; +import net.minecraft.world.phys.AABB; +import net.minecraft.core.Direction; +import net.minecraft.world.phys.shapes.DiscreteVoxelShape; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +/** + * Implement faster methods for determining penetration during collision resolution. + */ +@Mixin(VoxelShape.class) +public abstract class VoxelShapeMixin { + private static final double POSITIVE_EPSILON = +1.0E-7D; + private static final double NEGATIVE_EPSILON = -1.0E-7D; + + @Shadow + @Final + public DiscreteVoxelShape shape; + + @Shadow + public abstract boolean isEmpty(); + + @Shadow + protected abstract double get(Direction.Axis axis, int index); + + @Shadow + public abstract DoubleList getCoords(Direction.Axis axis); + + /** + * @reason Use optimized implementation which delays searching for coordinates as long as possible + * @author JellySquid + */ + @Overwrite + public double collideX(AxisCycle cycleDirection, AABB box, double maxDist) { + if (this.isEmpty()) { + return maxDist; + } + + if (Math.abs(maxDist) < POSITIVE_EPSILON) { + return 0.0D; + } + + AxisCycle cycle = cycleDirection.inverse(); + + Direction.Axis axisX = cycle.cycle(Direction.Axis.X); + Direction.Axis axisY = cycle.cycle(Direction.Axis.Y); + Direction.Axis axisZ = cycle.cycle(Direction.Axis.Z); + + int minY = Integer.MIN_VALUE; + int maxY = Integer.MIN_VALUE; + int minZ = Integer.MIN_VALUE; + int maxZ = Integer.MIN_VALUE; + + int x, y, z; + + double dist; + + if (maxDist > 0.0D) { + double max = box.max(axisX); + int maxIdx = this.findIndex(axisX, max - POSITIVE_EPSILON); + + int maxX = this.shape.getSize(axisX); + + for (x = maxIdx + 1; x < maxX; ++x) { + minY = minY == Integer.MIN_VALUE ? Math.max(0, this.findIndex(axisY, box.min(axisY) + POSITIVE_EPSILON)) : minY; + maxY = maxY == Integer.MIN_VALUE ? Math.min(this.shape.getSize(axisY), this.findIndex(axisY, box.max(axisY) - POSITIVE_EPSILON) + 1) : maxY; + + for (y = minY; y < maxY; ++y) { + minZ = minZ == Integer.MIN_VALUE ? Math.max(0, this.findIndex(axisZ, box.min(axisZ) + POSITIVE_EPSILON)) : minZ; + maxZ = maxZ == Integer.MIN_VALUE ? Math.min(this.shape.getSize(axisZ), this.findIndex(axisZ, box.max(axisZ) - POSITIVE_EPSILON) + 1) : maxZ; + + for (z = minZ; z < maxZ; ++z) { + if (this.shape.isFullWide(cycle, x, y, z)) { + dist = this.get(axisX, x) - max; + + if (dist >= NEGATIVE_EPSILON) { + maxDist = Math.min(maxDist, dist); + } + + return maxDist; + } + } + } + } + } else if (maxDist < 0.0D) { + double min = box.min(axisX); + int minIdx = this.findIndex(axisX, min + POSITIVE_EPSILON); + + for (x = minIdx - 1; x >= 0; --x) { + minY = minY == Integer.MIN_VALUE ? Math.max(0, this.findIndex(axisY, box.min(axisY) + POSITIVE_EPSILON)) : minY; + maxY = maxY == Integer.MIN_VALUE ? Math.min(this.shape.getSize(axisY), this.findIndex(axisY, box.max(axisY) - POSITIVE_EPSILON) + 1) : maxY; + + for (y = minY; y < maxY; ++y) { + minZ = minZ == Integer.MIN_VALUE ? Math.max(0, this.findIndex(axisZ, box.min(axisZ) + POSITIVE_EPSILON)) : minZ; + maxZ = maxZ == Integer.MIN_VALUE ? Math.min(this.shape.getSize(axisZ), this.findIndex(axisZ, box.max(axisZ) - POSITIVE_EPSILON) + 1) : maxZ; + + for (z = minZ; z < maxZ; ++z) { + if (this.shape.isFullWide(cycle, x, y, z)) { + dist = this.get(axisX, x + 1) - min; + + if (dist <= POSITIVE_EPSILON) { + maxDist = Math.max(maxDist, dist); + } + + return maxDist; + } + } + } + } + } + + return maxDist; + } + + /** + * Inlines the lambda passed to MathHelper#binarySearch. Simplifies the implementation very slightly for additional + * speed. + * + * @reason Use faster implementation + * @author JellySquid + */ + @Overwrite + public int findIndex(Direction.Axis axis, double coord) { + DoubleList list = this.getCoords(axis); + + int size = this.shape.getSize(axis); + + int start = 0; + int end = size + 1 - start; + + while (end > 0) { + int middle = end / 2; + int idx = start + middle; + + if (idx >= 0 && (idx > size || coord < list.getDouble(idx))) { + end = middle; + } else { + start = idx + 1; + end -= middle + 1; + } + } + + return start - 1; + } +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/specialized_shapes/VoxelShapesMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/specialized_shapes/VoxelShapesMixin.java new file mode 100644 index 0000000..43c827e --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/shapes/specialized_shapes/VoxelShapesMixin.java @@ -0,0 +1,113 @@ +package net.gensokyoreimagined.nitori.mixin.shapes.specialized_shapes; + +//TODO: Later + +//import me.jellysquid.mods.lithium.common.shapes.VoxelShapeAlignedCuboid; +//import me.jellysquid.mods.lithium.common.shapes.VoxelShapeEmpty; +//import me.jellysquid.mods.lithium.common.shapes.VoxelShapeSimpleCube; +//import net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape; +//import net.minecraft.world.phys.shapes.DiscreteVoxelShape; +//import net.minecraft.world.phys.shapes.VoxelShape; +//import net.minecraft.world.phys.shapes.Shapes; +//import org.spongepowered.asm.mixin.*; +// +///** +// * Shape specialization allows us to optimize comparison logic by guaranteeing certain constraints about the +// * configuration of vertices in a given shape. For example, most block shapes consist of only one cuboid and by +// * nature, only one voxel. This fact can be taken advantage of to create an optimized implementation which avoids +// * scanning over voxels as there are only ever two given vertices in the shape, allowing simple math operations to be +// * used for determining intersection and penetration. +// *

+// * In most cases, comparison logic is rather simple as the game often only deals with empty shapes or simple cubes. +// * Specialization provides a significant speed-up to entity collision resolution and various other parts of the game +// * without needing invasive patches, as we can simply replace the types returned by this class. Modern processors +// * (along with the help of the potent JVM) make the cost of dynamic dispatch negligible when compared to the execution +// * times of shape comparison methods. +// */ +//@Mixin(Shapes.class) +//public abstract class VoxelShapesMixin { +// @Mutable +// @Shadow +// @Final +// public static final VoxelShape INFINITY; +// +// @Mutable +// @Shadow +// @Final +// private static final VoxelShape BLOCK; +// +// @Mutable +// @Shadow +// @Final +// private static final VoxelShape EMPTY; +// +// private static final DiscreteVoxelShape FULL_CUBE_VOXELS; +// +// // Re-initialize the global cached shapes with our specialized ones. This will happen right after all the static +// // state has been initialized and before any external classes access it. +// static { +// // [VanillaCopy] The FULL_CUBE and UNBOUNDED shape is initialized with a single 1x1x1 voxel as neither will +// // contain multiple inner cuboids. +// FULL_CUBE_VOXELS = new BitSetDiscreteVoxelShape(1, 1, 1); +// FULL_CUBE_VOXELS.fill(0, 0, 0); +// +// // Used in some rare cases to indicate a shape which encompasses the entire world (such as a moving world border) +// INFINITY = new VoxelShapeSimpleCube(FULL_CUBE_VOXELS, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, +// Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); +// +// // Represents a full-block cube shape, such as that for a dirt block. +// BLOCK = new VoxelShapeSimpleCube(FULL_CUBE_VOXELS, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0); +// +// // Represents an empty cube shape with no vertices that cannot be collided with. +// EMPTY = new VoxelShapeEmpty(new BitSetDiscreteVoxelShape(0, 0, 0)); +// } +// +// /** +// * Vanilla implements some very complex logic in this function in order to allow entity boxes to be used in +// * collision resolution the same way as block shapes. The specialized simple cube shape however can trivially +// * represent these cases with nothing more than the two vertexes. This provides a modest speed up for entity +// * collision code by allowing them to also use our optimized shapes. +// *

+// * Vanilla uses different kinds of VoxelShapes depending on the size and position of the box. +// * A box that isn't aligned with 1/8th of a block will become a very simple ArrayVoxelShape, while others +// * will become a "SimpleVoxelShape" with a BitSetVoxelSet that possibly has a higher resolution (1-3 bits) per axis. +// *

+// * Shapes that have a high resolution (e.g. extended piston base has 2 bits on one axis) have collision +// * layers inside them. An upwards extended piston base has extra collision boxes at 0.25 and 0.5 height. +// * Slabs don't have extra collision boxes, because they are only as high as the smallest height that is possible +// * with their bit resolution (1, so half a block). +// * +// * @reason Use our optimized shape types +// * @author JellySquid, 2No2Name +// */ +// @Overwrite +// public static VoxelShape cuboidUnchecked(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { +// if (maxX - minX < 1.0E-7D || maxY - minY < 1.0E-7D || maxZ - minZ < 1.0E-7D) { +// return EMPTY; +// } +// +// int xRes; +// int yRes; +// int zRes; +// //findRequiredBitResolution(...) looks unnecessarily slow, and it seems to unintentionally return -1 on inputs like -1e-8, +// //A faster implementation is not in the scope of this mixin. +// +// //Description of what vanilla does: +// //If the VoxelShape cannot be represented by a BitSet with 3 bit resolution on any axis (BitSetVoxelSet), +// //a shape without boxes inside will be used in vanilla (ArrayVoxelShape with only 2 PointPositions on each axis) +// +// if ((xRes = Shapes.findBits(minX, maxX)) < 0 || +// (yRes = Shapes.findBits(minY, maxY)) < 0 || +// (zRes = Shapes.findBits(minZ, maxZ)) < 0) { +// //vanilla uses ArrayVoxelShape here without any rounding of the coordinates +// return new VoxelShapeSimpleCube(FULL_CUBE_VOXELS, minX, minY, minZ, maxX, maxY, maxZ); +// } else { +// if (xRes == 0 && yRes == 0 && zRes == 0) { +// return BLOCK; +// } +// // vanilla would use a SimpleVoxelShape with a BitSetVoxelSet of resolution of xRes, yRes, zRes here, we match its behavior +// return new VoxelShapeAlignedCuboid(Math.round(minX * 8D) / 8D, Math.round(minY * 8D) / 8D, Math.round(minZ * 8D) / 8D, +// Math.round(maxX * 8D) / 8D, Math.round(maxY * 8D) / 8D, Math.round(maxZ * 8D) / 8D, xRes, yRes, zRes); +// } +// } +//} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/entity/move_zero_velocity/MixinEntity.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/entity/move_zero_velocity/MixinEntity.java new file mode 100644 index 0000000..e21d7b5 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/entity/move_zero_velocity/MixinEntity.java @@ -0,0 +1,34 @@ +package net.gensokyoreimagined.nitori.mixin.vmp.entity.move_zero_velocity; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Entity.class) +public class MixinEntity { + + @Shadow private AABB bb; + @Unique + private boolean boundingBoxChanged = false; + + @Inject(method = "move", at = @At("HEAD"), cancellable = true) + private void onMove(MoverType movementType, Vec3 movement, CallbackInfo ci) { + if (!boundingBoxChanged && movement.equals(Vec3.ZERO)) { + ci.cancel(); + boundingBoxChanged = false; + } + } + + @Inject(method = "setBoundingBox", at = @At("HEAD")) + private void onBoundingBoxChanged(AABB boundingBox, CallbackInfo ci) { + if (!this.bb.equals(boundingBox)) boundingBoxChanged = true; + } + +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/general/collections/MixinTypeFilterableList.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/general/collections/MixinTypeFilterableList.java new file mode 100644 index 0000000..21c74eb --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/general/collections/MixinTypeFilterableList.java @@ -0,0 +1,76 @@ +package net.gensokyoreimagined.nitori.mixin.vmp.general.collections; + +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.gensokyoreimagined.nitori.access.ITypeFilterableList; +import net.minecraft.util.ClassInstanceMultiMap; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.*; + +@Mixin(value = ClassInstanceMultiMap.class, priority = 1005) // priority compatibility hack for lithium +public abstract class MixinTypeFilterableList extends AbstractCollection implements ITypeFilterableList { + + @Mutable + @Shadow @Final private Map, List> byClass; + + @Mutable + @Shadow @Final private List allInstances; + + @Shadow @Final private Class baseClass; + + @Redirect(method = "", at = @At(value = "FIELD", target = "Lnet/minecraft/util/ClassInstanceMultiMap;byClass:Ljava/util/Map;", opcode = Opcodes.PUTFIELD)) + private void redirectSetElementsByType(ClassInstanceMultiMap instance, Map, List> value) { + this.byClass = new Object2ObjectLinkedOpenHashMap<>(); + } + + @Redirect(method = "", at = @At(value = "FIELD", target = "Lnet/minecraft/util/ClassInstanceMultiMap;allInstances:Ljava/util/List;", opcode = Opcodes.PUTFIELD)) + private void redirectSetAllElements(ClassInstanceMultiMap instance, List value) { + this.allInstances = new ObjectArrayList<>(); + } + + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Maps;newHashMap()Ljava/util/HashMap;", remap = false)) + private HashMap redirectNewHashMap() { + return null; // avoid unnecessary alloc + } + + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList()Ljava/util/ArrayList;", remap = false)) + private ArrayList redirectNewArrayList() { + return null; + } + + @Override + public Object[] getBackingArray() { + return ((ObjectArrayList) this.allInstances).elements(); + } + + /** + * @author ishland + * @reason use fastutil array list for faster iteration & use array for filtering iteration + */ + @Overwrite + public Collection find(Class type) { + List cached = this.byClass.get(type); + if (cached != null) return (Collection) cached; + + if (!this.baseClass.isAssignableFrom(type)) { + throw new IllegalArgumentException("Don't know how to search for " + type); + } else { + List list = this.byClass.computeIfAbsent(type, + typeClass -> { + ObjectArrayList ts = new ObjectArrayList<>(this.allInstances.size()); + for (Object _allElement : ((ObjectArrayList) this.allInstances).elements()) { + if (typeClass.isInstance(_allElement)) { + ts.add((T) _allElement); + } + } + return ts; + } + ); + return (Collection) list; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/playerwatching/MixinChunkFilter.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/playerwatching/MixinChunkFilter.java similarity index 91% rename from src/main/java/net/gensokyoreimagined/nitori/mixin/playerwatching/MixinChunkFilter.java rename to src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/playerwatching/MixinChunkFilter.java index 0c04e76..2a6da58 100644 --- a/src/main/java/net/gensokyoreimagined/nitori/mixin/playerwatching/MixinChunkFilter.java +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/playerwatching/MixinChunkFilter.java @@ -1,4 +1,4 @@ -package net.gensokyoreimagined.nitori.mixin.playerwatching; +package net.gensokyoreimagined.nitori.mixin.vmp.playerwatching; import net.minecraft.server.level.ChunkTrackingView; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/playerwatching/MixinServerPlayerEntity.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/playerwatching/MixinServerPlayerEntity.java similarity index 95% rename from src/main/java/net/gensokyoreimagined/nitori/mixin/playerwatching/MixinServerPlayerEntity.java rename to src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/playerwatching/MixinServerPlayerEntity.java index 5357e9b..36d5eff 100644 --- a/src/main/java/net/gensokyoreimagined/nitori/mixin/playerwatching/MixinServerPlayerEntity.java +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/playerwatching/MixinServerPlayerEntity.java @@ -1,4 +1,4 @@ -package net.gensokyoreimagined.nitori.mixin.playerwatching; +package net.gensokyoreimagined.nitori.mixin.vmp.playerwatching; import net.gensokyoreimagined.nitori.common.chunkwatching.PlayerClientVDTracking; import net.minecraft.server.level.ClientInformation; diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/playerwatching/optimize_nearby_player_lookups/MixinMobEntity.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/playerwatching/optimize_nearby_player_lookups/MixinMobEntity.java similarity index 93% rename from src/main/java/net/gensokyoreimagined/nitori/mixin/playerwatching/optimize_nearby_player_lookups/MixinMobEntity.java rename to src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/playerwatching/optimize_nearby_player_lookups/MixinMobEntity.java index 3a4e019..24b16cc 100644 --- a/src/main/java/net/gensokyoreimagined/nitori/mixin/playerwatching/optimize_nearby_player_lookups/MixinMobEntity.java +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/vmp/playerwatching/optimize_nearby_player_lookups/MixinMobEntity.java @@ -1,4 +1,4 @@ -package net.gensokyoreimagined.nitori.mixin.playerwatching.optimize_nearby_player_lookups; +package net.gensokyoreimagined.nitori.mixin.vmp.playerwatching.optimize_nearby_player_lookups; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; diff --git a/src/main/java/net/gensokyoreimagined/nitori/mixin/world/portal_checks/DisablePortalChecksMixin.java b/src/main/java/net/gensokyoreimagined/nitori/mixin/world/portal_checks/DisablePortalChecksMixin.java new file mode 100644 index 0000000..3b25743 --- /dev/null +++ b/src/main/java/net/gensokyoreimagined/nitori/mixin/world/portal_checks/DisablePortalChecksMixin.java @@ -0,0 +1,23 @@ +package net.gensokyoreimagined.nitori.mixin.world.portal_checks; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.portal.PortalShape; +import net.minecraft.world.phys.Vec3; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityDimensions; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin({PortalShape.class}) +public class DisablePortalChecksMixin { + @Inject( + at = {@At("HEAD")}, + method = {"findCollisionFreePosition"}, + cancellable = true + ) + private static void init(Vec3 fallback, ServerLevel world, Entity entity, EntityDimensions dimensions, CallbackInfoReturnable cir) { + cir.setReturnValue(fallback); + } +} diff --git a/src/main/resources/mixins.core.json b/src/main/resources/mixins.core.json index 23bb71e..67be2c4 100755 --- a/src/main/resources/mixins.core.json +++ b/src/main/resources/mixins.core.json @@ -58,11 +58,16 @@ "math.vec.FastMathVec3DMixin", "network.microopt.VarIntsMixin", "network.microopt.StringEncodingMixin", - "playerwatching.MixinChunkFilter", - "playerwatching.MixinServerPlayerEntity", - "playerwatching.optimize_nearby_player_lookups.MixinMobEntity", + "vmp.playerwatching.MixinChunkFilter", + "vmp.playerwatching.MixinServerPlayerEntity", + "vmp.playerwatching.optimize_nearby_player_lookups.MixinMobEntity", + "vmp.general.collections.MixinTypeFilterableList", + "vmp.entity.move_zero_velocity.MixinEntity", "shapes.blockstate_cache.BlockMixin", "shapes.lazy_shape_context.EntityShapeContextMixin", + "shapes.precompute_shape_arrays.FractionalDoubleListMixin", + "shapes.precompute_shape_arrays.SimpleVoxelShapeMixin", + "shapes.specialized_shapes.VoxelShapeMixin", "util.MixinLevelBlockEntityRetrieval", "util.accessors.ClientEntityManagerAccessor", "util.accessors.EntityTrackingSectionAccessor", @@ -75,6 +80,7 @@ "world.block_entity_ticking.sleeping.furnace.AbstractFurnaceBlockEntityMixin", "world.block_entity_ticking.support_cache.BlockEntityMixin", "world.block_entity_ticking.support_cache.DirectBlockEntityTickInvokerMixin", - "world.block_entity_ticking.support_cache.WorldChunkMixin" + "world.block_entity_ticking.support_cache.WorldChunkMixin", + "world.portal_checks.DisablePortalChecksMixin" ] }