From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Mon, 21 Oct 2024 12:21:54 -0700 Subject: [PATCH] fixup! MC Utils diff --git a/src/main/java/ca/spottedleaf/moonrise/common/PlatformHooks.java b/src/main/java/ca/spottedleaf/moonrise/common/PlatformHooks.java new file mode 100644 index 0000000000000000000000000000000000000000..6c98d420ea84c10ef4f15d4deb3f04e610ed8548 --- /dev/null +++ b/src/main/java/ca/spottedleaf/moonrise/common/PlatformHooks.java @@ -0,0 +1,117 @@ +package ca.spottedleaf.moonrise.common; + +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DataFixer; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.GenerationChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.storage.SerializableChunkData; +import net.minecraft.world.level.entity.EntityTypeTest; +import net.minecraft.world.phys.AABB; +import java.util.List; +import java.util.ServiceLoader; +import java.util.function.Predicate; + +public interface PlatformHooks { + public static PlatformHooks get() { + return Holder.INSTANCE; + } + + public String getBrand(); + + public int getLightEmission(final BlockState blockState, final BlockGetter world, final BlockPos pos); + + public Predicate maybeHasLightEmission(); + + public boolean hasCurrentlyLoadingChunk(); + + public LevelChunk getCurrentlyLoadingChunk(final GenerationChunkHolder holder); + + public void setCurrentlyLoading(final GenerationChunkHolder holder, final LevelChunk levelChunk); + + public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original); + + public boolean allowAsyncTicketUpdates(); + + public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel); + + public void chunkUnloadFromWorld(final LevelChunk chunk); + + public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data); + + public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player); + + public void onChunkUnWatch(final ServerLevel world, final ChunkPos chunk, final ServerPlayer player); + + public void addToGetEntities(final Level world, final Entity entity, final AABB boundingBox, final Predicate predicate, + final List into); + + public void addToGetEntities(final Level world, final EntityTypeTest entityTypeTest, + final AABB boundingBox, final Predicate predicate, + final List into, final int maxCount); + + public void entityMove(final Entity entity, final long oldSection, final long newSection); + + public boolean screenEntity(final ServerLevel world, final Entity entity, final boolean fromDisk, final boolean event); + + public boolean configFixMC224294(); + + public boolean configAutoConfigSendDistance(); + + public double configPlayerMaxLoadRate(); + + public double configPlayerMaxGenRate(); + + public double configPlayerMaxSendRate(); + + public int configPlayerMaxConcurrentLoads(); + + public int configPlayerMaxConcurrentGens(); + + public long configAutoSaveInterval(final ServerLevel world); + + public int configMaxAutoSavePerTick(final ServerLevel world); + + public boolean configFixMC159283(); + + // support for CB chunk mustNotSave + public boolean forceNoSave(final ChunkAccess chunk); + + public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt, + final int fromVersion, final int toVersion); + + public boolean hasMainChunkLoadHook(); + + public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData); + + public List modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List entities); + + public void unloadEntity(final Entity entity); + + public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk); + + public int modifyEntityTrackingRange(final Entity entity, final int currentRange); + + public static final class Holder { + private Holder() { + } + + private static final PlatformHooks INSTANCE; + + static { + INSTANCE = ServiceLoader.load(PlatformHooks.class, PlatformHooks.class.getClassLoader()).findFirst() + .orElseThrow(() -> new RuntimeException("Failed to locate PlatformHooks")); + } + } +} diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java index ba68998f6ef57b24c72fd833bd7de440de9501cc..7fed43a1e7bcf35c4d7fd3224837a47fedd59860 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java @@ -13,15 +13,15 @@ import java.util.NoSuchElementException; */ public final class EntityList implements Iterable { - protected final Int2IntOpenHashMap entityToIndex = new Int2IntOpenHashMap(2, 0.8f); + private final Int2IntOpenHashMap entityToIndex = new Int2IntOpenHashMap(2, 0.8f); { this.entityToIndex.defaultReturnValue(Integer.MIN_VALUE); } - protected static final Entity[] EMPTY_LIST = new Entity[0]; + private static final Entity[] EMPTY_LIST = new Entity[0]; - protected Entity[] entities = EMPTY_LIST; - protected int count; + private Entity[] entities = EMPTY_LIST; + private int count; public int size() { return this.count; @@ -94,10 +94,9 @@ public final class EntityList implements Iterable { @Override public Iterator iterator() { - return new Iterator() { - - Entity lastRet; - int current; + return new Iterator<>() { + private Entity lastRet; + private int current; @Override public boolean hasNext() { diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/IBlockDataList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/IBlockDataList.java deleted file mode 100644 index fcfbca333234c09f7c056bbfcd9ac8860b20a8db..0000000000000000000000000000000000000000 --- a/src/main/java/ca/spottedleaf/moonrise/common/list/IBlockDataList.java +++ /dev/null @@ -1,125 +0,0 @@ -package ca.spottedleaf.moonrise.common.list; - -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.shorts.Short2LongOpenHashMap; -import java.util.Arrays; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.GlobalPalette; - -public final class IBlockDataList { - - private static final GlobalPalette GLOBAL_PALETTE = new GlobalPalette<>(Block.BLOCK_STATE_REGISTRY); - - // map of location -> (index | (location << 16) | (palette id << 32)) - private final Short2LongOpenHashMap map = new Short2LongOpenHashMap(2, 0.8f); - { - this.map.defaultReturnValue(Long.MAX_VALUE); - } - - private static final long[] EMPTY_LIST = new long[0]; - - private long[] byIndex = EMPTY_LIST; - private int size; - - public static int getLocationKey(final int x, final int y, final int z) { - return (x & 15) | (((z & 15) << 4)) | ((y & 255) << (4 + 4)); - } - - public static BlockState getBlockDataFromRaw(final long raw) { - return GLOBAL_PALETTE.valueFor((int)(raw >>> 32)); - } - - public static int getIndexFromRaw(final long raw) { - return (int)(raw & 0xFFFF); - } - - public static int getLocationFromRaw(final long raw) { - return (int)((raw >>> 16) & 0xFFFF); - } - - public static long getRawFromValues(final int index, final int location, final BlockState data) { - return (long)index | ((long)location << 16) | (((long)GLOBAL_PALETTE.idFor(data)) << 32); - } - - public static long setIndexRawValues(final long value, final int index) { - return value & ~(0xFFFF) | (index); - } - - public long add(final int x, final int y, final int z, final BlockState data) { - return this.add(getLocationKey(x, y, z), data); - } - - public long add(final int location, final BlockState data) { - final long curr = this.map.get((short)location); - - if (curr == Long.MAX_VALUE) { - final int index = this.size++; - final long raw = getRawFromValues(index, location, data); - this.map.put((short)location, raw); - - if (index >= this.byIndex.length) { - this.byIndex = Arrays.copyOf(this.byIndex, (int)Math.max(4L, this.byIndex.length * 2L)); - } - - this.byIndex[index] = raw; - return raw; - } else { - final int index = getIndexFromRaw(curr); - final long raw = this.byIndex[index] = getRawFromValues(index, location, data); - - this.map.put((short)location, raw); - - return raw; - } - } - - public long remove(final int x, final int y, final int z) { - return this.remove(getLocationKey(x, y, z)); - } - - public long remove(final int location) { - final long ret = this.map.remove((short)location); - final int index = getIndexFromRaw(ret); - if (ret == Long.MAX_VALUE) { - return ret; - } - - // move the entry at the end to this index - final int endIndex = --this.size; - final long end = this.byIndex[endIndex]; - if (index != endIndex) { - // not empty after this call - this.map.put((short)getLocationFromRaw(end), setIndexRawValues(end, index)); - } - this.byIndex[index] = end; - this.byIndex[endIndex] = 0L; - - return ret; - } - - public int size() { - return this.size; - } - - public long getRaw(final int index) { - return this.byIndex[index]; - } - - public int getLocation(final int index) { - return getLocationFromRaw(this.getRaw(index)); - } - - public BlockState getData(final int index) { - return getBlockDataFromRaw(this.getRaw(index)); - } - - public void clear() { - this.size = 0; - this.map.clear(); - } - - public LongIterator getRawIterator() { - return this.map.values().iterator(); - } -} \ No newline at end of file diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/IntList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/IntList.java new file mode 100644 index 0000000000000000000000000000000000000000..9f3b25bb2439f283f878db93973a02fcdcd14eed --- /dev/null +++ b/src/main/java/ca/spottedleaf/moonrise/common/list/IntList.java @@ -0,0 +1,77 @@ +package ca.spottedleaf.moonrise.common.list; + +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import java.util.Arrays; + +public final class IntList { + + private final Int2IntOpenHashMap map = new Int2IntOpenHashMap(); + { + this.map.defaultReturnValue(Integer.MIN_VALUE); + } + + private static final int[] EMPTY_LIST = new int[0]; + + private int[] byIndex = EMPTY_LIST; + private int count; + + public int size() { + return this.count; + } + + public void setMinCapacity(final int len) { + final int[] byIndex = this.byIndex; + if (byIndex.length < len) { + this.byIndex = Arrays.copyOf(byIndex, len); + } + } + + public int getRaw(final int index) { + return this.byIndex[index]; + } + + public boolean add(final int value) { + final int count = this.count; + final int currIndex = this.map.putIfAbsent(value, count); + + if (currIndex != Integer.MIN_VALUE) { + return false; // already in this list + } + + int[] list = this.byIndex; + + if (list.length == count) { + // resize required + list = this.byIndex = Arrays.copyOf(list, (int)Math.max(4L, count * 2L)); // overflow results in negative + } + + list[count] = value; + this.count = count + 1; + + return true; + } + + public boolean remove(final int value) { + final int index = this.map.remove(value); + if (index == Integer.MIN_VALUE) { + return false; + } + + // move the entry at the end to this index + final int endIndex = --this.count; + final int end = this.byIndex[endIndex]; + if (index != endIndex) { + // not empty after this call + this.map.put(end, index); + } + this.byIndex[index] = end; + this.byIndex[endIndex] = 0; + + return true; + } + + public void clear() { + this.count = 0; + this.map.clear(); + } +} diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java new file mode 100644 index 0000000000000000000000000000000000000000..2bae9949ef325d0001aa638150fbbdf968367e75 --- /dev/null +++ b/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java @@ -0,0 +1,77 @@ +package ca.spottedleaf.moonrise.common.list; + +import it.unimi.dsi.fastutil.shorts.Short2ShortOpenHashMap; +import java.util.Arrays; + +public final class ShortList { + + private final Short2ShortOpenHashMap map = new Short2ShortOpenHashMap(); + { + this.map.defaultReturnValue(Short.MIN_VALUE); + } + + private static final short[] EMPTY_LIST = new short[0]; + + private short[] byIndex = EMPTY_LIST; + private short count; + + public int size() { + return (int)this.count; + } + + public short getRaw(final int index) { + return this.byIndex[index]; + } + + public void setMinCapacity(final int len) { + final short[] byIndex = this.byIndex; + if (byIndex.length < len) { + this.byIndex = Arrays.copyOf(byIndex, len); + } + } + + public boolean add(final short value) { + final int count = (int)this.count; + final short currIndex = this.map.putIfAbsent(value, (short)count); + + if (currIndex != Short.MIN_VALUE) { + return false; // already in this list + } + + short[] list = this.byIndex; + + if (list.length == count) { + // resize required + list = this.byIndex = Arrays.copyOf(list, (int)Math.max(4L, count * 2L)); // overflow results in negative + } + + list[count] = value; + this.count = (short)(count + 1); + + return true; + } + + public boolean remove(final short value) { + final short index = this.map.remove(value); + if (index == Short.MIN_VALUE) { + return false; + } + + // move the entry at the end to this index + final short endIndex = --this.count; + final short end = this.byIndex[endIndex]; + if (index != endIndex) { + // not empty after this call + this.map.put(end, index); + } + this.byIndex[(int)index] = end; + this.byIndex[(int)endIndex] = (short)0; + + return true; + } + + public void clear() { + this.count = (short)0; + this.map.clear(); + } +} diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/LazyRunnable.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/LazyRunnable.java new file mode 100644 index 0000000000000000000000000000000000000000..c2d917c2eac55b8a4411a6e159f177f9428b1150 --- /dev/null +++ b/src/main/java/ca/spottedleaf/moonrise/common/misc/LazyRunnable.java @@ -0,0 +1,22 @@ +package ca.spottedleaf.moonrise.common.misc; + +import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; +import java.lang.invoke.VarHandle; + +public final class LazyRunnable implements Runnable { + + private volatile Runnable toRun; + private static final VarHandle TO_RUN_HANDLE = ConcurrentUtil.getVarHandle(LazyRunnable.class, "toRun", Runnable.class); + + public void setRunnable(final Runnable run) { + final Runnable prev = (Runnable)TO_RUN_HANDLE.compareAndExchange(this, (Runnable)null, run); + if (prev != null) { + throw new IllegalStateException("Runnable already set"); + } + } + + @Override + public void run() { + ((Runnable)TO_RUN_HANDLE.getVolatile(this)).run(); + } +} diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java index ab093b0e8ac6f762921eb1d15f5217345c4eba05..bb44de17a37082e57f2292a4f470740be1d09b11 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java @@ -4,13 +4,17 @@ import ca.spottedleaf.moonrise.common.list.ReferenceList; import ca.spottedleaf.moonrise.common.util.CoordinateUtils; import ca.spottedleaf.moonrise.common.util.MoonriseConstants; import ca.spottedleaf.moonrise.common.util.ChunkSystem; +import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel; +import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData; import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants; +import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel; import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.ChunkPos; +import java.util.ArrayList; public final class NearbyPlayers { @@ -20,7 +24,27 @@ public final class NearbyPlayers { GENERAL_REALLY_SMALL, TICK_VIEW_DISTANCE, VIEW_DISTANCE, - SPAWN_RANGE, // Moonrise - chunk tick iteration + // Moonrise start - chunk tick iteration + SPAWN_RANGE { + @Override + void addTo(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) { + ((ChunkTickServerLevel)world).moonrise$addPlayerTickingRequest(chunkX, chunkZ); + } + + @Override + void removeFrom(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) { + ((ChunkTickServerLevel)world).moonrise$removePlayerTickingRequest(chunkX, chunkZ); + } + }; + // Moonrise end - chunk tick iteration + + void addTo(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) { + + } + + void removeFrom(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) { + + } } private static final NearbyMapType[] MAP_TYPES = NearbyMapType.values(); @@ -37,6 +61,12 @@ public final class NearbyPlayers { private final ServerLevel world; private final Reference2ReferenceOpenHashMap players = new Reference2ReferenceOpenHashMap<>(); private final Long2ReferenceOpenHashMap byChunk = new Long2ReferenceOpenHashMap<>(); + private final Long2ReferenceOpenHashMap>[] directByChunk = new Long2ReferenceOpenHashMap[TOTAL_MAP_TYPES]; + { + for (int i = 0; i < this.directByChunk.length; ++i) { + this.directByChunk[i] = new Long2ReferenceOpenHashMap<>(); + } + } public NearbyPlayers(final ServerLevel world) { this.world = world; @@ -70,6 +100,16 @@ public final class NearbyPlayers { } } + public void clear() { + if (this.players.isEmpty()) { + return; + } + + for (final ServerPlayer player : new ArrayList<>(this.players.keySet())) { + this.removePlayer(player); + } + } + public void tickPlayer(final ServerPlayer player) { final TrackedPlayer[] players = this.players.get(player); if (players == null) { @@ -94,38 +134,41 @@ public final class NearbyPlayers { return this.byChunk.get(CoordinateUtils.getChunkKey(pos)); } - public ReferenceList getPlayers(final BlockPos pos, final NearbyMapType type) { - final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(pos)); + public TrackedChunk getChunk(final int chunkX, final int chunkZ) { + return this.byChunk.get(CoordinateUtils.getChunkKey(chunkX, chunkZ)); + } - return chunk == null ? null : chunk.players[type.ordinal()]; + public ReferenceList getPlayers(final BlockPos pos, final NearbyMapType type) { + return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(pos)); } public ReferenceList getPlayers(final ChunkPos pos, final NearbyMapType type) { - final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(pos)); - - return chunk == null ? null : chunk.players[type.ordinal()]; + return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(pos)); } public ReferenceList getPlayersByChunk(final int chunkX, final int chunkZ, final NearbyMapType type) { - final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(chunkX, chunkZ)); - - return chunk == null ? null : chunk.players[type.ordinal()]; + return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(chunkX, chunkZ)); } public ReferenceList getPlayersByBlock(final int blockX, final int blockZ, final NearbyMapType type) { - final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(blockX >> 4, blockZ >> 4)); - - return chunk == null ? null : chunk.players[type.ordinal()]; + return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(blockX >> 4, blockZ >> 4)); } public static final class TrackedChunk { private static final ServerPlayer[] EMPTY_PLAYERS_ARRAY = new ServerPlayer[0]; + private final long chunkKey; + private final NearbyPlayers nearbyPlayers; private final ReferenceList[] players = new ReferenceList[TOTAL_MAP_TYPES]; private int nonEmptyLists; private long updateCount; + public TrackedChunk(final long chunkKey, final NearbyPlayers nearbyPlayers) { + this.chunkKey = chunkKey; + this.nearbyPlayers = nearbyPlayers; + } + public boolean isEmpty() { return this.nonEmptyLists == 0; } @@ -145,7 +188,9 @@ public final class NearbyPlayers { final ReferenceList list = this.players[idx]; if (list == null) { ++this.nonEmptyLists; - (this.players[idx] = new ReferenceList<>(EMPTY_PLAYERS_ARRAY)).add(player); + final ReferenceList players = (this.players[idx] = new ReferenceList<>(EMPTY_PLAYERS_ARRAY)); + this.nearbyPlayers.directByChunk[idx].put(this.chunkKey, players); + players.add(player); return; } @@ -169,6 +214,7 @@ public final class NearbyPlayers { if (list.size() == 0) { this.players[idx] = null; + this.nearbyPlayers.directByChunk[idx].remove(this.chunkKey); --this.nonEmptyLists; } } @@ -187,9 +233,19 @@ public final class NearbyPlayers { protected void addCallback(final ServerPlayer parameter, final int chunkX, final int chunkZ) { final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ); - NearbyPlayers.this.byChunk.computeIfAbsent(chunkKey, (final long keyInMap) -> { - return new TrackedChunk(); - }).addPlayer(parameter, this.type); + final TrackedChunk chunk = NearbyPlayers.this.byChunk.get(chunkKey); + final NearbyMapType type = this.type; + if (chunk != null) { + chunk.addPlayer(parameter, type); + type.addTo(parameter, NearbyPlayers.this.world, chunkX, chunkZ); + } else { + final TrackedChunk created = new TrackedChunk(chunkKey, NearbyPlayers.this); + NearbyPlayers.this.byChunk.put(chunkKey, created); + created.addPlayer(parameter, type); + type.addTo(parameter, NearbyPlayers.this.world, chunkX, chunkZ); + + ((ChunkSystemLevel)NearbyPlayers.this.world).moonrise$requestChunkData(chunkKey).nearbyPlayers = created; + } } @Override @@ -201,10 +257,16 @@ public final class NearbyPlayers { throw new IllegalStateException("Chunk should exist at " + new ChunkPos(chunkKey)); } - chunk.removePlayer(parameter, this.type); + final NearbyMapType type = this.type; + chunk.removePlayer(parameter, type); + type.removeFrom(parameter, NearbyPlayers.this.world, chunkX, chunkZ); if (chunk.isEmpty()) { NearbyPlayers.this.byChunk.remove(chunkKey); + final ChunkData chunkData = ((ChunkSystemLevel)NearbyPlayers.this.world).moonrise$releaseChunkData(chunkKey); + if (chunkData != null) { + chunkData.nearbyPlayers = null; + } } } } diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java b/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java index da323a1105347d5cf4b946df10ded78a953236f2..94bba2b71918d79f54b3e28c35e76098ba0afd8c 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java @@ -1,6 +1,7 @@ package ca.spottedleaf.moonrise.common.util; -import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; +import ca.spottedleaf.concurrentutil.util.Priority; +import ca.spottedleaf.moonrise.common.PlatformHooks; import com.mojang.logging.LogUtils; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.FullChunkStatus; @@ -24,15 +25,15 @@ public final class ChunkSystem { } public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { - scheduleChunkTask(level, chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL); + scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL); } - public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { + public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final Priority priority) { level.chunkSource.mainThreadProcessor.execute(run); } public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, - final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, + final ChunkStatus toStatus, final boolean addTicket, final Priority priority, final Consumer onComplete) { if (gen) { scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); @@ -59,7 +60,7 @@ public final class ChunkSystem { private static long chunkLoadCounter = 0L; public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, - final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { + final boolean addTicket, final Priority priority, final Consumer onComplete) { if (!org.bukkit.Bukkit.isPrimaryThread()) { scheduleChunkTask(level, chunkX, chunkZ, () -> { scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); @@ -113,13 +114,13 @@ public final class ChunkSystem { } loadCallback.accept(result.orElse(null)); }, (final Runnable r) -> { - scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); + scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST); }); } public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, final FullChunkStatus toStatus, final boolean addTicket, - final PrioritisedExecutor.Priority priority, final Consumer onComplete) { + final Priority priority, final Consumer onComplete) { // This method goes unused until the chunk system rewrite if (toStatus == FullChunkStatus.INACCESSIBLE) { throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); @@ -196,7 +197,7 @@ public final class ChunkSystem { } loadCallback.accept(result.orElse(null)); }, (final Runnable r) -> { - scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); + scheduleChunkTask(level, chunkX, chunkZ, r, Priority.HIGHEST); }); } @@ -220,7 +221,10 @@ public final class ChunkSystem { return getUpdatingChunkHolderCount(level) != 0; } - public static boolean screenEntity(final ServerLevel level, final Entity entity) { + public static boolean screenEntity(final ServerLevel level, final Entity entity, final boolean fromDisk, final boolean event) { + if (!PlatformHooks.get().screenEntity(level, entity, fromDisk, event)) { + return false; + } return true; } diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MixinWorkarounds.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MixinWorkarounds.java index ac6f284ee4469d16c5655328b2488d7612832353..97848869df61648fc415e4d39f409f433202c274 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/util/MixinWorkarounds.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MixinWorkarounds.java @@ -3,8 +3,12 @@ package ca.spottedleaf.moonrise.common.util; public final class MixinWorkarounds { // mixins tries to find the owner of the clone() method, which doesn't exist and NPEs + // https://github.com/FabricMC/Mixin/pull/147 public static long[] clone(final long[] values) { return values.clone(); } + public static byte[] clone(final byte[] values) { + return values.clone(); + } } diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java index 3abe0bd2a820352b85306d554bf14a4cf6123091..c125c70a68130be373acc989053a6c0e487be924 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java @@ -1,45 +1,100 @@ package ca.spottedleaf.moonrise.common.util; -import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedThreadPool; +import ca.spottedleaf.concurrentutil.executor.thread.PrioritisedThreadPool; +import ca.spottedleaf.moonrise.common.PlatformHooks; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; public final class MoonriseCommon { private static final Logger LOGGER = LoggerFactory.getLogger(MoonriseCommon.class); - // Paper start - public static PrioritisedThreadPool WORKER_POOL; - public static int WORKER_THREADS; - public static void init(io.papermc.paper.configuration.GlobalConfiguration.ChunkSystem chunkSystem) { - // Paper end + public static final PrioritisedThreadPool WORKER_POOL = new PrioritisedThreadPool( + new Consumer<>() { + private final AtomicInteger idGenerator = new AtomicInteger(); + + @Override + public void accept(Thread thread) { + thread.setDaemon(true); + thread.setName(PlatformHooks.get().getBrand() + " Common Worker #" + this.idGenerator.getAndIncrement()); + thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(final Thread thread, final Throwable throwable) { + LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable); + } + }); + } + } + ); + public static final long WORKER_QUEUE_HOLD_TIME = (long)(20.0e6); // 20ms + public static final int CLIENT_DIVISION = 0; + public static final PrioritisedThreadPool.ExecutorGroup RENDER_EXECUTOR_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(CLIENT_DIVISION, 0); + public static final int SERVER_DIVISION = 1; + public static final PrioritisedThreadPool.ExecutorGroup PARALLEL_GEN_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(SERVER_DIVISION, 0); + public static final PrioritisedThreadPool.ExecutorGroup RADIUS_AWARE_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(SERVER_DIVISION, 0); + public static final PrioritisedThreadPool.ExecutorGroup LOAD_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(SERVER_DIVISION, 0); + + public static void adjustWorkerThreads(final int configWorkerThreads, final int configIoThreads) { int defaultWorkerThreads = Runtime.getRuntime().availableProcessors() / 2; if (defaultWorkerThreads <= 4) { defaultWorkerThreads = defaultWorkerThreads <= 3 ? 1 : 2; } else { defaultWorkerThreads = defaultWorkerThreads / 2; } - defaultWorkerThreads = Integer.getInteger("Paper.WorkerThreadCount", Integer.valueOf(defaultWorkerThreads)); // Paper + defaultWorkerThreads = Integer.getInteger(PlatformHooks.get().getBrand() + ".WorkerThreadCount", Integer.valueOf(defaultWorkerThreads)); - int workerThreads = chunkSystem.workerThreads; // Paper + int workerThreads = configWorkerThreads; if (workerThreads <= 0) { workerThreads = defaultWorkerThreads; } - WORKER_POOL = new PrioritisedThreadPool( - "Paper Worker Pool", workerThreads, // Paper - (final Thread thread, final Integer id) -> { - thread.setName("Paper Common Worker #" + id.intValue()); // Paper + final int ioThreads = Math.max(1, configIoThreads); + + WORKER_POOL.adjustThreadCount(workerThreads); + IO_POOL.adjustThreadCount(ioThreads); + + LOGGER.info(PlatformHooks.get().getBrand() + " is using " + workerThreads + " worker threads, " + ioThreads + " I/O threads"); + } + + public static final PrioritisedThreadPool IO_POOL = new PrioritisedThreadPool( + new Consumer<>() { + private final AtomicInteger idGenerator = new AtomicInteger(); + + @Override + public void accept(final Thread thread) { + thread.setDaemon(true); + thread.setName(PlatformHooks.get().getBrand() + " I/O Worker #" + this.idGenerator.getAndIncrement()); thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(final Thread thread, final Throwable throwable) { LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable); } }); - }, (long)(20.0e6)); // 20ms - WORKER_THREADS = workerThreads; + } + } + ); + public static final long IO_QUEUE_HOLD_TIME = (long)(100.0e6); // 100ms + public static final PrioritisedThreadPool.ExecutorGroup CLIENT_PROFILER_IO_GROUP = IO_POOL.createExecutorGroup(CLIENT_DIVISION, 0); + public static final PrioritisedThreadPool.ExecutorGroup SERVER_REGION_IO_GROUP = IO_POOL.createExecutorGroup(SERVER_DIVISION, 0); + + public static void haltExecutors() { + MoonriseCommon.WORKER_POOL.shutdown(false); + LOGGER.info("Awaiting termination of worker pool for up to 60s..."); + if (!MoonriseCommon.WORKER_POOL.join(TimeUnit.SECONDS.toMillis(60L))) { + LOGGER.error("Worker pool did not shut down in time!"); + MoonriseCommon.WORKER_POOL.halt(false); + } + + MoonriseCommon.IO_POOL.shutdown(false); + LOGGER.info("Awaiting termination of I/O pool for up to 60s..."); + if (!MoonriseCommon.IO_POOL.join(TimeUnit.SECONDS.toMillis(60L))) { + LOGGER.error("I/O pool did not shut down in time!"); + MoonriseCommon.IO_POOL.halt(false); + } } private MoonriseCommon() {} diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java index 1cf32d7d1bbc8a0a3f7cb9024c793f6744199f64..559c959aff3c9deef867b9e425fba3e2e669cac6 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java @@ -1,8 +1,10 @@ package ca.spottedleaf.moonrise.common.util; +import ca.spottedleaf.moonrise.common.PlatformHooks; + public final class MoonriseConstants { - public static final int MAX_VIEW_DISTANCE = 32; + public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", 32); private MoonriseConstants() {} diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/SimpleRandom.java b/src/main/java/ca/spottedleaf/moonrise/common/util/SimpleRandom.java new file mode 100644 index 0000000000000000000000000000000000000000..a9ff1c1a70faf4b7a64b265932f07a8b8f00c1ff --- /dev/null +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/SimpleRandom.java @@ -0,0 +1,52 @@ +package ca.spottedleaf.moonrise.common.util; + +import net.minecraft.world.level.levelgen.LegacyRandomSource; + +/** + * Avoid costly CAS of superclass + */ +public final class SimpleRandom extends LegacyRandomSource { + + private static final long MULTIPLIER = 25214903917L; + private static final long ADDEND = 11L; + private static final int BITS = 48; + private static final long MASK = (1L << BITS) - 1; + + private long value; + + public SimpleRandom(final long seed) { + super(0L); + this.value = seed; + } + + @Override + public void setSeed(final long seed) { + this.value = (seed ^ MULTIPLIER) & MASK; + } + + private long advanceSeed() { + return this.value = ((this.value * MULTIPLIER) + ADDEND) & MASK; + } + + @Override + public int next(final int bits) { + return (int)(this.advanceSeed() >>> (BITS - bits)); + } + + @Override + public int nextInt() { + final long seed = this.advanceSeed(); + return (int)(seed >>> (BITS - Integer.SIZE)); + } + + @Override + public int nextInt(final int bound) { + if (bound <= 0) { + throw new IllegalArgumentException(); + } + + // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ + final long value = this.advanceSeed() >>> (BITS - Integer.SIZE); + return (int)((value * (long)bound) >>> Integer.SIZE); + } +} diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java index 11b7f15755dde766140c29bedca456c80d53293f..217d1f908a36a5177ba3cbb80a33f73d4dab0fa0 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java @@ -77,11 +77,15 @@ public class TickThread extends Thread { } public TickThread(final Runnable run, final String name) { - this(run, name, ID_GENERATOR.incrementAndGet()); + this(null, run, name); } - private TickThread(final Runnable run, final String name, final int id) { - super(run, name); + public TickThread(final ThreadGroup group, final Runnable run, final String name) { + this(group, run, name, ID_GENERATOR.incrementAndGet()); + } + + private TickThread(final ThreadGroup group, final Runnable run, final String name, final int id) { + super(group, run, name); this.id = id; } diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/WorldUtil.java b/src/main/java/ca/spottedleaf/moonrise/common/util/WorldUtil.java index af9623240ff2d389aa7090623f507720e7dbab7d..efda2688ae1254a82ba7f6bf8bf597ef224cbb86 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/util/WorldUtil.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/WorldUtil.java @@ -8,11 +8,19 @@ public final class WorldUtil { // min, max are inclusive public static int getMaxSection(final LevelHeightAccessor world) { - return world.getMaxSection() - 1; // getMaxSection() is exclusive + return world.getMaxSectionY(); + } + + public static int getMaxSection(final Level world) { + return world.getMaxSectionY(); } public static int getMinSection(final LevelHeightAccessor world) { - return world.getMinSection(); + return world.getMinSectionY(); + } + + public static int getMinSection(final Level world) { + return world.getMinSectionY(); } public static int getMaxLightSection(final LevelHeightAccessor world) { diff --git a/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java b/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java new file mode 100644 index 0000000000000000000000000000000000000000..1aa6be257ce594d7a69fdff008cd29014a04fd75 --- /dev/null +++ b/src/main/java/ca/spottedleaf/moonrise/paper/PaperHooks.java @@ -0,0 +1,209 @@ +package ca.spottedleaf.moonrise.paper; + +import ca.spottedleaf.moonrise.common.PlatformHooks; +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.DataFixer; +import com.mojang.serialization.Dynamic; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.GenerationChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.storage.SerializableChunkData; +import net.minecraft.world.level.entity.EntityTypeTest; +import net.minecraft.world.phys.AABB; +import java.util.List; +import java.util.function.Predicate; + +public final class PaperHooks implements PlatformHooks { + + @Override + public String getBrand() { + return "Paper"; + } + + @Override + public int getLightEmission(final BlockState blockState, final BlockGetter world, final BlockPos pos) { + return blockState.getLightEmission(); + } + + @Override + public Predicate maybeHasLightEmission() { + return (final BlockState state) -> { + return state.getLightEmission() != 0; + }; + } + + @Override + public boolean hasCurrentlyLoadingChunk() { + return false; + } + + @Override + public LevelChunk getCurrentlyLoadingChunk(final GenerationChunkHolder holder) { + return null; + } + + @Override + public void setCurrentlyLoading(final GenerationChunkHolder holder, final LevelChunk levelChunk) { + + } + + @Override + public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) { + + } + + @Override + public boolean allowAsyncTicketUpdates() { + return true; + } + + @Override + public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel) { + + } + + @Override + public void chunkUnloadFromWorld(final LevelChunk chunk) { + + } + + @Override + public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data) { + + } + + @Override + public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player) { + + } + + @Override + public void onChunkUnWatch(final ServerLevel world, final ChunkPos chunk, final ServerPlayer player) { + + } + + @Override + public void addToGetEntities(final Level world, final Entity entity, final AABB boundingBox, final Predicate predicate, final List into) { + + } + + @Override + public void addToGetEntities(final Level world, final EntityTypeTest entityTypeTest, final AABB boundingBox, final Predicate predicate, final List into, final int maxCount) { + + } + + @Override + public void entityMove(final Entity entity, final long oldSection, final long newSection) { + + } + + @Override + public boolean screenEntity(final ServerLevel world, final Entity entity, final boolean fromDisk, final boolean event) { + return true; + } + + @Override + public boolean configFixMC224294() { + return true; + } + + @Override + public boolean configAutoConfigSendDistance() { + return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.autoConfigSendDistance; + } + + @Override + public double configPlayerMaxLoadRate() { + return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkLoadRate; + } + + @Override + public double configPlayerMaxGenRate() { + return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkGenerateRate; + } + + @Override + public double configPlayerMaxSendRate() { + return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkSendRate; + } + + @Override + public int configPlayerMaxConcurrentLoads() { + return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkLoads; + } + + @Override + public int configPlayerMaxConcurrentGens() { + return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkGenerates; + } + + @Override + public long configAutoSaveInterval(final ServerLevel world) { + return world.paperConfig().chunks.autoSaveInterval.value(); + } + + @Override + public int configMaxAutoSavePerTick(final ServerLevel world) { + return world.paperConfig().chunks.maxAutoSaveChunksPerTick; + } + + @Override + public boolean configFixMC159283() { + return true; + } + + @Override + public boolean forceNoSave(final ChunkAccess chunk) { + return chunk instanceof LevelChunk levelChunk && levelChunk.mustNotSave; + } + + @Override + public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt, + final int fromVersion, final int toVersion) { + return (CompoundTag)dataFixer.update( + type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion + ).getValue(); + } + + @Override + public boolean hasMainChunkLoadHook() { + return false; + } + + @Override + public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData) { + + } + + @Override + public List modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List entities) { + return entities; + } + + @Override + public void unloadEntity(final Entity entity) { + entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, org.bukkit.event.entity.EntityRemoveEvent.Cause.UNLOAD); + } + + @Override + public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) { + net.minecraft.world.level.chunk.status.ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities()); + } + + @Override + public int modifyEntityTrackingRange(final Entity entity, final int currentRange) { + return org.spigotmc.TrackingRange.getEntityTrackingRange(entity, currentRange); + } +} diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java index 61893f8216ddaedd899b573322f3ad0088074ac5..36b96e0ed5c0d25068ec4678eddd8a19a020d345 100644 --- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java @@ -242,7 +242,7 @@ public class GlobalConfiguration extends ConfigurationPart { @PostProcess private void postProcess() { - + ca.spottedleaf.moonrise.common.util.MoonriseCommon.adjustWorkerThreads(this.workerThreads, this.ioThreads); } } diff --git a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java index f18c2b85ed9541f646f157184221e333d0ae58bd..aff4c3d63a97d5bbde004a616f7e14fca59b5ab9 100644 --- a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java +++ b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java @@ -168,7 +168,7 @@ public class ChunkStatusTasks { }, context.mainThreadExecutor()); } - private static void postLoadProtoChunk(ServerLevel world, List entities) { + public static void postLoadProtoChunk(ServerLevel world, List entities) { // Paper - public if (!entities.isEmpty()) { // CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities world.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(entities, world, EntitySpawnReason.LOAD).filter((entity) -> { diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java index 6baa313b8201ed23193d7885c85606b0899ade3c..5aa74c00a61282830d82359eae2b114e2a48b6d9 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java @@ -94,15 +94,13 @@ public class PersistentEntitySectionManager implements A private boolean addEntity(T entity, boolean existing) { org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper // Paper start - chunk system hooks - if (existing) { - // I don't want to know why this is a generic type. - Entity entityCasted = (Entity)entity; - boolean wasRemoved = entityCasted.isRemoved(); - boolean screened = ca.spottedleaf.moonrise.common.util.ChunkSystem.screenEntity((net.minecraft.server.level.ServerLevel)entityCasted.level(), entityCasted); - if ((!wasRemoved && entityCasted.isRemoved()) || !screened) { - // removed by callback - return false; - } + // I don't want to know why this is a generic type. + Entity entityCasted = (Entity)entity; + boolean wasRemoved = entityCasted.isRemoved(); + boolean screened = ca.spottedleaf.moonrise.common.util.ChunkSystem.screenEntity((net.minecraft.server.level.ServerLevel)entityCasted.level(), entityCasted, existing, true); + if ((!wasRemoved && entityCasted.isRemoved()) || !screened) { + // removed by callback + return false; } // Paper end - chunk system hooks if (!this.addEntityUuid(entity)) { diff --git a/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks b/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks new file mode 100644 index 0000000000000000000000000000000000000000..e57c3ca79677b1dfe7cf3db36f0406de7ea5bd0a --- /dev/null +++ b/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks @@ -0,0 +1 @@ +ca.spottedleaf.moonrise.paper.PaperHooks