From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrIvanPlays <ivan@mrivanplays.com>
Date: Thu, 13 Aug 2020 15:14:36 +0300
Subject: [PATCH] Per entity (type) collision settings

Base patch was the only player collisions patch, the original author of was tr7zw <tr7zw@live.de>
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 <tr7zw@live.de>

diff --git a/src/main/java/de/minebench/origami/OrigamiConfig.java b/src/main/java/de/minebench/origami/OrigamiConfig.java
index 27599f422be266ad2fdbda49617661801c2c1991..2457b240f3b49dbd5fe0eb603d86418fd65f0205 100644
--- a/src/main/java/de/minebench/origami/OrigamiConfig.java
+++ b/src/main/java/de/minebench/origami/OrigamiConfig.java
@@ -135,6 +135,39 @@ public final class OrigamiConfig {
         private void pigmenDontTargetUnlessHit() {
             pigmenDontTargetUnlessHit = getBoolean("pigmen.dont-target-unless-hit", pigmenDontTargetUnlessHit);
         }
+
+        // Yatopia start
+        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
     }
 
 }
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java
index 424e0a1c31561aa06229a13b68d0cc367f392545..86493a37a1ca5d35e660dadf1d6005af55f67144 100644
--- a/src/main/java/net/minecraft/server/EntityLiving.java
+++ b/src/main/java/net/minecraft/server/EntityLiving.java
@@ -2957,7 +2957,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<Entity> list = com.tuinity.tuinity.util.CachedLists.getTempGetEntitiesList();
-        this.world.getEntities(this, this.getBoundingBox(), IEntitySelector.pushable(this, world.paperConfig.fixClimbingBypassingCrammingRule), list); // Paper - fix climbing bypassing cramming rule
+        this.world.getEntities(this, this.getBoundingBox(), org.yatopiamc.yatopia.server.EntityFilter.getFilter(this, world.paperConfig.fixClimbingBypassingCrammingRule), list); // Paper - fix climbing bypassing cramming rule // Yatopia
         try {
         // Tuinity end - reduce memory allocation from collideNearby
 
diff --git a/src/main/java/org/yatopiamc/yatopia/server/EntityFilter.java b/src/main/java/org/yatopiamc/yatopia/server/EntityFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..cb6bab603dcb20521868a482c872f65dd5733c15
--- /dev/null
+++ b/src/main/java/org/yatopiamc/yatopia/server/EntityFilter.java
@@ -0,0 +1,145 @@
+package org.yatopiamc.yatopia.server;
+
+import de.minebench.origami.OrigamiConfig;
+import java.util.function.Predicate;
+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;
+
+public class EntityFilter {
+
+    public static Predicate<Entity> getFilter(Entity entity, boolean ignoreClimbing) {
+        OrigamiConfig.WorldConfig config = entity.world.origamiConfig;
+        if (config.allCollisionsEnabled) {
+            return IEntitySelector.pushable(entity, ignoreClimbing);
+        }
+
+        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 tested -> false;
+        }
+
+        Predicate<Entity> ret = (tested) -> {
+            if (!tested.isCollidable(ignoreClimbing) || !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) -> {
+            if (tested.getEntityType() == EntityTypes.PLAYER && config.playerCollisions) {
+                return true;
+            }
+            if (tested.getEntityType().getEnumCreatureType() == EnumCreatureType.CREATURE && config.animalCollisions) {
+                return true;
+            }
+            if (tested.getEntityType().getEnumCreatureType() == EnumCreatureType.AMBIENT && config.ambientCollisions) {
+                return true;
+            }
+            if (tested.getEntityType().getEnumCreatureType() == EnumCreatureType.MONSTER) {
+                if (config.monsterCollisions) {
+                    if (config.pillagerCollisions) {
+                        return true;
+                    } else {
+                        return tested.getEntityType() != EntityTypes.PILLAGER;
+                    }
+                } else {
+                    if (config.pillagerCollisions) {
+                        return tested.getEntityType() == EntityTypes.PILLAGER;
+                    } else {
+                        return false;
+                    }
+                }
+            }
+            if (tested.getEntityType().getEnumCreatureType() == EnumCreatureType.MISC) {
+                if (config.miscCollisions) {
+                    if (config.villagerCollisions && config.ironGolemCollisions && config.itemCollisions) {
+                        return true;
+                    }
+                    if (!config.villagerCollisions) {
+                        if (tested.getEntityType() == EntityTypes.VILLAGER) {
+                            return false;
+                        }
+                    }
+                    if (!config.ironGolemCollisions) {
+                        if (tested.getEntityType() == EntityTypes.IRON_GOLEM) {
+                            return false;
+                        }
+                    }
+                    if (!config.itemCollisions) {
+                        if (tested.getEntityType() == EntityTypes.ITEM) {
+                            return false;
+                        }
+                    }
+                    return true;
+                } else {
+                    if (config.villagerCollisions && config.ironGolemCollisions && config.itemCollisions) {
+                        if (tested.getEntityType() == EntityTypes.VILLAGER) {
+                            return true;
+                        }
+                        if (tested.getEntityType() == EntityTypes.IRON_GOLEM) {
+                            return true;
+                        }
+                        if (tested.getEntityType() == EntityTypes.ITEM) {
+                            return true;
+                        }
+                    }
+                    if (config.villagerCollisions && config.ironGolemCollisions) {
+                        if (tested.getEntityType() == EntityTypes.VILLAGER) {
+                            return true;
+                        }
+                        if (tested.getEntityType() == EntityTypes.IRON_GOLEM) {
+                            return true;
+                        }
+                    }
+                    if (config.villagerCollisions) {
+                        if (tested.getEntityType() == EntityTypes.VILLAGER) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            }
+            if (tested.getEntityType().getEnumCreatureType() == EnumCreatureType.WATER_CREATURE && config.waterCreatureCollisions) {
+                return true;
+            }
+            if (tested.getEntityType().getEnumCreatureType() == EnumCreatureType.WATER_AMBIENT && config.waterAmbientCollisions) {
+                return true;
+            }
+            return false;
+        });
+
+        return ret;
+    }
+}
