From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrIvanPlays Date: Tue, 11 Aug 2020 10:28:04 +0300 Subject: [PATCH] Per entity (type) collision settings Base patch was the only player collisions patch, the original author of was tr7zw but pretty much the whole implementation changed. This patch implements per entity (type) collision settings with 100% compatibility with bukkit api and vanilla. The whole code is based around 1 class, the EntityFilter class. Whole filtering logic is there. Co-authored-by: tr7zw diff --git a/src/main/java/de/minebench/origami/OrigamiConfig.java b/src/main/java/de/minebench/origami/OrigamiConfig.java index e2bbbfeb7e2505479e6a457294aaa550b97319ca..a89209347418b3006745c50043d0abdf2b91babc 100644 --- a/src/main/java/de/minebench/origami/OrigamiConfig.java +++ b/src/main/java/de/minebench/origami/OrigamiConfig.java @@ -125,6 +125,37 @@ public final class OrigamiConfig { private void fastFeatureSearchDontLoad() { fastFeatureSearchDontLoad = getBoolean("fast-feature-search-dont-load", false); } + + public boolean playerCollisions = true; + public boolean animalCollisions = true; + public boolean ambientCollisions = true; + public boolean monsterCollisions = true; + public boolean villagerCollisions = true; + public boolean pillagerCollisions = true; + public boolean ironGolemCollisions = true; + public boolean miscCollisions = true; + public boolean itemCollisions = true; + public boolean waterCreatureCollisions = true; + public boolean waterAmbientCollisions = true; + public boolean allCollisionsEnabled = false; + private void specificCollisionSettings() { + playerCollisions = getBoolean("collisions.players", playerCollisions); + animalCollisions = getBoolean("collisions.animals", animalCollisions); + ambientCollisions = getBoolean("collisions.ambient", ambientCollisions); + monsterCollisions = getBoolean("collisions.monsters", monsterCollisions); + villagerCollisions = getBoolean("collisions.villagers", villagerCollisions); + pillagerCollisions = getBoolean("collisions.pillagers", pillagerCollisions); + ironGolemCollisions = getBoolean("collisions.iron-golems", ironGolemCollisions); + miscCollisions = getBoolean("collisions.misc", miscCollisions); + itemCollisions = getBoolean("collisions.items", itemCollisions); + waterCreatureCollisions = getBoolean("collisions.water-creature", waterCreatureCollisions); + waterAmbientCollisions = getBoolean("collisions.water-ambient", waterAmbientCollisions); + + allCollisionsEnabled = + playerCollisions && animalCollisions && ambientCollisions && monsterCollisions && villagerCollisions + && pillagerCollisions && ironGolemCollisions && miscCollisions && itemCollisions + && waterCreatureCollisions && waterAmbientCollisions; + } // Yatopia end } diff --git a/src/main/java/dev/tr7zw/yatopia/EntityFilter.java b/src/main/java/dev/tr7zw/yatopia/EntityFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..e6617833a7aea4803b78bc55b633fac9698688bd --- /dev/null +++ b/src/main/java/dev/tr7zw/yatopia/EntityFilter.java @@ -0,0 +1,131 @@ +package dev.tr7zw.yatopia; + +import com.google.common.base.Predicates; + +import de.minebench.origami.OrigamiConfig; + +import net.minecraft.server.Entity; +import net.minecraft.server.EntityTypes; +import net.minecraft.server.EnumCreatureType; +import net.minecraft.server.IEntitySelector; +import net.minecraft.server.ScoreboardTeamBase; +import net.minecraft.server.World; + +import java.util.function.Predicate; + +public class EntityFilter { + + public static Predicate getFilter(Entity entity) { + OrigamiConfig.WorldConfig config = entity.world.origamiConfig; + if (config.allCollisionsEnabled) { + return IEntitySelector.a(entity); + } + + ScoreboardTeamBase entityTeam = entity.getScoreboardTeam(); + ScoreboardTeamBase.EnumTeamPush entityTeamPush = + entityTeam == null ? + ScoreboardTeamBase.EnumTeamPush.ALWAYS : + entityTeam.getCollisionRule(); + + if (entityTeamPush == ScoreboardTeamBase.EnumTeamPush.NEVER || entity.world.isClientSide + || entity.isSpectator()) { + return Predicates.alwaysFalse(); + } + + Predicate ret = (tested) -> { + if (!tested.canCollideWith(entity) || !entity.canCollideWith(tested)) { + return false; + } + ScoreboardTeamBase testedTeam = tested.getScoreboardTeam(); + ScoreboardTeamBase.EnumTeamPush testedPush = + testedTeam == null ? + ScoreboardTeamBase.EnumTeamPush.ALWAYS : + testedTeam.getCollisionRule(); + + if (testedPush == ScoreboardTeamBase.EnumTeamPush.NEVER) { + return false; + } + if (testedTeam != null && entityTeam != null) { + // see IEntitySelector#a(Entity) + // copied from there, although for me this logic doesn't seem quite right + boolean ally = entityTeam.isAlly(testedTeam); + + if ((entityTeamPush == ScoreboardTeamBase.EnumTeamPush.PUSH_OWN_TEAM || + testedPush == ScoreboardTeamBase.EnumTeamPush.PUSH_OWN_TEAM) && ally) { + return false; + } + return (entityTeamPush != ScoreboardTeamBase.EnumTeamPush.PUSH_OTHER_TEAMS + && testedPush != ScoreboardTeamBase.EnumTeamPush.PUSH_OTHER_TEAMS) || ally; + } else { + return testedPush == ScoreboardTeamBase.EnumTeamPush.ALWAYS && + entityTeamPush == ScoreboardTeamBase.EnumTeamPush.ALWAYS; + } + }; + + ret = ret.and((tested) -> { + // no need to continue if we already got false from this check + if (!tested.canCollideWith(entity) || !entity.canCollideWith(tested)) { + return false; + } + + Predicate entitySpecific = (es) -> { + if (config.playerCollisions) { + return es.getEntityType() == EntityTypes.PLAYER; + } + return false; + }; + + if (config.animalCollisions) { + entitySpecific = entitySpecific.or((es) -> es.getEntityType().getEnumCreatureType() == EnumCreatureType.CREATURE); + } + + if (config.ambientCollisions) { + entitySpecific = entitySpecific.or((es) -> es.getEntityType().getEnumCreatureType() == EnumCreatureType.AMBIENT); + } + + if (config.monsterCollisions) { + entitySpecific = entitySpecific.or((es) -> es.getEntityType().getEnumCreatureType() == EnumCreatureType.MONSTER + && (config.pillagerCollisions || es.getEntityType() != EntityTypes.PILLAGER)); + } + + if (config.miscCollisions) { + entitySpecific = entitySpecific.or((es) -> { + if (es.getEntityType().getEnumCreatureType() == EnumCreatureType.MISC) { + return miscVPI(es, config, true); + } + return false; + }); + } else { + entitySpecific = entitySpecific.or((es) -> miscVPI(es, config, false)); + } + + if (config.waterCreatureCollisions) { + entitySpecific = entitySpecific.or((es) -> es.getEntityType().getEnumCreatureType() == EnumCreatureType.WATER_CREATURE); + } + + if (config.waterAmbientCollisions) { + entitySpecific = entitySpecific.or((es) -> es.getEntityType().getEnumCreatureType() == EnumCreatureType.WATER_AMBIENT); + } + + return entitySpecific.test(tested); + }); + + return ret; + } + + private static boolean miscVPI(Entity es, OrigamiConfig.WorldConfig config, boolean isMisc) { + Predicate ret = (p) -> { + if (config.villagerCollisions) { + return p.getEntityType() == EntityTypes.VILLAGER; + } + return isMisc; + }; + if (config.ironGolemCollisions) { + ret = ret.or((p) -> p.getEntityType() == EntityTypes.IRON_GOLEM); + } + if (config.itemCollisions) { + ret = ret.or((p) -> p.getEntityType() == EntityTypes.ITEM); + } + return ret.test(es); + } +} diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java index c30fee13723cef0f03eb5a87851158cf347fae3c..a4123c2c7dc84803194459895f29d35643b71d04 100644 --- a/src/main/java/net/minecraft/server/EntityLiving.java +++ b/src/main/java/net/minecraft/server/EntityLiving.java @@ -2846,7 +2846,7 @@ public abstract class EntityLiving extends Entity { // Paper - end don't run getEntities if we're not going to use its result // Tuinity start - reduce memory allocation from collideNearby List list = com.tuinity.tuinity.util.CachedLists.getTempGetEntitiesList(); - this.world.getEntities(this, this.getBoundingBox(), IEntitySelector.a(this), list); + this.world.getEntities(this, this.getBoundingBox(), dev.tr7zw.yatopia.EntityFilter.getFilter(this), list); // Yatopia try { // Tuinity end - reduce memory allocation from collideNearby