diff --git a/patches/server/0022-lithium-MixinBiome.patch b/patches/server/0022-lithium-MixinBiome.patch new file mode 100644 index 00000000..407f9174 --- /dev/null +++ b/patches/server/0022-lithium-MixinBiome.patch @@ -0,0 +1,211 @@ +From 25534c1f9b7f6fc7d0394851f278a520d738ad11 Mon Sep 17 00:00:00 2001 +From: tr7zw +Date: Tue, 12 May 2020 00:38:31 +0200 +Subject: [PATCH] lithium MixinBiome + +--- + .../common/util/collections/HashedList.java | 168 ++++++++++++++++++ + .../java/net/minecraft/server/BiomeBase.java | 4 +- + 2 files changed, 171 insertions(+), 1 deletion(-) + create mode 100644 src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java + +diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java +new file mode 100644 +index 000000000..a2e3e96e1 +--- /dev/null ++++ b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java +@@ -0,0 +1,168 @@ ++package me.jellysquid.mods.lithium.common.util.collections; ++ ++import it.unimi.dsi.fastutil.objects.ObjectArraySet; ++ ++import java.util.*; ++ ++/** ++ * Wraps a {@link List} with a hash table which provides O(1) lookups for {@link Collection#contains(Object)}. ++ * ++ * @see https://github.com/jellysquid3/lithium-fabric/blob/1.16.x/fabric/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java ++ */ ++public class HashedList implements List { ++ private final List list; ++ private final Set set; ++ ++ private HashedList(List list, Set set) { ++ this.list = list; ++ this.set = set; ++ } ++ ++ @Override ++ public int size() { ++ return this.list.size(); ++ } ++ ++ @Override ++ public boolean isEmpty() { ++ return this.list.isEmpty(); ++ } ++ ++ @Override ++ public boolean contains(Object o) { ++ return this.set.contains(o); ++ } ++ ++ @Override ++ public Iterator iterator() { ++ return this.list.iterator(); ++ } ++ ++ @Override ++ public Object[] toArray() { ++ return this.list.toArray(); ++ } ++ ++ @Override ++ public T1[] toArray(T1[] a) { ++ return this.list.toArray(a); ++ } ++ ++ @Override ++ public boolean add(T t) { ++ this.set.add(t); ++ ++ return this.list.add(t); ++ } ++ ++ @Override ++ public boolean remove(Object o) { ++ this.set.remove(o); ++ ++ return this.list.remove(o); ++ } ++ ++ @Override ++ public boolean containsAll(Collection c) { ++ return this.set.containsAll(c); ++ } ++ ++ @Override ++ public boolean addAll(Collection c) { ++ this.set.addAll(c); ++ ++ return this.list.addAll(c); ++ } ++ ++ @Override ++ public boolean addAll(int index, Collection c) { ++ this.set.addAll(c); ++ ++ return this.list.addAll(index, c); ++ } ++ ++ @Override ++ public boolean removeAll(Collection c) { ++ this.set.removeAll(c); ++ ++ return this.list.removeAll(c); ++ } ++ ++ @Override ++ public boolean retainAll(Collection c) { ++ this.set.retainAll(c); ++ ++ return this.list.retainAll(c); ++ } ++ ++ @Override ++ public void clear() { ++ this.set.clear(); ++ this.list.clear(); ++ } ++ ++ @Override ++ public T get(int index) { ++ return this.list.get(index); ++ } ++ ++ @Override ++ public T set(int index, T element) { ++ T prev = this.list.set(index, element); ++ ++ if (prev != null) { ++ this.set.remove(prev); ++ } ++ ++ this.set.add(element); ++ ++ return prev; ++ } ++ ++ @Override ++ public void add(int index, T element) { ++ this.set.add(element); ++ ++ this.list.add(index, element); ++ } ++ ++ @Override ++ public T remove(int index) { ++ T prev = this.list.remove(index); ++ ++ if (prev != null) { ++ this.set.remove(prev); ++ } ++ ++ return prev; ++ } ++ ++ @Override ++ public int indexOf(Object o) { ++ return this.list.indexOf(o); ++ } ++ ++ @Override ++ public int lastIndexOf(Object o) { ++ return this.list.lastIndexOf(o); ++ } ++ ++ @Override ++ public ListIterator listIterator() { ++ return this.list.listIterator(); ++ } ++ ++ @Override ++ public ListIterator listIterator(int index) { ++ return this.list.listIterator(index); ++ } ++ ++ @Override ++ public List subList(int fromIndex, int toIndex) { ++ return this.list.subList(fromIndex, toIndex); ++ } ++ ++ public static HashedList wrapper(List list) { ++ return new HashedList<>(list, new ObjectArraySet<>(list)); ++ } ++} +\ No newline at end of file +diff --git a/src/main/java/net/minecraft/server/BiomeBase.java b/src/main/java/net/minecraft/server/BiomeBase.java +index 798d84795..897e56f0c 100644 +--- a/src/main/java/net/minecraft/server/BiomeBase.java ++++ b/src/main/java/net/minecraft/server/BiomeBase.java +@@ -7,6 +7,8 @@ import com.google.common.collect.Sets; + import com.mojang.serialization.Codec; + import com.mojang.serialization.codecs.RecordCodecBuilder; + import it.unimi.dsi.fastutil.longs.Long2FloatLinkedOpenHashMap; ++import me.jellysquid.mods.lithium.common.util.collections.HashedList; ++ + import java.util.Arrays; + import java.util.Collection; + import java.util.Comparator; +@@ -139,7 +141,7 @@ public class BiomeBase { + for (j = 0; j < i; ++j) { + EnumCreatureType enumcreaturetype = aenumcreaturetype[j]; + +- this.v.put(enumcreaturetype, new MobList()); // Paper ++ this.v.put(enumcreaturetype, HashedList.wrapper(new MobList())); // Paper // YAPFA lithium change + } + + } else { +-- +2.25.1.windows.1 + diff --git a/patches/server/0023-Item-stuck-sleep-config.patch b/patches/server/0023-Item-stuck-sleep-config.patch new file mode 100644 index 00000000..4b7771ad --- /dev/null +++ b/patches/server/0023-Item-stuck-sleep-config.patch @@ -0,0 +1,41 @@ +From 86be96f8ba8285729813e2e397c762b4123c1357 Mon Sep 17 00:00:00 2001 +From: tr7zw +Date: Tue, 16 Jun 2020 17:29:20 +0200 +Subject: [PATCH] Item stuck sleep config + +--- + src/main/java/de/tr7zw/yapfa/YapfaConfig.java | 5 +++++ + src/main/java/net/minecraft/server/EntityItem.java | 2 +- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/main/java/de/tr7zw/yapfa/YapfaConfig.java b/src/main/java/de/tr7zw/yapfa/YapfaConfig.java +index 716b2dea9..a158e9dc8 100644 +--- a/src/main/java/de/tr7zw/yapfa/YapfaConfig.java ++++ b/src/main/java/de/tr7zw/yapfa/YapfaConfig.java +@@ -216,4 +216,9 @@ public class YapfaConfig { + pistonPushLimit = getInt("settings.pistonPushLimit", 12); + } + ++ public static int itemStuckSleepTicks = 1; ++ private static void itemStuckSleepTicks() { ++ itemStuckSleepTicks = getInt("settings.itemStuckSleepTicks", 1); ++ } ++ + } +\ No newline at end of file +diff --git a/src/main/java/net/minecraft/server/EntityItem.java b/src/main/java/net/minecraft/server/EntityItem.java +index a7860cb4d..6c320dca0 100644 +--- a/src/main/java/net/minecraft/server/EntityItem.java ++++ b/src/main/java/net/minecraft/server/EntityItem.java +@@ -81,7 +81,7 @@ public class EntityItem extends Entity { + + if (this.world.isClientSide) { + this.noclip = false; +- } else { ++ } else if(!this.onGround || this.noclip || this.ticksLived % de.tr7zw.yapfa.YapfaConfig.itemStuckSleepTicks == 0) { // YAPFA + this.noclip = !this.world.getCubes(this); + if (this.noclip) { + this.k(this.locX(), (this.getBoundingBox().minY + this.getBoundingBox().maxY) / 2.0D, this.locZ()); +-- +2.25.1.windows.1 + diff --git a/patches/server/0024-Option-for-simpler-Villagers.patch b/patches/server/0024-Option-for-simpler-Villagers.patch new file mode 100644 index 00000000..71e43e67 --- /dev/null +++ b/patches/server/0024-Option-for-simpler-Villagers.patch @@ -0,0 +1,194 @@ +From 41a6bfdd6dc58410f9b3e347f4e7b8c1b787cd4e Mon Sep 17 00:00:00 2001 +From: tr7zw +Date: Fri, 19 Jun 2020 19:21:35 +0200 +Subject: [PATCH] Option for simpler Villagers + +Option to extremly simplefy the villager AI. +--- + src/main/java/de/tr7zw/yapfa/YapfaConfig.java | 10 +++ + .../net/minecraft/server/EntityVillager.java | 83 ++++++++++++++++++- + 2 files changed, 92 insertions(+), 1 deletion(-) + +diff --git a/src/main/java/de/tr7zw/yapfa/YapfaConfig.java b/src/main/java/de/tr7zw/yapfa/YapfaConfig.java +index a158e9dc8..aea46527b 100644 +--- a/src/main/java/de/tr7zw/yapfa/YapfaConfig.java ++++ b/src/main/java/de/tr7zw/yapfa/YapfaConfig.java +@@ -221,4 +221,14 @@ public class YapfaConfig { + itemStuckSleepTicks = getInt("settings.itemStuckSleepTicks", 1); + } + ++ public static boolean simplerVillagerBehavior = false; ++ private static void simplerVillagerBehavior() { ++ simplerVillagerBehavior = getBoolean("settings.villager.simplerVillagerBehavior", false); ++ } ++ ++ public static boolean villagersHideAtNight = false; ++ private static void villagersHideAtNight() { ++ villagersHideAtNight = getBoolean("settings.villager.villagersHideAtNight", false); ++ } ++ + } +\ No newline at end of file +diff --git a/src/main/java/net/minecraft/server/EntityVillager.java b/src/main/java/net/minecraft/server/EntityVillager.java +index bf019043a..5db697b66 100644 +--- a/src/main/java/net/minecraft/server/EntityVillager.java ++++ b/src/main/java/net/minecraft/server/EntityVillager.java +@@ -7,6 +7,8 @@ import com.mojang.datafixers.util.Pair; + import com.mojang.serialization.DataResult; + import com.mojang.serialization.Dynamic; + import com.mojang.serialization.DynamicOps; ++ ++import de.tr7zw.yapfa.YapfaConfig; + import it.unimi.dsi.fastutil.ints.Int2ObjectMap; + import java.util.Collection; + import java.util.Iterator; +@@ -30,7 +32,9 @@ import org.bukkit.event.entity.VillagerReplenishTradeEvent; + // CraftBukkit end + + public class EntityVillager extends EntityVillagerAbstract implements ReputationHandler, VillagerDataHolder { +- ++ ++ //YAPFA ++ private boolean simplerVillagerBehavior = YapfaConfig.simplerVillagerBehavior; //get this during villager creation so a reloaded config doesn't get them into an invalid state + private static final DataWatcherObject by = DataWatcher.a(EntityVillager.class, DataWatcherRegistry.q); + public static final Map bw = ImmutableMap.of(Items.BREAD, 4, Items.POTATO, 1, Items.CARROT, 1, Items.BEETROOT, 1); + private static final Set bz = ImmutableSet.of(Items.BREAD, Items.POTATO, Items.CARROT, Items.WHEAT, Items.WHEAT_SEEDS, Items.BEETROOT, new Item[]{Items.BEETROOT_SEEDS}); +@@ -66,12 +70,49 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + public EntityVillager(EntityTypes entitytypes, World world, VillagerType villagertype) { + super(entitytypes, world); + this.bF = new Reputation(); ++ if(!simplerVillagerBehavior) { + ((Navigation) this.getNavigation()).a(true); + this.getNavigation().d(true); ++ }else { ++ initPathfinder(); ++ } + this.setCanPickupLoot(true); + this.setVillagerData(this.getVillagerData().withType(villagertype).withProfession(VillagerProfession.NONE)); + } + ++ //YAPFA start ++ @Override ++ protected void initPathfinder() { ++ if(!simplerVillagerBehavior)return; ++ this.goalSelector.a(0, new PathfinderGoalFloat(this)); ++ if(YapfaConfig.villagersHideAtNight) { ++ this.goalSelector.a(0, new PathfinderGoalUseItem<>(this, PotionUtil.a(new ItemStack(Items.POTION), Potions.INVISIBILITY), SoundEffects.ENTITY_WANDERING_TRADER_DISAPPEARED, (entityvillagertrader) -> { ++ return !this.world.isDay() && !entityvillagertrader.isInvisible(); ++ })); ++ this.goalSelector.a(0, new PathfinderGoalUseItem<>(this, new ItemStack(Items.MILK_BUCKET), SoundEffects.ENTITY_WANDERING_TRADER_REAPPEARED, (entityvillagertrader) -> { ++ return this.world.isDay() && entityvillagertrader.isInvisible(); ++ })); ++ } ++ this.goalSelector.a(1, new PathfinderGoalTradeWithPlayer(this)); ++ this.goalSelector.a(1, new PathfinderGoalAvoidTarget<>(this, EntityZombie.class, 8.0F, 0.5D, 0.5D)); ++ this.goalSelector.a(1, new PathfinderGoalAvoidTarget<>(this, EntityEvoker.class, 12.0F, 0.5D, 0.5D)); ++ this.goalSelector.a(1, new PathfinderGoalAvoidTarget<>(this, EntityVindicator.class, 8.0F, 0.5D, 0.5D)); ++ this.goalSelector.a(1, new PathfinderGoalAvoidTarget<>(this, EntityVex.class, 8.0F, 0.5D, 0.5D)); ++ this.goalSelector.a(1, new PathfinderGoalAvoidTarget<>(this, EntityPillager.class, 15.0F, 0.5D, 0.5D)); ++ this.goalSelector.a(1, new PathfinderGoalAvoidTarget<>(this, EntityIllagerIllusioner.class, 12.0F, 0.5D, 0.5D)); ++ this.goalSelector.a(1, new PathfinderGoalPanic(this, 0.5D)); ++ this.goalSelector.a(1, new PathfinderGoalLookAtTradingPlayer(this)); ++ this.goalSelector.a(2, new PathfinderGoalStrollVillageGolem(this, 0.6D)); ++ this.goalSelector.a(3, new PathfinderGoalMoveThroughVillage(this, 0.6D, false, 4, () -> { ++ return false; ++ })); ++ this.goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, 0.35D)); ++ this.goalSelector.a(8, new PathfinderGoalRandomStrollLand(this, 0.35D)); ++ this.goalSelector.a(9, new PathfinderGoalInteract(this, EntityHuman.class, 3.0F, 1.0F)); ++ this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F)); ++ } ++ //YAPFA end ++ + @Override + public BehaviorController getBehaviorController() { + return (BehaviorController) super.getBehaviorController(); // CraftBukkit - decompile error +@@ -84,6 +125,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + + @Override + protected BehaviorController a(Dynamic dynamic) { ++ if(simplerVillagerBehavior)return super.a(dynamic); //YAPFA Don't use behaviorcontroller for simple Villagers + BehaviorController behaviorcontroller = this.cJ().a(dynamic); + + this.a(behaviorcontroller); +@@ -162,10 +204,43 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + } + // Spigot End + ++ // YAPFA start ++ private VillagerProfession getRandomProfession() { ++ int type = random.nextInt(13); ++ switch(type) { ++ case 0: return VillagerProfession.ARMORER; ++ case 1: return VillagerProfession.BUTCHER; ++ case 2: return VillagerProfession.CARTOGRAPHER; ++ case 3: return VillagerProfession.CLERIC; ++ case 4: return VillagerProfession.FARMER; ++ case 5: return VillagerProfession.FISHERMAN; ++ case 6: return VillagerProfession.FLETCHER; ++ case 7: return VillagerProfession.LEATHERWORKER; ++ case 8: return VillagerProfession.LIBRARIAN; ++ case 9: return VillagerProfession.MASON; ++ case 10: return VillagerProfession.SHEPHERD; ++ case 11: return VillagerProfession.TOOLSMITH; ++ case 12: return VillagerProfession.WEAPONSMITH; ++ default: return VillagerProfession.FARMER; ++ } ++ } ++ ++ // YAPFA end ++ + @Override + protected void mobTick() { mobTick(false); } + protected void mobTick(boolean inactive) { ++ // YAPFA start ++ if(simplerVillagerBehavior && this.getVillagerData().getProfession() == VillagerProfession.NONE) ++ this.setVillagerData(this.getVillagerData().withProfession(getRandomProfession())); ++ if(simplerVillagerBehavior) { ++ if (canRefresh()) { ++ restUses(); ++ } ++ } ++ // YAPFA end + this.world.getMethodProfiler().enter("villagerBrain"); ++ if(!simplerVillagerBehavior) // YAPFA + if (!inactive) this.getBehaviorController().a((WorldServer) this.world, this); // CraftBukkit - decompile error // Paper + if (this.bM) { + this.bM = false; +@@ -296,6 +371,8 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + return true; + } + ++ public void restUses() {fb();} // YAPFA obf helper ++ + public void fb() { + this.fp(); + Iterator iterator = this.getOffers().iterator(); +@@ -330,6 +407,8 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + return this.bK == 0 || this.bK < 2 && this.world.getTime() > this.bJ + 2400L; + } + ++ public boolean canRefresh() {return fc();} // YAPFA obf helper ++ + public boolean fc() { + long i = this.bJ + 12000L; + long j = this.world.getTime(); +@@ -577,6 +656,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + } + + private void a(Entity entity) { ++ if(simplerVillagerBehavior)return; // YAPFA + if (this.world instanceof WorldServer) { + Optional> optional = this.bn.getMemory(MemoryModuleType.VISIBLE_MOBS); + +@@ -593,6 +673,7 @@ public class EntityVillager extends EntityVillagerAbstract implements Reputation + } + + public void a(MemoryModuleType memorymoduletype) { ++ if(simplerVillagerBehavior)return; // YAPFA + if (this.world instanceof WorldServer) { + MinecraftServer minecraftserver = ((WorldServer) this.world).getMinecraftServer(); + +-- +2.25.1.windows.1 + diff --git a/patches/server/0025-Heavily-optimize-furnance-fuel-and-recipe-lookups.patch b/patches/server/0025-Heavily-optimize-furnance-fuel-and-recipe-lookups.patch new file mode 100644 index 00000000..e09943d7 --- /dev/null +++ b/patches/server/0025-Heavily-optimize-furnance-fuel-and-recipe-lookups.patch @@ -0,0 +1,89 @@ +From 40fa0bc6f6838a9bb268864cc02a03b6c1e7e4d8 Mon Sep 17 00:00:00 2001 +From: tr7zw +Date: Thu, 25 Jun 2020 23:40:12 +0200 +Subject: [PATCH] Heavily optimize furnance fuel and recipe lookups + +--- + .../net/minecraft/server/CraftingManager.java | 19 +++++++++++++++- + .../minecraft/server/TileEntityFurnace.java | 22 +++++++++++++++++++ + 2 files changed, 40 insertions(+), 1 deletion(-) + +diff --git a/src/main/java/net/minecraft/server/CraftingManager.java b/src/main/java/net/minecraft/server/CraftingManager.java +index f27c7041c..384cb3c62 100644 +--- a/src/main/java/net/minecraft/server/CraftingManager.java ++++ b/src/main/java/net/minecraft/server/CraftingManager.java +@@ -89,7 +89,24 @@ public class CraftingManager extends ResourceDataJson { + }).findFirst(); + c0.setCurrentRecipe(recipe.orElse(null)); // CraftBukkit - Clear recipe when no recipe is found + // CraftBukkit end +- return recipe; ++ // YAPFA start ++ if(c0.getCurrentRecipe() != null) { ++ Optional optional = recipes.a(c0.getCurrentRecipe(), world, c0); ++ if(optional.isPresent()) { ++ c0.setCurrentRecipe(optional.get()); ++ return optional; ++ } ++ } ++ for(IRecipe rep : this.a(recipes)) { ++ Optional optional = recipes.a(rep, world, c0); ++ if(optional.isPresent()) { ++ c0.setCurrentRecipe(optional.get()); ++ return optional; ++ } ++ } ++ c0.setCurrentRecipe(null); // CraftBukkit - Clear recipe when no recipe is found ++ return Optional.empty(); ++ // YAPFA end + } + + public > List a(Recipes recipes) { +diff --git a/src/main/java/net/minecraft/server/TileEntityFurnace.java b/src/main/java/net/minecraft/server/TileEntityFurnace.java +index 59aa2f8a7..7b1d20d39 100644 +--- a/src/main/java/net/minecraft/server/TileEntityFurnace.java ++++ b/src/main/java/net/minecraft/server/TileEntityFurnace.java +@@ -99,7 +99,13 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I + this.c = recipes; + } + ++ //YAPFA ++ private static Map cachedFuelMap = null; ++ + public static Map f() { ++ if(cachedFuelMap != null) { ++ return cachedFuelMap; // YAPFA ++ } + Map map = Maps.newLinkedHashMap(); + + a(map, (IMaterial) Items.LAVA_BUCKET, 20000); +@@ -162,6 +168,7 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I + a(map, (IMaterial) Blocks.FLETCHING_TABLE, 300); + a(map, (IMaterial) Blocks.SMITHING_TABLE, 300); + a(map, (IMaterial) Blocks.COMPOSTER, 300); ++ cachedFuelMap = map; // YAPFA + return map; + } + +@@ -613,4 +620,19 @@ public abstract class TileEntityFurnace extends TileEntityContainer implements I + } + + } ++ ++ // YAPFA start ++ private IRecipe cachedRecipe = null; ++ @Override ++ public IRecipe getCurrentRecipe() { ++ return cachedRecipe; ++ } ++ @Override ++ public void setCurrentRecipe(IRecipe recipe) { ++ cachedRecipe = recipe; ++ } ++ ++ ++ // YAPFA end ++ + } +-- +2.25.1.windows.1 + diff --git a/patches/server/0026-Optimize-Hopper-logic.patch b/patches/server/0026-Optimize-Hopper-logic.patch new file mode 100644 index 00000000..529c9277 --- /dev/null +++ b/patches/server/0026-Optimize-Hopper-logic.patch @@ -0,0 +1,330 @@ +From 920e25115ab67f8faed683ea741742f81a933bb4 Mon Sep 17 00:00:00 2001 +From: tr7zw +Date: Fri, 26 Jun 2020 01:11:47 +0200 +Subject: [PATCH] Optimize Hopper logic + +--- + .../net/minecraft/server/BlockHopper.java | 230 ++++++++++++++++++ + .../minecraft/server/TileEntityHopper.java | 36 ++- + 2 files changed, 262 insertions(+), 4 deletions(-) + create mode 100644 src/main/java/net/minecraft/server/BlockHopper.java + +diff --git a/src/main/java/net/minecraft/server/BlockHopper.java b/src/main/java/net/minecraft/server/BlockHopper.java +new file mode 100644 +index 000000000..31ee358f8 +--- /dev/null ++++ b/src/main/java/net/minecraft/server/BlockHopper.java +@@ -0,0 +1,230 @@ ++package net.minecraft.server; ++ ++import java.util.OptionalInt; ++import net.minecraft.server.Block; ++import net.minecraft.server.BlockActionContext; ++import net.minecraft.server.BlockBase; ++import net.minecraft.server.BlockPosition; ++import net.minecraft.server.BlockProperties; ++import net.minecraft.server.BlockStateBoolean; ++import net.minecraft.server.BlockStateDirection; ++import net.minecraft.server.BlockStateList; ++import net.minecraft.server.BlockTileEntity; ++import net.minecraft.server.Container; ++import net.minecraft.server.Entity; ++import net.minecraft.server.EntityHuman; ++import net.minecraft.server.EntityLiving; ++import net.minecraft.server.EnumBlockMirror; ++import net.minecraft.server.EnumBlockRotation; ++import net.minecraft.server.EnumDirection; ++import net.minecraft.server.EnumHand; ++import net.minecraft.server.EnumInteractionResult; ++import net.minecraft.server.EnumRenderType; ++import net.minecraft.server.IBlockAccess; ++import net.minecraft.server.IBlockData; ++import net.minecraft.server.IBlockDataHolder; ++import net.minecraft.server.IBlockState; ++import net.minecraft.server.IChatBaseComponent; ++import net.minecraft.server.IHopper; ++import net.minecraft.server.IInventory; ++import net.minecraft.server.ITileInventory; ++import net.minecraft.server.InventoryUtils; ++import net.minecraft.server.ItemStack; ++import net.minecraft.server.MinecraftKey; ++import net.minecraft.server.MovingObjectPositionBlock; ++import net.minecraft.server.OperatorBoolean; ++import net.minecraft.server.PathMode; ++import net.minecraft.server.StatisticList; ++import net.minecraft.server.TileEntity; ++import net.minecraft.server.TileEntityHopper; ++import net.minecraft.server.VoxelShape; ++import net.minecraft.server.VoxelShapeCollision; ++import net.minecraft.server.VoxelShapes; ++import net.minecraft.server.World; ++ ++public class BlockHopper extends BlockTileEntity { ++ public static final BlockStateDirection FACING = BlockProperties.N; ++ public static final BlockStateBoolean ENABLED = BlockProperties.f; ++ private static final VoxelShape c = Block.a((double) 0.0, (double) 10.0, (double) 0.0, (double) 16.0, (double) 16.0, ++ (double) 16.0); ++ private static final VoxelShape d = Block.a((double) 4.0, (double) 4.0, (double) 4.0, (double) 12.0, (double) 10.0, ++ (double) 12.0); ++ private static final VoxelShape e = VoxelShapes.a((VoxelShape) d, (VoxelShape) c); ++ private static final VoxelShape f = VoxelShapes.a((VoxelShape) e, (VoxelShape) IHopper.a, ++ (OperatorBoolean) OperatorBoolean.ONLY_FIRST); ++ private static final VoxelShape g = VoxelShapes.a((VoxelShape) f, ++ (VoxelShape) Block.a((double) 6.0, (double) 0.0, (double) 6.0, (double) 10.0, (double) 4.0, (double) 10.0)); ++ private static final VoxelShape h = VoxelShapes.a((VoxelShape) f, (VoxelShape) Block.a((double) 12.0, (double) 4.0, ++ (double) 6.0, (double) 16.0, (double) 8.0, (double) 10.0)); ++ private static final VoxelShape i = VoxelShapes.a((VoxelShape) f, ++ (VoxelShape) Block.a((double) 6.0, (double) 4.0, (double) 0.0, (double) 10.0, (double) 8.0, (double) 4.0)); ++ private static final VoxelShape j = VoxelShapes.a((VoxelShape) f, (VoxelShape) Block.a((double) 6.0, (double) 4.0, ++ (double) 12.0, (double) 10.0, (double) 8.0, (double) 16.0)); ++ private static final VoxelShape k = VoxelShapes.a((VoxelShape) f, ++ (VoxelShape) Block.a((double) 0.0, (double) 4.0, (double) 6.0, (double) 4.0, (double) 8.0, (double) 10.0)); ++ private static final VoxelShape o = IHopper.a; ++ private static final VoxelShape p = VoxelShapes.a((VoxelShape) IHopper.a, (VoxelShape) Block.a((double) 12.0, ++ (double) 8.0, (double) 6.0, (double) 16.0, (double) 10.0, (double) 10.0)); ++ private static final VoxelShape q = VoxelShapes.a((VoxelShape) IHopper.a, ++ (VoxelShape) Block.a((double) 6.0, (double) 8.0, (double) 0.0, (double) 10.0, (double) 10.0, (double) 4.0)); ++ private static final VoxelShape r = VoxelShapes.a((VoxelShape) IHopper.a, (VoxelShape) Block.a((double) 6.0, ++ (double) 8.0, (double) 12.0, (double) 10.0, (double) 10.0, (double) 16.0)); ++ private static final VoxelShape s = VoxelShapes.a((VoxelShape) IHopper.a, ++ (VoxelShape) Block.a((double) 0.0, (double) 8.0, (double) 6.0, (double) 4.0, (double) 10.0, (double) 10.0)); ++ ++ public BlockHopper(BlockBase.Info var0) { ++ super(var0); ++ this.j((IBlockData) ((IBlockData) ((IBlockData) this.blockStateList.getBlockData()).set((IBlockState) FACING, ++ (Comparable) EnumDirection.DOWN)).set((IBlockState) ENABLED, (Comparable) Boolean.valueOf(true))); ++ } ++ ++ public VoxelShape b(IBlockData var0, IBlockAccess var1, BlockPosition var2, VoxelShapeCollision var3) { ++ switch ((EnumDirection) var0.get((IBlockState) FACING)) { ++ case DOWN : { ++ return g; ++ } ++ case NORTH : { ++ return i; ++ } ++ case SOUTH : { ++ return j; ++ } ++ case WEST : { ++ return k; ++ } ++ case EAST : { ++ return h; ++ } ++ } ++ return f; ++ } ++ ++ public VoxelShape a_(IBlockData var0, IBlockAccess var1, BlockPosition var2) { ++ switch ((EnumDirection) var0.get((IBlockState) FACING)) { ++ case DOWN : { ++ return o; ++ } ++ case NORTH : { ++ return q; ++ } ++ case SOUTH : { ++ return r; ++ } ++ case WEST : { ++ return s; ++ } ++ case EAST : { ++ return p; ++ } ++ } ++ return IHopper.a; ++ } ++ ++ public IBlockData getPlacedState(BlockActionContext var0) { ++ EnumDirection var1; ++ return (IBlockData) ((IBlockData) this.getBlockData().set((IBlockState) FACING, ++ (Comparable) ((var1 = var0.getClickedFace().opposite()).n() == EnumDirection.EnumAxis.Y ++ ? EnumDirection.DOWN ++ : var1))).set((IBlockState) ENABLED, (Comparable) Boolean.valueOf(true)); ++ } ++ ++ public TileEntity createTile(IBlockAccess var0) { ++ return new TileEntityHopper(); ++ } ++ ++ public void postPlace(World var0, BlockPosition var1, IBlockData var2, EntityLiving var3, ItemStack var4) { ++ TileEntity var5; ++ if (var4.hasName() && (var5 = var0.getTileEntity(var1)) instanceof TileEntityHopper) { ++ ((TileEntityHopper) var5).setCustomName(var4.getName()); ++ } ++ } ++ ++ public void onPlace(IBlockData var0, World var1, BlockPosition var2, IBlockData var3, boolean var4) { ++ if (var3.a(var0.getBlock())) { ++ return; ++ } ++ this.a(var1, var2, var0); ++ } ++ ++ public EnumInteractionResult interact(IBlockData var0, World var1, BlockPosition var2, EntityHuman var3, ++ EnumHand var4, MovingObjectPositionBlock var5) { ++ if (var1.isClientSide) { ++ return EnumInteractionResult.SUCCESS; ++ } ++ TileEntity var6 = var1.getTileEntity(var2); ++ if (var6 instanceof TileEntityHopper) { ++ var3.openContainer((ITileInventory) ((TileEntityHopper) var6)); ++ var3.a(StatisticList.INSPECT_HOPPER); ++ } ++ return EnumInteractionResult.CONSUME; ++ } ++ ++ public void doPhysics(IBlockData var0, World var1, BlockPosition var2, Block var3, BlockPosition var4, ++ boolean var5) { ++ this.a(var1, var2, var0); ++ //YAPFA start ++ TileEntity tileEntity = var1.getTileEntity(var2); ++ if (tileEntity instanceof TileEntityHopper) { ++ ((TileEntityHopper)tileEntity).flushCaches(); ++ } ++ // YAPFA end ++ } ++ ++ private void a(World var0, BlockPosition var1, IBlockData var2) { ++ boolean var3; ++ boolean bl = var3 = !var0.isBlockIndirectlyPowered(var1); ++ if (var3 != (Boolean) var2.get((IBlockState) ENABLED)) { ++ var0.setTypeAndData(var1, (IBlockData) var2.set((IBlockState) ENABLED, (Comparable) Boolean.valueOf(var3)), ++ 4); ++ } ++ } ++ ++ public void remove(IBlockData var0, World var1, BlockPosition var2, IBlockData var3, boolean var4) { ++ if (var0.a(var3.getBlock())) { ++ return; ++ } ++ TileEntity var5 = var1.getTileEntity(var2); ++ if (var5 instanceof TileEntityHopper) { ++ InventoryUtils.dropInventory((World) var1, (BlockPosition) var2, (IInventory) ((TileEntityHopper) var5)); ++ var1.updateAdjacentComparators(var2, (Block) this); ++ } ++ super.remove(var0, var1, var2, var3, var4); ++ } ++ ++ public EnumRenderType b(IBlockData var0) { ++ return EnumRenderType.MODEL; ++ } ++ ++ public boolean isComplexRedstone(IBlockData var0) { ++ return true; ++ } ++ ++ public int a(IBlockData var0, World var1, BlockPosition var2) { ++ return Container.a((TileEntity) var1.getTileEntity(var2)); ++ } ++ ++ public IBlockData a(IBlockData var0, EnumBlockRotation var1) { ++ return (IBlockData) var0.set((IBlockState) FACING, ++ (Comparable) var1.a((EnumDirection) var0.get((IBlockState) FACING))); ++ } ++ ++ public IBlockData a(IBlockData var0, EnumBlockMirror var1) { ++ return var0.a(var1.a((EnumDirection) var0.get((IBlockState) FACING))); ++ } ++ ++ protected void a(BlockStateList.a var0) { ++ var0.a(new IBlockState[]{FACING, ENABLED}); ++ } ++ ++ public void a(IBlockData var0, World var1, BlockPosition var2, Entity var3) { ++ TileEntity var4 = var1.getTileEntity(var2); ++ if (var4 instanceof TileEntityHopper) { ++ ((TileEntityHopper) var4).a(var3); ++ } ++ } ++ ++ public boolean a(IBlockData var0, IBlockAccess var1, BlockPosition var2, PathMode var3) { ++ return false; ++ } ++ ++} +\ No newline at end of file +diff --git a/src/main/java/net/minecraft/server/TileEntityHopper.java b/src/main/java/net/minecraft/server/TileEntityHopper.java +index 728c829c1..42bd33197 100644 +--- a/src/main/java/net/minecraft/server/TileEntityHopper.java ++++ b/src/main/java/net/minecraft/server/TileEntityHopper.java +@@ -2,6 +2,7 @@ package net.minecraft.server; + + import java.util.Iterator; + import java.util.List; ++import java.util.Optional; + import java.util.function.Supplier; + import java.util.stream.Collectors; + import java.util.stream.IntStream; +@@ -611,14 +612,28 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + + @Nullable + private IInventory l() { ++ if(this.cachedPush != null)return this.cachedPush; + EnumDirection enumdirection = (EnumDirection) this.getBlock().get(BlockHopper.FACING); + +- return b(this.getWorld(), this.position.shift(enumdirection)); ++ this.cachedPush = b(this.getWorld(), this.position.shift(enumdirection)); ++ return this.cachedPush; + } + + @Nullable + public static IInventory b(IHopper ihopper) { +- return a(ihopper.getWorld(), ihopper.x(), ihopper.z() + 1.0D, ihopper.A()); ++ //YAPFA start ++ if(ihopper instanceof TileEntityHopper) { ++ TileEntityHopper hopper = (TileEntityHopper) ihopper; ++ if(hopper.cachedAbove != null) { ++ return hopper.cachedAbove; ++ } ++ IInventory inv = a(ihopper.getWorld(), ihopper.x(), ihopper.z() + 1.0D, ihopper.A()); ++ hopper.cachedAbove = inv; ++ return inv; ++ } else { ++ return a(ihopper.getWorld(), ihopper.x(), ihopper.z() + 1.0D, ihopper.A()); ++ } ++ //YAPFA end + } + + public static List c(IHopper ihopper) { +@@ -658,7 +673,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + } + } + } +- ++ + if (object == null && (!optimizeEntities || !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding())) { // Paper + List list = world.getEntities((Entity) null, new AxisAlignedBB(d0 - 0.5D, d1 - 0.5D, d2 - 0.5D, d0 + 0.5D, d1 + 0.5D, d2 + 0.5D), IEntitySelector.d); + +@@ -666,7 +681,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + object = (IInventory) list.get(world.random.nextInt(list.size())); + } + } +- ++ + return (IInventory) object; + } + +@@ -728,4 +743,17 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi + protected Container createContainer(int i, PlayerInventory playerinventory) { + return new ContainerHopper(i, playerinventory, this); + } ++ ++ // YAPFA start ++ ++ private IInventory cachedAbove = null; ++ private IInventory cachedPush = null; ++ ++ public void flushCaches() { ++ cachedAbove = null; ++ cachedPush = null; ++ } ++ ++ // YAPFA end ++ + } +-- +2.25.1.windows.1 +