Skip to content

Commit

Permalink
Update collision optimization to handle wind charges and use it in mo…
Browse files Browse the repository at this point in the history
…re places
  • Loading branch information
2No2Name committed May 20, 2024
1 parent a29281a commit 44f4330
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Class<?>> classFitEvaluator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -38,7 +40,7 @@ public class WorldHelper {
* @return iterator of entities with collision boxes
*/
public static List<Entity> 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<Entity> cache = getEntityCacheOrNull(world);
if (cache != null) {
world.getProfiler().visit("getEntities");
Expand All @@ -50,6 +52,21 @@ public static List<Entity> getEntitiesForCollision(EntityView entityView, Box bo
return entityView.getOtherEntities(collidingEntity, box);
}

public static List<Entity> getOtherEntitiesForCollision(EntityView entityView, Box box, @Nullable Entity collidingEntity, Predicate<? super Entity> 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<Entity> 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<Entity> getEntityCacheOrNull(World world) {
Expand All @@ -73,7 +90,7 @@ public static List<Entity> getEntitiesOfClassGroup(SectionedEntityCache<Entity>
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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Entity> getCollisionEntities(EntityView instance, @Nullable Entity entity, Box box, Predicate<? super Entity> predicate) {
return WorldHelper.getOtherEntitiesForCollision(instance, box, entity, predicate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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")
}
)
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/lithium.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 44f4330

Please sign in to comment.