From 44f4330b9ab1cef568e80336d949c61386f747b9 Mon Sep 17 00:00:00 2001 From: 2No2Name <2no2name@web.de> Date: Mon, 20 May 2024 19:28:46 +0200 Subject: [PATCH] Update collision optimization to handle wind charges and use it in more places --- .../common/entity/EntityClassGroup.java | 15 +++++++---- .../entity/LithiumEntityCollisions.java | 2 +- .../lithium/common/world/WorldHelper.java | 21 ++++++++++++++-- .../world/blockview/SingleBlockBlockView.java | 10 -------- .../intersection/EntityViewMixin.java | 25 +++++++++++++++++++ .../collisions/intersection/WorldMixin.java | 3 +-- .../collisions/intersection/package-info.java | 1 - src/main/resources/lithium.mixins.json | 1 + 8 files changed, 57 insertions(+), 21 deletions(-) create mode 100644 src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/EntityViewMixin.java diff --git a/src/main/java/me/jellysquid/mods/lithium/common/entity/EntityClassGroup.java b/src/main/java/me/jellysquid/mods/lithium/common/entity/EntityClassGroup.java index 68402bd22..d96722931 100644 --- a/src/main/java/me/jellysquid/mods/lithium/common/entity/EntityClassGroup.java +++ b/src/main/java/me/jellysquid/mods/lithium/common/entity/EntityClassGroup.java @@ -6,6 +6,8 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.boss.dragon.EnderDragonEntity; import net.minecraft.entity.mob.ShulkerEntity; +import net.minecraft.entity.projectile.BreezeWindChargeEntity; +import net.minecraft.entity.projectile.WindChargeEntity; import net.minecraft.entity.vehicle.MinecartEntity; import java.util.Objects; @@ -21,22 +23,25 @@ * @author 2No2Name */ public class EntityClassGroup { - public static final EntityClassGroup MINECART_BOAT_LIKE_COLLISION; //aka entities that will attempt to collide with all other entities when moving + public static final EntityClassGroup CUSTOM_COLLIDE_LIKE_MINECART_BOAT_WINDCHARGE; //aka entities that will attempt to collide with all other entities when moving static { String remapped_collidesWith = FabricLoader.getInstance().getMappingResolver().mapMethodName("intermediary", "net.minecraft.class_1297", "method_30949", "(Lnet/minecraft/class_1297;)Z"); - MINECART_BOAT_LIKE_COLLISION = new EntityClassGroup( + CUSTOM_COLLIDE_LIKE_MINECART_BOAT_WINDCHARGE = new EntityClassGroup( (Class entityClass) -> ReflectionUtil.hasMethodOverride(entityClass, Entity.class, true, remapped_collidesWith, Entity.class)); //sanity check: in case intermediary mappings changed, we fail - if ((!MINECART_BOAT_LIKE_COLLISION.contains(MinecartEntity.class))) { + if ((!CUSTOM_COLLIDE_LIKE_MINECART_BOAT_WINDCHARGE.contains(MinecartEntity.class))) { throw new AssertionError(); } - if ((MINECART_BOAT_LIKE_COLLISION.contains(ShulkerEntity.class))) { + if ((!CUSTOM_COLLIDE_LIKE_MINECART_BOAT_WINDCHARGE.contains(WindChargeEntity.class)) || (!CUSTOM_COLLIDE_LIKE_MINECART_BOAT_WINDCHARGE.contains(BreezeWindChargeEntity.class))) { + throw new AssertionError(); + } + if ((CUSTOM_COLLIDE_LIKE_MINECART_BOAT_WINDCHARGE.contains(ShulkerEntity.class))) { //should not throw an Error here, because another mod *could* add the method to ShulkerEntity. Wwarning when this sanity check fails. Logger.getLogger("Lithium EntityClassGroup").warning("Either Lithium EntityClassGroup is broken or something else gave Shulkers the minecart-like collision behavior."); } - MINECART_BOAT_LIKE_COLLISION.clear(); + CUSTOM_COLLIDE_LIKE_MINECART_BOAT_WINDCHARGE.clear(); } private final Predicate> classFitEvaluator; diff --git a/src/main/java/me/jellysquid/mods/lithium/common/entity/LithiumEntityCollisions.java b/src/main/java/me/jellysquid/mods/lithium/common/entity/LithiumEntityCollisions.java index 55b91b27c..a893e3a0a 100644 --- a/src/main/java/me/jellysquid/mods/lithium/common/entity/LithiumEntityCollisions.java +++ b/src/main/java/me/jellysquid/mods/lithium/common/entity/LithiumEntityCollisions.java @@ -101,7 +101,7 @@ protected VoxelShape computeNext() { if (entityList == null) { /* * In case entity's class is overriding Entity#collidesWith(Entity), all types of entities may be (=> are assumed to be) required. - * Otherwise only get entities that override Entity#isCollidable(), as other entities cannot collide. + * Otherwise, only get entities that override Entity#isCollidable(), as other entities cannot collide. */ entityList = WorldHelper.getEntitiesForCollision(view, box, entity); nextFilterIndex = 0; diff --git a/src/main/java/me/jellysquid/mods/lithium/common/world/WorldHelper.java b/src/main/java/me/jellysquid/mods/lithium/common/world/WorldHelper.java index 3b48b031c..22f431b99 100644 --- a/src/main/java/me/jellysquid/mods/lithium/common/world/WorldHelper.java +++ b/src/main/java/me/jellysquid/mods/lithium/common/world/WorldHelper.java @@ -16,10 +16,12 @@ import net.minecraft.world.EntityView; import net.minecraft.world.World; import net.minecraft.world.entity.SectionedEntityCache; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.function.Predicate; public class WorldHelper { public static final boolean CUSTOM_TYPE_FILTERABLE_LIST_DISABLED = !ClassGroupFilterableList.class.isAssignableFrom(TypeFilterableList.class); @@ -38,7 +40,7 @@ public class WorldHelper { * @return iterator of entities with collision boxes */ public static List getEntitiesForCollision(EntityView entityView, Box box, Entity collidingEntity) { - if (!CUSTOM_TYPE_FILTERABLE_LIST_DISABLED && entityView instanceof World world && (collidingEntity == null || !EntityClassGroup.MINECART_BOAT_LIKE_COLLISION.contains(collidingEntity.getClass()))) { + if (!CUSTOM_TYPE_FILTERABLE_LIST_DISABLED && entityView instanceof World world && (collidingEntity == null || !EntityClassGroup.CUSTOM_COLLIDE_LIKE_MINECART_BOAT_WINDCHARGE.contains(collidingEntity.getClass()))) { SectionedEntityCache cache = getEntityCacheOrNull(world); if (cache != null) { world.getProfiler().visit("getEntities"); @@ -50,6 +52,21 @@ public static List getEntitiesForCollision(EntityView entityView, Box bo return entityView.getOtherEntities(collidingEntity, box); } + public static List getOtherEntitiesForCollision(EntityView entityView, Box box, @Nullable Entity collidingEntity, Predicate entityPredicate) { + if (!CUSTOM_TYPE_FILTERABLE_LIST_DISABLED && entityView instanceof World world) { + if (collidingEntity == null || !EntityClassGroup.CUSTOM_COLLIDE_LIKE_MINECART_BOAT_WINDCHARGE.contains(collidingEntity.getClass())) { + SectionedEntityCache cache = getEntityCacheOrNull(world); + if (cache != null) { + world.getProfiler().visit("getEntities"); + return getEntitiesOfClassGroup(cache, collidingEntity, EntityClassGroup.NoDragonClassGroup.BOAT_SHULKER_LIKE_COLLISION, box); + } + } + } + //use vanilla code in case the shortcut is not applicable + // due to the reference entity implementing special collision or the mixin being disabled in the config + return entityView.getOtherEntities(collidingEntity, box, entityPredicate); + } + //Requires util.accessors public static SectionedEntityCache getEntityCacheOrNull(World world) { @@ -73,7 +90,7 @@ public static List getEntitiesOfClassGroup(SectionedEntityCache if (!entitiesOfType.isEmpty()) { for (Entity entity : entitiesOfType) { if (entity.getBoundingBox().intersects(box) && !entity.isSpectator() && entity != collidingEntity) { - //skip the dragon piece check without issues by only allowing only EntityClassGroup.NoDragonClassGroup as type + //skip the dragon piece check without issues by only allowing EntityClassGroup.NoDragonClassGroup as type entities.add(entity); } } diff --git a/src/main/java/me/jellysquid/mods/lithium/common/world/blockview/SingleBlockBlockView.java b/src/main/java/me/jellysquid/mods/lithium/common/world/blockview/SingleBlockBlockView.java index 16c6e6c82..41193ba73 100644 --- a/src/main/java/me/jellysquid/mods/lithium/common/world/blockview/SingleBlockBlockView.java +++ b/src/main/java/me/jellysquid/mods/lithium/common/world/blockview/SingleBlockBlockView.java @@ -82,16 +82,6 @@ public boolean doesNotIntersectEntities(Entity entity) { throw SingleBlockViewException.INSTANCE; } - @Override - public boolean isSpaceEmpty(Box box) { - throw SingleBlockViewException.INSTANCE; - } - - @Override - public boolean isSpaceEmpty(Entity entity) { - throw SingleBlockViewException.INSTANCE; - } - @Override public boolean isSpaceEmpty(@Nullable Entity entity, Box box) { throw SingleBlockViewException.INSTANCE; diff --git a/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/EntityViewMixin.java b/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/EntityViewMixin.java new file mode 100644 index 000000000..75d22a9dd --- /dev/null +++ b/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/EntityViewMixin.java @@ -0,0 +1,25 @@ +package me.jellysquid.mods.lithium.mixin.entity.collisions.intersection; + +import me.jellysquid.mods.lithium.common.world.WorldHelper; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.Box; +import net.minecraft.world.EntityView; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.List; +import java.util.function.Predicate; + +@Mixin(EntityView.class) +public interface EntityViewMixin { + + @Redirect( + method = "getEntityCollisions(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/Box;)Ljava/util/List;", + at = @At(value = "INVOKE", target = "Lnet/minecraft/world/EntityView;getOtherEntities(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/Box;Ljava/util/function/Predicate;)Ljava/util/List;") + ) + private List getCollisionEntities(EntityView instance, @Nullable Entity entity, Box box, Predicate predicate) { + return WorldHelper.getOtherEntitiesForCollision(instance, box, entity, predicate); + } +} diff --git a/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/WorldMixin.java b/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/WorldMixin.java index 9cb463fe6..7edbcc27f 100644 --- a/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/WorldMixin.java +++ b/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/WorldMixin.java @@ -3,7 +3,6 @@ import me.jellysquid.mods.lithium.common.entity.LithiumEntityCollisions; import net.minecraft.entity.Entity; import net.minecraft.util.math.Box; -import net.minecraft.world.EntityView; import net.minecraft.world.World; import net.minecraft.world.WorldAccess; import org.jetbrains.annotations.Nullable; @@ -25,7 +24,7 @@ public boolean isSpaceEmpty(@Nullable Entity entity, Box box) { boolean ret = !LithiumEntityCollisions.doesBoxCollideWithBlocks((World) (Object) this, entity, box); // If no blocks were collided with, try to check for entity collisions if we can read entities - if (ret && this instanceof EntityView) { + if (ret) { //needs to include world border collision ret = !LithiumEntityCollisions.doesBoxCollideWithHardEntities(this, entity, box); } diff --git a/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/package-info.java b/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/package-info.java index 15e71e53a..b67d67e40 100644 --- a/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/package-info.java +++ b/src/main/java/me/jellysquid/mods/lithium/mixin/entity/collisions/intersection/package-info.java @@ -1,7 +1,6 @@ @MixinConfigOption( description = "Uses faster block access for block collisions and delayed entity access with grouped boat/shulker for entity collisions when available", depends = { - @MixinConfigDependency(dependencyPath = "mixin.util.block_tracking"), @MixinConfigDependency(dependencyPath = "mixin.util.chunk_access") } ) diff --git a/src/main/resources/lithium.mixins.json b/src/main/resources/lithium.mixins.json index d1cf4f63e..7ca9b8adc 100644 --- a/src/main/resources/lithium.mixins.json +++ b/src/main/resources/lithium.mixins.json @@ -98,6 +98,7 @@ "collections.mob_spawning.PoolMixin", "collections.mob_spawning.SpawnSettingsMixin", "entity.collisions.fluid.EntityMixin", + "entity.collisions.intersection.EntityViewMixin", "entity.collisions.intersection.WorldMixin", "entity.collisions.movement.EntityMixin", "entity.collisions.unpushable_cramming.AbstractMinecartEntityMixin",