Yatopia/patches/removed/server/0065-lithium-AI.patch

2155 lines
99 KiB
Diff
Raw Normal View History

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: JellySquid <jellysquid+atwork@protonmail.com>
Date: Sun, 24 Jan 2021 12:17:19 +0100
Subject: [PATCH] lithium AI
Co-authored-by: Hugo Planque <hookwood01@gmail.com>
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/ai/pathing/PathNodeCache.java b/src/main/java/me/jellysquid/mods/lithium/common/ai/pathing/PathNodeCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..b97dc93ba3708811cd8a1409aa5992a548586ed0
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/ai/pathing/PathNodeCache.java
@@ -0,0 +1,92 @@
+package me.jellysquid.mods.lithium.common.ai.pathing;
+
+import it.unimi.dsi.fastutil.objects.Reference2BooleanMap;
+import it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap;
+import net.minecraft.world.level.chunk.ChunkSection;
+import net.minecraft.world.level.block.state.IBlockData;
+import net.minecraft.world.level.pathfinder.PathType;
+
+public class PathNodeCache {
+ /**
+ * A transient hash table of chunk sections and whether or not they contain dangerous block types. Used as a cache
+ * to avoid scanning for many neighbors when we know the chunk is free of dangers. This is only safe to use when
+ * we know the world is not going to be modified while it is active.
+ */
+ private static final Reference2BooleanMap<ChunkSection> chunkNeighborDangerCache = new Reference2BooleanOpenHashMap<>();
+
+ /**
+ * True if the chunk danger cache is enabled and can be used.
+ */
+ private static boolean dangerCacheEnabled = false;
+
+ /**
+ * The previous chunk section that was queried for neighboring dangers.
+ */
+ private static ChunkSection prevQueriedNeighborSectionKey;
+
+ /**
+ * The result of the previous query belonging to {@link PathNodeCache#prevQueriedNeighborSectionKey}.
+ */
+ private static boolean prevQueriedNeighborSectionResult;
+
+ /**
+ * Enables the chunk danger cache. This should be called immediately before a controlled path-finding code path
+ * begins so that we can accelerate nearby danger checks.
+ */
+ public static void enableChunkCache() {
+ dangerCacheEnabled = true;
+ }
+
+ /**
+ * Disables and clears the chunk danger cache. This should be called immediately before path-finding ends so that
+ * block updates are reflected for future path-finding tasks.
+ */
+ public static void disableChunkCache() {
+ dangerCacheEnabled = false;
+ chunkNeighborDangerCache.clear();
+
+ prevQueriedNeighborSectionKey = null;
+ prevQueriedNeighborSectionResult = false;
+ }
+
+ private static boolean isChunkSectionDangerousNeighbor(ChunkSection section) {
+ return section.getBlocks()
+ .contains(state -> getNeighborPathNodeType(state) != PathType.OPEN);
+ }
+
+ public static PathType getPathNodeType(IBlockData state) {
+ return state.getPathNodeType();
+ }
+
+ public static PathType getNeighborPathNodeType(IBlockData state) {
+ return state.getNeighborPathNodeType();
+ }
+
+ /**
+ * Returns whether or not a chunk section is free of dangers. This makes use of a caching layer to greatly
+ * accelerate neighbor danger checks when path-finding.
+ *
+ * @param section The chunk section to test for dangers
+ * @return True if this neighboring section is free of any dangers, otherwise false if it could
+ * potentially contain dangers
+ */
+ public static boolean isSectionSafeAsNeighbor(ChunkSection section) {
+ // Empty sections can never contribute a danger
+ if (ChunkSection.isEmpty(section)) {
+ return true;
+ }
+
+ // If the caching code path is disabled, the section must be assumed to potentially contain dangers
+ if (!dangerCacheEnabled) {
+ return false;
+ }
+
+ if (prevQueriedNeighborSectionKey != section) {
+ prevQueriedNeighborSectionKey = section;
+ prevQueriedNeighborSectionResult = !chunkNeighborDangerCache.computeBooleanIfAbsent(section,
+ PathNodeCache::isChunkSectionDangerousNeighbor);
+ }
+
+ return prevQueriedNeighborSectionResult;
+ }
+}
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/ai/pathing/PathNodeDefaults.java b/src/main/java/me/jellysquid/mods/lithium/common/ai/pathing/PathNodeDefaults.java
new file mode 100644
index 0000000000000000000000000000000000000000..4427f2171671896c978908b1c3d72b3f64f16a0b
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/ai/pathing/PathNodeDefaults.java
@@ -0,0 +1,110 @@
+package me.jellysquid.mods.lithium.common.ai.pathing;
+
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.BlockCampfire;
+import net.minecraft.world.level.block.BlockDoor;
+import net.minecraft.world.level.block.BlockFenceGate;
+import net.minecraft.world.level.block.BlockLeaves;
+import net.minecraft.world.level.block.BlockMinecartTrackAbstract;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.material.Fluid;
+import net.minecraft.world.level.block.state.IBlockData;
+import net.minecraft.world.level.material.Material;
+import net.minecraft.world.level.pathfinder.PathType;
+import net.minecraft.tags.TagsBlock;
+import net.minecraft.tags.TagsFluid;
+
+public class PathNodeDefaults {
+ public static PathType getNeighborNodeType(IBlockData state) {
+ if (state.isAir()) {
+ return PathType.OPEN;
+ }
+
+ // [VanillaCopy] LandPathNodeMaker#getNodeTypeFromNeighbors
+ // Determine what kind of obstacle type this neighbor is
+ if (state.a(Blocks.CACTUS)) {
+ return PathType.DANGER_CACTUS;
+ } else if (state.a(Blocks.SWEET_BERRY_BUSH)) {
+ return PathType.DANGER_OTHER;
+ } else if (isFireDangerSource(state)) {
+ return PathType.DANGER_FIRE;
+ } else if (state.getFluid().a(TagsFluid.WATER)) {
+ return PathType.WATER_BORDER;
+ } else {
+ return PathType.OPEN;
+ }
+ }
+
+ public static PathType getNodeType(IBlockData state) {
+ if (state.isAir()) {
+ return PathType.OPEN;
+ }
+
+ Block block = state.getBlock();
+ Material material = state.getMaterial();
+
+ if (state.hasTag(TagsBlock.TRAPDOORS) || state.a(Blocks.LILY_PAD)) {
+ return PathType.TRAPDOOR;
+ }
+
+ if (state.a(Blocks.CACTUS)) {
+ return PathType.DAMAGE_CACTUS;
+ }
+
+ if (state.a(Blocks.SWEET_BERRY_BUSH) || state.a(Blocks.STONECUTTER)) {
+ return PathType.DAMAGE_OTHER;
+ }
+
+ if (state.a(Blocks.HONEY_BLOCK)) {
+ return PathType.STICKY_HONEY;
+ }
+
+ if (state.a(Blocks.COCOA)) {
+ return PathType.COCOA;
+ }
+
+ if (isFireDangerSource(state)) {
+ return PathType.DAMAGE_FIRE;
+ }
+
+ if (BlockDoor.l(state) && !state.get(BlockDoor.OPEN)) {
+ return PathType.DOOR_WOOD_CLOSED;
+ }
+
+ if ((block instanceof BlockDoor) && (material == Material.ORE) && !state.get(BlockDoor.OPEN)) {
+ return PathType.DOOR_IRON_CLOSED;
+ }
+
+ if ((block instanceof BlockDoor) && state.get(BlockDoor.OPEN)) {
+ return PathType.DOOR_OPEN;
+ }
+
+ if (block instanceof BlockMinecartTrackAbstract) {
+ return PathType.RAIL;
+ }
+
+ if (block instanceof BlockLeaves) {
+ return PathType.LEAVES;
+ }
+
+ if (block.a(TagsBlock.FENCES) || block.a(TagsBlock.WALLS) || ((block instanceof BlockFenceGate) && !state.get(BlockFenceGate.OPEN))) {
+ return PathType.FENCE;
+ }
+
+ // Retrieve the fluid state from the block state to avoid a second lookup
+ Fluid fluid = state.getFluid();
+ if (fluid == null) {
+ return PathType.OPEN;
+ } else if (fluid.a(TagsFluid.WATER)) {
+ return PathType.WATER;
+ } else if (fluid.a(TagsFluid.LAVA)) {
+ return PathType.LAVA;
+ }
+
+ return PathType.OPEN;
+ }
+
+ private static boolean isFireDangerSource(IBlockData blockState) {
+ return blockState.a(TagsBlock.FIRE) || blockState.a(Blocks.LAVA) || blockState.a(Blocks.MAGMA_BLOCK) || BlockCampfire.g(blockState);
+ }
+}
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/EntityTrackerEngine.java b/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/EntityTrackerEngine.java
new file mode 100644
index 0000000000000000000000000000000000000000..23ea99d0ec8622eadadc2073022e59c4aac8dc3a
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/EntityTrackerEngine.java
@@ -0,0 +1,254 @@
+package me.jellysquid.mods.lithium.common.entity.tracker;
+
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
+import me.jellysquid.mods.lithium.common.entity.tracker.nearby.NearbyEntityListener;
+import net.minecraft.core.BlockPosition;
+import net.minecraft.world.entity.EntityLiving;
+import net.minecraft.core.SectionPosition;
+import net.minecraft.world.level.levelgen.structure.StructureBoundingBox;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tracks the entities within a world and provides notifications to listeners when a tracked entity enters or leaves a
+ * watched area. This removes the necessity to constantly poll the world for nearby entities each tick and generally
+ * provides a sizable boost to performance.
+ */
+public class EntityTrackerEngine {
+ private final Long2ObjectOpenHashMap<TrackedEntityList> sections;
+ private final Reference2ReferenceOpenHashMap<NearbyEntityListener, List<TrackedEntityList>> sectionsByEntity;
+
+
+ public EntityTrackerEngine() {
+ this.sections = new Long2ObjectOpenHashMap<>();
+ this.sectionsByEntity = new Reference2ReferenceOpenHashMap<>();
+ }
+
+ /**
+ * Called when an entity is added to the world.
+ */
+ public void onEntityAdded(int x, int y, int z, EntityLiving entity) {
+ if (this.addEntity(x, y, z, entity)) {
+ this.addListener(x, y, z, entity.getListener());
+ }
+ }
+
+ /**
+ * Called when an entity is removed from the world.
+ */
+ public void onEntityRemoved(int x, int y, int z, EntityLiving entity) {
+ if (this.removeEntity(x, y, z, entity)) {
+ this.removeListener(entity.getListener());
+ }
+ }
+
+ private boolean addEntity(int x, int y, int z, EntityLiving entity) {
+ return this.getOrCreateList(x, y, z).addTrackedEntity(entity);
+ }
+
+ private boolean removeEntity(int x, int y, int z, EntityLiving entity) {
+ TrackedEntityList list = this.getList(x, y, z);
+
+ if (list == null) {
+ return false;
+ }
+
+ return list.removeTrackedEntity(entity);
+ }
+
+ private void addListener(int x, int y, int z, NearbyEntityListener listener) {
+ int r = listener.getChunkRange();
+
+ if (r == 0) {
+ return;
+ }
+
+ if (this.sectionsByEntity.containsKey(listener)) {
+
+ throw new IllegalStateException(errorMessageAlreadyListening(this.sectionsByEntity, listener, SectionPosition.a(x, y, z)));
+ }
+
+ int yMin = Math.max(0, y - r);
+ int yMax = Math.min(y + r, 15);
+
+ List<TrackedEntityList> all = new ArrayList<>((2 * r + 1) * (yMax - yMin + 1) * (2 * r + 1));
+
+ for (int x2 = x - r; x2 <= x + r; x2++) {
+ for (int y2 = yMin; y2 <= yMax; y2++) {
+ for (int z2 = z - r; z2 <= z + r; z2++) {
+ TrackedEntityList list = this.getOrCreateList(x2, y2, z2);
+ list.addListener(listener);
+
+ all.add(list);
+ }
+ }
+ }
+
+ this.sectionsByEntity.put(listener, all);
+ }
+
+ private void removeListener(NearbyEntityListener listener) {
+ int r = listener.getChunkRange();
+
+ if (r == 0) {
+ return;
+ }
+
+ List<TrackedEntityList> all = this.sectionsByEntity.remove(listener);
+
+ if (all != null) {
+ for (TrackedEntityList list : all) {
+ list.removeListener(listener);
+ }
+ } else {
+ throw new IllegalArgumentException("Entity listener not tracked:" + listener.toString());
+ }
+ }
+
+ // Faster implementation which avoids removing from/adding to every list twice on an entity move event
+ private void moveListener(int aX, int aY, int aZ, int bX, int bY, int bZ, NearbyEntityListener listener) {
+ int radius = listener.getChunkRange();
+
+ if (radius == 0) {
+ return;
+ }
+
+ StructureBoundingBox before = new StructureBoundingBox(aX - radius, aY - radius, aZ - radius, aX + radius, aY + radius, aZ + radius);
+ StructureBoundingBox after = new StructureBoundingBox(aX - radius, aY - radius, aZ - radius, bX + radius, bY + radius, bZ + radius);
+
+ StructureBoundingBox merged = new StructureBoundingBox(before);
+ merged.c(after);
+
+ BlockPosition.MutableBlockPosition pos = new BlockPosition.MutableBlockPosition();
+
+ for (int x = merged.a; x <= merged.d; x++) {
+ for (int y = merged.b; y <= merged.e; y++) {
+ for (int z = merged.c; z <= merged.f; z++) {
+ pos.setValues(x, y, z);
+
+ boolean leaving = before.hasPoint(pos);
+ boolean entering = after.hasPoint(pos);
+
+ // Nothing to change
+ if (leaving == entering) {
+ continue;
+ }
+
+ if (leaving) {
+ // The listener has left the chunk
+ TrackedEntityList list = this.getList(x, y, z);
+
+ if (list == null) {
+ throw new IllegalStateException("Expected there to be a listener list while moving entity but there was none");
+ }
+
+ list.removeListener(listener);
+ } else {
+ // The listener has entered the chunk
+ TrackedEntityList list = this.getOrCreateList(x, y, z);
+ list.addListener(listener);
+ }
+ }
+ }
+ }
+ }
+
+ private TrackedEntityList getOrCreateList(int x, int y, int z) {
+ return this.sections.computeIfAbsent(encode(x, y, z), TrackedEntityList::new);
+ }
+
+ private TrackedEntityList getList(int x, int y, int z) {
+ return this.sections.get(encode(x, y, z));
+ }
+
+ private static long encode(int x, int y, int z) {
+ return SectionPosition.asLong(x, y, z);
+ }
+
+ private static SectionPosition decode(long xyz) {
+ return SectionPosition.a(xyz);
+ }
+
+ private class TrackedEntityList {
+ private final Set<EntityLiving> entities = new ReferenceOpenHashSet<>();
+ private final Set<NearbyEntityListener> listeners = new ReferenceOpenHashSet<>();
+
+ private final long key;
+
+ private TrackedEntityList(long key) {
+ this.key = key;
+ }
+
+ public void addListener(NearbyEntityListener listener) {
+ for (EntityLiving entity : this.entities) {
+ listener.onEntityEnteredRange(entity);
+ }
+
+ this.listeners.add(listener);
+ }
+
+ public void removeListener(NearbyEntityListener listener) {
+ if (this.listeners.remove(listener)) {
+ for (EntityLiving entity : this.entities) {
+ listener.onEntityLeftRange(entity);
+ }
+
+ this.checkEmpty();
+ }
+ }
+
+ public boolean addTrackedEntity(EntityLiving entity) {
+ for (NearbyEntityListener listener : this.listeners) {
+ listener.onEntityEnteredRange(entity);
+ }
+
+ return this.entities.add(entity);
+ }
+
+ public boolean removeTrackedEntity(EntityLiving entity) {
+ boolean ret = this.entities.remove(entity);
+
+ if (ret) {
+ for (NearbyEntityListener listener : this.listeners) {
+ listener.onEntityLeftRange(entity);
+ }
+
+ this.checkEmpty();
+ }
+
+ return ret;
+ }
+
+ private void checkEmpty() {
+ if (this.entities.isEmpty() && this.listeners.isEmpty()) {
+ EntityTrackerEngine.this.sections.remove(this.key);
+ }
+ }
+ }
+
+
+ private static String errorMessageAlreadyListening(Reference2ReferenceOpenHashMap<NearbyEntityListener, List<TrackedEntityList>> sectionsByEntity, NearbyEntityListener listener, SectionPosition newLocation) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Adding Entity listener a second time: ").append(listener.toString());
+ builder.append("\n");
+ builder.append(" wants to listen at: ").append(newLocation.toString());
+ builder.append(" with cube radius: ").append(listener.getChunkRange());
+ builder.append("\n");
+ builder.append(" but was already listening at chunk sections: ");
+ String[] comma = new String[]{""};
+ if (sectionsByEntity.get(listener) == null) {
+ builder.append("null");
+ } else {
+ sectionsByEntity.get(listener).forEach(a -> {
+ builder.append(comma[0]);
+ builder.append(decode(a.key).toString());
+ comma[0] = ", ";
+ });
+ }
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/nearby/NearbyEntityListener.java b/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/nearby/NearbyEntityListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..f84366ad98333c2b17b838883d9a3889572bba63
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/nearby/NearbyEntityListener.java
@@ -0,0 +1,25 @@
+package me.jellysquid.mods.lithium.common.entity.tracker.nearby;
+
+import net.minecraft.world.entity.EntityLiving;
+
+/**
+ * The main interface used to receive events from the
+ * {@link me.jellysquid.mods.lithium.common.entity.tracker.EntityTrackerEngine} of a world.
+ */
+public interface NearbyEntityListener {
+ /**
+ * Returns the range (in chunks) of this listener. This must never change during the lifetime of the listener.
+ * TODO: Allow entity listeners to change the radius they receive updates within
+ */
+ int getChunkRange();
+
+ /**
+ * Called by the entity tracker when an entity enters the range of this listener.
+ */
+ void onEntityEnteredRange(EntityLiving entity);
+
+ /**
+ * Called by the entity tracker when an entity leaves the range of this listener or is removed from the world.
+ */
+ void onEntityLeftRange(EntityLiving entity);
+}
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/nearby/NearbyEntityListenerMulti.java b/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/nearby/NearbyEntityListenerMulti.java
new file mode 100644
index 0000000000000000000000000000000000000000..a56b23f0fbc1f2e31a79aa8b47635fecdf2490c9
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/nearby/NearbyEntityListenerMulti.java
@@ -0,0 +1,59 @@
+package me.jellysquid.mods.lithium.common.entity.tracker.nearby;
+
+import net.minecraft.world.entity.EntityLiving;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Allows for multiple listeners on an entity to be grouped under one logical listener. No guarantees are made about the
+ * order of which each sub-listener will be notified.
+ */
+public class NearbyEntityListenerMulti implements NearbyEntityListener {
+ private final List<NearbyEntityListener> listeners = new ArrayList<>();
+
+ public void addListener(NearbyEntityListener listener) {
+ this.listeners.add(listener);
+ }
+
+ public void removeListener(NearbyEntityListener listener) {
+ this.listeners.remove(listener);
+ }
+
+ @Override
+ public int getChunkRange() {
+ int range = 0;
+
+ for (NearbyEntityListener listener : this.listeners) {
+ range = Math.max(range, listener.getChunkRange());
+ }
+
+ return range;
+ }
+
+ @Override
+ public void onEntityEnteredRange(EntityLiving entity) {
+ for (NearbyEntityListener listener : this.listeners) {
+ listener.onEntityEnteredRange(entity);
+ }
+ }
+
+ @Override
+ public void onEntityLeftRange(EntityLiving entity) {
+ for (NearbyEntityListener listener : this.listeners) {
+ listener.onEntityLeftRange(entity);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sublisteners = new StringBuilder();
+ String comma = "";
+ for (NearbyEntityListener listener : this.listeners) {
+ sublisteners.append(comma).append(listener.toString());
+ comma = ","; //trick to drop the first comma
+ }
+
+ return super.toString() + " with sublisteners: [" + sublisteners + "]";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/nearby/NearbyEntityTracker.java b/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/nearby/NearbyEntityTracker.java
new file mode 100644
index 0000000000000000000000000000000000000000..01f9a626e761dd8cc26216e316e3a39362dc463d
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/entity/tracker/nearby/NearbyEntityTracker.java
@@ -0,0 +1,94 @@
+package me.jellysquid.mods.lithium.common.entity.tracker.nearby;
+
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
+import net.minecraft.world.phys.AxisAlignedBB;
+import net.minecraft.world.entity.EntityLiving;
+import net.minecraft.util.MathHelper;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.entity.ai.targeting.PathfinderTargetCondition;
+
+import java.util.Set;
+
+/**
+ * Maintains a collection of all entities within the range of this listener. This allows AI goals to quickly
+ * assess nearby entities which match the provided class.
+ */
+public class NearbyEntityTracker<T extends EntityLiving> implements NearbyEntityListener {
+ private final Class<T> clazz;
+ private final EntityLiving self;
+
+ private final int rangeC;
+ private final float rangeSq;
+
+ private final Set<T> nearby = new ReferenceOpenHashSet<>();
+
+ public NearbyEntityTracker(Class<T> clazz, EntityLiving self, float range) {
+ this.clazz = clazz;
+ this.self = self;
+ this.rangeSq = range * range;
+ this.rangeC = Math.max((MathHelper.f(range) + 15) >> 4, 1);
+ }
+
+ @Override
+ public int getChunkRange() {
+ return this.rangeC;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void onEntityEnteredRange(EntityLiving entity) {
+ if (!this.clazz.isInstance(entity)) {
+ return;
+ }
+
+ this.nearby.add((T) entity);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void onEntityLeftRange(EntityLiving entity) {
+ if (this.nearby.isEmpty() || !this.clazz.isInstance(entity)) {
+ return;
+ }
+
+ this.nearby.remove((T) entity);
+ }
+
+ /**
+ * Gets the closest T (extends LivingEntity) to the center of this tracker that also intersects with the given box and meets the
+ * requirements of the targetPredicate.
+ * The result may be different from vanilla if there are multiple closest entities.
+ *
+ * @param box the box the entities have to intersect
+ * @param targetPredicate predicate the entity has to meet
+ * @return the closest Entity that meets all requirements (distance, box intersection, predicate, type T)
+ */
+ public T getClosestEntity(AxisAlignedBB box, PathfinderTargetCondition targetPredicate) {
+ double x = this.self.locX();
+ double y = this.self.locY();
+ double z = this.self.locZ();
+
+ T nearest = null;
+ double nearestDistance = Double.POSITIVE_INFINITY;
+
+ for (T entity : this.nearby) {
+ double distance = entity.getDistanceSquared(x, y, z);
+
+ if (distance < nearestDistance && (box == null || box.intersects(entity.getBoundingBox())) && targetPredicate.test(this.self, entity)) {
+ nearest = entity;
+ nearestDistance = distance;
+ }
+ }
+
+ if (nearestDistance <= this.rangeSq) {
+ return nearest;
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " for entity class: " + this.clazz.getName() + ", in rangeSq: " + this.rangeSq + ", around entity: " + this.self.toString() + " with NBT: " + this.self.save(new NBTTagCompound());
+ }
+}
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/Collector.java b/src/main/java/me/jellysquid/mods/lithium/common/util/Collector.java
new file mode 100644
index 0000000000000000000000000000000000000000..8323c05845cd652e5ea5dd4b71c388a1f7374bf6
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/util/Collector.java
@@ -0,0 +1,11 @@
+package me.jellysquid.mods.lithium.common.util;
+
+public interface Collector<T> {
+ /**
+ * Collects the passed object and performs additional processing on it, returning a flag as to whether or not
+ * collection should continue.
+ *
+ * @return True if collection should continue, otherwise false.
+ */
+ boolean collect(T obj);
+}
\ No newline at end of file
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/collections/ListeningLong2ObjectOpenHashMap.java b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/ListeningLong2ObjectOpenHashMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..a94a40dcc3502d29950e5e387d658232a0bf5552
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/ListeningLong2ObjectOpenHashMap.java
@@ -0,0 +1,46 @@
+package me.jellysquid.mods.lithium.common.util.collections;
+
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+
+/**
+ * An extension for {@link Long2ObjectOpenHashMap} which allows callbacks to be installed for when an item is added to
+ * or removed from the map.
+ */
+public class ListeningLong2ObjectOpenHashMap<V> extends Long2ObjectOpenHashMap<V> {
+ private final Callback<V> addCallback, removeCallback;
+
+ public ListeningLong2ObjectOpenHashMap(Callback<V> addCallback, Callback<V> removeCallback) {
+ this.addCallback = addCallback;
+ this.removeCallback = removeCallback;
+ }
+
+ @Override
+ public V put(long k, V v) {
+ V ret = super.put(k, v);
+
+ if (ret != v) {
+ if (ret != null) {
+ this.removeCallback.apply(k, v);
+ }
+
+ this.addCallback.apply(k, v);
+ }
+
+ return ret;
+ }
+
+ @Override
+ public V remove(long k) {
+ V ret = super.remove(k);
+
+ if (ret != null) {
+ this.removeCallback.apply(k, ret);
+ }
+
+ return ret;
+ }
+
+ public interface Callback<V> {
+ void apply(long key, V value);
+ }
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..5959d66582342f614bdadb2a1ef163e4fff25341
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/world/WorldHelper.java
@@ -0,0 +1,18 @@
+package me.jellysquid.mods.lithium.common.world;
+
+import net.minecraft.core.BlockPosition;
+
+public class WorldHelper {
+
+ public static boolean areNeighborsWithinSameChunk(BlockPosition pos) {
+ int localX = pos.getX() & 15;
+ int localY = pos.getY() & 15;
+ int localZ = pos.getZ() & 15;
+
+ return localX > 0 && localY > 0 && localZ > 0 && localX < 15 && localY < 15 && localZ < 15;
+ }
+
+ public static boolean areAllNeighborsOutOfBounds(BlockPosition pos) {
+ return pos.getY() < -1 || pos.getY() > 256;
+ }
+}
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/world/interests/PointOfInterestCollectors.java b/src/main/java/me/jellysquid/mods/lithium/common/world/interests/PointOfInterestCollectors.java
new file mode 100644
index 0000000000000000000000000000000000000000..069b204764d04b126ac8ef30eae8f7e1234badf5
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/world/interests/PointOfInterestCollectors.java
@@ -0,0 +1,28 @@
+package me.jellysquid.mods.lithium.common.world.interests;
+
+import me.jellysquid.mods.lithium.common.util.Collector;
+import net.minecraft.core.BlockPosition;
+import net.minecraft.world.entity.ai.village.poi.VillagePlace;
+import net.minecraft.world.entity.ai.village.poi.VillagePlaceRecord;
+import net.minecraft.world.entity.ai.village.poi.VillagePlaceSection;
+import net.minecraft.world.entity.ai.village.poi.VillagePlaceType;
+
+import java.util.function.Predicate;
+
+public class PointOfInterestCollectors {
+ public static Collector<VillagePlaceRecord> collectAllWithinRadius(BlockPosition pos, double radius, Collector<VillagePlaceRecord> out) {
+ double radiusSq = radius * radius;
+
+ return (point) -> {
+ if (point.getPosition().distanceSquared(pos) <= radiusSq) {
+ return out.collect(point);
+ }
+
+ return true;
+ };
+ }
+
+ public static Collector<VillagePlaceSection> collectAllMatching(Predicate<VillagePlaceType> predicate, VillagePlace.Occupancy status, Collector<VillagePlaceRecord> out) {
+ return set -> set.get(predicate, status, out);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/world/interests/PointOfInterestTypeHelper.java b/src/main/java/me/jellysquid/mods/lithium/common/world/interests/PointOfInterestTypeHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..06d7c8a5ae23ec8b55661b4129c7c88657d1b9bf
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/world/interests/PointOfInterestTypeHelper.java
@@ -0,0 +1,22 @@
+package me.jellysquid.mods.lithium.common.world.interests;
+
+import it.unimi.dsi.fastutil.objects.ObjectSet;
+import net.minecraft.world.level.chunk.ChunkSection;
+import net.minecraft.world.level.block.state.IBlockData;
+
+public class PointOfInterestTypeHelper {
+ private static ObjectSet<IBlockData> TYPES;
+
+ public static void init(ObjectSet<IBlockData> types) {
+ if (TYPES != null) {
+ throw new IllegalStateException("Already initialized");
+ }
+
+ TYPES = types;
+ }
+
+ public static boolean shouldScan(ChunkSection section) {
+ return section.hasAny(TYPES::contains);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/SectionPosition.java b/src/main/java/net/minecraft/core/SectionPosition.java
index a206a729b3afa01bf591fa4da1e5c14902da4778..716f91246c4a45fd49af806afd1781f11ff3b346 100644
--- a/src/main/java/net/minecraft/core/SectionPosition.java
+++ b/src/main/java/net/minecraft/core/SectionPosition.java
@@ -22,6 +22,7 @@ public class SectionPosition extends BaseBlockPosition {
return new SectionPosition(blockposition.getX() >> 4, blockposition.getY() >> 4, blockposition.getZ() >> 4); // Paper
}
+ public static SectionPosition from(ChunkCoordIntPair chunkCoordIntPair, int i){ return a(chunkCoordIntPair, i); } // Yatopia - OBFHELPER
public static SectionPosition a(ChunkCoordIntPair chunkcoordintpair, int i) {
return new SectionPosition(chunkcoordintpair.x, i, chunkcoordintpair.z);
}
@@ -94,14 +95,17 @@ public class SectionPosition extends BaseBlockPosition {
return i << 4;
}
+ public static int unpackX(long i){ return b(i); } // Yatopia - OBFHELPER
public static int b(long i) {
return (int) (i << 0 >> 42);
}
+ public static int unpackY(long i){ return c(i); } // Yatopia - OBFHELPER
public static int c(long i) {
return (int) (i << 44 >> 44);
}
+ public static int unpackZ(long i){ return d(i); } // Yatopia - OBFHELPER
public static int d(long i) {
return (int) (i << 22 >> 42);
}
diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java
Upstream (#469) * Updated Upstream and Sidestream(s) (Paper/Tuinity/Airplane/Purpur/Empirecraft) Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: fbae9dbe0 [Auto] Updated Upstream (Bukkit/CraftBukkit) ac4a33aab [Auto] Updated Upstream (Bukkit) c1e07158b [Auto] Updated Upstream (Bukkit/CraftBukkit) 5e4b88e95 Fix dangling sout 23afda179 basic hostname validation 0fb8bdf0e Updated Upstream (Bukkit/CraftBukkit) (#5508) 88ab784da [Auto] Updated Upstream (CraftBukkit) ca7111d5f Fix PlayerItemConsumeEvent cancelling (fixes #4682) (#5383) 06fb560dc Add support for tab completing and highlighting console input from the Brigadier command tree (#5437) 0a9b89c7a Fix occasional light gen issues for neighbor blocks (#5500) a08be1ec7 [Auto] Updated Upstream (CraftBukkit) Tuinity Changes: 7d36676 Fix light source locking f1ec0c2 Add concurrency check to ProtoChunk light sources 159d146 Improvements to chunk loader system Airplane Changes: 3b3cde7 Correctly use DEAR values, fix config reloading dd60919 Updated Upstream (Tuinity) Purpur Changes: 5674cdc Updated Upstream (Paper) Empirecraft Changes: efda8c5b Updated Paper * Updated Upstream and Sidestream(s) (Paper/Tuinity) Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: 39bf5b525 Update teams known as code owners Tuinity Changes: b12d0cc Replace ticket level propagator 42df8e1 Correctly handle recursion for chunkholder updates 73eb2a8 Do not copy visible chunks 8a4f3be Do not schedule poi task for each block write on chunk gen * Multithreaded Entity Tracker fixup
2021-04-21 23:26:49 +02:00
index d7f95bd32842fdee0ce53fc97d31ffb3577cdc78..e6f85b07f731859c8b8c380afad699ccc1d6c3e8 100644
--- a/src/main/java/net/minecraft/server/level/WorldServer.java
+++ b/src/main/java/net/minecraft/server/level/WorldServer.java
@@ -177,6 +177,7 @@ import org.bukkit.event.world.TimeSkipEvent;
// CraftBukkit end
import it.unimi.dsi.fastutil.ints.IntArrayList; // Tuinity
import net.gegy1000.tictacs.NonBlockingWorldAccess; // Yatopia
+import me.jellysquid.mods.lithium.common.entity.tracker.EntityTrackerEngine; // Yatopia
public class WorldServer extends World implements GeneratorAccessSeed, NonBlockingWorldAccess { // Yatopia
@@ -2031,6 +2032,16 @@ public class WorldServer extends World implements GeneratorAccessSeed, NonBlocki
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
+ if (entity instanceof EntityLiving) { // Yatopia start - Port lithium
+
+ int chunkX = MathHelper.floor(entity.locX()) >> 4;
+ int chunkY = MathHelper.clamp(MathHelper.floor(entity.locY()) >> 4, 0, 15);
+ int chunkZ = MathHelper.floor(entity.locZ()) >> 4;
+
+ EntityTrackerEngine tracker = this.getEntityTracker();
+ tracker.onEntityRemoved(chunkX, chunkY, chunkZ, (EntityLiving) entity);
+ } // Yatopia End
+
if (!(entity instanceof EntityPlayer)) {
if (false && this.tickingEntities) { // Tuinity
throw (IllegalStateException) SystemUtils.c((Throwable) (new IllegalStateException("Removing entity while ticking!")));
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index cd1f94e5c1c923ee9d8dd451406ac2bee360e9c3..7befe4263a2d046922438e1a9853f2d8290ee230 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -177,6 +177,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, ne
private CraftEntity bukkitEntity;
public PlayerChunkMap.EntityTracker tracker; // Paper package private -> public
+ public PlayerChunkMap.EntityTracker getTracker() { return tracker; } // Yatopia
public boolean collisionLoadChunks = false; // Paper
public Throwable addedToWorldStack; // Paper - entity debug
public CraftEntity getBukkitEntity() {
diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java
Upstream (#469) * Updated Upstream and Sidestream(s) (Paper/Tuinity/Airplane/Purpur/Empirecraft) Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: fbae9dbe0 [Auto] Updated Upstream (Bukkit/CraftBukkit) ac4a33aab [Auto] Updated Upstream (Bukkit) c1e07158b [Auto] Updated Upstream (Bukkit/CraftBukkit) 5e4b88e95 Fix dangling sout 23afda179 basic hostname validation 0fb8bdf0e Updated Upstream (Bukkit/CraftBukkit) (#5508) 88ab784da [Auto] Updated Upstream (CraftBukkit) ca7111d5f Fix PlayerItemConsumeEvent cancelling (fixes #4682) (#5383) 06fb560dc Add support for tab completing and highlighting console input from the Brigadier command tree (#5437) 0a9b89c7a Fix occasional light gen issues for neighbor blocks (#5500) a08be1ec7 [Auto] Updated Upstream (CraftBukkit) Tuinity Changes: 7d36676 Fix light source locking f1ec0c2 Add concurrency check to ProtoChunk light sources 159d146 Improvements to chunk loader system Airplane Changes: 3b3cde7 Correctly use DEAR values, fix config reloading dd60919 Updated Upstream (Tuinity) Purpur Changes: 5674cdc Updated Upstream (Paper) Empirecraft Changes: efda8c5b Updated Paper * Updated Upstream and Sidestream(s) (Paper/Tuinity) Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: 39bf5b525 Update teams known as code owners Tuinity Changes: b12d0cc Replace ticket level propagator 42df8e1 Correctly handle recursion for chunkholder updates 73eb2a8 Do not copy visible chunks 8a4f3be Do not schedule poi task for each block write on chunk gen * Multithreaded Entity Tracker fixup
2021-04-21 23:26:49 +02:00
index a057be22f488f76b926c81dc5c63e7f9c3fb54a1..a897ad3de8c18be8bb3c320950a7421477040e8a 100644
--- a/src/main/java/net/minecraft/world/entity/EntityLiving.java
+++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java
@@ -141,9 +141,11 @@ import org.bukkit.event.player.PlayerItemConsumeEvent;
// CraftBukkit end
import net.gegy1000.tictacs.NonBlockingWorldAccess; // Yatopia
+import me.jellysquid.mods.lithium.common.entity.tracker.nearby.NearbyEntityListenerMulti; // Yatopia
public abstract class EntityLiving extends Entity {
+ private NearbyEntityListenerMulti tracker; // Yatopia - Port lithium
private static final UUID b = UUID.fromString("662A6B8D-DA3E-4C1C-8813-96EA6097278D");
private static final UUID c = UUID.fromString("87f46a96-686f-4796-b035-22e16ee9e038");
private static final AttributeModifier d = new AttributeModifier(EntityLiving.b, "Sprinting speed boost", 0.30000001192092896D, AttributeModifier.Operation.MULTIPLY_TOTAL);
@@ -277,8 +279,14 @@ public abstract class EntityLiving extends Entity {
DynamicOpsNBT dynamicopsnbt = DynamicOpsNBT.a;
this.bg = this.a(new Dynamic(dynamicopsnbt, dynamicopsnbt.createMap((Map) ImmutableMap.of(dynamicopsnbt.createString("memories"), dynamicopsnbt.emptyMap()))));
+ this.tracker = new NearbyEntityListenerMulti(); // Yatopia - Port lithium
}
+ // Yatopia start - Port lithium
+ public NearbyEntityListenerMulti getListener() {
+ return this.tracker;
+ }
+ // Yatopia end
protected void initAttributes() {} // Purpur
public BehaviorController<?> getBehaviorController() {
diff --git a/src/main/java/net/minecraft/world/entity/ai/BehaviorController.java b/src/main/java/net/minecraft/world/entity/ai/BehaviorController.java
index e38cdf81e3f3ba1a2ee86c3a202e5643dd9c0fd1..48524cdf7a1a5d4cff12b24b11dbea9935c85131 100644
--- a/src/main/java/net/minecraft/world/entity/ai/BehaviorController.java
+++ b/src/main/java/net/minecraft/world/entity/ai/BehaviorController.java
@@ -223,6 +223,7 @@ public class BehaviorController<E extends EntityLiving> {
}).isPresent();
}
+ public boolean isMemoryInState(MemoryModuleType<?> memorymoduletype, MemoryStatus memorystatus){ return a(memorymoduletype, memorystatus); } // Yatopia - OBFHELPER
public boolean a(MemoryModuleType<?> memorymoduletype, MemoryStatus memorystatus) {
Optional<? extends ExpirableMemory<?>> optional = (Optional) this.memories.get(memorymoduletype);
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java
index ed3a3593b417131837341784b09cb3f9f76a44be..922f7bf57e65b0bab18b9044ff6467a2660aa992 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java
@@ -1,5 +1,8 @@
package net.minecraft.world.entity.ai.behavior;
+import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
+import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps;
+import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
@@ -10,7 +13,7 @@ import net.minecraft.world.entity.ai.memory.MemoryStatus;
public abstract class Behavior<E extends EntityLiving> {
- protected final Map<MemoryModuleType<?>, MemoryStatus> a;
+ protected final Map<MemoryModuleType<?>, MemoryStatus> a; protected final Map<MemoryModuleType<?>, MemoryStatus> getRequiredMemoryStates(){ return a; } // Yatopia - OBFHELPER
private Behavior.Status b; public final Behavior.Status getStatus() { return this.b; } // Tuinity - OBFHELPER
private long c;
co.aikar.timings.Timing timing; // Origami - behavior timing
@@ -29,7 +32,7 @@ public abstract class Behavior<E extends EntityLiving> {
this.b = Behavior.Status.STOPPED;
this.d = i;
this.e = j;
- this.a = map;
+ this.a = new Reference2ObjectOpenHashMap<>(map); // Yatopia - Port lithium
String key = getClass().getSimpleName(); // Yatopia Compatible Fix
// Origami start - behavior timing
timing = co.aikar.timings.WorldTimingsHandler.getBehaviorTimings(key);
@@ -40,6 +43,7 @@ public abstract class Behavior<E extends EntityLiving> {
return this.b;
}
+ public final boolean tryStarting(WorldServer worldserver, E e0, long i){ return e(worldserver, e0, i); } // Yatopia - OBFHELPER
public final boolean e(WorldServer worldserver, E e0, long i) {
if (this.a(e0) && this.a(worldserver, e0)) {
this.b = Behavior.Status.RUNNING;
@@ -92,23 +96,17 @@ public abstract class Behavior<E extends EntityLiving> {
}
private boolean a(E e0) {
- Iterator iterator = this.a.entrySet().iterator();
+ // Yatopia start - port lithium
+ Iterable<Reference2ObjectMap.Entry<MemoryModuleType<?>, MemoryStatus>> iterable =
+ Reference2ObjectMaps.fastIterable((Reference2ObjectOpenHashMap<MemoryModuleType<?>, MemoryStatus>)this.getRequiredMemoryStates());
- MemoryModuleType memorymoduletype;
- MemoryStatus memorystatus;
-
- do {
- if (!iterator.hasNext()) {
- return true;
+ for (Reference2ObjectMap.Entry<MemoryModuleType<?>, MemoryStatus> entry : iterable) {
+ if (!e0.getBehaviorController().isMemoryInState(entry.getKey(), entry.getValue())) {
+ return false;
}
+ }
- Entry<MemoryModuleType<?>, MemoryStatus> entry = (Entry) iterator.next();
-
- memorymoduletype = (MemoryModuleType) entry.getKey();
- memorystatus = (MemoryStatus) entry.getValue();
- } while (e0.getBehaviorController().a(memorymoduletype, memorystatus));
-
- return false;
+ return true; // Yatopia end
}
public static enum Status {
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorGate.java b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorGate.java
index c46cdffe3d877bff70b843766c8189eae06148ff..9cf43a86b573ad2c553956c081ae40820cbc7d5e 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorGate.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/BehaviorGate.java
@@ -31,17 +31,15 @@ public class BehaviorGate<E extends EntityLiving> extends Behavior<E> {
@Override
protected boolean b(WorldServer worldserver, E e0, long i) {
- // Tuinity start - remove streams
- List<WeightedList.a<Behavior<? super E>>> list = this.getList().getList();
- for (int index = 0, len = list.size(); index < len; ++index) {
- Behavior<? super E> behavior = list.get(index).getValue();
+ // Tuinity start - remove streams // Yatopia start - Port lithium
+ for (Behavior<? super E> behavior : this.getList()) {
if (behavior.getStatus() == Status.RUNNING && behavior.b(worldserver, e0, i)) { // copied from removed code, make sure to update
return true;
}
}
return false;
- // Tuinity end - remove streams
+ // Tuinity end - remove streams // Yatopia start - Port lithium
}
@Override
@@ -57,23 +55,19 @@ public class BehaviorGate<E extends EntityLiving> extends Behavior<E> {
@Override
protected void d(WorldServer worldserver, E e0, long i) {
- // Tuinity start - remove streams
- List<WeightedList.a<Behavior<? super E>>> list = this.getList().getList();
- for (int index = 0, len = list.size(); index < len; ++index) {
- Behavior<? super E> behavior = list.get(index).getValue();
+ // Tuinity start - remove streams // Yatopia start - Port lithium
+ for (Behavior<? super E> behavior : this.getList()) {
if (behavior.getStatus() == Behavior.Status.RUNNING) {
behavior.f(worldserver, e0, i); // copied from removed code, make sure to update
}
}
- // Tuinity end - remove streams
+ // Tuinity end - remove streams // Yatopia end
}
@Override
protected void c(WorldServer worldserver, E e0, long i) {
- // Tuinity start - remove streams
- List<WeightedList.a<Behavior<? super E>>> list = this.getList().getList();
- for (int index = 0, len = list.size(); index < len; ++index) {
- Behavior<? super E> behavior = list.get(index).getValue();
+ // Tuinity start - remove streams// Yatopia start - Port lithium
+ for (Behavior<? super E> behavior : this.getList()) {
if (behavior.getStatus() == Behavior.Status.RUNNING) {
behavior.g(worldserver, e0, i); // copied from removed code, make sure to update
}
@@ -81,7 +75,9 @@ public class BehaviorGate<E extends EntityLiving> extends Behavior<E> {
// Tuinity end - remove streams
BehaviorController behaviorcontroller = e0.getBehaviorController();
- this.b.forEach(behaviorcontroller::removeMemory); // Paper - decomp fix
+ for(MemoryModuleType<?> moduleType : this.b){
+ behaviorcontroller.removeMemory(moduleType);
+ } // Yatopia end
}
@Override
@@ -98,29 +94,25 @@ public class BehaviorGate<E extends EntityLiving> extends Behavior<E> {
RUN_ONE {
@Override
public <E extends EntityLiving> void a(WeightedList<Behavior<? super E>> weightedlist, WorldServer worldserver, E e0, long i) {
- // Tuinity start - remove streams
- List<WeightedList.a<Behavior<? super E>>> list = weightedlist.getList();
- for (int index = 0, len = list.size(); index < len; ++index) {
- Behavior<? super E> behavior = list.get(index).getValue();
- if (behavior.getStatus() == Behavior.Status.STOPPED && behavior.e(worldserver, e0, i)) { // copied from removed code, make sure to update
+ // Tuinity start - remove streams // Yatopia start - port lithium
+ for (Behavior<? super E> behavior : weightedlist) {
+ if (behavior.getStatus() == Behavior.Status.STOPPED && behavior.tryStarting(worldserver, e0, i)) { // copied from removed code, make sure to update
break;
}
}
- // Tuinity end - remove streams
+ // Tuinity end - remove streams // Yatopia end
}
},
TRY_ALL {
@Override
public <E extends EntityLiving> void a(WeightedList<Behavior<? super E>> weightedlist, WorldServer worldserver, E e0, long i) {
- // Tuinity start - remove streams
- List<WeightedList.a<Behavior<? super E>>> list = weightedlist.getList();
- for (int index = 0, len = list.size(); index < len; ++index) {
- Behavior<? super E> behavior = list.get(index).getValue();
+ // Tuinity start - remove streams // Yatopia start - port lithium
+ for (Behavior<? super E> behavior : weightedlist) {
if (behavior.getStatus() == Behavior.Status.STOPPED) {
- behavior.e(worldserver, e0, i); // copied from removed code, make sure to update
+ behavior.tryStarting(worldserver, e0, i); // copied from removed code, make sure to update
}
}
- // Tuinity end - remove streams
+ // Tuinity end - remove streams // Yatopia end
}
};
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/WeightedList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/WeightedList.java
index e2b5d6155bebdbf99b0850de7f9e1f5d342f9e2f..a3236e6359a2e72b4a41be4717780c20e2a31af3 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/WeightedList.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/WeightedList.java
@@ -8,11 +8,12 @@ import com.mojang.serialization.Dynamic;
import com.mojang.serialization.DynamicOps;
import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;
-public class WeightedList<U> {
+public class WeightedList<U> implements Iterable<U> { // Yatopia - Port lithium
protected final List<WeightedList.a<U>> list; public final List<WeightedList.a<U>> getList() { return this.list; } // Paper - decompile conflict // Tuinity - OBFHELPER
private final Random b;
@@ -116,4 +117,35 @@ public class WeightedList<U> {
};
}
}
-}
+
+
+ // Yatopia start - Port lithium
+ /**
+ * A wrapper type for an iterator over the entries of a {@link WeightedList} which de-references the contained
+ * values for consumers.
+ *
+ * @param <U> The value type stored in each list entry
+ */
+ class ListIterator<U> implements Iterator<U> {
+ private final Iterator<WeightedList.a<U>> inner;
+
+ public ListIterator(Iterator<WeightedList.a<U>> inner) {
+ this.inner = inner;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return this.inner.hasNext();
+ }
+
+ @Override
+ public U next() {
+ return this.inner.next().getValue();
+ }
+ }
+
+ @Override
+ public Iterator<U> iterator() {
+ return new ListIterator<>(this.list.iterator());
+ }
+} // Yatopia End
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalAvoidTarget.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalAvoidTarget.java
index 35502bd2f7d9cebf5cfe1060e300a5032dbe6a5d..eea1a396f06e8feaa5637ba4e589a13169f514da 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalAvoidTarget.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalAvoidTarget.java
@@ -1,5 +1,7 @@
package net.minecraft.world.entity.ai.goal;
+import me.jellysquid.mods.lithium.common.entity.tracker.nearby.NearbyEntityTracker;
+
import java.util.EnumSet;
import java.util.function.Predicate;
import net.minecraft.world.entity.Entity;
@@ -25,6 +27,7 @@ public class PathfinderGoalAvoidTarget<T extends EntityLiving> extends Pathfinde
protected final Predicate<EntityLiving> g;
protected final Predicate<EntityLiving> h;
private final PathfinderTargetCondition k;
+ private NearbyEntityTracker<T> tracker; // Yatopia - Port Lithium
public PathfinderGoalAvoidTarget(EntityCreature entitycreature, Class<T> oclass, float f, double d0, double d1) {
this(entitycreature, oclass, entityliving -> true, f, d0, d1, IEntitySelector.e::test); // Purpur - decompile fix
@@ -41,6 +44,10 @@ public class PathfinderGoalAvoidTarget<T extends EntityLiving> extends Pathfinde
this.e = entitycreature.getNavigation();
this.a(EnumSet.of(PathfinderGoal.Type.MOVE));
this.k = (new PathfinderTargetCondition()).a((double) f).a(predicate1.and(predicate));
+ // Yatopia start - Port Lithium
+ this.tracker = new NearbyEntityTracker<>(oclass, entitycreature, f);
+ entitycreature.getListener().addListener(this.tracker);
+ // Yatopia end
}
public PathfinderGoalAvoidTarget(EntityCreature entitycreature, Class<T> oclass, float f, double d0, double d1, Predicate<EntityLiving> predicate) {
@@ -51,7 +58,7 @@ public class PathfinderGoalAvoidTarget<T extends EntityLiving> extends Pathfinde
@Override
public boolean a() {
- this.b = this.a.world.b(this.f, this.k, this.a, this.a.locX(), this.a.locY(), this.a.locZ(), this.a.getBoundingBox().grow((double) this.c, 3.0D, (double) this.c));
+ this.b = this.tracker.getClosestEntity(this.a.getBoundingBox().grow((double) this.c, 3.0D, (double) this.c), this.k); // Yatopia - Port lithium
if (this.b == null) {
return false;
} else {
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLookAtPlayer.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLookAtPlayer.java
index 3bcbad5e298cf05c1b41476a08a3a69cb7fdf79f..8b41274aa388a758bd8acf9637e2a19caf744c57 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLookAtPlayer.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalLookAtPlayer.java
@@ -1,5 +1,6 @@
package net.minecraft.world.entity.ai.goal;
+import me.jellysquid.mods.lithium.common.entity.tracker.nearby.NearbyEntityTracker;
import java.util.EnumSet;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityInsentient;
@@ -10,6 +11,7 @@ import net.minecraft.world.entity.player.EntityHuman;
public class PathfinderGoalLookAtPlayer extends PathfinderGoal {
+ private NearbyEntityTracker<? extends EntityLiving> tracker; // Yatopia - Port lithium
protected final EntityInsentient a;
protected Entity b;
protected final float c;
@@ -27,7 +29,7 @@ public class PathfinderGoalLookAtPlayer extends PathfinderGoal {
this.e = oclass;
this.c = f;
this.d = f1;
- this.a(EnumSet.of(PathfinderGoal.Type.LOOK));
+ this.a(EnumSet.of(Type.LOOK)); // Yatopia - Port lithium
if (oclass == EntityHuman.class) {
this.f = (new PathfinderTargetCondition()).a((double) f).b().a().d().a((entityliving) -> {
return IEntitySelector.b(entityinsentient).test(entityliving);
@@ -35,7 +37,10 @@ public class PathfinderGoalLookAtPlayer extends PathfinderGoal {
} else {
this.f = (new PathfinderTargetCondition()).a((double) f).b().a().d();
}
-
+ // Yatopia start - Port lithium
+ this.tracker = new NearbyEntityTracker<>(oclass, entityinsentient, f);
+ entityinsentient.getListener().addListener(this.tracker);
+ // Yatopia end
}
@Override
@@ -48,9 +53,9 @@ public class PathfinderGoalLookAtPlayer extends PathfinderGoal {
}
if (this.e == EntityHuman.class) {
- this.b = this.a.world.a(this.f, this.a, this.a.locX(), this.a.getHeadY(), this.a.locZ());
+ this.b = this.tracker.getClosestEntity(null, this.f); // Yatopia - Port lithium
} else {
- this.b = this.a.world.b(this.e, this.f, this.a, this.a.locX(), this.a.getHeadY(), this.a.locZ(), this.a.getBoundingBox().grow((double) this.c, 3.0D, (double) this.c));
+ this.b = this.tracker.getClosestEntity(this.a.getBoundingBox().grow((double) this.c, 3.0D, (double) this.c), this.f); // Yatopia - Port lithium
}
return this.b != null;
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
index 29cd71efe86eea2227f373c15c39dc530e9e8199..7dcd055b37bb7051127e10f5d191d23e0562b29e 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
@@ -7,7 +7,12 @@ import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; // Tuinity
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
+import me.jellysquid.mods.lithium.common.util.Collector;
+import me.jellysquid.mods.lithium.common.world.interests.PointOfInterestCollectors;
+import me.jellysquid.mods.lithium.common.world.interests.PointOfInterestTypeHelper;
+
import java.io.File;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -193,7 +198,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
public long count(Predicate<VillagePlaceType> predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) { return a(predicate, blockposition, i, villageplace_occupancy); } // Purpur - OBFHELPER
public long a(Predicate<VillagePlaceType> predicate, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) {
- return this.cList(predicate, blockposition, i, villageplace_occupancy).size(); // Yatopia
+ return this.getAllWithinCircle(predicate, blockposition, i, villageplace_occupancy).size(); // Yatopia
}
public boolean a(VillagePlaceType villageplacetype, BlockPosition blockposition) {
@@ -236,6 +241,35 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
return ret;
}
+ private List<VillagePlaceRecord> getAllWithinCircle(Predicate<VillagePlaceType> predicate, BlockPosition pos, int radius, Occupancy status) {
+ List<VillagePlaceRecord> points = new ArrayList<>();
+
+ this.collectWithinCircle(predicate, pos, radius, status, points::add);
+
+ return points;
+ }
+
+ private void collectWithinCircle(Predicate<VillagePlaceType> predicate, BlockPosition pos, int radius, Occupancy status, Collector<VillagePlaceRecord> collector) {
+ Collector<VillagePlaceRecord> filter = PointOfInterestCollectors.collectAllWithinRadius(pos, radius, collector);
+ Collector<VillagePlaceSection> consumer = PointOfInterestCollectors.collectAllMatching(predicate, status, filter);
+
+ int minChunkX = (pos.getX() - radius - 1) >> 4;
+ int minChunkZ = (pos.getZ() - radius - 1) >> 4;
+
+ int maxChunkX = (pos.getX() + radius + 1) >> 4;
+ int maxChunkZ = (pos.getZ() + radius + 1) >> 4;
+
+ // noinspection unchecked
+
+ for (int x = minChunkX; x <= maxChunkX; x++) {
+ for (int z = minChunkZ; z <= maxChunkZ; z++) {
+ if (!this.collectWithinChunkColumn(x, z, consumer)) {
+ return;
+ }
+ }
+ }
+ }
+
public java.util.List<BlockPosition> cListPositions(Predicate<VillagePlaceType> predicate, Predicate<VillagePlaceRecord> recordFilter, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) {
int j = i * i;
java.util.List<BlockPosition> ret = new java.util.ArrayList<>();
@@ -255,12 +289,12 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
});
}
+ /**
+ * @reason Retrieve all points of interest in one operation
+ * @author JellySquid
+ */
public Stream<VillagePlaceRecord> a(Predicate<VillagePlaceType> predicate, ChunkCoordIntPair chunkcoordintpair, VillagePlace.Occupancy villageplace_occupancy) {
- return IntStream.range(0, 16).boxed().map((integer) -> {
- return this.d(SectionPosition.a(chunkcoordintpair, integer).s());
- }).filter(Optional::isPresent).flatMap((optional) -> {
- return ((VillagePlaceSection) optional.get()).a(predicate, villageplace_occupancy);
- });
+ return this.getWithinChunkColumn(chunkcoordintpair.x, chunkcoordintpair.z).flatMap((set) -> set.get(predicate, villageplace_occupancy));
}
// Yatopia start
@@ -273,12 +307,16 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
}
return ret;
}
- // Yatopia end
+
+ /**
+ * @reason Retrieve all points of interest in one operation
+ * @author JellySquid
+ */
public Stream<BlockPosition> a(Predicate<VillagePlaceType> predicate, Predicate<BlockPosition> predicate1, BlockPosition blockposition, int i, VillagePlace.Occupancy villageplace_occupancy) {
return this.c(predicate, blockposition, i, villageplace_occupancy).map(VillagePlaceRecord::f).filter(predicate1);
}
- // Yatopia start
+
public java.util.List<BlockPosition> bList(Predicate<VillagePlaceType> predicate, Predicate<BlockPosition> posFilter, BlockPosition pos, int i, VillagePlace.Occupancy occupancy) {
java.util.List<BlockPosition> ret = aList(predicate, posFilter, pos, i, occupancy);
ret.sort(Comparator.comparingDouble((pos1) -> pos1.distanceSquared(pos)));
@@ -404,24 +442,28 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
this.updateDistanceTracking(i); // Tuinity - move to new distance tracking util
}
+ /**
+ * @reason Avoid Stream API
+ * @author Jellysquid
+ */
public void a(ChunkCoordIntPair chunkcoordintpair, ChunkSection chunksection) {
- SectionPosition sectionposition = SectionPosition.a(chunkcoordintpair, chunksection.getYPosition() >> 4);
+ SectionPosition sectionPos = SectionPosition.from(chunkcoordintpair, chunksection.getYPosition() >> 4);
- SystemUtils.a(this.d(sectionposition.s()), (villageplacesection) -> {
- villageplacesection.a((biconsumer) -> {
- if (a(chunksection)) {
- this.a(chunksection, sectionposition, biconsumer);
- }
+ VillagePlaceSection set = this.get(sectionPos.asLong()).orElse(null);
+ if (set != null) {
+ set.refresh((consumer) -> {
+ if (PointOfInterestTypeHelper.shouldScan(chunksection)) {
+ this.scanAndPopulate(chunksection, sectionPos, consumer);
+ }
});
- }, () -> {
- if (a(chunksection)) {
- VillagePlaceSection villageplacesection = (VillagePlaceSection) this.e(sectionposition.s());
+ } else {
+ if (PointOfInterestTypeHelper.shouldScan(chunksection)) {
+ set = this.getOrCreate(sectionPos.asLong());
- this.a(chunksection, sectionposition, villageplacesection::a);
+ this.scanAndPopulate(chunksection, sectionPos, set::add);
}
-
- });
+ }
}
private static boolean a(ChunkSection chunksection) {
@@ -431,6 +473,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
return chunksection.a(set::contains);
}
+ private void scanAndPopulate(ChunkSection chunksection, SectionPosition sectionposition, BiConsumer<BlockPosition, VillagePlaceType> biconsumer){ a(chunksection, sectionposition, biconsumer); } // Yatopia - OBFHELPER
private void a(ChunkSection chunksection, SectionPosition sectionposition, BiConsumer<BlockPosition, VillagePlaceType> biconsumer) {
sectionposition.tList().forEach((blockposition) -> { // Yatopia
IBlockData iblockdata = chunksection.getType(SectionPosition.b(blockposition.getX()), SectionPosition.b(blockposition.getY()), SectionPosition.b(blockposition.getZ()));
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceSection.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceSection.java
index 866e9a434423702d2edaf9b52fa0e6219e13c2d7..640aee2b8afd66082cc867b14980f06d9811fc28 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceSection.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceSection.java
@@ -26,6 +26,7 @@ import net.minecraft.core.SectionPosition;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.Supplier;
+import me.jellysquid.mods.lithium.common.util.Collector;
public class VillagePlaceSection {
@@ -73,7 +74,28 @@ public class VillagePlaceSection {
}
return ret;
}
+
+ public boolean get(Predicate<VillagePlaceType> type, VillagePlace.Occupancy status, Collector<VillagePlaceRecord> consumer) {
+ for (Map.Entry<VillagePlaceType, Set<VillagePlaceRecord>> entry : this.getData().entrySet()) {
+ if (!type.test(entry.getKey())) {
+ continue;
+ }
+
+ for (VillagePlaceRecord poi : entry.getValue()) {
+ if (!status.getPredicate().test(poi)) {
+ continue;
+ }
+
+ if (!consumer.collect(poi)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
// Yatopia end
+ public Stream<VillagePlaceRecord> get(Predicate<VillagePlaceType> predicate, VillagePlace.Occupancy villageplace_occupancy){ return a(predicate, villageplace_occupancy); } // Yatopia - OBFHELPER
public Stream<VillagePlaceRecord> a(Predicate<VillagePlaceType> predicate, VillagePlace.Occupancy villageplace_occupancy) {
return this.c.entrySet().stream().filter((entry) -> {
return predicate.test(entry.getKey());
@@ -82,6 +104,7 @@ public class VillagePlaceSection {
}).filter(villageplace_occupancy.a());
}
+ public void add(BlockPosition blockPosition, VillagePlaceType villagePlaceType) { a(blockPosition, villagePlaceType); } // Yatopia - OBFHELPER
public void a(BlockPosition blockposition, VillagePlaceType villageplacetype) {
if (this.a(new VillagePlaceRecord(blockposition, villageplacetype, this.d))) {
VillagePlaceSection.LOGGER.debug("Added POI of type {} @ {}", new Supplier[]{() -> {
@@ -160,6 +183,7 @@ public class VillagePlaceSection {
return villageplacerecord != null ? Optional.of(villageplacerecord.g()) : Optional.empty();
}
+ public void refresh(Consumer<BiConsumer<BlockPosition, VillagePlaceType>> consumer){ a(consumer); } // Yatopia - OBFHELPER
public void a(Consumer<BiConsumer<BlockPosition, VillagePlaceType>> consumer) {
if (!this.e) {
Short2ObjectMap<VillagePlaceRecord> short2objectmap = new Short2ObjectOpenHashMap(this.b);
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java
index 4af526ecbed506161cb021ea320b0f21112d7bf0..4a7b3750f1b3ce3143053215dbca6da6eee052bd 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlaceType.java
@@ -4,7 +4,11 @@ import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
+import it.unimi.dsi.fastutil.objects.ObjectArraySet;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
+import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
+import me.jellysquid.mods.lithium.common.world.interests.PointOfInterestTypeHelper;
+
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -46,7 +50,8 @@ public class VillagePlaceType {
}).filter((iblockdata) -> {
return iblockdata.get(BlockBed.PART) == BlockPropertyBedPart.HEAD;
}).collect(ImmutableSet.toImmutableSet());
- private static final Map<IBlockData, VillagePlaceType> A = Maps.newHashMap();
+ private static final Map<IBlockData, VillagePlaceType> A = new Reference2ReferenceOpenHashMap<>(); // Yatopia - Port Lithium
+ public static final Map<IBlockData, VillagePlaceType> getBlockStateToPointOfInterestType(){ return A; } // Yatopia - OBFHELPER
public static final VillagePlaceType c = a("unemployed", ImmutableSet.of(), 1, VillagePlaceType.a, 1);
public static final VillagePlaceType d = a("armorer", a(Blocks.BLAST_FURNACE), 1, 1);
public static final VillagePlaceType e = a("butcher", a(Blocks.SMOKER), 1, 1);
@@ -75,6 +80,12 @@ public class VillagePlaceType {
private final Predicate<VillagePlaceType> E;
private final int F;
+ // Yatopia Start - Port lithium
+ static {
+ PointOfInterestTypeHelper.init(new ObjectArraySet<>(getBlockStateToPointOfInterestType().keySet()));
+ }
+ // Yatopia End
+
private static Set<IBlockData> a(Block block) {
return ImmutableSet.copyOf(block.getStates().a());
}
diff --git a/src/main/java/net/minecraft/world/entity/raid/EntityRaider.java b/src/main/java/net/minecraft/world/entity/raid/EntityRaider.java
index 8eec32af12c69e1963dcd304a25ec4811b2f1f5a..e4bb472002934f749ff0e2f43744c73fcd74d3cc 100644
--- a/src/main/java/net/minecraft/world/entity/raid/EntityRaider.java
+++ b/src/main/java/net/minecraft/world/entity/raid/EntityRaider.java
@@ -47,9 +47,10 @@ import net.minecraft.world.phys.Vec3D;
public abstract class EntityRaider extends EntityMonsterPatrolling {
+ private static final ItemStack CACHED_OMINOUS_BANNER = Raid.getOminousBanner(); // Yatopia - Port lithium
protected static final DataWatcherObject<Boolean> c = DataWatcher.a(EntityRaider.class, DataWatcherRegistry.i);
private static final Predicate<EntityItem> b = (entityitem) -> {
- return !entityitem.p() && entityitem.isAlive() && ItemStack.matches(entityitem.getItemStack(), Raid.s());
+ return !entityitem.p() && entityitem.isAlive() && ItemStack.matches(entityitem.getItemStack(), CACHED_OMINOUS_BANNER); // Yatopia - Port lithium
};
@Nullable
protected Raid d;
@@ -151,7 +152,7 @@ public abstract class EntityRaider extends EntityMonsterPatrolling {
}
}
- if (!itemstack.isEmpty() && ItemStack.matches(itemstack, Raid.s()) && entityhuman != null) {
+ if (!itemstack.isEmpty() && ItemStack.matches(itemstack, CACHED_OMINOUS_BANNER) && entityhuman != null) { // Yatopia - Port lithium
MobEffect mobeffect = entityhuman.getEffect(MobEffects.BAD_OMEN);
byte b0 = 1;
int i;
@@ -242,7 +243,7 @@ public abstract class EntityRaider extends EntityMonsterPatrolling {
ItemStack itemstack = entityitem.getItemStack();
boolean flag = this.fb() && this.fa().b(this.fc()) != null;
- if (this.fb() && !flag && ItemStack.matches(itemstack, Raid.s())) {
+ if (this.fb() && !flag && ItemStack.matches(itemstack, CACHED_OMINOUS_BANNER)) { // Yatopia - Port lithium
EnumItemSlot enumitemslot = EnumItemSlot.HEAD;
ItemStack itemstack1 = this.getEquipment(enumitemslot);
double d0 = (double) this.e(enumitemslot);
@@ -535,7 +536,7 @@ public abstract class EntityRaider extends EntityMonsterPatrolling {
if ((!getRaider().world.purpurConfig.pillagerBypassMobGriefing && !getRaider().world.getGameRules().getBoolean(GameRules.MOB_GRIEFING)) || !getRaider().canPickupLoot()) return false; // Paper - respect game and entity rules for picking up items // Purpur
Raid raid = this.b.fa();
- if (this.b.fb() && !this.b.fa().a() && this.b.eN() && !ItemStack.matches(this.b.getEquipment(EnumItemSlot.HEAD), Raid.s())) {
+ if (this.b.fb() && !this.b.fa().a() && this.b.eN() && !ItemStack.matches(this.b.getEquipment(EnumItemSlot.HEAD), CACHED_OMINOUS_BANNER)) { // Yatopia - Port lithium
EntityRaider entityraider = raid.b(this.b.fc());
if (entityraider == null || !entityraider.isAlive()) {
diff --git a/src/main/java/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java
index f9d03b6d11ad5ffbfe5be072e8631f046bcd1646..52def6de2225cf5ed70c807b74fb5c2ccd133503 100644
--- a/src/main/java/net/minecraft/world/entity/raid/Raid.java
+++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java
@@ -227,8 +227,14 @@ public class Raid {
this.status = Raid.Status.STOPPED;
}
+ private boolean isBarDirty; // Yatopia - Port lithium
public void o() {
if (!this.isStopped()) {
+ if (this.isBarDirty) { // Yatopia Start - Port lithium
+ this.bossBattle.setProgress(MathHelper.a(this.sumMobHealth() / this.totalHealth, 0.0F, 1.0F));
+
+ this.isBarDirty = false;
+ } // Yatopia End
if (this.status == Raid.Status.ONGOING) {
boolean flag = this.active;
@@ -596,7 +602,7 @@ public class Raid {
}
public void updateProgress() {
- this.bossBattle.setProgress(MathHelper.a(this.sumMobHealth() / this.totalHealth, 0.0F, 1.0F));
+ this.isBarDirty = true; // Yatopia - Port lithium
}
public float sumMobHealth() {
@@ -647,6 +653,7 @@ public class Raid {
this.world.getPersistentRaid().b();
}
+ public static ItemStack getOminousBanner(){ return s(); } // Yatopia - OBFHELPER
public static ItemStack s() {
ItemStack itemstack = new ItemStack(Items.WHITE_BANNER);
NBTTagCompound nbttagcompound = itemstack.a("BlockEntityTag");
diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java
index f5badbe0dee5c40cf83a5d2993d27ed70ddd2c85..db2b1863b7f46be53839fb3e86870745fb7567fd 100644
--- a/src/main/java/net/minecraft/world/level/World.java
+++ b/src/main/java/net/minecraft/world/level/World.java
@@ -97,6 +97,7 @@ import org.bukkit.event.block.BlockPhysicsEvent;
// CraftBukkit end
import net.gegy1000.tictacs.NonBlockingWorldAccess; // Yatopia
+import me.jellysquid.mods.lithium.common.entity.tracker.EntityTrackerEngine; // Yatopia
public abstract class World implements GeneratorAccess, AutoCloseable, NonBlockingWorldAccess { // Yatopia
@@ -291,6 +292,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki
}
// Tuinity end - optimise checkDespawn
+ private EntityTrackerEngine tracker; // Yatopia - Port lithium
protected World(WorldDataMutable worlddatamutable, ResourceKey<World> resourcekey, final DimensionManager dimensionmanager, Supplier<GameProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.WorldDataServer) worlddatamutable).getName()); // Spigot
@@ -368,8 +370,14 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki
this.keepSpawnInMemory = this.paperConfig.keepSpawnInMemory; // Paper
this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
+ this.tracker = new EntityTrackerEngine(); // Yatopia - Port lithium
}
+ // Yatopia start - Port lithium
+ public EntityTrackerEngine getEntityTracker() {
+ return this.tracker;
+ } // Yatopia end
+
// Paper start
// ret true if no collision
public final boolean checkEntityCollision(IBlockData data, Entity source, VoxelShapeCollision voxelshapedcollision,
@@ -536,6 +544,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable, NonBlocki
return b(blockposition.getY());
}
+ public static boolean isOutOfBuildLimitVertically(int y){ return b(y); } // Yatopia - OBFHELPER
public static boolean b(int i) {
return i < 0 || i >= 256;
}
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
index fab55929f72c5784291b3bc87f7717ac24b7806f..20c2c05ab09ac3f2b2924f2b5bc938fdc5cdd32e 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -55,6 +55,7 @@ import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.phys.shapes.VoxelShapes;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import me.jellysquid.mods.lithium.common.ai.pathing.PathNodeDefaults;
public class Block extends BlockBase implements IMaterial {
@@ -89,6 +90,17 @@ public class Block extends BlockBase implements IMaterial {
return timing;
}
// Paper end
+
+ // Yatopia start - Port lithium
+ public net.minecraft.world.level.pathfinder.PathType getPathNodeType(IBlockData state) {
+ return PathNodeDefaults.getNodeType(state);
+ }
+
+ public net.minecraft.world.level.pathfinder.PathType getNeighborPathNodeType(IBlockData state) {
+ return PathNodeDefaults.getNeighborNodeType(state);
+ }
+ // Yatopia end
+
public Material getMaterial() { return material; } // Purpur - OBFHELPER
@Nullable
private String name;
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java
index b6de70c3630d96d0782a657c0389ce03839d8c43..611066964d11b2da7ab6dd59c6083c5c25c75de7 100644
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java
@@ -3,6 +3,8 @@ package net.minecraft.world.level.block.state;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.MapCodec;
+import org.apache.commons.lang3.Validate;
+
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -63,6 +65,7 @@ import net.minecraft.world.phys.Vec3D;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.phys.shapes.VoxelShapeCollision;
import net.minecraft.world.phys.shapes.VoxelShapes;
+import net.minecraft.world.level.pathfinder.PathType;
public abstract class BlockBase {
@@ -349,6 +352,8 @@ public abstract class BlockBase {
public abstract static class BlockData extends IBlockDataHolder<Block, IBlockData> {
+ public net.minecraft.world.level.pathfinder.PathType pathNodeType = PathType.OPEN; // Yatopia - Port lithium
+ public net.minecraft.world.level.pathfinder.PathType pathNodeTypeNeighbor = PathType.OPEN; // Yatopia - Port lithium
private final int b; public final int getEmittedLight() { return this.b; } // Tuinity - OBFHELPER
private final boolean e; public final boolean isTransparentOnSomeFaces() { return this.e; } // Tuinity - OBFHELPER
private final boolean f;
@@ -420,6 +425,16 @@ public abstract class BlockBase {
}
// Tuinity end
+ // Yatopia start - Port lithium
+ public net.minecraft.world.level.pathfinder.PathType getPathNodeType() {
+ return this.pathNodeType;
+ }
+
+ public net.minecraft.world.level.pathfinder.PathType getNeighborPathNodeType() {
+ return this.pathNodeTypeNeighbor;
+ }
+ // Yatopia end
+
public void a() {
this.fluid = this.getBlock().d(this.p()); // Paper - moved from getFluid()
this.isTicking = this.getBlock().isTicking(this.p()); // Paper - moved from isTicking()
@@ -429,6 +444,9 @@ public abstract class BlockBase {
this.shapeExceedsCube = this.a == null || this.a.c; // Tuinity - moved from actual method to here
this.staticPathType = null; // Tuinity - cache static path type
this.neighbourOverridePathType = null; // Tuinity - cache static path types
+ IBlockData state = this.getBlockData(); // Yatopia - Port lithium
+ this.pathNodeType = Validate.notNull(this.getBlock().getPathNodeType(state)); // Yatopia - Port lithium
+ this.pathNodeTypeNeighbor = Validate.notNull(this.getBlock().getNeighborPathNodeType(state)); // Yatopia - Port lithium
this.opacityIfCached = this.a == null || this.isConditionallyFullOpaque() ? -1 : this.a.getOpacity(); // Tuinity - cache opacity for light
// Tuinity start - optimise culling shape cache for light
if (this.a != null && this.a.getCullingShapeCache() != null) {
diff --git a/src/main/java/net/minecraft/world/level/chunk/Chunk.java b/src/main/java/net/minecraft/world/level/chunk/Chunk.java
Upstream (#469) * Updated Upstream and Sidestream(s) (Paper/Tuinity/Airplane/Purpur/Empirecraft) Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: fbae9dbe0 [Auto] Updated Upstream (Bukkit/CraftBukkit) ac4a33aab [Auto] Updated Upstream (Bukkit) c1e07158b [Auto] Updated Upstream (Bukkit/CraftBukkit) 5e4b88e95 Fix dangling sout 23afda179 basic hostname validation 0fb8bdf0e Updated Upstream (Bukkit/CraftBukkit) (#5508) 88ab784da [Auto] Updated Upstream (CraftBukkit) ca7111d5f Fix PlayerItemConsumeEvent cancelling (fixes #4682) (#5383) 06fb560dc Add support for tab completing and highlighting console input from the Brigadier command tree (#5437) 0a9b89c7a Fix occasional light gen issues for neighbor blocks (#5500) a08be1ec7 [Auto] Updated Upstream (CraftBukkit) Tuinity Changes: 7d36676 Fix light source locking f1ec0c2 Add concurrency check to ProtoChunk light sources 159d146 Improvements to chunk loader system Airplane Changes: 3b3cde7 Correctly use DEAR values, fix config reloading dd60919 Updated Upstream (Tuinity) Purpur Changes: 5674cdc Updated Upstream (Paper) Empirecraft Changes: efda8c5b Updated Paper * Updated Upstream and Sidestream(s) (Paper/Tuinity) Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: 39bf5b525 Update teams known as code owners Tuinity Changes: b12d0cc Replace ticket level propagator 42df8e1 Correctly handle recursion for chunkholder updates 73eb2a8 Do not copy visible chunks 8a4f3be Do not schedule poi task for each block write on chunk gen * Multithreaded Entity Tracker fixup
2021-04-21 23:26:49 +02:00
index 2e8eb0bb8fb4f7ce6b92fe01a81327da30e614ae..34af81b75e7927cccc0d4aea1b80ab677ca31795 100644
--- a/src/main/java/net/minecraft/world/level/chunk/Chunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/Chunk.java
@@ -68,6 +68,7 @@ import net.minecraft.world.level.material.FluidTypes;
import net.minecraft.world.phys.AxisAlignedBB;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import net.minecraft.world.entity.EntityLiving; // Yatopia
public class Chunk implements IChunkAccess {
Upstream (#469) * Updated Upstream and Sidestream(s) (Paper/Tuinity/Airplane/Purpur/Empirecraft) Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: fbae9dbe0 [Auto] Updated Upstream (Bukkit/CraftBukkit) ac4a33aab [Auto] Updated Upstream (Bukkit) c1e07158b [Auto] Updated Upstream (Bukkit/CraftBukkit) 5e4b88e95 Fix dangling sout 23afda179 basic hostname validation 0fb8bdf0e Updated Upstream (Bukkit/CraftBukkit) (#5508) 88ab784da [Auto] Updated Upstream (CraftBukkit) ca7111d5f Fix PlayerItemConsumeEvent cancelling (fixes #4682) (#5383) 06fb560dc Add support for tab completing and highlighting console input from the Brigadier command tree (#5437) 0a9b89c7a Fix occasional light gen issues for neighbor blocks (#5500) a08be1ec7 [Auto] Updated Upstream (CraftBukkit) Tuinity Changes: 7d36676 Fix light source locking f1ec0c2 Add concurrency check to ProtoChunk light sources 159d146 Improvements to chunk loader system Airplane Changes: 3b3cde7 Correctly use DEAR values, fix config reloading dd60919 Updated Upstream (Tuinity) Purpur Changes: 5674cdc Updated Upstream (Paper) Empirecraft Changes: efda8c5b Updated Paper * Updated Upstream and Sidestream(s) (Paper/Tuinity) Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: 39bf5b525 Update teams known as code owners Tuinity Changes: b12d0cc Replace ticket level propagator 42df8e1 Correctly handle recursion for chunkholder updates 73eb2a8 Do not copy visible chunks 8a4f3be Do not schedule poi task for each block write on chunk gen * Multithreaded Entity Tracker fixup
2021-04-21 23:26:49 +02:00
@@ -863,6 +864,11 @@ public class Chunk implements IChunkAccess {
if (!this.entitySlices[i].remove(entity)) { // Tuinity - optimise hard colliding entities // Tuinity - entities by class // Tuinity
return;
}
+ // Yatopia start - Port lithium
+ if (entity instanceof EntityLiving) {
+ this.world.getEntityTracker().onEntityAdded(entity.chunkX, entity.chunkY, entity.chunkZ, (EntityLiving) entity);
+ }
+ // Yatopia end
if (entity instanceof EntityItem) {
itemCounts[i]--;
} else if (entity instanceof IInventory) {
Upstream (#469) * Updated Upstream and Sidestream(s) (Paper/Tuinity/Airplane/Purpur/Empirecraft) Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: fbae9dbe0 [Auto] Updated Upstream (Bukkit/CraftBukkit) ac4a33aab [Auto] Updated Upstream (Bukkit) c1e07158b [Auto] Updated Upstream (Bukkit/CraftBukkit) 5e4b88e95 Fix dangling sout 23afda179 basic hostname validation 0fb8bdf0e Updated Upstream (Bukkit/CraftBukkit) (#5508) 88ab784da [Auto] Updated Upstream (CraftBukkit) ca7111d5f Fix PlayerItemConsumeEvent cancelling (fixes #4682) (#5383) 06fb560dc Add support for tab completing and highlighting console input from the Brigadier command tree (#5437) 0a9b89c7a Fix occasional light gen issues for neighbor blocks (#5500) a08be1ec7 [Auto] Updated Upstream (CraftBukkit) Tuinity Changes: 7d36676 Fix light source locking f1ec0c2 Add concurrency check to ProtoChunk light sources 159d146 Improvements to chunk loader system Airplane Changes: 3b3cde7 Correctly use DEAR values, fix config reloading dd60919 Updated Upstream (Tuinity) Purpur Changes: 5674cdc Updated Upstream (Paper) Empirecraft Changes: efda8c5b Updated Paper * Updated Upstream and Sidestream(s) (Paper/Tuinity) Upstream/An Sidestream has released updates that appears to apply and compile correctly This update has NOT been tested by YatopiaMC and as with ANY update, please do your own testing. Paper Changes: 39bf5b525 Update teams known as code owners Tuinity Changes: b12d0cc Replace ticket level propagator 42df8e1 Correctly handle recursion for chunkholder updates 73eb2a8 Do not copy visible chunks 8a4f3be Do not schedule poi task for each block write on chunk gen * Multithreaded Entity Tracker fixup
2021-04-21 23:26:49 +02:00
@@ -872,6 +878,11 @@ public class Chunk implements IChunkAccess {
this.markDirty(); // Paper
// Paper end
this.entities.remove(entity); // Paper
+ // Yatopia start - Port lithium
+ if (entity instanceof EntityLiving) {
+ this.world.getEntityTracker().onEntityRemoved(entity.chunkX, entity.chunkY, entity.chunkZ, (EntityLiving) entity);
+ }
+ // Yatopia end
}
public final int getHighestBlockY(HeightMap.Type heightmap_type, int i, int j) { return this.getHighestBlock(heightmap_type, i, j) + 1; } // Paper - sort of an obfhelper, but without -1
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java
index b5eb43174d2c2f34bb17bbcdb803aafe58989678..92f6301005031f4afab225e9fd01010eacd3ed26 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java
@@ -177,6 +177,7 @@ public class ChunkSection {
return 2 + this.blockIds.c();
}
+ public boolean hasAny(Predicate<IBlockData> predicate) { return a(predicate); } // Yatopia - OBFHELPER
public boolean a(Predicate<IBlockData> predicate) {
return this.blockIds.contains(predicate);
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java
index f70c14385c95763b5f270a6e2ce372cf047ba7bb..5968712468ad1bea4894d31d0d08b213735743e5 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java
@@ -13,10 +13,13 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
import java.io.File;
import java.io.IOException;
+import java.util.BitSet;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
+import java.util.stream.Stream;
import javax.annotation.Nullable;
import net.minecraft.SharedConstants;
import net.minecraft.SystemUtils;
@@ -29,27 +32,118 @@ import net.minecraft.world.level.ChunkCoordIntPair;
import net.minecraft.world.level.World;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import me.jellysquid.mods.lithium.common.util.Collector;
+import me.jellysquid.mods.lithium.common.util.collections.ListeningLong2ObjectOpenHashMap;
public class RegionFileSection<R> extends RegionFileCache implements AutoCloseable { // Paper - nuke IOWorker
private static final Logger LOGGER = LogManager.getLogger();
// Paper - nuke IOWorker
- private final Long2ObjectMap<Optional<R>> c = new Long2ObjectOpenHashMap(); protected final Long2ObjectMap<Optional<R>> getDataBySection() { return this.c; } // Tuinity - OBFHELPER
+ private Long2ObjectMap<Optional<R>> c = new Long2ObjectOpenHashMap(); protected final Long2ObjectMap<Optional<R>> getDataBySection() { return this.c; } // Tuinity - OBFHELPER
public final LongLinkedOpenHashSet d = new LongLinkedOpenHashSet(); protected final LongLinkedOpenHashSet getDirtySections() { return this.d; } // Paper - private -> public // Tuinity - OBFHELPER
private final Function<Runnable, Codec<R>> e;
private final Function<Runnable, R> f;
private final DataFixer g;
private final DataFixTypes h;
+ private Long2ObjectOpenHashMap<BitSet> columns; // Yatopia - Port lithium
+
public RegionFileSection(File file, Function<Runnable, Codec<R>> function, Function<Runnable, R> function1, DataFixer datafixer, DataFixTypes datafixtypes, boolean flag) {
super(file, flag); // Paper - nuke IOWorker
this.e = function;
this.f = function1;
this.g = datafixer;
this.h = datafixtypes;
+ // Yatopia Start - Port lithium
+ this.columns = new Long2ObjectOpenHashMap<>();
+ this.c = new ListeningLong2ObjectOpenHashMap<>(this::onEntryAdded, this::onEntryRemoved);
//this.b = new IOWorker(file, flag, file.getName()); // Paper - nuke IOWorker
}
+ private void onEntryRemoved(long key, Optional<R> value) {
+ // NO-OP... vanilla never removes anything, leaking entries.
+ // We might want to fix this.
+ }
+
+ private void onEntryAdded(long key, Optional<R> value) {
+ int y = SectionPosition.unpackY(key);
+
+ // We only care about items belonging to a valid sub-chunk
+ if (y < 0 || y >= 16) {
+ return;
+ }
+
+ int x = SectionPosition.unpackX(key);
+ int z = SectionPosition.unpackZ(key);
+
+ long pos = ChunkCoordIntPair.pair(x, z);
+
+ BitSet flags = this.columns.get(pos);
+
+ if (flags == null) {
+ this.columns.put(pos, flags = new BitSet(16));
+ }
+
+ flags.set(y, value.isPresent());
+ }
+
+ public Stream<R> getWithinChunkColumn(int chunkX, int chunkZ) {
+ BitSet flags = this.getCachedColumnInfo(chunkX, chunkZ);
+
+ // No items are present in this column
+ if (flags.isEmpty()) {
+ return Stream.empty();
+ }
+
+ return flags.stream()
+ .mapToObj((chunkY) -> this.getDataBySection().get(SectionPosition.asLong(chunkX, chunkY, chunkZ)).orElse(null))
+ .filter(Objects::nonNull);
+ }
+
+ public boolean collectWithinChunkColumn(int chunkX, int chunkZ, Collector<R> consumer) {
+ BitSet flags = this.getCachedColumnInfo(chunkX, chunkZ);
+
+ // No items are present in this column
+ if (flags.isEmpty()) {
+ return true;
+ }
+
+ for (int chunkY = flags.nextSetBit(0); chunkY >= 0; chunkY = flags.nextSetBit(chunkY + 1)) {
+ R obj = this.getDataBySection().get(SectionPosition.asLong(chunkX, chunkY, chunkZ)).orElse(null);
+
+ if (obj != null && !consumer.collect(obj)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private BitSet getCachedColumnInfo(int chunkX, int chunkZ) {
+ long pos = ChunkCoordIntPair.pair(chunkX, chunkZ);
+
+ BitSet flags = this.getColumnInfo(pos, false);
+
+ if (flags != null) {
+ return flags;
+ }
+
+ this.loadDataAt(new ChunkCoordIntPair(pos));
+
+ return this.getColumnInfo(pos, true);
+ }
+
+ private BitSet getColumnInfo(long pos, boolean required) {
+ BitSet set = this.columns.get(pos);
+
+ if (set == null && required) {
+ throw new NullPointerException("No data is present for column: " + new ChunkCoordIntPair(pos));
+ }
+
+ return set;
+ }
+ // Yatopia end
+
protected void a(BooleanSupplier booleansupplier) {
while (!this.d.isEmpty() && booleansupplier.getAsBoolean()) {
ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(this.d.firstLong()).r(); // Paper - conflict here to avoid obfhelpers
@@ -92,6 +186,7 @@ public class RegionFileSection<R> extends RegionFileCache implements AutoCloseab
return true;
}
// Tuinity end - actually unload POI data
+ protected Optional<R> get(long i){ return d(i); } // Yatopia - OBFHELPER
@Nullable public final Optional<R> getIfLoaded(long value) { return this.c(value); } // Tuinity - OBFHELPER // Tuinity - OBFHELPER
@Nullable protected Optional<R> c(long i) { // Tuinity - OBFHELPER
@@ -125,6 +220,7 @@ public class RegionFileSection<R> extends RegionFileCache implements AutoCloseab
return World.b(SectionPosition.c(sectionposition.b()));
}
+ protected R getOrCreate(long i){ return e(i); } // Yatopia - OBFHELPER
protected R e(long i) {
Optional<R> optional = this.d(i);
@@ -140,6 +236,7 @@ public class RegionFileSection<R> extends RegionFileCache implements AutoCloseab
}
}
+ public void loadDataAt(ChunkCoordIntPair chunkcoordintpair) { b(chunkcoordintpair); } // Yatopia - OBFHELPER
private void b(ChunkCoordIntPair chunkcoordintpair) {
// Paper start - load data in function
this.loadInData(chunkcoordintpair, this.c(chunkcoordintpair));
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/Pathfinder.java b/src/main/java/net/minecraft/world/level/pathfinder/Pathfinder.java
index 76e19f3a4ae988f6f3b59763d639fa5e084fa0bf..be67d9a931aec19105305f316959e97813c4feda 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/Pathfinder.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/Pathfinder.java
@@ -3,6 +3,8 @@ package net.minecraft.world.level.pathfinder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import me.jellysquid.mods.lithium.common.ai.pathing.PathNodeCache; // Yatopia
+
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@@ -48,7 +50,7 @@ public class Pathfinder {
@Nullable
private PathEntity a(PathPoint pathpoint, List<Map.Entry<PathDestination, BlockPosition>> list, float f, int i, float f1) { // Paper - optimize collection
//Set<PathDestination> set = map.keySet(); // Paper
-
+ PathNodeCache.enableChunkCache(); // Yatopia - Port lithium
pathpoint.e = 0.0F;
pathpoint.f = this.a(pathpoint, list); // Paper - optimize collection
pathpoint.g = pathpoint.f;
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/PathfinderNormal.java b/src/main/java/net/minecraft/world/level/pathfinder/PathfinderNormal.java
index 9d08094165cf18d99116b5c721fff888f3cb42e2..b95804e73050dc7eb9786ca4bb5ea095904bad45 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/PathfinderNormal.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathfinderNormal.java
@@ -4,6 +4,9 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
+import me.jellysquid.mods.lithium.common.ai.pathing.PathNodeCache; // Yatopia
+import me.jellysquid.mods.lithium.common.world.WorldHelper; // Yatopia
+
import java.util.EnumSet;
import java.util.Iterator;
import javax.annotation.Nullable;
@@ -30,6 +33,10 @@ import net.minecraft.world.level.material.Material;
import net.minecraft.world.phys.AxisAlignedBB;
import net.minecraft.world.phys.Vec3D;
import net.minecraft.world.phys.shapes.VoxelShape;
+import net.minecraft.world.level.chunk.ChunkSection; // Yatopia
+import net.minecraft.world.level.chunk.IChunkAccess; // Yatopia
+import net.minecraft.world.level.World; // Yatopia
+import net.minecraft.world.level.ICollisionAccess; // Yatopia
public class PathfinderNormal extends PathfinderAbstract {
@@ -476,68 +483,111 @@ public class PathfinderNormal extends PathfinderAbstract {
return pathtype;
}
+ /**
+ * @reason Use optimized implementation
+ * @author JellySquid
+ */
public static PathType a(IBlockAccess iblockaccess, BlockPosition.MutableBlockPosition blockposition_mutableblockposition, PathType pathtype) {
- int i = blockposition_mutableblockposition.getX();
- int j = blockposition_mutableblockposition.getY();
- int k = blockposition_mutableblockposition.getZ();
+ // Yatopia start - Port lithium
+ int x = blockposition_mutableblockposition.getX();
+ int y = blockposition_mutableblockposition.getY();
+ int z = blockposition_mutableblockposition.getZ();
+
+ ChunkSection section = null;
+
+ // Check that all the block's neighbors are within the same chunk column. If so, we can isolate all our block
+ // reads to just one chunk and avoid hits against the server chunk manager.
+ if (iblockaccess instanceof ICollisionAccess && WorldHelper.areNeighborsWithinSameChunk(blockposition_mutableblockposition)) {
+ // If the y-coordinate is within bounds, we can cache the chunk section. Otherwise, the if statement to check
+ // if the cached chunk section was initialized will early-exit.
+ if (!World.b(y)) {
+ // This cast is always safe and is necessary to obtain direct references to chunk sections.
+ IChunkAccess chunk = (IChunkAccess) ((ICollisionAccess) iblockaccess).c(x >> 4, z >> 4);
+
+ // If the chunk is absent, the cached section above will remain null, as there is no chunk section anyways.
+ // An empty chunk or section will never pose any danger sources, which will be caught later.
+ if (chunk != null) {
+ section = chunk.getSections()[y >> 4];
+ }
+ }
- for (int l = -1; l <= 1; ++l) {
- for (int i1 = -1; i1 <= 1; ++i1) {
- for (int j1 = -1; j1 <= 1; ++j1) {
- if (l != 0 || j1 != 0) {
- blockposition_mutableblockposition.d(i + l, j + i1, k + j1);
- // Paper start
- IBlockData iblockdata = iblockaccess.getTypeIfLoaded(blockposition_mutableblockposition);
- if (iblockdata == null) {
- pathtype = PathType.BLOCKED;
- } else {
- // Paper end
- // Tuinity start - reduce pathfinder branching
- if (iblockdata.neighbourOverridePathType == PathType.OPEN) {
- continue;
- } else if (iblockdata.neighbourOverridePathType != null) {
- return iblockdata.neighbourOverridePathType;
- }
- // Tuinity end - reduce pathfinder branching
- if (iblockdata.a(Blocks.CACTUS)) {
- return iblockdata.neighbourOverridePathType = PathType.DANGER_CACTUS; // Tuinity - reduce pathfinder branching
- }
+ // If we can guarantee that blocks won't be modified while the cache is active, try to see if the chunk
+ // section is empty or contains any dangerous blocks within the palette. If not, we can assume any checks
+ // against this chunk section will always fail, allowing us to fast-exit.
+ if (ChunkSection.isEmpty(section) || PathNodeCache.isSectionSafeAsNeighbor(section)) {
+ return pathtype;
+ }
+ }
- if (iblockdata.a(Blocks.SWEET_BERRY_BUSH) || iblockdata.a(Blocks.STONECUTTER)) { // Purpur
- return iblockdata.neighbourOverridePathType = PathType.DANGER_OTHER; // Tuinity - reduce pathfinder branching
- }
+ int xStart = x - 1;
+ int yStart = y - 1;
+ int zStart = z - 1;
+
+ int xEnd = x + 1;
+ int yEnd = y + 1;
+ int zEnd = z + 1;
+
+ // Vanilla iteration order is XYZ
+ for (int adjX = xStart; adjX <= xEnd; adjX++) {
+ for (int adjY = yStart; adjY <= yEnd; adjY++) {
+ for (int adjZ = zStart; adjZ <= zEnd; adjZ++) {
+ // Skip the vertical column of the origin block
+ if (adjX == x && adjZ == z) {
+ continue;
+ }
- if (a(iblockdata)) {
- return iblockdata.neighbourOverridePathType = PathType.DANGER_FIRE; // Tuinity - reduce pathfinder branching
- }
+ IBlockData state;
- if (iblockdata.getFluid().a((Tag) TagsFluid.WATER)) { // Paper - remove another getType call
- return iblockdata.neighbourOverridePathType = PathType.WATER_BORDER; // Tuinity - reduce pathfinder branching
- }
- iblockdata.neighbourOverridePathType = PathType.OPEN; // Tuinity - reduce pathfinder branching
- } // Paper
+ // If we're not accessing blocks outside a given section, we can greatly accelerate block state
+ // retrieval by calling upon the cached chunk directly.
+ if (section != null) {
+ state = section.getType(adjX & 15, adjY & 15, adjZ & 15);
+ } else {
+ state = iblockaccess.getType(blockposition_mutableblockposition.setValues(adjX, adjY, adjZ));
+ }
+
+ // Ensure that the block isn't air first to avoid expensive hash table accesses
+ if (state.isAir()) {
+ continue;
+ }
+
+ PathType neighborType = PathNodeCache.getNeighborPathNodeType(state);
+
+ if (neighborType != PathType.OPEN) {
+ return neighborType;
}
}
}
}
- return pathtype;
+ return pathtype; // Yatopia end
}
+ /**
+ * @reason Use optimized implementation which avoids scanning blocks for dangers where possible
+ * @author JellySquid
+ */
protected static PathType b(IBlockAccess iblockaccess, BlockPosition blockposition) {
- IBlockData iblockdata = iblockaccess.getTypeIfLoaded(blockposition); // Paper
- if (iblockdata == null) return PathType.BLOCKED; // Paper
- // Tuinity start - reduce pathfinder branches
- if (iblockdata.staticPathType != null) {
- return iblockdata.staticPathType;
- }
- if (iblockdata.getShapeCache() == null) {
- // while it might be called static, it might vary on shape! However, only a few blocks have variable shape.
- // So we rarely enter here.
- return getStaticTypeSlow(iblockaccess, blockposition, iblockdata);
- } else {
- return iblockdata.staticPathType = getStaticTypeSlow(iblockaccess, blockposition, iblockdata);
+ // Yatopia start - Port lithium
+ IBlockData blockState = iblockaccess.getType(blockposition);
+ if (blockState == null) return PathType.BLOCKED;
+ PathType type = PathNodeCache.getPathNodeType(blockState);
+
+ // If the node type is open, it means that we were unable to determine a more specific type, so we need
+ // to check the fallback path.
+ if (type == PathType.OPEN) {
+ // This is only ever called in vanilla after all other possibilities are exhausted, but before fluid checks
+ // It should be safe to perform it last in actuality and take advantage of the cache for fluid types as well
+ // since fluids will always pass this check.
+ if (!blockState.a(iblockaccess, blockposition, PathMode.LAND)) {
+ return PathType.BLOCKED;
+ }
+
+ // All checks succeed, this path node really is open!
+ return PathType.OPEN;
}
+ return type;
+ // Yatopia end
}
protected static PathType getStaticTypeSlow(IBlockAccess iblockaccess, BlockPosition blockposition, IBlockData iblockdata) {
// Tuinity end - reduce pathfinder branches
diff --git a/src/main/java/net/pl3x/purpur/controller/ControllerLookWASD.java b/src/main/java/net/pl3x/purpur/controller/ControllerLookWASD.java
index 292821f039d99a03ba4daeb3a941616ef5f6287e..9b7110a805b81906512acc3771217a56a102db67 100644
--- a/src/main/java/net/pl3x/purpur/controller/ControllerLookWASD.java
+++ b/src/main/java/net/pl3x/purpur/controller/ControllerLookWASD.java
@@ -42,7 +42,7 @@ public class ControllerLookWASD extends ControllerLook {
entity.setHeadRotation(entity.yaw);
entity.pitch = normalizePitch(pitch + pitchOffset);
- entity.tracker.broadcast(new PacketPlayOutEntity
+ entity.getTracker().broadcast(new PacketPlayOutEntity // Yatopia
.PacketPlayOutRelEntityMoveLook(entity.getId(),
(short) 0, (short) 0, (short) 0,
(byte) MathHelper.d(entity.yaw * 256.0F / 360.0F),