== AT ==
public net.minecraft.server.level.ServerChunkCache mainThread
public net.minecraft.server.level.ServerLevel chunkSource
public org.bukkit.craftbukkit.inventory.CraftItemStack handle
public net.minecraft.server.level.ChunkMap getVisibleChunkIfPresent(J)Lnet/minecraft/server/level/ChunkHolder;
public net.minecraft.server.level.ServerChunkCache mainThreadProcessor
public net.minecraft.server.level.ServerChunkCache$MainThreadExecutor
public net.minecraft.world.level.chunk.LevelChunkSection states
This commit is contained in:
Aikar
2016-03-28 20:55:47 -04:00
parent a82a09d198
commit b01c811c2f
81 changed files with 6261 additions and 473 deletions

View File

@@ -1,5 +1,14 @@
--- a/net/minecraft/Util.java
+++ b/net/minecraft/Util.java
@@ -136,7 +136,7 @@
}
public static long getNanos() {
- return timeSource.getAsLong();
+ return System.nanoTime(); // Paper
}
public static long getEpochMillis() {
@@ -537,7 +537,7 @@
public static <K extends Enum<K>, V> EnumMap<K, V> makeEnumMap(Class<K> enumClass, Function<K, V> mapper) {
EnumMap<K, V> enumMap = new EnumMap<>(enumClass);

View File

@@ -0,0 +1,13 @@
--- a/net/minecraft/nbt/CompoundTag.java
+++ b/net/minecraft/nbt/CompoundTag.java
@@ -235,6 +235,10 @@
this.tags.put(key, NbtUtils.createUUID(value));
}
+
+ /**
+ * You must use {@link #hasUUID(String)} before or else it <b>will</b> throw an NPE.
+ */
public UUID getUUID(String key) {
return NbtUtils.loadUUID(this.get(key));
}

View File

@@ -12,15 +12,27 @@
@Nullable
private volatile PacketListener disconnectListener;
@Nullable
@@ -114,6 +119,7 @@
@@ -114,6 +119,19 @@
private volatile DisconnectionDetails delayedDisconnect;
@Nullable
BandwidthDebugMonitor bandwidthDebugMonitor;
+ public String hostname = ""; // CraftBukkit - add field
+
+ // Paper start - add utility methods
+ public final net.minecraft.server.level.ServerPlayer getPlayer() {
+ if (this.packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl impl) {
+ return impl.player;
+ } else if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) {
+ org.bukkit.craftbukkit.entity.CraftPlayer player = impl.getCraftPlayer();
+ return player == null ? null : player.getHandle();
+ }
+ return null;
+ }
+ // Paper end - add utility methods
public Connection(PacketFlow side) {
this.receiving = side;
@@ -123,6 +129,9 @@
@@ -123,6 +141,9 @@
super.channelActive(channelhandlercontext);
this.channel = channelhandlercontext.channel();
this.address = this.channel.remoteAddress();
@@ -30,7 +42,7 @@
if (this.delayedDisconnect != null) {
this.disconnect(this.delayedDisconnect);
}
@@ -176,6 +185,7 @@
@@ -176,6 +197,7 @@
}
}
@@ -38,7 +50,7 @@
}
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
@@ -205,7 +215,7 @@
@@ -205,7 +227,7 @@
}
private static <T extends PacketListener> void genericsFtw(Packet<T> packet, PacketListener listener) {
@@ -47,7 +59,7 @@
}
private void validateListener(ProtocolInfo<?> state, PacketListener listener) {
@@ -464,12 +474,15 @@
@@ -464,12 +486,15 @@
}
public void disconnect(DisconnectionDetails disconnectionInfo) {
@@ -64,7 +76,7 @@
this.disconnectionDetails = disconnectionInfo;
}
@@ -537,7 +550,7 @@
@@ -537,7 +562,7 @@
}
public void configurePacketHandler(ChannelPipeline pipeline) {
@@ -73,7 +85,7 @@
public void write(ChannelHandlerContext channelhandlercontext, Object object, ChannelPromise channelpromise) throws Exception {
super.write(channelhandlercontext, object, channelpromise);
}
@@ -661,6 +674,7 @@
@@ -661,6 +686,7 @@
packetlistener1.onDisconnect(disconnectiondetails);
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/network/PacketEncoder.java
+++ b/net/minecraft/network/PacketEncoder.java
@@ -31,7 +31,7 @@
JvmProfiler.INSTANCE.onPacketSent(this.protocolInfo.id(), packetType, channelHandlerContext.channel().remoteAddress(), i);
} catch (Throwable var9) {
- LOGGER.error("Error sending packet {}", packetType, var9);
+ LOGGER.error("Error sending packet {} (skippable? {})", packetType, packet.isSkippable(), var9);
if (packet.isSkippable()) {
throw new SkipPacketException(var9);
}

View File

@@ -0,0 +1,17 @@
--- a/net/minecraft/network/protocol/login/ClientboundCustomQueryPacket.java
+++ b/net/minecraft/network/protocol/login/ClientboundCustomQueryPacket.java
@@ -47,4 +47,14 @@
public void handle(ClientLoginPacketListener listener) {
listener.handleCustomQuery(this);
}
+
+ // Paper start - MC Utils - default query payloads
+ public static record PlayerInfoChannelPayload(ResourceLocation id, FriendlyByteBuf buffer) implements CustomQueryPayload {
+
+ @Override
+ public void write(final FriendlyByteBuf buf) {
+ buf.writeBytes(this.buffer.copy());
+ }
+ }
+ // Paper end - MC Utils - default query payloads
}

View File

@@ -0,0 +1,43 @@
--- a/net/minecraft/network/protocol/login/ServerboundCustomQueryAnswerPacket.java
+++ b/net/minecraft/network/protocol/login/ServerboundCustomQueryAnswerPacket.java
@@ -20,7 +20,17 @@
}
private static CustomQueryAnswerPayload readPayload(int queryId, FriendlyByteBuf buf) {
- return readUnknownPayload(buf);
+ // Paper start - MC Utils - default query payloads
+ FriendlyByteBuf buffer = buf.readNullable((buf2) -> {
+ int i = buf2.readableBytes();
+ if (i >= 0 && i <= MAX_PAYLOAD_SIZE) {
+ return new FriendlyByteBuf(buf2.readBytes(i));
+ } else {
+ throw new IllegalArgumentException("Payload may not be larger than " + MAX_PAYLOAD_SIZE + " bytes");
+ }
+ });
+ return buffer == null ? null : new net.minecraft.network.protocol.login.ServerboundCustomQueryAnswerPacket.QueryAnswerPayload(buffer);
+ // Paper end - MC Utils - default query payloads
}
private static CustomQueryAnswerPayload readUnknownPayload(FriendlyByteBuf buf) {
@@ -47,4 +57,21 @@
public void handle(ServerLoginPacketListener listener) {
listener.handleCustomQueryPacket(this);
}
+
+ // Paper start - MC Utils - default query payloads
+ public static final class QueryAnswerPayload implements CustomQueryAnswerPayload {
+
+ public final FriendlyByteBuf buffer;
+
+ public QueryAnswerPayload(final net.minecraft.network.FriendlyByteBuf buffer) {
+ this.buffer = buffer;
+ }
+
+ @Override
+ public void write(final net.minecraft.network.FriendlyByteBuf buf) {
+ buf.writeBytes(this.buffer.copy());
+ }
+ }
+ // Paper end - MC Utils - default query payloads
+
}

View File

@@ -107,11 +107,10 @@
private static final int OVERLOADED_TICKS_THRESHOLD = 20;
private static final long OVERLOADED_WARNING_INTERVAL_NANOS = 10L * TimeUtil.NANOSECONDS_PER_SECOND;
private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100;
@@ -276,6 +301,26 @@
private static final AtomicReference<RuntimeException> fatalException = new AtomicReference();
@@ -277,6 +302,26 @@
private final SuppressedExceptionCollector suppressedExceptions;
private final DiscontinuousFrame tickFrame;
+
+ // CraftBukkit start
+ public final WorldLoader.DataLoadContext worldLoader;
+ public org.bukkit.craftbukkit.CraftServer server;
@@ -131,9 +130,10 @@
+ public final double[] recentTps = new double[ 3 ];
+ // Spigot end
+ public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files
+
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
AtomicReference<S> atomicreference = new AtomicReference();
Thread thread = new Thread(() -> {
@@ -290,14 +335,14 @@
thread.setPriority(8);
}
@@ -513,8 +513,7 @@
- }
-
- worldborder.applySettings(iworlddataserver.getWorldBorder());
- }
+ }
}
+ // CraftBukkit end
private static void setInitialSpawn(ServerLevel world, ServerLevelData worldProperties, boolean bonusChest, boolean debugWorld) {
@@ -671,11 +670,14 @@
}
MinecraftServer.LOGGER.info("Saving worlds");
@@ -693,6 +987,12 @@
@@ -693,6 +987,15 @@
} catch (IOException ioexception1) {
MinecraftServer.LOGGER.error("Failed to unlock level {}", this.storageSource.getLevelId(), ioexception1);
}
+ // Spigot start
+ io.papermc.paper.util.MCUtil.ASYNC_EXECUTOR.shutdown(); // Paper
+ try { io.papermc.paper.util.MCUtil.ASYNC_EXECUTOR.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS); // Paper
+ } catch (java.lang.InterruptedException ignored) {} // Paper
+ if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) {
+ MinecraftServer.LOGGER.info("Saving usercache.json");
+ this.getProfileCache().save();
@@ -684,7 +686,7 @@
}
@@ -720,6 +1020,13 @@
@@ -720,6 +1023,13 @@
}
@@ -698,7 +700,7 @@
protected void runServer() {
try {
if (!this.initServer()) {
@@ -727,9 +1034,12 @@
@@ -727,9 +1037,12 @@
}
this.nextTickTimeNanos = Util.getNanos();
@@ -712,7 +714,7 @@
while (this.running) {
long i;
@@ -744,11 +1054,23 @@
@@ -744,11 +1057,23 @@
if (j > MinecraftServer.OVERLOADED_THRESHOLD_NANOS + 20L * i && this.nextTickTimeNanos - this.lastOverloadWarningNanos >= MinecraftServer.OVERLOADED_WARNING_INTERVAL_NANOS + 100L * i) {
long k = j / i;
@@ -736,7 +738,7 @@
boolean flag = i == 0L;
@@ -757,6 +1079,7 @@
@@ -757,6 +1082,7 @@
this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount);
}
@@ -744,7 +746,7 @@
this.nextTickTimeNanos += i;
try {
@@ -830,6 +1153,13 @@
@@ -830,6 +1156,13 @@
this.services.profileCache().clearExecutor();
}
@@ -758,7 +760,7 @@
this.onServerExit();
}
@@ -889,9 +1219,16 @@
@@ -889,9 +1222,16 @@
}
private boolean haveTime() {
@@ -776,7 +778,7 @@
public static boolean throwIfFatalException() {
RuntimeException runtimeexception = (RuntimeException) MinecraftServer.fatalException.get();
@@ -903,7 +1240,7 @@
@@ -903,7 +1243,7 @@
}
public static void setFatalException(RuntimeException exception) {
@@ -785,7 +787,7 @@
}
@Override
@@ -977,7 +1314,7 @@
@@ -977,7 +1317,7 @@
}
}
@@ -794,7 +796,7 @@
Profiler.get().incrementCounter("runTask");
super.doRunTask(ticktask);
}
@@ -1025,6 +1362,7 @@
@@ -1025,6 +1365,7 @@
}
public void tickServer(BooleanSupplier shouldKeepTicking) {
@@ -802,7 +804,7 @@
long i = Util.getNanos();
int j = this.pauseWhileEmptySeconds() * 20;
@@ -1041,11 +1379,13 @@
@@ -1041,11 +1382,13 @@
this.autoSave();
}
@@ -816,7 +818,7 @@
++this.tickCount;
this.tickRateManager.tick();
this.tickChildren(shouldKeepTicking);
@@ -1055,7 +1395,7 @@
@@ -1055,7 +1398,7 @@
}
--this.ticksUntilAutosave;
@@ -825,7 +827,7 @@
this.autoSave();
}
@@ -1071,10 +1411,13 @@
@@ -1071,10 +1414,13 @@
this.smoothedTickTimeMillis = this.smoothedTickTimeMillis * 0.8F + (float) k / (float) TimeUtil.NANOSECONDS_PER_MILLISECOND * 0.19999999F;
this.logTickMethodTime(i);
gameprofilerfiller.pop();
@@ -840,7 +842,7 @@
MinecraftServer.LOGGER.debug("Autosave started");
ProfilerFiller gameprofilerfiller = Profiler.get();
@@ -1082,6 +1425,7 @@
@@ -1082,6 +1428,7 @@
this.saveEverything(true, false, false);
gameprofilerfiller.pop();
MinecraftServer.LOGGER.debug("Autosave finished");
@@ -848,7 +850,7 @@
}
private void logTickMethodTime(long tickStartTime) {
@@ -1154,11 +1498,34 @@
@@ -1154,11 +1501,34 @@
this.getPlayerList().getPlayers().forEach((entityplayer) -> {
entityplayer.connection.suspendFlushing();
});
@@ -883,7 +885,7 @@
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();
@@ -1167,16 +1534,20 @@
@@ -1167,16 +1537,20 @@
return s + " " + String.valueOf(worldserver.dimension().location());
});
@@ -904,7 +906,7 @@
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
@@ -1189,18 +1560,24 @@
@@ -1189,18 +1563,24 @@
}
gameprofilerfiller.popPush("connection");
@@ -929,7 +931,7 @@
gameprofilerfiller.popPush("send chunks");
iterator = this.playerList.getPlayers().iterator();
@@ -1265,7 +1642,23 @@
@@ -1265,7 +1645,23 @@
@Nullable
public ServerLevel getLevel(ResourceKey<Level> key) {
return (ServerLevel) this.levels.get(key);
@@ -953,7 +955,7 @@
public Set<ResourceKey<Level>> levelKeys() {
return this.levels.keySet();
@@ -1296,7 +1689,7 @@
@@ -1296,7 +1692,7 @@
@DontObfuscate
public String getServerModName() {
@@ -962,7 +964,7 @@
}
public SystemReport fillSystemReport(SystemReport details) {
@@ -1507,7 +1900,7 @@
@@ -1507,7 +1903,7 @@
}
public ServerConnectionListener getConnection() {
@@ -971,7 +973,7 @@
}
public boolean isReady() {
@@ -1634,11 +2027,11 @@
@@ -1634,11 +2030,11 @@
public CompletableFuture<Void> reloadResources(Collection<String> dataPacks) {
CompletableFuture<Void> completablefuture = CompletableFuture.supplyAsync(() -> {
@@ -985,7 +987,7 @@
}, this).thenCompose((immutablelist) -> {
MultiPackResourceManager resourcemanager = new MultiPackResourceManager(PackType.SERVER_DATA, immutablelist);
List<Registry.PendingTags<?>> list = TagLoader.loadTagsForExistingRegistries(resourcemanager, this.registries.compositeAccess());
@@ -1654,6 +2047,7 @@
@@ -1654,6 +2050,7 @@
}).thenAcceptAsync((minecraftserver_reloadableresources) -> {
this.resources.close();
this.resources = minecraftserver_reloadableresources;
@@ -993,7 +995,7 @@
this.packRepository.setSelected(dataPacks);
WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(MinecraftServer.getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures());
@@ -1952,7 +2346,7 @@
@@ -1952,7 +2349,7 @@
final List<String> list = Lists.newArrayList();
final GameRules gamerules = this.getGameRules();
@@ -1002,7 +1004,7 @@
@Override
public <T extends GameRules.Value<T>> void visit(GameRules.Key<T> key, GameRules.Type<T> type) {
list.add(String.format(Locale.ROOT, "%s=%s\n", key.getId(), gamerules.getRule(key)));
@@ -2058,7 +2452,7 @@
@@ -2058,7 +2455,7 @@
try {
label51:
{
@@ -1011,7 +1013,7 @@
try {
arraylist = Lists.newArrayList(NativeModuleLister.listModules());
@@ -2105,8 +2499,24 @@
@@ -2105,8 +2502,24 @@
if (bufferedwriter != null) {
bufferedwriter.close();
}
@@ -1036,7 +1038,7 @@
private ProfilerFiller createProfiler() {
if (this.willStartRecordingMetrics) {
@@ -2235,6 +2645,11 @@
@@ -2235,6 +2648,11 @@
}

View File

@@ -1,6 +1,6 @@
--- a/net/minecraft/server/level/ChunkHolder.java
+++ b/net/minecraft/server/level/ChunkHolder.java
@@ -28,6 +28,10 @@
@@ -28,14 +28,18 @@
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.lighting.LevelLightEngine;
@@ -11,6 +11,17 @@
public class ChunkHolder extends GenerationChunkHolder {
public static final ChunkResult<LevelChunk> UNLOADED_LEVEL_CHUNK = ChunkResult.error("Unloaded level chunk");
private static final CompletableFuture<ChunkResult<LevelChunk>> UNLOADED_LEVEL_CHUNK_FUTURE = CompletableFuture.completedFuture(ChunkHolder.UNLOADED_LEVEL_CHUNK);
private final LevelHeightAccessor levelHeightAccessor;
- private volatile CompletableFuture<ChunkResult<LevelChunk>> fullChunkFuture;
- private volatile CompletableFuture<ChunkResult<LevelChunk>> tickingChunkFuture;
- private volatile CompletableFuture<ChunkResult<LevelChunk>> entityTickingChunkFuture;
+ private volatile CompletableFuture<ChunkResult<LevelChunk>> fullChunkFuture; private int fullChunkCreateCount; private volatile boolean isFullChunkReady; // Paper - cache chunk ticking stage
+ private volatile CompletableFuture<ChunkResult<LevelChunk>> tickingChunkFuture; private volatile boolean isTickingReady; // Paper - cache chunk ticking stage
+ private volatile CompletableFuture<ChunkResult<LevelChunk>> entityTickingChunkFuture; private volatile boolean isEntityTickingReady; // Paper - cache chunk ticking stage
public int oldTicketLevel;
private int ticketLevel;
private int queueLevel;
@@ -58,9 +62,9 @@
this.entityTickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE;
this.blockChangedLightSectionFilter = new BitSet();
@@ -24,12 +35,10 @@
this.levelHeightAccessor = world;
this.lightEngine = lightingProvider;
this.onLevelChange = levelUpdateListener;
@@ -70,7 +74,19 @@
this.queueLevel = this.oldTicketLevel;
this.setTicketLevel(level);
@@ -72,6 +76,18 @@
this.changedBlocksPerSection = new ShortSet[world.getSectionsCount()];
+ }
+
}
+ // CraftBukkit start
+ public LevelChunk getFullChunkNow() {
+ // Note: We use the oldTicketLevel for isLoaded checks.
@@ -39,16 +48,19 @@
+
+ public LevelChunk getFullChunkNowUnchecked() {
+ return (LevelChunk) this.getChunkIfPresentUnchecked(ChunkStatus.FULL);
}
+ }
+ // CraftBukkit end
+
public CompletableFuture<ChunkResult<LevelChunk>> getTickingChunkFuture() {
return this.tickingChunkFuture;
@@ -86,7 +102,7 @@
}
@@ -85,8 +101,8 @@
}
@Nullable
public LevelChunk getTickingChunk() {
- public LevelChunk getTickingChunk() {
- return (LevelChunk) ((ChunkResult) this.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).orElse((Object) null);
+ public final LevelChunk getTickingChunk() { // Paper - final for inline
+ return (LevelChunk) ((ChunkResult) this.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).orElse(null); // CraftBukkit - decompile error
}
@@ -83,12 +95,10 @@
});
});
}
@@ -299,7 +319,39 @@
private void demoteFullChunk(ChunkMap chunkLoadingManager, FullChunkStatus target) {
this.pendingFullStateConfirmation.cancel(false);
@@ -301,6 +321,38 @@
chunkLoadingManager.onFullChunkStatusChange(this.pos, target);
+ }
+
}
+ // CraftBukkit start
+ // ChunkUnloadEvent: Called before the chunk is unloaded: isChunkLoaded is still true and chunk can still be modified by plugins.
+ // SPIGOT-7780: Moved out of updateFutures to call all chunk unload events before calling updateHighestAllowedStatus for all chunks
@@ -118,12 +128,95 @@
+ // Run callback right away if the future was already done
+ playerchunkmap.callbackExecutor.run();
+ }
}
+ }
+ // CraftBukkit end
+
protected void updateFutures(ChunkMap chunkLoadingManager, Executor executor) {
FullChunkStatus fullchunkstatus = ChunkLevel.fullStatus(this.oldTicketLevel);
@@ -357,6 +409,26 @@
FullChunkStatus fullchunkstatus1 = ChunkLevel.fullStatus(this.ticketLevel);
@@ -309,12 +361,28 @@
this.wasAccessibleSinceLastSave |= flag1;
if (!flag && flag1) {
+ int expectCreateCount = ++this.fullChunkCreateCount; // Paper
this.fullChunkFuture = chunkLoadingManager.prepareAccessibleChunk(this);
this.scheduleFullChunkPromotion(chunkLoadingManager, this.fullChunkFuture, executor, FullChunkStatus.FULL);
+ // Paper start - cache ticking ready status
+ this.fullChunkFuture.thenAccept(chunkResult -> {
+ chunkResult.ifSuccess(chunk -> {
+ if (ChunkHolder.this.fullChunkCreateCount == expectCreateCount) {
+ ChunkHolder.this.isFullChunkReady = true;
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkBorder(chunk, this);
+ }
+ });
+ });
+ // Paper end - cache ticking ready status
this.addSaveDependency(this.fullChunkFuture);
}
if (flag && !flag1) {
+ // Paper start
+ if (this.isFullChunkReady) {
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkNotBorder(this.fullChunkFuture.join().orElseThrow(IllegalStateException::new), this); // Paper
+ }
+ // Paper end
this.fullChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK);
this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE;
}
@@ -325,11 +393,25 @@
if (!flag2 && flag3) {
this.tickingChunkFuture = chunkLoadingManager.prepareTickingChunk(this);
this.scheduleFullChunkPromotion(chunkLoadingManager, this.tickingChunkFuture, executor, FullChunkStatus.BLOCK_TICKING);
+ // Paper start - cache ticking ready status
+ this.tickingChunkFuture.thenAccept(chunkResult -> {
+ chunkResult.ifSuccess(chunk -> {
+ // note: Here is a very good place to add callbacks to logic waiting on this.
+ ChunkHolder.this.isTickingReady = true;
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkTicking(chunk, this);
+ });
+ });
+ // Paper end
this.addSaveDependency(this.tickingChunkFuture);
}
if (flag2 && !flag3) {
- this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK);
+ // Paper start
+ if (this.isTickingReady) {
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().orElseThrow(IllegalStateException::new), this); // Paper
+ }
+ // Paper end
+ this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isTickingReady = false; // Paper - cache chunk ticking stage
this.tickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE;
}
@@ -343,11 +425,24 @@
this.entityTickingChunkFuture = chunkLoadingManager.prepareEntityTickingChunk(this);
this.scheduleFullChunkPromotion(chunkLoadingManager, this.entityTickingChunkFuture, executor, FullChunkStatus.ENTITY_TICKING);
+ // Paper start - cache ticking ready status
+ this.entityTickingChunkFuture.thenAccept(chunkResult -> {
+ chunkResult.ifSuccess(chunk -> {
+ ChunkHolder.this.isEntityTickingReady = true;
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkEntityTicking(chunk, this);
+ });
+ });
+ // Paper end
this.addSaveDependency(this.entityTickingChunkFuture);
}
if (flag4 && !flag5) {
- this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK);
+ // Paper start
+ if (this.isEntityTickingReady) {
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().orElseThrow(IllegalStateException::new), this);
+ }
+ // Paper end
+ this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage
this.entityTickingChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE;
}
@@ -357,6 +452,26 @@
this.onLevelChange.onLevelChange(this.pos, this::getQueueLevel, this.ticketLevel, this::setQueueLevel);
this.oldTicketLevel = this.ticketLevel;

View File

@@ -11,11 +11,10 @@
public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider, GeneratingChunkMap {
private static final ChunkResult<List<ChunkAccess>> UNLOADED_CHUNK_LIST_RESULT = ChunkResult.error("Unloaded chunks found in range");
@@ -148,6 +152,27 @@
private final AtomicInteger activeChunkWrites;
@@ -149,6 +153,33 @@
public int serverViewDistance;
private final WorldGenContext worldGenContext;
+
+ // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback()
+ public final CallbackExecutor callbackExecutor = new CallbackExecutor();
+ public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable {
@@ -36,10 +35,17 @@
+ }
+ };
+ // CraftBukkit end
+
+ // Paper start
+ public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) {
+ return this.pendingUnloads.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ));
+ }
+ // Paper end
+
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
super(new RegionStorageInfo(session.getLevelId(), world.dimension(), "chunk"), session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
@@ -170,13 +195,19 @@
this.visibleChunkMap = this.updatingChunkMap.clone();
@@ -170,13 +201,19 @@
RegistryAccess iregistrycustom = world.registryAccess();
long j = world.getSeed();
@@ -61,7 +67,20 @@
this.mainThreadExecutor = mainThreadExecutor;
ConsecutiveExecutor consecutiveexecutor = new ConsecutiveExecutor(executor, "worldgen");
@@ -325,7 +356,7 @@
@@ -198,6 +235,12 @@
this.chunksToEagerlySave.add(pos.toLong());
}
+ // Paper start
+ public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
+ return -1;
+ }
+ // Paper end
+
protected ChunkGenerator generator() {
return this.worldGenContext.generator();
}
@@ -325,7 +368,7 @@
throw this.debugFuturesAndCreateReportedException(new IllegalStateException("At least one of the chunk futures were null"), "n/a");
}
@@ -70,7 +89,131 @@
if (ichunkaccess == null) {
return ChunkMap.UNLOADED_CHUNK_LIST_RESULT;
@@ -977,7 +1008,8 @@
@@ -354,9 +397,9 @@
};
stringbuilder.append("Updating:").append(System.lineSeparator());
- this.updatingChunkMap.values().forEach(consumer);
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.getUpdatingChunkHolders(this.level).forEach(consumer); // Paper
stringbuilder.append("Visible:").append(System.lineSeparator());
- this.visibleChunkMap.values().forEach(consumer);
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.level).forEach(consumer); // Paper
CrashReport crashreport = CrashReport.forThrowable(exception, "Chunk loading");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk loading");
@@ -398,6 +441,9 @@
holder.setTicketLevel(level);
} else {
holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this::onLevelChange, this);
+ // Paper start
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkHolderCreate(this.level, holder);
+ // Paper end
}
this.updatingChunkMap.put(pos, holder);
@@ -427,7 +473,7 @@
protected void saveAllChunks(boolean flush) {
if (flush) {
- List<ChunkHolder> list = this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).toList();
+ List<ChunkHolder> list = ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).toList(); // Paper
MutableBoolean mutableboolean = new MutableBoolean();
do {
@@ -453,7 +499,7 @@
} else {
this.nextChunkSaveTime.clear();
long i = Util.getMillis();
- ObjectIterator objectiterator = this.visibleChunkMap.values().iterator();
+ Iterator<ChunkHolder> objectiterator = ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper
while (objectiterator.hasNext()) {
ChunkHolder playerchunk = (ChunkHolder) objectiterator.next();
@@ -478,7 +524,7 @@
}
public boolean hasWork() {
- return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || !this.updatingChunkMap.isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.worldgenTaskDispatcher.hasWork() || this.lightTaskDispatcher.hasWork() || this.distanceManager.hasTickets();
+ return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || ca.spottedleaf.moonrise.common.util.ChunkSystem.hasAnyChunkHolders(this.level) || !this.updatingChunkMap.isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.worldgenTaskDispatcher.hasWork() || this.lightTaskDispatcher.hasWork() || this.distanceManager.hasTickets();
}
private void processUnloads(BooleanSupplier shouldKeepTicking) {
@@ -537,8 +583,11 @@
this.scheduleUnload(pos, chunk);
} else {
ChunkAccess ichunkaccess = chunk.getLatestChunk();
-
- if (this.pendingUnloads.remove(pos, chunk) && ichunkaccess != null) {
+ // Paper start
+ boolean removed;
+ if ((removed = this.pendingUnloads.remove(pos, chunk)) && ichunkaccess != null) {
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkHolderDelete(this.level, chunk);
+ // Paper end
LevelChunk chunk1;
if (ichunkaccess instanceof LevelChunk) {
@@ -556,7 +605,9 @@
this.lightEngine.tryScheduleUpdate();
this.progressListener.onStatusChange(ichunkaccess.getPos(), (ChunkStatus) null);
this.nextChunkSaveTime.remove(ichunkaccess.getPos().toLong());
- }
+ } else if (removed) { // Paper start
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.onChunkHolderDelete(this.level, chunk);
+ } // Paper end
}
};
@@ -905,7 +956,7 @@
}
}
- protected void setServerViewDistance(int watchDistance) {
+ public void setServerViewDistance(int watchDistance) { // Paper - public
int j = Mth.clamp(watchDistance, 2, 32);
if (j != this.serverViewDistance) {
@@ -922,7 +973,7 @@
}
- int getPlayerViewDistance(ServerPlayer player) {
+ public int getPlayerViewDistance(ServerPlayer player) { // Paper - public
return Mth.clamp(player.requestedViewDistance(), 2, this.serverViewDistance);
}
@@ -951,7 +1002,7 @@
}
public int size() {
- return this.visibleChunkMap.size();
+ return ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolderCount(this.level); // Paper
}
public DistanceManager getDistanceManager() {
@@ -959,25 +1010,26 @@
}
protected Iterable<ChunkHolder> getChunks() {
- return Iterables.unmodifiableIterable(this.visibleChunkMap.values());
+ return Iterables.unmodifiableIterable(ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.level)); // Paper
}
void dumpChunks(Writer writer) throws IOException {
CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer);
TickingTracker tickingtracker = this.distanceManager.tickingTracker();
- ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator();
+ Iterator<ChunkHolder> objectbidirectionaliterator = ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper
while (objectbidirectionaliterator.hasNext()) {
- Entry<ChunkHolder> entry = (Entry) objectbidirectionaliterator.next();
- long i = entry.getLongKey();
+ ChunkHolder playerchunk = objectbidirectionaliterator.next(); // Paper
+ long i = playerchunk.pos.toLong(); // Paper
ChunkPos chunkcoordintpair = new ChunkPos(i);
- ChunkHolder playerchunk = (ChunkHolder) entry.getValue();
+ // Paper - move up
Optional<ChunkAccess> optional = Optional.ofNullable(playerchunk.getLatestChunk());
Optional<LevelChunk> optional1 = optional.flatMap((ichunkaccess) -> {
return ichunkaccess instanceof LevelChunk ? Optional.of((LevelChunk) ichunkaccess) : Optional.empty();
});
@@ -80,7 +223,7 @@
return chunk.getBlockEntities().size();
}).orElse(0), tickingtracker.getTicketDebugString(i), tickingtracker.getLevel(i), optional1.map((chunk) -> {
return chunk.getBlockTicks().count();
@@ -990,7 +1022,7 @@
@@ -990,7 +1042,7 @@
private static String printFuture(CompletableFuture<ChunkResult<LevelChunk>> future) {
try {
@@ -89,7 +232,7 @@
return chunkresult != null ? (chunkresult.isSuccess() ? "done" : "unloaded") : "not completed";
} catch (CompletionException completionexception) {
@@ -1002,12 +1034,14 @@
@@ -1002,12 +1054,14 @@
private CompletableFuture<Optional<CompoundTag>> readChunk(ChunkPos chunkPos) {
return this.read(chunkPos).thenApplyAsync((optional) -> {
@@ -107,7 +250,7 @@
}
void forEachSpawnCandidateChunk(Consumer<ChunkHolder> callback) {
@@ -1025,10 +1059,27 @@
@@ -1025,10 +1079,27 @@
}
public boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) {
@@ -136,7 +279,7 @@
Iterator iterator = this.playerMap.getAllPlayers().iterator();
ServerPlayer entityplayer;
@@ -1039,7 +1090,7 @@
@@ -1039,7 +1110,7 @@
}
entityplayer = (ServerPlayer) iterator.next();
@@ -145,7 +288,7 @@
return true;
}
@@ -1056,7 +1107,7 @@
@@ -1056,7 +1127,7 @@
while (iterator.hasNext()) {
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
@@ -154,7 +297,7 @@
builder.add(entityplayer);
}
}
@@ -1065,13 +1116,13 @@
@@ -1065,13 +1136,13 @@
}
}
@@ -172,7 +315,7 @@
}
}
@@ -1215,9 +1266,11 @@
@@ -1215,9 +1286,11 @@
}
public void addEntity(Entity entity) {
@@ -184,7 +327,7 @@
if (i != 0) {
int j = entitytypes.updateInterval();
@@ -1250,6 +1303,7 @@
@@ -1250,6 +1323,7 @@
}
protected void removeEntity(Entity entity) {
@@ -192,7 +335,16 @@
if (entity instanceof ServerPlayer entityplayer) {
this.updatePlayerStatus(entityplayer, false);
ObjectIterator objectiterator = this.entityMap.values().iterator();
@@ -1424,7 +1478,7 @@
@@ -1391,7 +1465,7 @@
});
}
- private class ChunkDistanceManager extends DistanceManager {
+ public class ChunkDistanceManager extends DistanceManager { // Paper - public
protected ChunkDistanceManager(final Executor workerExecutor, final Executor mainThreadExecutor) {
super(workerExecutor, mainThreadExecutor);
@@ -1424,7 +1498,7 @@
public final Set<ServerPlayerConnection> seenBy = Sets.newIdentityHashSet();
public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) {
@@ -201,7 +353,7 @@
this.entity = entity;
this.range = i;
this.lastSectionPos = SectionPos.of((EntityAccess) entity);
@@ -1469,6 +1523,7 @@
@@ -1469,6 +1543,7 @@
}
public void removePlayer(ServerPlayer player) {
@@ -209,7 +361,7 @@
if (this.seenBy.remove(player.connection)) {
this.serverEntity.removePairing(player);
}
@@ -1476,6 +1531,7 @@
@@ -1476,6 +1551,7 @@
}
public void updatePlayer(ServerPlayer player) {
@@ -217,7 +369,7 @@
if (player != this.entity) {
Vec3 vec3d = player.position().subtract(this.entity.position());
int i = ChunkMap.this.getPlayerViewDistance(player);
@@ -1484,6 +1540,11 @@
@@ -1484,6 +1560,11 @@
double d2 = d0 * d0;
boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z);

View File

@@ -108,10 +108,21 @@
objectset.remove(player);
if (objectset.isEmpty()) {
@@ -391,6 +418,26 @@
return !this.tickets.isEmpty();
@@ -358,7 +385,7 @@
}
public void removeTicketsOnClosing() {
- ImmutableSet<TicketType<?>> immutableset = ImmutableSet.of(TicketType.UNKNOWN);
+ ImmutableSet<TicketType<?>> immutableset = ImmutableSet.of(TicketType.UNKNOWN, TicketType.POST_TELEPORT, TicketType.FUTURE_AWAIT); // Paper - add additional tickets to preserve
ObjectIterator<Entry<SortedArraySet<Ticket<?>>>> objectiterator = this.tickets.long2ObjectEntrySet().fastIterator();
while (objectiterator.hasNext()) {
@@ -389,7 +416,27 @@
public boolean hasTickets() {
return !this.tickets.isEmpty();
+ }
+
+ // CraftBukkit start
+ public <T> void removeAllTicketsFor(TicketType<T> ticketType, int ticketLevel, T ticketIdentifier) {
+ Ticket<T> target = new Ticket<>(ticketType, ticketLevel, ticketIdentifier);
@@ -129,9 +140,8 @@
+ }
+ }
+ }
+ }
}
+ // CraftBukkit end
+
private class ChunkTicketTracker extends ChunkTracker {
private static final int MAX_LEVEL = ChunkLevel.MAX_LEVEL + 1;

View File

@@ -1,6 +1,20 @@
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -95,6 +95,16 @@
@@ -74,6 +74,13 @@
@Nullable
@VisibleForDebug
private NaturalSpawner.SpawnState lastSpawnState;
+ // Paper start
+ private final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<net.minecraft.world.level.chunk.LevelChunk> fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>();
+ public int getFullChunksCount() {
+ return this.fullChunks.size();
+ }
+ long chunkFutureAwaitCounter;
+ // Paper end
public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory) {
this.level = world;
@@ -95,6 +102,64 @@
this.clearCache();
}
@@ -13,11 +27,59 @@
+ return chunk.getFullChunkNow() != null;
+ }
+ // CraftBukkit end
+ // Paper start
+ public void addLoadedChunk(LevelChunk chunk) {
+ this.fullChunks.put(chunk.coordinateKey, chunk);
+ }
+
+ public void removeLoadedChunk(LevelChunk chunk) {
+ this.fullChunks.remove(chunk.coordinateKey);
+ }
+
+ @Nullable
+ public ChunkAccess getChunkAtImmediately(int x, int z) {
+ ChunkHolder holder = this.chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
+ if (holder == null) {
+ return null;
+ }
+
+ return holder.getLatestChunk();
+ }
+
+ public <T> void addTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
+ this.distanceManager.addTicket(ticketType, chunkPos, ticketLevel, identifier);
+ }
+
+ public <T> void removeTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
+ this.distanceManager.removeTicket(ticketType, chunkPos, ticketLevel, identifier);
+ }
+
+ // "real" get chunk if loaded
+ // Note: Partially copied from the getChunkAt method below
+ @Nullable
+ public LevelChunk getChunkAtIfCachedImmediately(int x, int z) {
+ long k = ChunkPos.asLong(x, z);
+
+ // Note: Bypass cache since we need to check ticket level, and to make this MT-Safe
+
+ ChunkHolder playerChunk = this.getVisibleChunkIfPresent(k);
+ if (playerChunk == null) {
+ return null;
+ }
+
+ return playerChunk.getFullChunkNowUnchecked();
+ }
+
+ @Nullable
+ public LevelChunk getChunkAtIfLoadedImmediately(int x, int z) {
+ return this.fullChunks.get(ChunkPos.asLong(x, z));
+ }
+ // Paper end
+
@Override
public ThreadedLevelLightEngine getLightEngine() {
return this.lightEngine;
@@ -138,20 +148,22 @@
@@ -138,20 +203,22 @@
if (k == this.lastChunkPos[l] && leastStatus == this.lastChunkStatus[l]) {
ChunkAccess ichunkaccess = this.lastChunk[l];
@@ -42,7 +104,7 @@
if (ichunkaccess1 == null && create) {
throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("Chunk not there when requested: " + chunkresult.getError()));
@@ -231,7 +243,15 @@
@@ -231,7 +298,15 @@
int l = ChunkLevel.byStatus(leastStatus);
ChunkHolder playerchunk = this.getVisibleChunkIfPresent(k);
@@ -59,7 +121,7 @@
this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair);
if (this.chunkAbsent(playerchunk, l)) {
ProfilerFiller gameprofilerfiller = Profiler.get();
@@ -250,7 +270,7 @@
@@ -250,7 +325,7 @@
}
private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) {
@@ -68,7 +130,16 @@
}
@Override
@@ -309,30 +329,58 @@
@@ -279,7 +354,7 @@
return this.mainThreadProcessor.pollTask();
}
- boolean runDistanceManagerUpdates() {
+ public boolean runDistanceManagerUpdates() { // Paper - public
boolean flag = this.distanceManager.runAllUpdates(this.chunkMap);
boolean flag1 = this.chunkMap.promoteChunkMap();
@@ -309,30 +384,58 @@
@Override
public void close() throws IOException {
@@ -85,8 +156,8 @@
this.dataStorage.close();
this.lightEngine.close();
this.chunkMap.close();
+ }
+
}
+ // CraftBukkit start - modelled on below
+ public void purgeUnload() {
+ ProfilerFiller gameprofilerfiller = Profiler.get();
@@ -98,9 +169,9 @@
+ this.chunkMap.tick(() -> true);
+ gameprofilerfiller.pop();
+ this.clearCache();
}
+ }
+ // CraftBukkit end
+
@Override
public void tick(BooleanSupplier shouldKeepTicking, boolean tickChunks) {
ProfilerFiller gameprofilerfiller = Profiler.get();
@@ -129,7 +200,7 @@
gameprofilerfiller.pop();
this.clearCache();
}
@@ -401,14 +449,14 @@
@@ -401,14 +504,14 @@
this.lastSpawnState = spawnercreature_d;
profiler.popPush("spawnAndTick");
@@ -147,7 +218,7 @@
} else {
list1 = List.of();
}
@@ -420,12 +468,14 @@
@@ -420,12 +523,14 @@
ChunkPos chunkcoordintpair = chunk.getPos();
chunk.incrementInhabitedTime(timeDelta);
@@ -163,7 +234,7 @@
}
}
@@ -541,10 +591,16 @@
@@ -541,10 +646,16 @@
@Override
public void setSpawnSettings(boolean spawnMonsters) {
@@ -182,7 +253,7 @@
public String getChunkDebugData(ChunkPos pos) {
return this.chunkMap.getChunkDebugData(pos);
}
@@ -618,14 +674,20 @@
@@ -618,14 +729,20 @@
}
@Override

View File

@@ -62,7 +62,7 @@
private int lastSpawnChunkRadius;
final EntityTickList entityTickList = new EntityTickList();
public final PersistentEntitySectionManager<Entity> entityManager;
@@ -214,52 +227,87 @@
@@ -214,52 +227,184 @@
private final boolean tickTime;
private final RandomSequences randomSequences;
@@ -79,7 +79,7 @@
+ // CraftBukkit start
+ public final LevelStorageSource.LevelStorageAccess convertable;
+ public final UUID uuid;
+
+ public LevelChunk getChunkIfLoaded(int x, int z) {
+ return this.chunkSource.getChunk(x, z, false);
+ }
@@ -89,6 +89,103 @@
+ return this.convertable.dimensionType;
+ }
+
+ // Paper start
+ public final boolean areChunksLoadedForMove(AABB axisalignedbb) {
+ // copied code from collision methods, so that we can guarantee that they wont load chunks (we don't override
+ // ICollisionAccess methods for VoxelShapes)
+ // be more strict too, add a block (dumb plugins in move events?)
+ int minBlockX = Mth.floor(axisalignedbb.minX - 1.0E-7D) - 3;
+ int maxBlockX = Mth.floor(axisalignedbb.maxX + 1.0E-7D) + 3;
+
+ int minBlockZ = Mth.floor(axisalignedbb.minZ - 1.0E-7D) - 3;
+ int maxBlockZ = Mth.floor(axisalignedbb.maxZ + 1.0E-7D) + 3;
+
+ int minChunkX = minBlockX >> 4;
+ int maxChunkX = maxBlockX >> 4;
+
+ int minChunkZ = minBlockZ >> 4;
+ int maxChunkZ = maxBlockZ >> 4;
+
+ ServerChunkCache chunkProvider = this.getChunkSource();
+
+ for (int cx = minChunkX; cx <= maxChunkX; ++cx) {
+ for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) {
+ if (chunkProvider.getChunkAtIfLoadedImmediately(cx, cz) == null) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public final void loadChunksForMoveAsync(AABB axisalignedbb, ca.spottedleaf.concurrentutil.util.Priority priority,
+ java.util.function.Consumer<List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) {
+ if (Thread.currentThread() != this.thread) {
+ this.getChunkSource().mainThreadProcessor.execute(() -> {
+ this.loadChunksForMoveAsync(axisalignedbb, priority, onLoad);
+ });
+ return;
+ }
+ int minBlockX = Mth.floor(axisalignedbb.minX - 1.0E-7D) - 3;
+ int minBlockZ = Mth.floor(axisalignedbb.minZ - 1.0E-7D) - 3;
+
+ int maxBlockX = Mth.floor(axisalignedbb.maxX + 1.0E-7D) + 3;
+ int maxBlockZ = Mth.floor(axisalignedbb.maxZ + 1.0E-7D) + 3;
+
+ int minChunkX = minBlockX >> 4;
+ int minChunkZ = minBlockZ >> 4;
+
+ int maxChunkX = maxBlockX >> 4;
+ int maxChunkZ = maxBlockZ >> 4;
+
+ this.loadChunks(minChunkX, minChunkZ, maxChunkX, maxChunkZ, priority, onLoad);
+ }
+
+ public final void loadChunks(int minChunkX, int minChunkZ, int maxChunkX, int maxChunkZ,
+ ca.spottedleaf.concurrentutil.util.Priority priority,
+ java.util.function.Consumer<List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) {
+ List<net.minecraft.world.level.chunk.ChunkAccess> ret = new java.util.ArrayList<>();
+ it.unimi.dsi.fastutil.ints.IntArrayList ticketLevels = new it.unimi.dsi.fastutil.ints.IntArrayList();
+ ServerChunkCache chunkProvider = this.getChunkSource();
+
+ int requiredChunks = (maxChunkX - minChunkX + 1) * (maxChunkZ - minChunkZ + 1);
+ int[] loadedChunks = new int[1];
+
+ Long holderIdentifier = Long.valueOf(chunkProvider.chunkFutureAwaitCounter++);
+
+ java.util.function.Consumer<net.minecraft.world.level.chunk.ChunkAccess> consumer = (net.minecraft.world.level.chunk.ChunkAccess chunk) -> {
+ if (chunk != null) {
+ int ticketLevel = Math.max(33, chunkProvider.chunkMap.getUpdatingChunkIfPresent(chunk.getPos().toLong()).getTicketLevel());
+ ret.add(chunk);
+ ticketLevels.add(ticketLevel);
+ chunkProvider.addTicketAtLevel(TicketType.FUTURE_AWAIT, chunk.getPos(), ticketLevel, holderIdentifier);
+ }
+ if (++loadedChunks[0] == requiredChunks) {
+ try {
+ onLoad.accept(java.util.Collections.unmodifiableList(ret));
+ } finally {
+ for (int i = 0, len = ret.size(); i < len; ++i) {
+ ChunkPos chunkPos = ret.get(i).getPos();
+ int ticketLevel = ticketLevels.getInt(i);
+
+ chunkProvider.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, ticketLevel, chunkPos);
+ chunkProvider.removeTicketAtLevel(TicketType.FUTURE_AWAIT, chunkPos, ticketLevel, holderIdentifier);
+ }
+ }
+ }
+ };
+
+ for (int cx = minChunkX; cx <= maxChunkX; ++cx) {
+ for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) {
+ ca.spottedleaf.moonrise.common.util.ChunkSystem.scheduleChunkLoad(
+ this, cx, cz, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, true, priority, consumer
+ );
+ }
+ }
+ }
+ // Paper end
+
+ // Add env and gen to constructor, IWorldDataServer -> WorldDataServer
+ public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
+ super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig, minecraftserver.registryAccess(), iworlddataserver.getGameRules()))); // Paper - create paper world configs
@@ -103,7 +200,7 @@
+ ChunkGenerator chunkgenerator = worlddimension.generator();
+ // CraftBukkit start
+ this.serverLevelData.setWorld(this);
+
+ if (biomeProvider != null) {
+ BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().lookupOrThrow(Registries.BIOME));
+ if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) {
@@ -174,7 +271,7 @@
}
/** @deprecated */
@@ -305,12 +353,20 @@
@@ -305,12 +450,20 @@
long j;
if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) {
@@ -198,7 +295,7 @@
if (this.getGameRules().getBoolean(GameRules.RULE_WEATHER_CYCLE) && this.isRaining()) {
this.resetWeatherCycle();
}
@@ -322,6 +378,7 @@
@@ -322,6 +475,7 @@
}
gameprofilerfiller.push("tickPending");
@@ -206,7 +303,7 @@
if (!this.isDebug() && flag) {
j = this.getGameTime();
gameprofilerfiller.push("blockTicks");
@@ -330,6 +387,7 @@
@@ -330,6 +484,7 @@
this.fluidTicks.tick(j, 65536, this::tickFluid);
gameprofilerfiller.pop();
}
@@ -214,7 +311,7 @@
gameprofilerfiller.popPush("raid");
if (flag) {
@@ -340,12 +398,14 @@
@@ -340,12 +495,14 @@
this.getChunkSource().tick(shouldKeepTicking, true);
gameprofilerfiller.popPush("blockEvents");
if (flag) {
@@ -230,7 +327,7 @@
if (flag1) {
this.resetEmptyTime();
@@ -353,12 +413,15 @@
@@ -353,12 +510,15 @@
if (flag1 || this.emptyTime++ < 300) {
gameprofilerfiller.push("entities");
@@ -246,7 +343,7 @@
this.entityTickList.forEach((entity) -> {
if (!entity.isRemoved()) {
if (!tickratemanager.isEntityFrozen(entity)) {
@@ -383,6 +446,8 @@
@@ -383,6 +543,8 @@
}
}
});
@@ -255,7 +352,7 @@
gameprofilerfiller.pop();
this.tickBlockEntities();
}
@@ -429,7 +494,7 @@
@@ -429,7 +591,7 @@
private void wakeUpAllPlayers() {
this.sleepStatus.removeAllSleepers();
@@ -264,7 +361,7 @@
entityplayer.stopSleepInBed(false, false);
});
}
@@ -442,7 +507,7 @@
@@ -442,7 +604,7 @@
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push("thunder");
@@ -273,7 +370,7 @@
BlockPos blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
if (this.isRainingAt(blockposition)) {
@@ -456,7 +521,7 @@
@@ -456,7 +618,7 @@
entityhorseskeleton.setTrap(true);
entityhorseskeleton.setAge(0);
entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ());
@@ -282,7 +379,7 @@
}
}
@@ -465,7 +530,7 @@
@@ -465,7 +627,7 @@
if (entitylightning != null) {
entitylightning.moveTo(Vec3.atBottomCenterOf(blockposition));
entitylightning.setVisualOnly(flag1);
@@ -291,7 +388,7 @@
}
}
}
@@ -521,7 +586,7 @@
@@ -521,7 +683,7 @@
Biome biomebase = (Biome) this.getBiome(blockposition1).value();
if (biomebase.shouldFreeze(this, blockposition2)) {
@@ -300,7 +397,7 @@
}
if (this.isRaining()) {
@@ -537,10 +602,10 @@
@@ -537,10 +699,10 @@
BlockState iblockdata1 = (BlockState) iblockdata.setValue(SnowLayerBlock.LAYERS, j + 1);
Block.pushEntitiesUp(iblockdata, iblockdata1, this, blockposition1);
@@ -313,7 +410,7 @@
}
}
@@ -701,33 +766,67 @@
@@ -701,33 +863,67 @@
this.rainLevel = Mth.clamp(this.rainLevel, 0.0F, 1.0F);
}
@@ -331,9 +428,10 @@
if (flag != this.isRaining()) {
if (flag) {
- this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.STOP_RAINING, 0.0F));
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.STOP_RAINING, 0.0F));
} else {
- } else {
- this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.START_RAINING, 0.0F));
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.STOP_RAINING, 0.0F));
+ } else {
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.START_RAINING, 0.0F));
}
@@ -341,14 +439,14 @@
- this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, this.thunderLevel));
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.RAIN_LEVEL_CHANGE, this.rainLevel));
+ this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.THUNDER_LEVEL_CHANGE, this.thunderLevel));
+ }
}
+ // */
+ for (int idx = 0; idx < this.players.size(); ++idx) {
+ if (((ServerPlayer) this.players.get(idx)).level() == this) {
+ ((ServerPlayer) this.players.get(idx)).tickWeather();
+ }
+ }
+
+ if (flag != this.isRaining()) {
+ // Only send weather packets to those affected
+ for (int idx = 0; idx < this.players.size(); ++idx) {
@@ -361,9 +459,9 @@
+ if (((ServerPlayer) this.players.get(idx)).level() == this) {
+ ((ServerPlayer) this.players.get(idx)).updateWeather(this.oRainLevel, this.rainLevel, this.oThunderLevel, this.thunderLevel);
+ }
}
+ }
+ // CraftBukkit end
+
}
@VisibleForTesting
@@ -389,7 +487,7 @@
}
public void resetEmptyTime() {
@@ -754,6 +853,14 @@
@@ -754,6 +950,14 @@
}
public void tickNonPassenger(Entity entity) {
@@ -404,7 +502,7 @@
entity.setOldPosAndRot();
ProfilerFiller gameprofilerfiller = Profiler.get();
@@ -763,6 +870,7 @@
@@ -763,6 +967,7 @@
});
gameprofilerfiller.incrementCounter("tickNonPassenger");
entity.tick();
@@ -412,7 +510,7 @@
gameprofilerfiller.pop();
Iterator iterator = entity.getPassengers().iterator();
@@ -771,6 +879,7 @@
@@ -771,6 +976,7 @@
this.tickPassenger(entity, entity1);
}
@@ -420,7 +518,7 @@
}
@@ -786,6 +895,7 @@
@@ -786,6 +992,7 @@
});
gameprofilerfiller.incrementCounter("tickPassenger");
passenger.rideTick();
@@ -428,7 +526,7 @@
gameprofilerfiller.pop();
Iterator iterator = passenger.getPassengers().iterator();
@@ -810,6 +920,7 @@
@@ -810,6 +1017,7 @@
ServerChunkCache chunkproviderserver = this.getChunkSource();
if (!savingDisabled) {
@@ -436,7 +534,7 @@
if (progressListener != null) {
progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel"));
}
@@ -827,11 +938,19 @@
@@ -827,11 +1035,19 @@
}
}
@@ -457,21 +555,21 @@
}
DimensionDataStorage worldpersistentdata = this.getChunkSource().getDataStorage();
@@ -903,18 +1022,40 @@
@@ -903,18 +1119,40 @@
@Override
public boolean addFreshEntity(Entity entity) {
- return this.addEntity(entity);
+ // CraftBukkit start
+ return this.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.DEFAULT);
+ }
+
}
+ @Override
+ public boolean addFreshEntity(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
+ return this.addEntity(entity, reason);
+ // CraftBukkit end
}
+ }
+
public boolean addWithUUID(Entity entity) {
- return this.addEntity(entity);
+ // CraftBukkit start
@@ -501,7 +599,7 @@
}
}
@@ -939,41 +1080,86 @@
@@ -939,41 +1177,86 @@
this.entityManager.addNewEntity(player);
}
@@ -593,20 +691,20 @@
while (iterator.hasNext()) {
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
@@ -982,6 +1168,12 @@
@@ -981,6 +1264,12 @@
double d0 = (double) pos.getX() - entityplayer.getX();
double d1 = (double) pos.getY() - entityplayer.getY();
double d2 = (double) pos.getZ() - entityplayer.getZ();
+
+ // CraftBukkit start
+ if (entityhuman != null && !entityplayer.getBukkitEntity().canSee(entityhuman.getBukkitEntity())) {
+ continue;
+ }
+ // CraftBukkit end
+
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
entityplayer.connection.send(new ClientboundBlockDestructionPacket(entityId, pos, progress));
}
@@ -1060,7 +1252,18 @@
@@ -1060,7 +1349,18 @@
Iterator iterator = this.navigatingMobs.iterator();
while (iterator.hasNext()) {
@@ -626,7 +724,7 @@
PathNavigation navigationabstract = entityinsentient.getNavigation();
if (navigationabstract.shouldRecomputePath(pos)) {
@@ -1126,9 +1329,15 @@
@@ -1126,9 +1426,15 @@
@Override
public void explode(@Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Level.ExplosionInteraction explosionSourceType, ParticleOptions smallParticle, ParticleOptions largeParticle, Holder<SoundEvent> soundEvent) {
@@ -643,7 +741,7 @@
case NONE:
explosion_effect = Explosion.BlockInteraction.KEEP;
break;
@@ -1144,16 +1353,26 @@
@@ -1144,16 +1450,26 @@
case TRIGGER:
explosion_effect = Explosion.BlockInteraction.TRIGGER_BLOCK;
break;
@@ -673,7 +771,7 @@
Iterator iterator = this.players.iterator();
while (iterator.hasNext()) {
@@ -1162,10 +1381,11 @@
@@ -1162,10 +1478,11 @@
if (entityplayer.distanceToSqr(vec3d) < 4096.0D) {
Optional<Vec3> optional = Optional.ofNullable((Vec3) serverexplosion.getHitPlayers().get(entityplayer));
@@ -686,7 +784,7 @@
}
private Explosion.BlockInteraction getDestroyType(GameRules.Key<GameRules.BooleanValue> decayRule) {
@@ -1226,17 +1446,24 @@
@@ -1226,17 +1543,24 @@
}
public <T extends ParticleOptions> int sendParticles(T parameters, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double speed) {
@@ -714,7 +812,7 @@
++j;
}
}
@@ -1292,7 +1519,7 @@
@@ -1292,7 +1616,7 @@
@Nullable
public BlockPos findNearestMapStructure(TagKey<Structure> structureTag, BlockPos pos, int radius, boolean skipReferencedStructures) {
@@ -723,7 +821,7 @@
return null;
} else {
Optional<HolderSet.Named<Structure>> optional = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag);
@@ -1334,11 +1561,22 @@
@@ -1334,11 +1658,22 @@
@Nullable
@Override
public MapItemSavedData getMapData(MapId id) {
@@ -747,7 +845,7 @@
this.getServer().overworld().getDataStorage().set(id.key(), state);
}
@@ -1649,6 +1887,11 @@
@@ -1649,6 +1984,11 @@
@Override
public void blockUpdated(BlockPos pos, Block block) {
if (!this.isDebug()) {
@@ -759,7 +857,7 @@
this.updateNeighborsAt(pos, block);
}
@@ -1668,12 +1911,12 @@
@@ -1668,12 +2008,12 @@
}
public boolean isFlat() {
@@ -774,7 +872,7 @@
}
@Nullable
@@ -1696,7 +1939,7 @@
@@ -1696,7 +2036,7 @@
private static <T> String getTypeCount(Iterable<T> items, Function<T, String> classifier) {
try {
Object2IntOpenHashMap<String> object2intopenhashmap = new Object2IntOpenHashMap();
@@ -783,7 +881,7 @@
while (iterator.hasNext()) {
T t0 = iterator.next();
@@ -1705,7 +1948,7 @@
@@ -1705,7 +2045,7 @@
object2intopenhashmap.addTo(s, 1);
}
@@ -792,7 +890,7 @@
String s1 = (String) entry.getKey();
return s1 + ":" + entry.getIntValue();
@@ -1717,6 +1960,7 @@
@@ -1717,6 +2057,7 @@
@Override
public LevelEntityGetter<Entity> getEntities() {
@@ -800,7 +898,7 @@
return this.entityManager.getEntityGetter();
}
@@ -1836,6 +2080,7 @@
@@ -1836,6 +2177,7 @@
}
public void onTrackingStart(Entity entity) {
@@ -808,7 +906,7 @@
ServerLevel.this.getChunkSource().addEntity(entity);
if (entity instanceof ServerPlayer entityplayer) {
ServerLevel.this.players.add(entityplayer);
@@ -1864,9 +2109,42 @@
@@ -1864,9 +2206,42 @@
}
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
@@ -851,7 +949,7 @@
ServerLevel.this.getChunkSource().removeEntity(entity);
if (entity instanceof ServerPlayer entityplayer) {
ServerLevel.this.players.remove(entityplayer);
@@ -1895,6 +2173,14 @@
@@ -1895,6 +2270,14 @@
}
entity.updateDynamicGameEventListener(DynamicGameEventListener::remove);

View File

@@ -112,7 +112,7 @@
@Nullable
private Vec3 startingToFallPosition;
@Nullable
@@ -258,6 +291,22 @@
@@ -258,6 +291,23 @@
private final CommandSource commandSource;
private int containerCounter;
public boolean wonGame;
@@ -132,10 +132,11 @@
+ public boolean sentListPacket = false;
+ public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent
+ // CraftBukkit end
+ public boolean isRealPlayer; // Paper
public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) {
super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile);
@@ -340,6 +389,13 @@
@@ -340,6 +390,13 @@
public void sendSystemMessage(Component message) {
ServerPlayer.this.sendSystemMessage(message);
}
@@ -149,7 +150,7 @@
};
this.textFilter = server.createTextFilterForPlayer(this);
this.gameMode = server.createGameModeForPlayer(this);
@@ -352,14 +408,67 @@
@@ -352,14 +409,67 @@
this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F);
this.updateOptions(clientOptions);
this.object = null;
@@ -218,7 +219,7 @@
int i = Math.max(0, this.server.getSpawnRadius(world));
int j = Mth.floor(world.getWorldBorder().getDistanceToBorder((double) basePos.getX(), (double) basePos.getZ()));
@@ -395,14 +504,20 @@
@@ -395,14 +505,20 @@
Objects.requireNonNull(basePos);
crashreportsystemdetails.setDetail("Origin", basePos::toString);
@@ -241,7 +242,7 @@
});
throw new ReportedException(crashreport);
}
@@ -440,7 +555,7 @@
@@ -440,7 +556,7 @@
dataresult = WardenSpawnTracker.CODEC.parse(new Dynamic(NbtOps.INSTANCE, nbt.get("warden_spawn_tracker")));
logger = ServerPlayer.LOGGER;
Objects.requireNonNull(logger);
@@ -250,7 +251,7 @@
this.wardenSpawnTracker = wardenspawntracker;
});
}
@@ -457,17 +572,26 @@
@@ -457,17 +573,26 @@
return this.server.getRecipeManager().byKey(resourcekey).isPresent();
});
}
@@ -278,7 +279,7 @@
Logger logger1 = ServerPlayer.LOGGER;
Objects.requireNonNull(logger1);
@@ -482,7 +606,7 @@
@@ -482,7 +607,7 @@
dataresult = BlockPos.CODEC.parse(NbtOps.INSTANCE, nbtbase);
logger = ServerPlayer.LOGGER;
Objects.requireNonNull(logger);
@@ -287,7 +288,7 @@
this.raidOmenPosition = blockposition;
});
}
@@ -492,7 +616,7 @@
@@ -492,7 +617,7 @@
@Override
public void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
@@ -296,7 +297,7 @@
Logger logger = ServerPlayer.LOGGER;
Objects.requireNonNull(logger);
@@ -526,6 +650,7 @@
@@ -526,6 +651,7 @@
nbt.put("SpawnDimension", nbtbase);
});
}
@@ -304,7 +305,7 @@
nbt.putBoolean("spawn_extra_particles_on_fall", this.spawnExtraParticlesOnFall);
if (this.raidOmenPosition != null) {
@@ -544,7 +669,20 @@
@@ -544,7 +670,20 @@
Entity entity = this.getRootVehicle();
Entity entity1 = this.getVehicle();
@@ -326,7 +327,7 @@
CompoundTag nbttagcompound1 = new CompoundTag();
CompoundTag nbttagcompound2 = new CompoundTag();
@@ -598,12 +736,12 @@
@@ -598,12 +737,12 @@
if (!this.isPassenger()) {
ServerPlayer.LOGGER.warn("Couldn't reattach entity to player");
@@ -341,7 +342,7 @@
}
}
}
@@ -625,7 +763,7 @@
@@ -625,7 +764,7 @@
CompoundTag nbttagcompound1 = new CompoundTag();
entityenderpearl.save(nbttagcompound1);
@@ -350,7 +351,7 @@
Logger logger = ServerPlayer.LOGGER;
Objects.requireNonNull(logger);
@@ -651,7 +789,7 @@
@@ -651,7 +790,7 @@
nbttaglist.forEach((nbtbase1) -> {
if (nbtbase1 instanceof CompoundTag nbttagcompound) {
if (nbttagcompound.contains("ender_pearl_dimension")) {
@@ -359,7 +360,7 @@
Logger logger = ServerPlayer.LOGGER;
Objects.requireNonNull(logger);
@@ -684,7 +822,30 @@
@@ -684,7 +823,30 @@
}
}
@@ -390,7 +391,7 @@
public void setExperiencePoints(int points) {
float f = (float) this.getXpNeededForNextLevel();
@@ -744,6 +905,11 @@
@@ -744,6 +906,11 @@
@Override
public void tick() {
@@ -402,7 +403,7 @@
this.tickClientLoadTimeout();
this.gameMode.tick();
this.wardenSpawnTracker.tick();
@@ -820,7 +986,7 @@
@@ -820,7 +987,7 @@
}
if (this.getHealth() != this.lastSentHealth || this.lastSentFood != this.foodData.getFoodLevel() || this.foodData.getSaturationLevel() == 0.0F != this.lastFoodSaturationZero) {
@@ -411,7 +412,7 @@
this.lastSentHealth = this.getHealth();
this.lastSentFood = this.foodData.getFoodLevel();
this.lastFoodSaturationZero = this.foodData.getSaturationLevel() == 0.0F;
@@ -851,6 +1017,12 @@
@@ -851,6 +1018,12 @@
this.updateScoreForCriteria(ObjectiveCriteria.EXPERIENCE, Mth.ceil((float) this.lastRecordedExperience));
}
@@ -424,17 +425,15 @@
if (this.experienceLevel != this.lastRecordedLevel) {
this.lastRecordedLevel = this.experienceLevel;
this.updateScoreForCriteria(ObjectiveCriteria.LEVEL, Mth.ceil((float) this.lastRecordedLevel));
@@ -863,8 +1035,22 @@
if (this.tickCount % 20 == 0) {
@@ -865,6 +1038,20 @@
CriteriaTriggers.LOCATION.trigger(this);
+ }
+
}
+ // CraftBukkit start - initialize oldLevel, fire PlayerLevelChangeEvent, and tick client-sided world border
+ if (this.oldLevel == -1) {
+ this.oldLevel = this.experienceLevel;
}
+ }
+
+ if (this.oldLevel != this.experienceLevel) {
+ CraftEventFactory.callPlayerLevelChangeEvent(this.getBukkitEntity(), this.oldLevel, this.experienceLevel);
+ this.oldLevel = this.experienceLevel;
@@ -447,7 +446,7 @@
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking player");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Player being ticked");
@@ -893,7 +1079,7 @@
@@ -893,7 +1080,7 @@
if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.serverLevel().getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION)) {
if (this.tickCount % 20 == 0) {
if (this.getHealth() < this.getMaxHealth()) {
@@ -456,7 +455,7 @@
}
float f = this.foodData.getSaturationLevel();
@@ -946,7 +1132,8 @@
@@ -946,7 +1133,8 @@
}
private void updateScoreForCriteria(ObjectiveCriteria criterion, int score) {
@@ -466,7 +465,7 @@
scoreaccess.set(score);
});
}
@@ -955,10 +1142,48 @@
@@ -955,9 +1143,47 @@
public void die(DamageSource damageSource) {
this.gameEvent(GameEvent.ENTITY_DIE);
boolean flag = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES);
@@ -489,7 +488,7 @@
+ // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule)
+ this.dropFromLootTable(this.serverLevel(), damageSource, this.lastHurtByPlayerTime > 0);
+ this.dropCustomDeathLoot(this.serverLevel(), damageSource, flag);
+
+ loot.addAll(this.drops);
+ this.drops.clear(); // SPIGOT-5188: make sure to clear
+
@@ -513,11 +512,10 @@
+ } else {
+ ichatbasecomponent = org.bukkit.craftbukkit.util.CraftChatMessage.fromStringOrNull(deathMessage);
+ }
+
this.connection.send(new ClientboundPlayerCombatKillPacket(this.getId(), ichatbasecomponent), PacketSendListener.exceptionallySend(() -> {
boolean flag1 = true;
String s = ichatbasecomponent.getString(256);
@@ -988,12 +1213,18 @@
@@ -988,12 +1214,18 @@
if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_FORGIVE_DEAD_PLAYERS)) {
this.tellNeutralMobsThatIDied();
}
@@ -540,7 +538,7 @@
LivingEntity entityliving = this.getKillCredit();
if (entityliving != null) {
@@ -1028,10 +1259,12 @@
@@ -1028,10 +1260,12 @@
public void awardKillScore(Entity entityKilled, DamageSource damageSource) {
if (entityKilled != this) {
super.awardKillScore(entityKilled, damageSource);
@@ -556,7 +554,7 @@
} else {
this.awardStat(Stats.MOB_KILLS);
}
@@ -1049,7 +1282,8 @@
@@ -1049,7 +1283,8 @@
int i = scoreboardteam.getColor().getId();
if (i >= 0 && i < criterions.length) {
@@ -566,7 +564,7 @@
}
}
@@ -1062,8 +1296,8 @@
@@ -1062,8 +1297,8 @@
} else {
Entity entity = source.getEntity();
@@ -577,7 +575,7 @@
if (!this.canHarmPlayer(entityhuman)) {
return false;
@@ -1074,8 +1308,8 @@
@@ -1074,8 +1309,8 @@
AbstractArrow entityarrow = (AbstractArrow) entity;
Entity entity1 = entityarrow.getOwner();
@@ -588,7 +586,7 @@
if (!this.canHarmPlayer(entityhuman1)) {
return false;
@@ -1088,33 +1322,63 @@
@@ -1088,33 +1323,63 @@
}
@Override
@@ -659,7 +657,7 @@
}
public static Optional<ServerPlayer.RespawnPosAngle> findRespawnAndUseSpawnBlock(ServerLevel world, BlockPos pos, float spawnAngle, boolean spawnForced, boolean alive) {
@@ -1129,11 +1393,11 @@
@@ -1129,11 +1394,11 @@
}
return optional.map((vec3d) -> {
@@ -673,7 +671,7 @@
});
} else if (!spawnForced) {
return Optional.empty();
@@ -1142,7 +1406,7 @@
@@ -1142,7 +1407,7 @@
BlockState iblockdata1 = world.getBlockState(pos.above());
boolean flag3 = iblockdata1.getBlock().isPossibleToRespawnInThis(iblockdata1);
@@ -682,7 +680,7 @@
}
}
@@ -1160,6 +1424,7 @@
@@ -1160,6 +1425,7 @@
@Nullable
@Override
public ServerPlayer teleport(TeleportTransition teleportTarget) {
@@ -690,7 +688,7 @@
if (this.isRemoved()) {
return null;
} else {
@@ -1169,39 +1434,73 @@
@@ -1169,39 +1435,73 @@
ServerLevel worldserver = teleportTarget.newLevel();
ServerLevel worldserver1 = this.serverLevel();
@@ -772,7 +770,7 @@
this.connection.resetPosition();
worldserver.addDuringTeleport(this);
gameprofilerfiller.pop();
@@ -1215,12 +1514,30 @@
@@ -1215,12 +1515,30 @@
this.lastSentExp = -1;
this.lastSentHealth = -1.0F;
this.lastSentFood = -1;
@@ -803,7 +801,7 @@
public void forceSetRotation(float yaw, float pitch) {
this.connection.send(new ClientboundPlayerRotationPacket(yaw, pitch));
}
@@ -1228,13 +1545,21 @@
@@ -1228,13 +1546,21 @@
public void triggerDimensionChangeTriggers(ServerLevel origin) {
ResourceKey<Level> resourcekey = origin.dimension();
ResourceKey<Level> resourcekey1 = this.level().dimension();
@@ -828,7 +826,7 @@
this.enteredNetherPosition = null;
}
@@ -1251,36 +1576,63 @@
@@ -1251,36 +1577,63 @@
this.containerMenu.broadcastChanges();
}
@@ -907,7 +905,7 @@
this.awardStat(Stats.SLEEP_IN_BED);
CriteriaTriggers.SLEPT_IN_BED.trigger(this);
});
@@ -1293,9 +1645,8 @@
@@ -1293,9 +1646,8 @@
return either;
}
}
@@ -918,7 +916,7 @@
}
@Override
@@ -1322,13 +1673,31 @@
@@ -1322,13 +1674,31 @@
@Override
public void stopSleepInBed(boolean skipSleepTimer, boolean updateSleepingPlayers) {
@@ -951,7 +949,7 @@
}
}
@@ -1387,8 +1756,9 @@
@@ -1387,8 +1757,9 @@
this.connection.send(new ClientboundOpenSignEditorPacket(sign.getBlockPos(), front));
}
@@ -962,7 +960,7 @@
}
@Override
@@ -1396,13 +1766,35 @@
@@ -1396,13 +1767,35 @@
if (factory == null) {
return OptionalInt.empty();
} else {
@@ -998,7 +996,7 @@
if (container == null) {
if (this.isSpectator()) {
this.displayClientMessage(Component.translatable("container.spectatorCantOpen").withStyle(ChatFormatting.RED), true);
@@ -1410,9 +1802,11 @@
@@ -1410,9 +1803,11 @@
return OptionalInt.empty();
} else {
@@ -1012,7 +1010,7 @@
return OptionalInt.of(this.containerCounter);
}
}
@@ -1425,15 +1819,26 @@
@@ -1425,15 +1820,26 @@
@Override
public void openHorseInventory(AbstractHorse horse, Container inventory) {
@@ -1041,7 +1039,7 @@
this.initMenu(this.containerMenu);
}
@@ -1456,6 +1861,7 @@
@@ -1456,6 +1862,7 @@
@Override
public void closeContainer() {
@@ -1049,7 +1047,7 @@
this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
this.doCloseContainer();
}
@@ -1485,19 +1891,19 @@
@@ -1485,19 +1892,19 @@
i = Math.round((float) Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) * 100.0F);
if (i > 0) {
this.awardStat(Stats.SWIM_ONE_CM, i);
@@ -1072,7 +1070,7 @@
}
} else if (this.onClimbable()) {
if (deltaY > 0.0D) {
@@ -1508,13 +1914,13 @@
@@ -1508,13 +1915,13 @@
if (i > 0) {
if (this.isSprinting()) {
this.awardStat(Stats.SPRINT_ONE_CM, i);
@@ -1089,7 +1087,7 @@
}
}
} else if (this.isFallFlying()) {
@@ -1557,7 +1963,7 @@
@@ -1557,7 +1964,7 @@
@Override
public void awardStat(Stat<?> stat, int amount) {
this.stats.increment(this, stat, amount);
@@ -1098,7 +1096,7 @@
scoreaccess.add(amount);
});
}
@@ -1565,7 +1971,7 @@
@@ -1565,7 +1972,7 @@
@Override
public void resetStat(Stat<?> stat) {
this.stats.setValue(this, stat, 0);
@@ -1107,7 +1105,7 @@
}
@Override
@@ -1597,9 +2003,9 @@
@@ -1597,9 +2004,9 @@
super.jumpFromGround();
this.awardStat(Stats.JUMP);
if (this.isSprinting()) {
@@ -1119,7 +1117,7 @@
}
}
@@ -1625,6 +2031,7 @@
@@ -1625,6 +2032,7 @@
public void resetSentInfo() {
this.lastSentHealth = -1.0E8F;
@@ -1127,7 +1125,7 @@
}
@Override
@@ -1661,7 +2068,7 @@
@@ -1661,7 +2069,7 @@
this.onUpdateAbilities();
if (alive) {
this.getAttributes().assignBaseValues(oldPlayer.getAttributes());
@@ -1136,7 +1134,7 @@
this.setHealth(oldPlayer.getHealth());
this.foodData = oldPlayer.foodData;
Iterator iterator = oldPlayer.getActiveEffects().iterator();
@@ -1669,7 +2076,7 @@
@@ -1669,7 +2077,7 @@
while (iterator.hasNext()) {
MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
@@ -1145,7 +1143,7 @@
}
this.getInventory().replaceWith(oldPlayer.getInventory());
@@ -1680,7 +2087,7 @@
@@ -1680,7 +2088,7 @@
this.portalProcess = oldPlayer.portalProcess;
} else {
this.getAttributes().assignBaseValues(oldPlayer.getAttributes());
@@ -1154,7 +1152,7 @@
if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || oldPlayer.isSpectator()) {
this.getInventory().replaceWith(oldPlayer.getInventory());
this.experienceLevel = oldPlayer.experienceLevel;
@@ -1696,7 +2103,7 @@
@@ -1696,7 +2104,7 @@
this.lastSentExp = -1;
this.lastSentHealth = -1.0F;
this.lastSentFood = -1;
@@ -1163,7 +1161,7 @@
this.seenCredits = oldPlayer.seenCredits;
this.enteredNetherPosition = oldPlayer.enteredNetherPosition;
this.chunkTrackingView = oldPlayer.chunkTrackingView;
@@ -1752,19 +2159,19 @@
@@ -1752,19 +2160,19 @@
}
@Override
@@ -1187,7 +1185,7 @@
}
return flag1;
@@ -1878,6 +2285,16 @@
@@ -1878,6 +2286,16 @@
}
public void updateOptions(ClientInformation clientOptions) {
@@ -1204,7 +1202,7 @@
this.language = clientOptions.language();
this.requestedViewDistance = clientOptions.viewDistance();
this.chatVisibility = clientOptions.chatVisibility();
@@ -1962,7 +2379,7 @@
@@ -1962,7 +2380,7 @@
if (world instanceof ServerLevel) {
ServerLevel worldserver = (ServerLevel) world;
@@ -1213,7 +1211,7 @@
}
if (entity != null) {
@@ -1999,11 +2416,11 @@
@@ -1999,11 +2417,11 @@
@Nullable
public Component getTabListDisplayName() {
@@ -1227,7 +1225,7 @@
}
@Override
@@ -2046,17 +2463,43 @@
@@ -2046,17 +2464,43 @@
}
public void setRespawnPosition(ResourceKey<Level> dimension, @Nullable BlockPos pos, float angle, boolean forced, boolean sendMessage) {
@@ -1278,7 +1276,7 @@
} else {
this.respawnPosition = null;
this.respawnDimension = Level.OVERWORLD;
@@ -2088,18 +2531,44 @@
@@ -2088,18 +2532,44 @@
}
@Override
@@ -1327,7 +1325,7 @@
}
this.awardStat(Stats.DROP);
@@ -2375,16 +2844,160 @@
@@ -2375,16 +2845,160 @@
return TicketType.ENDER_PEARL.timeout();
}

View File

@@ -1,11 +1,20 @@
--- a/net/minecraft/server/level/TicketType.java
+++ b/net/minecraft/server/level/TicketType.java
@@ -22,6 +22,8 @@
@@ -7,6 +7,7 @@
import net.minecraft.world.level.ChunkPos;
public class TicketType<T> {
+ public static final TicketType<Long> FUTURE_AWAIT = create("future_await", Long::compareTo); // Paper
private final String name;
private final Comparator<T> comparator;
@@ -22,6 +23,9 @@
public static final TicketType<BlockPos> PORTAL = TicketType.create("portal", Vec3i::compareTo, 300);
public static final TicketType<ChunkPos> ENDER_PEARL = TicketType.create("ender_pearl", Comparator.comparingLong(ChunkPos::toLong), 40);
public static final TicketType<ChunkPos> UNKNOWN = TicketType.create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1);
+ public static final TicketType<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit
+ public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit
+ public static final TicketType<Integer> POST_TELEPORT = TicketType.create("post_teleport", Integer::compare, 5); // Paper - post teleport ticket type
public static <T> TicketType<T> create(String name, Comparator<T> argumentComparator) {
return new TicketType<>(name, argumentComparator, 0L);

View File

@@ -1,6 +1,34 @@
--- a/net/minecraft/server/level/WorldGenRegion.java
+++ b/net/minecraft/server/level/WorldGenRegion.java
@@ -217,7 +217,7 @@
@@ -169,7 +169,27 @@
return k < this.generatingStep.directDependencies().size();
}
+ // Paper start - if loaded util
+ @Nullable
@Override
+ public ChunkAccess getChunkIfLoadedImmediately(int x, int z) {
+ return this.getChunk(x, z, ChunkStatus.FULL, false);
+ }
+
+ @Override
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
+ ChunkAccess chunk = this.getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ return chunk == null ? null : chunk.getBlockState(blockposition);
+ }
+
+ @Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ ChunkAccess chunk = this.getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ return chunk == null ? null : chunk.getFluidState(blockposition);
+ }
+ // Paper end
+
+ @Override
public BlockState getBlockState(BlockPos pos) {
return this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())).getBlockState(pos);
}
@@ -217,7 +237,7 @@
if (iblockdata.isAir()) {
return false;
} else {
@@ -9,7 +37,7 @@
BlockEntity tileentity = iblockdata.hasBlockEntity() ? this.getBlockEntity(pos) : null;
Block.dropResources(iblockdata, this.level, pos, tileentity, breakingEntity, ItemStack.EMPTY);
@@ -336,6 +336,13 @@
@@ -336,6 +356,13 @@
@Override
public boolean addFreshEntity(Entity entity) {

View File

@@ -90,8 +90,11 @@
this.server = server;
this.registries = registryManager;
this.maxPlayers = maxPlayers;
@@ -150,25 +183,34 @@
@@ -148,27 +181,37 @@
}
public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) {
+ player.isRealPlayer = true; // Paper
GameProfile gameprofile = player.getGameProfile();
GameProfileCache usercache = this.server.getProfileCache();
- Optional optional;
@@ -130,7 +133,7 @@
ServerLevel worldserver = this.server.getLevel(resourcekey);
ServerLevel worldserver1;
@@ -182,10 +224,24 @@
@@ -182,10 +225,24 @@
player.setServerLevel(worldserver1);
String s1 = connection.getLoggableAddress(this.server.logIPs());
@@ -157,7 +160,7 @@
ServerGamePacketListenerImpl playerconnection = new ServerGamePacketListenerImpl(this.server, connection, player, clientData);
connection.setupInboundProtocol(GameProtocols.SERVERBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess())), playerconnection);
@@ -194,7 +250,9 @@
@@ -194,7 +251,9 @@
boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO);
boolean flag2 = gamerules.getBoolean(GameRules.RULE_LIMITED_CRAFTING);
@@ -168,7 +171,7 @@
playerconnection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked()));
playerconnection.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities()));
playerconnection.send(new ClientboundSetHeldSlotPacket(player.getInventory().selected));
@@ -213,8 +271,10 @@
@@ -213,8 +272,10 @@
} else {
ichatmutablecomponent = Component.translatable("multiplayer.player.joined.renamed", player.getDisplayName(), s);
}
@@ -180,7 +183,7 @@
playerconnection.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot());
ServerStatus serverping = this.server.getStatus();
@@ -222,17 +282,71 @@
@@ -222,17 +283,71 @@
player.sendServerStatus(serverping);
}
@@ -256,7 +259,7 @@
}
public void updateEntireScoreboard(ServerScoreboard scoreboard, ServerPlayer player) {
@@ -269,30 +383,31 @@
@@ -269,30 +384,31 @@
}
public void addWorldborderListener(ServerLevel world) {
@@ -293,7 +296,7 @@
}
@Override
@@ -319,14 +434,15 @@
@@ -319,14 +435,15 @@
}
protected void save(ServerPlayer player) {
@@ -311,7 +314,7 @@
if (advancementdataplayer != null) {
advancementdataplayer.save();
@@ -334,95 +450,176 @@
@@ -334,95 +451,176 @@
}
@@ -527,7 +530,7 @@
if (entityplayer1 != null) {
set.add(entityplayer1);
@@ -431,30 +628,50 @@
@@ -431,30 +629,50 @@
Iterator iterator1 = set.iterator();
while (iterator1.hasNext()) {
@@ -591,7 +594,7 @@
while (iterator.hasNext()) {
String s = (String) iterator.next();
@@ -462,41 +679,87 @@
@@ -462,41 +680,88 @@
entityplayer1.addTag(s);
}
@@ -617,6 +620,7 @@
- entityplayer1.moveTo(vec3d.x, vec3d.y, vec3d.z, teleporttransition.yRot(), teleporttransition.xRot());
+ entityplayer1.forceSetPositionRotation(vec3d.x, vec3d.y, vec3d.z, teleporttransition.yRot(), teleporttransition.xRot());
+ worldserver.getChunkSource().addRegionTicket(net.minecraft.server.level.TicketType.POST_TELEPORT, new net.minecraft.world.level.ChunkPos(net.minecraft.util.Mth.floor(vec3d.x()) >> 4, net.minecraft.util.Mth.floor(vec3d.z()) >> 4), 1, entityplayer.getId()); // Paper - post teleport ticket type
+ // CraftBukkit end
if (teleporttransition.missingRespawnBlock()) {
entityplayer1.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F));
@@ -687,7 +691,7 @@
return entityplayer1;
}
@@ -524,7 +787,18 @@
@@ -524,7 +789,18 @@
public void tick() {
if (++this.sendAllPlayerInfoIn > 600) {
@@ -707,7 +711,7 @@
this.sendAllPlayerInfoIn = 0;
}
@@ -541,6 +815,25 @@
@@ -541,6 +817,25 @@
}
@@ -733,7 +737,7 @@
public void broadcastAll(Packet<?> packet, ResourceKey<Level> dimension) {
Iterator iterator = this.players.iterator();
@@ -554,7 +847,7 @@
@@ -554,7 +849,7 @@
}
@@ -742,7 +746,7 @@
PlayerTeam scoreboardteam = source.getTeam();
if (scoreboardteam != null) {
@@ -573,7 +866,7 @@
@@ -573,7 +868,7 @@
}
}
@@ -751,7 +755,7 @@
PlayerTeam scoreboardteam = source.getTeam();
if (scoreboardteam == null) {
@@ -619,7 +912,7 @@
@@ -619,7 +914,7 @@
}
public void deop(GameProfile profile) {
@@ -760,7 +764,7 @@
ServerPlayer entityplayer = this.getPlayer(profile.getId());
if (entityplayer != null) {
@@ -643,6 +936,7 @@
@@ -643,6 +938,7 @@
player.connection.send(new ClientboundEntityEventPacket(player, b0));
}
@@ -768,7 +772,7 @@
this.server.getCommands().sendCommands(player);
}
@@ -656,23 +950,19 @@
@@ -656,23 +952,19 @@
@Nullable
public ServerPlayer getPlayerByName(String name) {
@@ -800,7 +804,7 @@
if (entityplayer != player && entityplayer.level().dimension() == worldKey) {
double d4 = x - entityplayer.getX();
double d5 = y - entityplayer.getY();
@@ -712,15 +1002,19 @@
@@ -712,15 +1004,19 @@
public void reloadWhiteList() {}
public void sendLevelInfo(ServerPlayer player, ServerLevel world) {
@@ -824,7 +828,7 @@
}
player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LEVEL_CHUNKS_LOAD_START, 0.0F));
@@ -729,8 +1023,16 @@
@@ -729,8 +1025,16 @@
public void sendAllPlayerInfo(ServerPlayer player) {
player.inventoryMenu.sendAllDataToRemote();
@@ -842,7 +846,7 @@
}
public int getPlayerCount() {
@@ -786,12 +1088,22 @@
@@ -786,12 +1090,22 @@
}
public void removeAll() {
@@ -867,7 +871,7 @@
public void broadcastSystemMessage(Component message, boolean overlay) {
this.broadcastSystemMessage(message, (entityplayer) -> {
return message;
@@ -849,16 +1161,23 @@
@@ -849,16 +1163,23 @@
return message.hasSignature() && !message.hasExpiredServer(Instant.now());
}
@@ -895,7 +899,7 @@
Path path = file2.toPath();
if (FileUtil.isPathNormalized(path) && FileUtil.isPathPortable(path) && path.startsWith(file.getPath()) && file2.isFile()) {
@@ -867,7 +1186,7 @@
@@ -867,7 +1188,7 @@
}
serverstatisticmanager = new ServerStatsCounter(this.server, file1);
@@ -904,7 +908,7 @@
}
return serverstatisticmanager;
@@ -875,13 +1194,13 @@
@@ -875,13 +1196,13 @@
public PlayerAdvancements getPlayerAdvancements(ServerPlayer player) {
UUID uuid = player.getUUID();
@@ -920,7 +924,7 @@
}
advancementdataplayer.setPlayer(player);
@@ -932,15 +1251,28 @@
@@ -932,15 +1253,28 @@
}
public void reloadResources() {

View File

@@ -0,0 +1,16 @@
--- a/net/minecraft/util/thread/BlockableEventLoop.java
+++ b/net/minecraft/util/thread/BlockableEventLoop.java
@@ -82,6 +82,13 @@
runnable.run();
}
}
+ // Paper start
+ public void scheduleOnMain(Runnable runnable) {
+ // postToMainThread does not work the same as older versions of mc
+ // This method is actually used to create a TickTask, which can then be posted onto main
+ this.schedule(this.wrapRunnable(runnable));
+ }
+ // Paper end
@Override
public void schedule(R runnable) {

View File

@@ -96,7 +96,7 @@
private static final EntityDataAccessor<Integer> DATA_TICKS_FROZEN = SynchedEntityData.defineId(Entity.class, EntityDataSerializers.INT);
private EntityInLevelCallback levelCallback;
private final VecDeltaCodec packetPositionCodec;
@@ -253,7 +312,38 @@
@@ -253,6 +312,42 @@
private final List<Entity.Movement> movementThisTick;
private final Set<BlockState> blocksInside;
private final LongSet visitedBlocks;
@@ -122,7 +122,7 @@
+ public long activatedTick = Integer.MIN_VALUE;
+ public void inactiveTick() { }
+ // Spigot end
+
+ public float getBukkitYaw() {
+ return this.yRot;
+ }
@@ -131,11 +131,15 @@
+ return this.level.hasChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4);
+ }
+ // CraftBukkit end
+
+ // Paper start
+ public final AABB getBoundingBoxAt(double x, double y, double z) {
+ return this.dimensions.makeBoundingBox(x, y, z);
+ }
+ // Paper end
public Entity(EntityType<?> type, Level world) {
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
this.passengers = ImmutableList.of();
@@ -284,6 +374,13 @@
@@ -284,6 +379,13 @@
this.position = Vec3.ZERO;
this.blockPosition = BlockPos.ZERO;
this.chunkPosition = ChunkPos.ZERO;
@@ -149,7 +153,7 @@
SynchedEntityData.Builder datawatcher_a = new SynchedEntityData.Builder(this);
datawatcher_a.define(Entity.DATA_SHARED_FLAGS_ID, (byte) 0);
@@ -292,7 +389,7 @@
@@ -292,7 +394,7 @@
datawatcher_a.define(Entity.DATA_CUSTOM_NAME, Optional.empty());
datawatcher_a.define(Entity.DATA_SILENT, false);
datawatcher_a.define(Entity.DATA_NO_GRAVITY, false);
@@ -158,7 +162,7 @@
datawatcher_a.define(Entity.DATA_TICKS_FROZEN, 0);
this.defineSynchedData(datawatcher_a);
this.entityData = datawatcher_a.build();
@@ -362,20 +459,36 @@
@@ -362,20 +464,36 @@
}
public void kill(ServerLevel world) {
@@ -197,7 +201,7 @@
public boolean equals(Object object) {
return object instanceof Entity ? ((Entity) object).id == this.id : false;
}
@@ -385,22 +498,34 @@
@@ -385,22 +503,34 @@
}
public void remove(Entity.RemovalReason reason) {
@@ -237,7 +241,7 @@
return this.getPose() == pose;
}
@@ -417,6 +542,33 @@
@@ -417,6 +547,33 @@
}
public void setRot(float yaw, float pitch) {
@@ -271,7 +275,7 @@
this.setYRot(yaw % 360.0F);
this.setXRot(pitch % 360.0F);
}
@@ -462,6 +614,15 @@
@@ -462,6 +619,15 @@
this.baseTick();
}
@@ -287,7 +291,7 @@
public void baseTick() {
ProfilerFiller gameprofilerfiller = Profiler.get();
@@ -475,7 +636,7 @@
@@ -475,7 +641,7 @@
--this.boardingCooldown;
}
@@ -296,7 +300,7 @@
if (this.canSpawnSprintParticle()) {
this.spawnSprintParticle();
}
@@ -514,6 +675,10 @@
@@ -514,6 +680,10 @@
if (this.isInLava()) {
this.lavaHurt();
this.fallDistance *= 0.5F;
@@ -307,7 +311,7 @@
}
this.checkBelowWorld();
@@ -525,7 +690,7 @@
@@ -525,7 +695,7 @@
world = this.level();
if (world instanceof ServerLevel worldserver) {
if (this instanceof Leashable) {
@@ -316,7 +320,7 @@
}
}
@@ -568,15 +733,32 @@
@@ -568,15 +738,32 @@
public void lavaHurt() {
if (!this.fireImmune()) {
@@ -351,7 +355,7 @@
}
}
@@ -587,9 +769,25 @@
@@ -587,9 +774,25 @@
}
public final void igniteForSeconds(float seconds) {
@@ -378,7 +382,7 @@
public void igniteForTicks(int ticks) {
if (this.remainingFireTicks < ticks) {
this.setRemainingFireTicks(ticks);
@@ -610,7 +808,7 @@
@@ -610,7 +813,7 @@
}
protected void onBelowWorld() {
@@ -387,7 +391,7 @@
}
public boolean isFree(double offsetX, double offsetY, double offsetZ) {
@@ -672,6 +870,7 @@
@@ -672,6 +875,7 @@
}
public void move(MoverType type, Vec3 movement) {
@@ -395,10 +399,13 @@
if (this.noPhysics) {
this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
} else {
@@ -750,6 +949,28 @@
}
}
@@ -747,8 +951,30 @@
if (movement.y != vec3d1.y) {
block.updateEntityMovementAfterFallOn(this.level(), this);
+ }
+ }
+
+ // CraftBukkit start
+ if (this.horizontalCollision && this.getBukkitEntity() instanceof Vehicle) {
+ Vehicle vehicle = (Vehicle) this.getBukkitEntity();
@@ -412,19 +419,18 @@
+ bl = bl.getRelative(BlockFace.SOUTH);
+ } else if (movement.z < vec3d1.z) {
+ bl = bl.getRelative(BlockFace.NORTH);
+ }
}
+
+ if (!bl.getType().isAir()) {
+ VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl);
+ this.level.getCraftServer().getPluginManager().callEvent(event);
+ }
+ }
}
+ // CraftBukkit end
+
if (!this.level().isClientSide() || this.isControlledByLocalInstance()) {
Entity.MovementEmission entity_movementemission = this.getMovementEmission();
@@ -764,6 +985,7 @@
@@ -764,6 +990,7 @@
gameprofilerfiller.pop();
}
}
@@ -432,7 +438,7 @@
}
private void applyMovementEmissionAndPlaySound(Entity.MovementEmission moveEffect, Vec3 movement, BlockPos landingPos, BlockState landingState) {
@@ -1133,6 +1355,20 @@
@@ -1133,6 +1360,20 @@
return SoundEvents.GENERIC_SPLASH;
}
@@ -453,7 +459,7 @@
public void recordMovementThroughBlocks(Vec3 oldPos, Vec3 newPos) {
this.movementThisTick.add(new Entity.Movement(oldPos, newPos));
}
@@ -1609,6 +1845,7 @@
@@ -1609,6 +1850,7 @@
this.yo = y;
this.zo = d4;
this.setPos(d3, y, d4);
@@ -461,7 +467,7 @@
}
public void moveTo(Vec3 pos) {
@@ -1861,6 +2098,12 @@
@@ -1861,6 +2103,12 @@
return false;
}
@@ -474,7 +480,7 @@
public void awardKillScore(Entity entityKilled, DamageSource damageSource) {
if (entityKilled instanceof ServerPlayer) {
CriteriaTriggers.ENTITY_KILLED_PLAYER.trigger((ServerPlayer) entityKilled, this, damageSource);
@@ -1889,16 +2132,22 @@
@@ -1889,16 +2137,22 @@
}
public boolean saveAsPassenger(CompoundTag nbt) {
@@ -500,7 +506,7 @@
return true;
}
}
@@ -1909,54 +2158,98 @@
@@ -1909,54 +2163,98 @@
}
public CompoundTag saveWithoutId(CompoundTag nbt) {
@@ -619,7 +625,7 @@
}
ListTag nbttaglist;
@@ -1972,10 +2265,10 @@
@@ -1972,10 +2270,10 @@
nbttaglist.add(StringTag.valueOf(s));
}
@@ -632,7 +638,7 @@
if (this.isVehicle()) {
nbttaglist = new ListTag();
iterator = this.getPassengers().iterator();
@@ -1984,17 +2277,22 @@
@@ -1984,17 +2282,22 @@
Entity entity = (Entity) iterator.next();
CompoundTag nbttagcompound1 = new CompoundTag();
@@ -658,11 +664,10 @@
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being saved");
@@ -2079,7 +2377,51 @@
}
@@ -2080,6 +2383,50 @@
} else {
throw new IllegalStateException("Entity has invalid position");
+ }
}
+
+ // CraftBukkit start
+ // Spigot start
@@ -698,7 +703,7 @@
+ }
+
+ ((ServerPlayer) this).setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle());
}
+ }
+ this.getBukkitEntity().readBukkitValues(nbt);
+ if (nbt.contains("Bukkit.invisible")) {
+ boolean bukkitInvisible = nbt.getBoolean("Bukkit.invisible");
@@ -710,7 +715,7 @@
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being loaded");
@@ -2101,6 +2443,12 @@
@@ -2101,6 +2448,12 @@
return entitytypes.canSerialize() && minecraftkey != null ? minecraftkey.toString() : null;
}
@@ -723,7 +728,7 @@
protected abstract void readAdditionalSaveData(CompoundTag nbt);
protected abstract void addAdditionalSaveData(CompoundTag nbt);
@@ -2153,9 +2501,22 @@
@@ -2153,9 +2506,22 @@
if (stack.isEmpty()) {
return null;
} else {
@@ -746,7 +751,7 @@
world.addFreshEntity(entityitem);
return entityitem;
}
@@ -2184,6 +2545,12 @@
@@ -2184,6 +2550,12 @@
if (this.isAlive() && this instanceof Leashable leashable) {
if (leashable.getLeashHolder() == player) {
if (!this.level().isClientSide()) {
@@ -759,7 +764,7 @@
if (player.hasInfiniteMaterials()) {
leashable.removeLeash();
} else {
@@ -2200,6 +2567,13 @@
@@ -2200,6 +2572,13 @@
if (itemstack.is(Items.LEAD) && leashable.canHaveALeashAttachedToIt()) {
if (!this.level().isClientSide()) {
@@ -773,7 +778,7 @@
leashable.setLeashedTo(player, true);
}
@@ -2265,7 +2639,7 @@
@@ -2265,7 +2644,7 @@
}
public boolean showVehicleHealth() {
@@ -782,7 +787,7 @@
}
public boolean startRiding(Entity entity, boolean force) {
@@ -2273,7 +2647,7 @@
@@ -2273,7 +2652,7 @@
return false;
} else if (!entity.couldAcceptPassenger()) {
return false;
@@ -791,7 +796,7 @@
return false;
} else {
for (Entity entity1 = entity; entity1.vehicle != null; entity1 = entity1.vehicle) {
@@ -2285,11 +2659,32 @@
@@ -2285,11 +2664,32 @@
if (!force && (!this.canRide(entity) || !entity.canAddPassenger(this))) {
return false;
} else {
@@ -825,7 +830,7 @@
this.vehicle = entity;
this.vehicle.addPassenger(this);
entity.getIndirectPassengersStream().filter((entity2) -> {
@@ -2318,7 +2713,7 @@
@@ -2318,7 +2718,7 @@
Entity entity = this.vehicle;
this.vehicle = null;
@@ -834,7 +839,7 @@
}
}
@@ -2349,21 +2744,50 @@
@@ -2349,21 +2749,50 @@
}
}
@@ -891,7 +896,7 @@
}
protected boolean canAddPassenger(Entity passenger) {
@@ -2464,7 +2888,7 @@
@@ -2464,7 +2893,7 @@
if (teleporttransition != null) {
ServerLevel worldserver1 = teleporttransition.newLevel();
@@ -900,7 +905,7 @@
this.teleport(teleporttransition);
}
}
@@ -2547,7 +2971,7 @@
@@ -2547,7 +2976,7 @@
}
public boolean isCrouching() {
@@ -909,7 +914,7 @@
}
public boolean isSprinting() {
@@ -2563,7 +2987,7 @@
@@ -2563,7 +2992,7 @@
}
public boolean isVisuallySwimming() {
@@ -918,7 +923,7 @@
}
public boolean isVisuallyCrawling() {
@@ -2571,6 +2995,13 @@
@@ -2571,6 +3000,13 @@
}
public void setSwimming(boolean swimming) {
@@ -932,7 +937,7 @@
this.setSharedFlag(4, swimming);
}
@@ -2624,8 +3055,12 @@
@@ -2624,8 +3060,12 @@
return this.getTeam() != null ? this.getTeam().isAlliedTo(team) : false;
}
@@ -946,7 +951,7 @@
}
public boolean getSharedFlag(int index) {
@@ -2644,7 +3079,7 @@
@@ -2644,7 +3084,7 @@
}
public int getMaxAirSupply() {
@@ -955,7 +960,7 @@
}
public int getAirSupply() {
@@ -2652,7 +3087,18 @@
@@ -2652,7 +3092,18 @@
}
public void setAirSupply(int air) {
@@ -975,7 +980,7 @@
}
public int getTicksFrozen() {
@@ -2679,11 +3125,40 @@
@@ -2679,11 +3130,40 @@
public void thunderHit(ServerLevel world, LightningBolt lightning) {
this.setRemainingFireTicks(this.remainingFireTicks + 1);
@@ -1018,7 +1023,7 @@
}
public void onAboveBubbleCol(boolean drag) {
@@ -2713,7 +3188,7 @@
@@ -2713,7 +3193,7 @@
this.resetFallDistance();
}
@@ -1027,7 +1032,7 @@
return true;
}
@@ -2852,6 +3327,18 @@
@@ -2852,6 +3332,18 @@
if (world instanceof ServerLevel worldserver) {
if (!this.isRemoved()) {
@@ -1046,7 +1051,7 @@
ServerLevel worldserver1 = teleportTarget.newLevel();
boolean flag = worldserver1.dimension() != worldserver.dimension();
@@ -2920,8 +3407,12 @@
@@ -2920,8 +3412,12 @@
} else {
entity.restoreFrom(this);
this.removeAfterChangingDimensions();
@@ -1060,7 +1065,7 @@
Iterator iterator1 = list1.iterator();
while (iterator1.hasNext()) {
@@ -2947,7 +3438,7 @@
@@ -2947,7 +3443,7 @@
}
private void sendTeleportTransitionToRidingPlayers(TeleportTransition teleportTarget) {
@@ -1069,7 +1074,7 @@
Iterator iterator = this.getIndirectPassengers().iterator();
while (iterator.hasNext()) {
@@ -2995,8 +3486,9 @@
@@ -2995,8 +3491,9 @@
}
protected void removeAfterChangingDimensions() {
@@ -1080,7 +1085,7 @@
leashable.removeLeash();
}
@@ -3006,6 +3498,20 @@
@@ -3006,6 +3503,20 @@
return PortalShape.getRelativePosition(portalRect, portalAxis, this.position(), this.getDimensions(this.getPose()));
}
@@ -1101,7 +1106,7 @@
public boolean canUsePortal(boolean allowVehicles) {
return (allowVehicles || !this.isPassenger()) && this.isAlive();
}
@@ -3134,10 +3640,16 @@
@@ -3134,9 +3645,15 @@
return (Boolean) this.entityData.get(Entity.DATA_CUSTOM_NAME_VISIBLE);
}
@@ -1112,16 +1117,15 @@
+ public final boolean teleportTo(ServerLevel world, double destX, double destY, double destZ, Set<Relative> flags, float yaw, float pitch, boolean resetCamera) {
+ return this.teleportTo(world, destX, destY, destZ, flags, yaw, pitch, resetCamera, PlayerTeleportEvent.TeleportCause.UNKNOWN);
+ }
+
+ public boolean teleportTo(ServerLevel worldserver, double d0, double d1, double d2, Set<Relative> set, float f, float f1, boolean flag, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) {
+ float f2 = Mth.clamp(f1, -90.0F, 90.0F);
+ Entity entity = this.teleport(new TeleportTransition(worldserver, new Vec3(d0, d1, d2), Vec3.ZERO, f, f2, set, TeleportTransition.DO_NOTHING, cause));
+ // CraftBukkit end
+
return entity != null;
}
@@ -3187,7 +3699,7 @@
@@ -3187,7 +3704,7 @@
/** @deprecated */
@Deprecated
protected void fixupDimensions() {
@@ -1130,7 +1134,7 @@
EntityDimensions entitysize = this.getDimensions(entitypose);
this.dimensions = entitysize;
@@ -3196,7 +3708,7 @@
@@ -3196,7 +3713,7 @@
public void refreshDimensions() {
EntityDimensions entitysize = this.dimensions;
@@ -1139,7 +1143,7 @@
EntityDimensions entitysize1 = this.getDimensions(entitypose);
this.dimensions = entitysize1;
@@ -3258,10 +3770,29 @@
@@ -3258,10 +3775,29 @@
}
public final void setBoundingBox(AABB boundingBox) {
@@ -1171,7 +1175,7 @@
return this.getDimensions(pose).eyeHeight();
}
@@ -3335,7 +3866,7 @@
@@ -3335,7 +3871,7 @@
}
@Nullable
@@ -1180,7 +1184,7 @@
return null;
}
@@ -3435,7 +3966,7 @@
@@ -3435,7 +3971,7 @@
}
public boolean isControlledByLocalInstance() {
@@ -1189,7 +1193,7 @@
if (entityliving instanceof Player entityhuman) {
return entityhuman.isLocalPlayer();
@@ -3445,7 +3976,7 @@
@@ -3445,7 +3981,7 @@
}
public boolean isControlledByClient() {
@@ -1198,7 +1202,7 @@
return entityliving != null && entityliving.isControlledByClient();
}
@@ -3463,7 +3994,7 @@
@@ -3463,7 +3999,7 @@
return new Vec3((double) f1 * d2 / (double) f3, 0.0D, (double) f2 * d2 / (double) f3);
}
@@ -1207,7 +1211,7 @@
return new Vec3(this.getX(), this.getBoundingBox().maxY, this.getZ());
}
@@ -3489,8 +4020,37 @@
@@ -3489,8 +4025,37 @@
return 1;
}
@@ -1246,7 +1250,7 @@
}
public void lookAt(EntityAnchorArgument.Anchor anchorPoint, Vec3 target) {
@@ -3550,7 +4110,12 @@
@@ -3550,7 +4115,12 @@
vec3d = vec3d.add(vec3d1);
++k1;
@@ -1259,7 +1263,7 @@
}
}
}
@@ -3613,7 +4178,7 @@
@@ -3613,7 +4183,7 @@
return new ClientboundAddEntityPacket(this, entityTrackerEntry);
}
@@ -1268,7 +1272,7 @@
return this.type.getDimensions();
}
@@ -3818,8 +4383,16 @@
@@ -3818,8 +4388,16 @@
@Override
public final void setRemoved(Entity.RemovalReason reason) {
@@ -1286,7 +1290,7 @@
}
if (this.removalReason.shouldDestroy()) {
@@ -3827,8 +4400,8 @@
@@ -3827,8 +4405,8 @@
}
this.getPassengers().forEach(Entity::stopRiding);
@@ -1297,7 +1301,7 @@
}
public void unsetRemoved() {
@@ -3887,7 +4460,7 @@
@@ -3887,7 +4465,7 @@
}
public Vec3 getKnownMovement() {

View File

@@ -68,7 +68,7 @@
public int lastHurtByPlayerTime;
protected boolean dead;
protected int noActionTime;
@@ -260,7 +287,27 @@
@@ -260,6 +287,27 @@
protected boolean skipDropExperience;
private final EnumMap<EquipmentSlot, Reference2ObjectMap<Enchantment, Set<EnchantmentLocationBasedEffect>>> activeLocationDependentEnchantments;
protected float appliedScale;
@@ -79,7 +79,8 @@
+ public boolean collides = true;
+ public Set<UUID> collidableExemptions = new HashSet<>();
+ public boolean bukkitPickUpLoot;
+ public org.bukkit.craftbukkit.entity.CraftLivingEntity getBukkitLivingEntity() { return (org.bukkit.craftbukkit.entity.CraftLivingEntity) super.getBukkitEntity(); } // Paper
+
+ @Override
+ public float getBukkitYaw() {
+ return this.getYHeadRot();
@@ -92,11 +93,10 @@
+ ++this.noActionTime; // Above all the floats
+ }
+ // Spigot end
+
protected LivingEntity(EntityType<? extends LivingEntity> type, Level world) {
super(type, world);
this.lastHandItemStacks = NonNullList.withSize(2, ItemStack.EMPTY);
@@ -276,7 +323,9 @@
@@ -276,7 +324,9 @@
this.activeLocationDependentEnchantments = new EnumMap(EquipmentSlot.class);
this.appliedScale = 1.0F;
this.attributes = new AttributeMap(DefaultAttributes.getSupplier(type));
@@ -107,7 +107,7 @@
this.blocksBuilding = true;
this.rotA = (float) ((Math.random() + 1.0D) * 0.009999999776482582D);
this.reapplyPosition();
@@ -356,7 +405,13 @@
@@ -356,7 +406,13 @@
double d8 = Math.min((double) (0.2F + f / 15.0F), 2.5D);
int i = (int) (150.0D * d8);
@@ -122,7 +122,7 @@
}
}
}
@@ -402,7 +457,7 @@
@@ -402,7 +458,7 @@
}
if (this.isAlive()) {
@@ -131,7 +131,7 @@
Level world1 = this.level();
ServerLevel worldserver1;
double d0;
@@ -424,7 +479,7 @@
@@ -424,7 +480,7 @@
}
if (this.isEyeInFluid(FluidTags.WATER) && !this.level().getBlockState(BlockPos.containing(this.getX(), this.getEyeY(), this.getZ())).is(Blocks.BUBBLE_COLUMN)) {
@@ -140,7 +140,7 @@
if (flag1) {
this.setAirSupply(this.decreaseAirSupply(this.getAirSupply()));
@@ -573,7 +628,7 @@
@@ -573,7 +629,7 @@
++this.deathTime;
if (this.deathTime >= 20 && !this.level().isClientSide() && !this.isRemoved()) {
this.level().broadcastEntityEvent(this, (byte) 60);
@@ -149,7 +149,7 @@
}
}
@@ -629,7 +684,7 @@
@@ -629,7 +685,7 @@
return this.lastHurtByMobTimestamp;
}
@@ -158,25 +158,26 @@
this.lastHurtByPlayer = attacking;
this.lastHurtByPlayerTime = this.tickCount;
}
@@ -679,17 +734,23 @@
@@ -679,17 +735,23 @@
}
public void onEquipItem(EquipmentSlot slot, ItemStack oldStack, ItemStack newStack) {
- if (!this.level().isClientSide() && !this.isSpectator()) {
- boolean flag = newStack.isEmpty() && oldStack.isEmpty();
-
- if (!flag && !ItemStack.isSameItemSameComponents(oldStack, newStack) && !this.firstTick) {
- Equippable equippable = (Equippable) newStack.get(DataComponents.EQUIPPABLE);
+ // CraftBukkit start
+ this.onEquipItem(slot, oldStack, newStack, false);
+ }
- if (!flag && !ItemStack.isSameItemSameComponents(oldStack, newStack) && !this.firstTick) {
- Equippable equippable = (Equippable) newStack.get(DataComponents.EQUIPPABLE);
- if (!this.isSilent() && equippable != null && slot == equippable.slot()) {
- this.level().playSeededSound((Player) null, this.getX(), this.getY(), this.getZ(), equippable.equipSound(), this.getSoundSource(), 1.0F, 1.0F, this.random.nextLong());
+ public void onEquipItem(EquipmentSlot enumitemslot, ItemStack itemstack, ItemStack itemstack1, boolean silent) {
+ // CraftBukkit end
+ if (!this.level().isClientSide() && !this.isSpectator()) {
+ boolean flag = itemstack1.isEmpty() && itemstack.isEmpty();
- if (!this.isSilent() && equippable != null && slot == equippable.slot()) {
- this.level().playSeededSound((Player) null, this.getX(), this.getY(), this.getZ(), equippable.equipSound(), this.getSoundSource(), 1.0F, 1.0F, this.random.nextLong());
+
+ if (!flag && !ItemStack.isSameItemSameComponents(itemstack, itemstack1) && !this.firstTick) {
+ Equippable equippable = (Equippable) itemstack1.get(DataComponents.EQUIPPABLE);
+
@@ -189,7 +190,7 @@
this.gameEvent(equippable != null ? GameEvent.EQUIP : GameEvent.UNEQUIP);
}
@@ -699,17 +760,24 @@
@@ -699,17 +761,24 @@
@Override
public void remove(Entity.RemovalReason reason) {
@@ -217,7 +218,7 @@
this.brain.clearMemories();
}
@@ -722,6 +790,7 @@
@@ -722,6 +791,7 @@
mobeffect.onMobRemoved(world, this, reason);
}
@@ -225,7 +226,7 @@
this.activeEffects.clear();
}
@@ -781,6 +850,17 @@
@@ -781,6 +851,17 @@
}
}
@@ -243,7 +244,7 @@
if (nbt.contains("Health", 99)) {
this.setHealth(nbt.getFloat("Health"));
}
@@ -819,9 +899,32 @@
@@ -819,9 +900,32 @@
}
@@ -276,7 +277,7 @@
try {
while (iterator.hasNext()) {
Holder<MobEffect> holder = (Holder) iterator.next();
@@ -831,6 +934,12 @@
@@ -831,6 +935,12 @@
this.onEffectUpdated(mobeffect, true, (Entity) null);
})) {
if (!this.level().isClientSide) {
@@ -289,7 +290,7 @@
iterator.remove();
this.onEffectsRemoved(List.of(mobeffect));
}
@@ -841,6 +950,17 @@
@@ -841,6 +951,17 @@
} catch (ConcurrentModificationException concurrentmodificationexception) {
;
}
@@ -307,7 +308,7 @@
if (this.effectsDirty) {
if (!this.level().isClientSide) {
@@ -921,7 +1041,7 @@
@@ -921,7 +1042,7 @@
}
public boolean canAttack(LivingEntity target) {
@@ -316,7 +317,7 @@
}
public boolean canBeSeenAsEnemy() {
@@ -952,17 +1072,36 @@
@@ -952,17 +1073,36 @@
this.entityData.set(LivingEntity.DATA_EFFECT_PARTICLES, List.of());
}
@@ -357,7 +358,7 @@
}
}
@@ -987,24 +1126,55 @@
@@ -987,24 +1127,55 @@
return this.addEffect(effect, (Entity) null);
}
@@ -421,7 +422,7 @@
return flag;
}
}
@@ -1031,14 +1201,40 @@
@@ -1031,14 +1202,40 @@
return this.getType().is(EntityTypeTags.INVERTED_HEALING_AND_HARM);
}
@@ -464,7 +465,7 @@
if (mobeffect != null) {
this.onEffectsRemoved(List.of(mobeffect));
return true;
@@ -1142,20 +1338,55 @@
@@ -1142,20 +1339,55 @@
}
@@ -521,7 +522,7 @@
this.entityData.set(LivingEntity.DATA_HEALTH_ID, Mth.clamp(health, 0.0F, this.getMaxHealth()));
}
@@ -1167,7 +1398,7 @@
@@ -1167,7 +1399,7 @@
public boolean hurtServer(ServerLevel world, DamageSource source, float amount) {
if (this.isInvulnerableTo(world, source)) {
return false;
@@ -530,7 +531,7 @@
return false;
} else if (source.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) {
return false;
@@ -1182,10 +1413,11 @@
@@ -1182,10 +1414,11 @@
}
float f1 = amount;
@@ -544,7 +545,7 @@
this.hurtCurrentlyUsedShield(amount);
f2 = amount;
amount = 0.0F;
@@ -1202,15 +1434,26 @@
@@ -1202,15 +1435,26 @@
flag = true;
}
@@ -573,7 +574,7 @@
this.walkAnimation.setSpeed(1.5F);
if (Float.isNaN(amount) || Float.isInfinite(amount)) {
amount = Float.MAX_VALUE;
@@ -1218,18 +1461,27 @@
@@ -1218,18 +1462,27 @@
boolean flag1 = true;
@@ -605,7 +606,7 @@
this.hurtDuration = 10;
this.hurtTime = this.hurtDuration;
}
@@ -1243,7 +1495,7 @@
@@ -1243,7 +1496,7 @@
world.broadcastDamageEvent(this, source);
}
@@ -614,7 +615,7 @@
this.markHurt();
}
@@ -1263,7 +1515,7 @@
@@ -1263,7 +1516,7 @@
d1 = source.getSourcePosition().z() - this.getZ();
}
@@ -623,7 +624,7 @@
if (!flag) {
this.indicateDamage(d0, d1);
}
@@ -1282,7 +1534,7 @@
@@ -1282,7 +1535,7 @@
this.playHurtSound(source);
}
@@ -632,7 +633,7 @@
if (flag2) {
this.lastDamageSource = source;
@@ -1329,10 +1581,10 @@
@@ -1329,10 +1582,10 @@
}
@Nullable
@@ -645,7 +646,7 @@
this.lastHurtByPlayerTime = 100;
this.lastHurtByPlayer = entityhuman;
return entityhuman;
@@ -1342,8 +1594,8 @@
@@ -1342,8 +1595,8 @@
this.lastHurtByPlayerTime = 100;
LivingEntity entityliving = entitywolf.getOwner();
@@ -656,7 +657,7 @@
this.lastHurtByPlayer = entityhuman1;
} else {
@@ -1363,7 +1615,7 @@
@@ -1363,7 +1616,7 @@
}
protected void blockedByShield(LivingEntity target) {
@@ -665,7 +666,7 @@
}
private boolean checkTotemDeathProtection(DamageSource source) {
@@ -1375,20 +1627,33 @@
@@ -1375,20 +1628,33 @@
InteractionHand[] aenumhand = InteractionHand.values();
int i = aenumhand.length;
@@ -703,7 +704,7 @@
ServerPlayer entityplayer = (ServerPlayer) this;
entityplayer.awardStat(Stats.ITEM_USED.get(itemstack.getItem()));
@@ -1477,7 +1742,7 @@
@@ -1477,7 +1743,7 @@
}
if (!this.level().isClientSide && this.hasCustomName()) {
@@ -712,7 +713,7 @@
}
this.dead = true;
@@ -1512,14 +1777,22 @@
@@ -1512,14 +1778,22 @@
BlockState iblockdata = Blocks.WITHER_ROSE.defaultBlockState();
if (this.level().getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level(), blockposition)) {
@@ -737,7 +738,7 @@
this.level().addFreshEntity(entityitem);
}
}
@@ -1530,24 +1803,39 @@
@@ -1530,22 +1804,37 @@
protected void dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
boolean flag = this.lastHurtByPlayerTime > 0;
@@ -767,8 +768,8 @@
}
+ return 0; // CraftBukkit
}
+ }
+
+ protected void dropExperience(ServerLevel world, @Nullable Entity attacker) {
+ // CraftBukkit start - Update getExpReward() above if the removed if() changes!
+ if (!(this instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time
@@ -776,12 +777,10 @@
+ this.expToDrop = 0;
+ }
+ // CraftBukkit end
+ }
+
protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {}
}
public long getLootTableSeed() {
@@ -1612,19 +1900,31 @@
protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {}
@@ -1612,19 +1901,31 @@
}
public void knockback(double strength, double x, double z) {
@@ -820,7 +819,7 @@
}
}
@@ -1683,6 +1983,20 @@
@@ -1683,6 +1984,20 @@
return new LivingEntity.Fallsounds(SoundEvents.GENERIC_SMALL_FALL, SoundEvents.GENERIC_BIG_FALL);
}
@@ -841,7 +840,7 @@
public Optional<BlockPos> getLastClimbablePos() {
return this.lastClimbablePos;
}
@@ -1757,9 +2071,14 @@
@@ -1757,9 +2072,14 @@
int i = this.calculateFallDamage(fallDistance, damageMultiplier);
if (i > 0) {
@@ -857,7 +856,7 @@
return true;
} else {
return flag;
@@ -1830,7 +2149,7 @@
@@ -1830,7 +2150,7 @@
protected float getDamageAfterArmorAbsorb(DamageSource source, float amount) {
if (!source.is(DamageTypeTags.BYPASSES_ARMOR)) {
@@ -866,7 +865,7 @@
amount = CombatRules.getDamageAfterAbsorb(this, amount, source, (float) this.getArmorValue(), (float) this.getAttributeValue(Attributes.ARMOR_TOUGHNESS));
}
@@ -1841,7 +2160,8 @@
@@ -1841,7 +2161,8 @@
if (source.is(DamageTypeTags.BYPASSES_EFFECTS)) {
return amount;
} else {
@@ -876,7 +875,7 @@
int i = (this.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() + 1) * 5;
int j = 25 - i;
float f1 = amount * (float) j;
@@ -1884,18 +2204,144 @@
@@ -1884,18 +2205,144 @@
}
}
@@ -1030,7 +1029,7 @@
if (entity instanceof ServerPlayer) {
ServerPlayer entityplayer = (ServerPlayer) entity;
@@ -1904,13 +2350,48 @@
@@ -1904,13 +2351,48 @@
}
}
@@ -1083,7 +1082,7 @@
}
public CombatTracker getCombatTracker() {
@@ -1935,8 +2416,18 @@
@@ -1935,8 +2417,18 @@
}
public final void setArrowCount(int stuckArrowCount) {
@@ -1103,7 +1102,7 @@
public final int getStingerCount() {
return (Integer) this.entityData.get(LivingEntity.DATA_STINGER_COUNT_ID);
@@ -1999,7 +2490,7 @@
@@ -1999,7 +2491,7 @@
this.playSound(soundeffect, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
}
@@ -1112,7 +1111,7 @@
this.setHealth(0.0F);
this.die(this.damageSources().generic());
}
@@ -2182,6 +2673,12 @@
@@ -2182,6 +2674,12 @@
public abstract ItemStack getItemBySlot(EquipmentSlot slot);
@@ -1125,7 +1124,7 @@
public abstract void setItemSlot(EquipmentSlot slot, ItemStack stack);
public Iterable<ItemStack> getHandSlots() {
@@ -2494,7 +2991,7 @@
@@ -2494,7 +2992,7 @@
}
@@ -1134,7 +1133,7 @@
Vec3 vec3d1 = this.getRiddenInput(controllingPlayer, movementInput);
this.tickRidden(controllingPlayer, vec3d1);
@@ -2507,13 +3004,13 @@
@@ -2507,13 +3005,13 @@
}
@@ -1151,7 +1150,7 @@
return this.getSpeed();
}
@@ -2571,7 +3068,7 @@
@@ -2571,7 +3069,7 @@
double d1 = Mth.clamp(motion.z, -0.15000000596046448D, 0.15000000596046448D);
double d2 = Math.max(motion.y, -0.15000000596046448D);
@@ -1160,7 +1159,7 @@
d2 = 0.0D;
}
@@ -2586,7 +3083,7 @@
@@ -2586,7 +3084,7 @@
}
protected float getFlyingSpeed() {
@@ -1169,7 +1168,7 @@
}
public float getSpeed() {
@@ -2604,6 +3101,7 @@
@@ -2604,6 +3102,7 @@
@Override
public void tick() {
@@ -1177,7 +1176,7 @@
super.tick();
this.updatingUsingItem();
this.updateSwimAmount();
@@ -2634,7 +3132,7 @@
@@ -2634,7 +3133,7 @@
}
}
@@ -1186,7 +1185,7 @@
if (this.tickCount % 20 == 0) {
this.getCombatTracker().recheckStatus();
}
@@ -2645,7 +3143,9 @@
@@ -2645,7 +3144,9 @@
}
if (!this.isRemoved()) {
@@ -1196,7 +1195,7 @@
}
double d0 = this.getX() - this.xo;
@@ -2739,9 +3239,10 @@
@@ -2739,9 +3240,10 @@
}
this.elytraAnimationState.tick();
@@ -1208,7 +1207,7 @@
Map<EquipmentSlot, ItemStack> map = this.collectEquipmentChanges();
if (map != null) {
@@ -2945,6 +3446,7 @@
@@ -2945,6 +3447,7 @@
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push("ai");
@@ -1216,7 +1215,7 @@
if (this.isImmobile()) {
this.jumping = false;
this.xxa = 0.0F;
@@ -2954,6 +3456,7 @@
@@ -2954,6 +3457,7 @@
this.serverAiStep();
gameprofilerfiller.pop();
}
@@ -1224,7 +1223,7 @@
gameprofilerfiller.pop();
gameprofilerfiller.push("jump");
@@ -2996,11 +3499,12 @@
@@ -2996,11 +3500,12 @@
this.resetFallDistance();
}
@@ -1238,7 +1237,7 @@
if (this.isAlive()) {
this.travelRidden(entityhuman, vec3d1);
break label112;
@@ -3009,6 +3513,7 @@
@@ -3009,6 +3514,7 @@
this.travel(vec3d1);
}
@@ -1246,7 +1245,7 @@
if (!this.level().isClientSide() || this.isControlledByLocalInstance()) {
this.applyEffectsFromBlocks();
@@ -3044,7 +3549,9 @@
@@ -3044,7 +3550,9 @@
this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox());
}
@@ -1256,7 +1255,7 @@
gameprofilerfiller.pop();
world = this.level();
if (world instanceof ServerLevel worldserver) {
@@ -3063,6 +3570,7 @@
@@ -3063,6 +3571,7 @@
this.checkSlowFallDistance();
if (!this.level().isClientSide) {
if (!this.canGlide()) {
@@ -1264,7 +1263,7 @@
this.setSharedFlag(7, false);
return;
}
@@ -3113,7 +3621,7 @@
@@ -3113,7 +3622,7 @@
Level world = this.level();
if (!(world instanceof ServerLevel worldserver)) {
@@ -1273,7 +1272,7 @@
} else {
List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this));
@@ -3305,15 +3813,22 @@
@@ -3305,15 +3814,22 @@
@Override
public boolean isPickable() {
@@ -1298,7 +1297,7 @@
public float getYHeadRot() {
return this.yHeadRot;
}
@@ -3483,8 +3998,31 @@
@@ -3483,8 +3999,31 @@
this.releaseUsingItem();
} else {
if (!this.useItem.isEmpty() && this.isUsingItem()) {
@@ -1331,7 +1330,7 @@
if (itemstack != this.useItem) {
this.setItemInHand(enumhand, itemstack);
}
@@ -3568,12 +4106,18 @@
@@ -3568,12 +4107,18 @@
}
public boolean randomTeleport(double x, double y, double z, boolean particleEffects) {
@@ -1352,7 +1351,7 @@
Level world = this.level();
if (world.hasChunkAt(blockposition)) {
@@ -3592,18 +4136,43 @@
@@ -3592,18 +4137,43 @@
}
if (flag2) {
@@ -1400,7 +1399,7 @@
world.broadcastEntityEvent(this, (byte) 46);
}
@@ -3613,7 +4182,7 @@
@@ -3613,7 +4183,7 @@
entitycreature.getNavigation().stop();
}
@@ -1409,7 +1408,7 @@
}
}
@@ -3706,7 +4275,7 @@
@@ -3706,7 +4276,7 @@
}
public void stopSleeping() {
@@ -1418,7 +1417,7 @@
Level world = this.level();
java.util.Objects.requireNonNull(world);
@@ -3718,9 +4287,9 @@
@@ -3718,9 +4288,9 @@
this.level().setBlock(blockposition, (BlockState) iblockdata.setValue(BedBlock.OCCUPIED, false), 3);
Vec3 vec3d = (Vec3) BedBlock.findStandUpPosition(this.getType(), this.level(), blockposition, enumdirection, this.getYRot()).orElseGet(() -> {
@@ -1430,7 +1429,7 @@
});
Vec3 vec3d1 = Vec3.atBottomCenterOf(blockposition).subtract(vec3d).normalize();
float f = (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D);
@@ -3740,7 +4309,7 @@
@@ -3740,7 +4310,7 @@
@Nullable
public Direction getBedOrientation() {
@@ -1439,7 +1438,7 @@
return blockposition != null ? BedBlock.getBedOrientation(this.level(), blockposition) : null;
}
@@ -3905,7 +4474,7 @@
@@ -3905,7 +4475,7 @@
public float maxUpStep() {
float f = (float) this.getAttributeValue(Attributes.STEP_HEIGHT);

View File

@@ -454,7 +454,34 @@
@Nullable
public <T> T set(DataComponentType<? super T> type, @Nullable T value) {
@@ -858,7 +1082,7 @@
@@ -804,7 +1028,26 @@
} else {
this.getItem().verifyComponentsAfterLoad(this);
}
+ }
+
+ // Paper start - (this is just a good no conflict location)
+ public org.bukkit.inventory.ItemStack asBukkitMirror() {
+ return CraftItemStack.asCraftMirror(this);
+ }
+ public org.bukkit.inventory.ItemStack asBukkitCopy() {
+ return CraftItemStack.asCraftMirror(this.copy());
+ }
+ public static ItemStack fromBukkitCopy(org.bukkit.inventory.ItemStack itemstack) {
+ return CraftItemStack.asNMSCopy(itemstack);
+ }
+ private org.bukkit.craftbukkit.inventory.CraftItemStack bukkitStack;
+ public org.bukkit.inventory.ItemStack getBukkitStack() {
+ if (bukkitStack == null || bukkitStack.handle != this) {
+ bukkitStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this);
+ }
+ return bukkitStack;
}
+ // Paper end
public void applyComponents(DataComponentPatch changes) {
this.components.applyPatch(changes);
@@ -858,7 +1101,7 @@
}
private <T extends TooltipProvider> void addToTooltip(DataComponentType<T> componentType, Item.TooltipContext context, Consumer<Component> textConsumer, TooltipFlag type) {
@@ -463,7 +490,7 @@
if (t0 != null) {
t0.addToTooltip(context, textConsumer, type);
@@ -866,7 +1090,7 @@
@@ -866,7 +1109,7 @@
}
@@ -472,7 +499,7 @@
boolean flag = this.getItem().shouldPrintOpWarning(this, player);
if (!type.isCreative() && this.has(DataComponents.HIDE_TOOLTIP)) {
@@ -941,7 +1165,7 @@
@@ -941,7 +1184,7 @@
}
}
@@ -481,7 +508,7 @@
ItemAttributeModifiers itemattributemodifiers = (ItemAttributeModifiers) this.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY);
if (itemattributemodifiers.showInTooltip()) {
@@ -966,7 +1190,7 @@
@@ -966,7 +1209,7 @@
}
}
@@ -490,13 +517,14 @@
double d0 = modifier.amount();
boolean flag = false;
@@ -1091,6 +1315,13 @@
@@ -1091,6 +1334,14 @@
EnchantmentHelper.forEachModifier(this, slot, attributeModifierConsumer);
}
+ // CraftBukkit start
+ @Deprecated
+ public void setItem(Item item) {
+ this.bukkitStack = null; // Paper
+ this.item = item;
+ }
+ // CraftBukkit end
@@ -504,7 +532,7 @@
public Component getDisplayName() {
MutableComponent ichatmutablecomponent = Component.empty().append(this.getHoverName());
@@ -1153,7 +1384,7 @@
@@ -1153,7 +1404,7 @@
}
public void consume(int amount, @Nullable LivingEntity entity) {

View File

@@ -1,6 +1,14 @@
--- a/net/minecraft/world/level/BlockGetter.java
+++ b/net/minecraft/world/level/BlockGetter.java
@@ -31,7 +31,7 @@
@@ -12,6 +12,7 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
+import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
@@ -31,10 +32,19 @@
default <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos pos, BlockEntityType<T> type) {
BlockEntity tileentity = this.getBlockEntity(pos);
@@ -9,7 +17,19 @@
}
BlockState getBlockState(BlockPos pos);
@@ -59,8 +59,8 @@
+ // Paper start - if loaded util
+ @Nullable BlockState getBlockStateIfLoaded(BlockPos blockposition);
+
+ default @Nullable Block getBlockIfLoaded(BlockPos blockposition) {
+ BlockState type = this.getBlockStateIfLoaded(blockposition);
+ return type == null ? null : type.getBlock();
+ }
+ @Nullable FluidState getFluidIfLoaded(BlockPos blockposition);
+ // Paper end
FluidState getFluidState(BlockPos pos);
@@ -59,8 +69,8 @@
});
}
@@ -20,7 +40,7 @@
BlockState iblockdata = this.getBlockState(blockposition);
FluidState fluid = this.getFluidState(blockposition);
Vec3 vec3d = raytrace1.getFrom();
@@ -73,6 +73,12 @@
@@ -73,6 +83,12 @@
double d1 = movingobjectpositionblock1 == null ? Double.MAX_VALUE : raytrace1.getFrom().distanceToSqr(movingobjectpositionblock1.getLocation());
return d0 <= d1 ? movingobjectpositionblock : movingobjectpositionblock1;
@@ -33,7 +53,7 @@
}, (raytrace1) -> {
Vec3 vec3d = raytrace1.getFrom().subtract(raytrace1.getTo());
@@ -145,7 +151,7 @@
@@ -145,7 +161,7 @@
double d13 = d10 * (i1 > 0 ? 1.0D - Mth.frac(d4) : Mth.frac(d4));
double d14 = d11 * (j1 > 0 ? 1.0D - Mth.frac(d5) : Mth.frac(d5));

View File

@@ -0,0 +1,39 @@
--- a/net/minecraft/world/level/ChunkPos.java
+++ b/net/minecraft/world/level/ChunkPos.java
@@ -46,6 +46,7 @@
public static final int REGION_MAX_INDEX = 31;
public final int x;
public final int z;
+ public final long longKey; // Paper
private static final int HASH_A = 1664525;
private static final int HASH_C = 1013904223;
private static final int HASH_Z_XOR = -559038737;
@@ -53,16 +54,19 @@
public ChunkPos(int x, int z) {
this.x = x;
this.z = z;
+ this.longKey = asLong(this.x, this.z); // Paper
}
public ChunkPos(BlockPos pos) {
this.x = SectionPos.blockToSectionCoord(pos.getX());
this.z = SectionPos.blockToSectionCoord(pos.getZ());
+ this.longKey = asLong(this.x, this.z); // Paper
}
public ChunkPos(long pos) {
this.x = (int)pos;
this.z = (int)(pos >> 32);
+ this.longKey = asLong(this.x, this.z); // Paper
}
public static ChunkPos minFromRegion(int x, int z) {
@@ -74,7 +78,7 @@
}
public long toLong() {
- return asLong(this.x, this.z);
+ return longKey; // Paper
}
public static long asLong(int chunkX, int chunkZ) {

View File

@@ -0,0 +1,22 @@
--- a/net/minecraft/world/level/EmptyBlockGetter.java
+++ b/net/minecraft/world/level/EmptyBlockGetter.java
@@ -17,7 +17,19 @@
return null;
}
+ // Paper start - If loaded util
@Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ return Fluids.EMPTY.defaultFluidState();
+ }
+
+ @Override
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
+ return Blocks.AIR.defaultBlockState();
+ }
+ // Paper end
+
+ @Override
public BlockState getBlockState(BlockPos pos) {
return Blocks.AIR.defaultBlockState();
}

View File

@@ -31,7 +31,7 @@
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.level.entity.LevelEntityGetter;
import net.minecraft.world.level.gameevent.GameEvent;
@@ -81,6 +85,25 @@
@@ -81,6 +85,26 @@
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.Scoreboard;
@@ -48,6 +48,7 @@
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.SpigotTimings; // Spigot
+import org.bukkit.craftbukkit.block.CapturedBlockState;
+import org.bukkit.craftbukkit.block.CraftBlockState;
+import org.bukkit.craftbukkit.block.data.CraftBlockData;
+import org.bukkit.craftbukkit.util.CraftSpawnCategory;
+import org.bukkit.entity.SpawnCategory;
@@ -57,7 +58,7 @@
public abstract class Level implements LevelAccessor, AutoCloseable {
public static final Codec<ResourceKey<Level>> RESOURCE_KEY_CODEC = ResourceKey.codec(Registries.DIMENSION);
@@ -121,23 +144,73 @@
@@ -121,23 +145,73 @@
private final DamageSources damageSources;
private long subTickCount;
@@ -140,7 +141,7 @@
}
};
} else {
@@ -145,11 +218,50 @@
@@ -145,11 +219,50 @@
}
this.thread = Thread.currentThread();
@@ -196,7 +197,77 @@
}
@Override
@@ -207,6 +319,18 @@
@@ -163,6 +276,13 @@
return null;
}
+ // Paper start
+ public net.minecraft.world.phys.BlockHitResult.Type clipDirect(Vec3 start, Vec3 end, net.minecraft.world.phys.shapes.CollisionContext context) {
+ // To be patched over
+ return this.clip(new ClipContext(start, end, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, context)).getType();
+ }
+ // Paper end
+
public boolean isInWorldBounds(BlockPos pos) {
return !this.isOutsideBuildHeight(pos) && Level.isInWorldBoundsHorizontal(pos);
}
@@ -179,18 +299,52 @@
return y < -20000000 || y >= 20000000;
}
- public LevelChunk getChunkAt(BlockPos pos) {
+ public final LevelChunk getChunkAt(BlockPos pos) { // Paper - help inline
return this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()));
}
@Override
- public LevelChunk getChunk(int chunkX, int chunkZ) {
- return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL);
+ public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline
+ return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump
}
+ // Paper start - if loaded
@Nullable
@Override
+ public final ChunkAccess getChunkIfLoadedImmediately(int x, int z) {
+ return ((ServerLevel)this).chunkSource.getChunkAtIfLoadedImmediately(x, z);
+ }
+
+ @Override
+ @Nullable
+ public final BlockState getBlockStateIfLoaded(BlockPos pos) {
+ // CraftBukkit start - tree generation
+ if (this.captureTreeGeneration) {
+ CraftBlockState previous = this.capturedBlockStates.get(pos);
+ if (previous != null) {
+ return previous.getHandle();
+ }
+ }
+ // CraftBukkit end
+ if (this.isOutsideBuildHeight(pos)) {
+ return Blocks.VOID_AIR.defaultBlockState();
+ } else {
+ ChunkAccess chunk = this.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4);
+
+ return chunk == null ? null : chunk.getBlockState(pos);
+ }
+ }
+
+ @Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ ChunkAccess chunk = this.getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+
+ return chunk == null ? null : chunk.getFluidState(blockposition);
+ }
+
+ @Override
public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) {
+ // Paper end
ChunkAccess ichunkaccess = this.getChunkSource().getChunk(chunkX, chunkZ, leastStatus, create);
if (ichunkaccess == null && create) {
@@ -207,6 +361,18 @@
@Override
public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
@@ -215,7 +286,7 @@
if (this.isOutsideBuildHeight(pos)) {
return false;
} else if (!this.isClientSide && this.isDebug()) {
@@ -214,45 +338,124 @@
@@ -214,44 +380,123 @@
} else {
LevelChunk chunk = this.getChunkAt(pos);
Block block = state.getBlock();
@@ -299,10 +370,10 @@
+ // CraftBukkit end
+
return true;
}
}
}
+ }
+ }
+ }
+
+ // CraftBukkit start - Split off from above in order to directly send client and physic updates
+ public void notifyAndUpdatePhysics(BlockPos blockposition, LevelChunk chunk, BlockState oldBlock, BlockState newBlock, BlockState actualBlock, int i, int j) {
+ BlockState iblockdata = newBlock;
@@ -322,7 +393,7 @@
+ if (!this.isClientSide && iblockdata.hasAnalogOutputSignal()) {
+ this.updateNeighbourForOutputSignal(blockposition, newBlock.getBlock());
+ }
+ }
}
+
+ if ((i & 16) == 0 && j > 0) {
+ int k = i & -34;
@@ -348,14 +419,13 @@
+ this.onBlockStateChange(blockposition, iblockdata1, iblockdata2);
+ }
+ // CraftBukkit end
+ }
+ }
}
}
+ // CraftBukkit end
+
public void onBlockStateChange(BlockPos pos, BlockState oldBlock, BlockState newBlock) {}
@Override
@@ -340,6 +543,14 @@
@@ -340,10 +585,18 @@
@Override
public BlockState getBlockState(BlockPos pos) {
@@ -370,7 +440,12 @@
if (this.isOutsideBuildHeight(pos)) {
return Blocks.VOID_AIR.defaultBlockState();
} else {
@@ -440,32 +651,48 @@
- LevelChunk chunk = this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()));
+ ChunkAccess chunk = this.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.FULL, true); // Paper - manually inline to reduce hops and avoid unnecessary null check to reduce total byte code size, this should never return null and if it does we will see it the next line but the real stack trace will matter in the chunk engine
return chunk.getBlockState(pos);
}
@@ -440,32 +693,48 @@
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push("blockEntities");
@@ -423,7 +498,7 @@
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked");
@@ -510,13 +737,29 @@
@@ -510,13 +779,29 @@
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pos) {
@@ -454,7 +529,7 @@
this.getChunkAt(blockposition).addAndRegisterBlockEntity(blockEntity);
}
}
@@ -643,7 +886,7 @@
@@ -643,7 +928,7 @@
for (int k = 0; k < j; ++k) {
EnderDragonPart entitycomplexpart = aentitycomplexpart[k];
@@ -463,7 +538,7 @@
if (t0 != null && predicate.test(t0)) {
result.add(t0);
@@ -912,7 +1155,7 @@
@@ -912,7 +1197,7 @@
public static enum ExplosionInteraction implements StringRepresentable {

View File

@@ -0,0 +1,12 @@
--- a/net/minecraft/world/level/LevelReader.java
+++ b/net/minecraft/world/level/LevelReader.java
@@ -26,6 +26,9 @@
@Nullable
ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create);
+ @Nullable ChunkAccess getChunkIfLoadedImmediately(int x, int z); // Paper - ifLoaded api (we need this since current impl blocks if the chunk is loading)
+ @Nullable default ChunkAccess getChunkIfLoadedImmediately(BlockPos pos) { return this.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4);}
+
@Deprecated
boolean hasChunk(int chunkX, int chunkZ);

View File

@@ -0,0 +1,51 @@
--- a/net/minecraft/world/level/PathNavigationRegion.java
+++ b/net/minecraft/world/level/PathNavigationRegion.java
@@ -8,6 +8,7 @@
import net.minecraft.core.Holder;
import net.minecraft.core.SectionPos;
import net.minecraft.core.registries.Registries;
+import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
@@ -66,7 +67,7 @@
private ChunkAccess getChunk(int chunkX, int chunkZ) {
int i = chunkX - this.centerX;
int j = chunkZ - this.centerZ;
- if (i >= 0 && i < this.chunks.length && j >= 0 && j < this.chunks[i].length) {
+ if (i >= 0 && i < this.chunks.length && j >= 0 && j < this.chunks[i].length) { // Paper - if this changes, update getChunkIfLoaded below
ChunkAccess chunkAccess = this.chunks[i][j];
return (ChunkAccess)(chunkAccess != null ? chunkAccess : new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ), this.plains.get()));
} else {
@@ -74,7 +75,31 @@
}
}
+ // Paper start - if loaded util
+ private @Nullable ChunkAccess getChunkIfLoaded(int x, int z) {
+ // Based on getChunk(int, int)
+ int xx = x - this.centerX;
+ int zz = z - this.centerZ;
+
+ if (xx >= 0 && xx < this.chunks.length && zz >= 0 && zz < this.chunks[xx].length) {
+ return this.chunks[xx][zz];
+ }
+ return null;
+ }
@Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ ChunkAccess chunk = getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ return chunk == null ? null : chunk.getFluidState(blockposition);
+ }
+
+ @Override
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
+ ChunkAccess chunk = getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ return chunk == null ? null : chunk.getBlockState(blockposition);
+ }
+ // Paper end
+
+ @Override
public WorldBorder getWorldBorder() {
return this.level.getWorldBorder();
}

View File

@@ -50,7 +50,33 @@
}
state.spawnAfterBreak(world, pos, ItemStack.EMPTY, flag);
@@ -1125,9 +1139,15 @@
@@ -873,12 +887,14 @@
}
}
+ protected boolean shapeExceedsCube = true; // Paper - moved from actual method to here
public void initCache() {
this.fluidState = ((Block) this.owner).getFluidState(this.asState());
this.isRandomlyTicking = ((Block) this.owner).isRandomlyTicking(this.asState());
if (!this.getBlock().hasDynamicShape()) {
this.cache = new BlockBehaviour.BlockStateBase.Cache(this.asState());
}
+ this.shapeExceedsCube = this.cache == null || this.cache.largeCollisionShape; // Paper - moved from actual method to here
this.legacySolid = this.calculateSolid();
this.occlusionShape = this.canOcclude ? ((Block) this.owner).getOcclusionShape(this.asState()) : Shapes.empty();
@@ -945,8 +961,8 @@
return this.occlusionShape;
}
- public boolean hasLargeCollisionShape() {
- return this.cache == null || this.cache.largeCollisionShape;
+ public final boolean hasLargeCollisionShape() { // Paper
+ return this.shapeExceedsCube; // Paper - moved into shape cache init
}
public boolean useShapeForLightOcclusion() {
@@ -1125,9 +1141,15 @@
}
public void onPlace(Level world, BlockPos pos, BlockState state, boolean notify) {

View File

@@ -1,6 +1,15 @@
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
@@ -85,6 +85,11 @@
@@ -65,7 +65,7 @@
protected final ShortList[] postProcessing;
private volatile boolean unsaved;
private volatile boolean isLightCorrect;
- protected final ChunkPos chunkPos;
+ protected final ChunkPos chunkPos; public final long coordinateKey; public final int locX; public final int locZ; // Paper - cache coordinate key
private long inhabitedTime;
/** @deprecated */
@Nullable
@@ -85,8 +85,14 @@
protected final LevelHeightAccessor levelHeightAccessor;
protected final LevelChunkSection[] sections;
@@ -10,9 +19,13 @@
+ // CraftBukkit end
+
public ChunkAccess(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor heightLimitView, Registry<Biome> biomeRegistry, long inhabitedTime, @Nullable LevelChunkSection[] sectionArray, @Nullable BlendingData blendingData) {
this.chunkPos = pos;
- this.chunkPos = pos;
+ this.locX = pos.x; this.locZ = pos.z; // Paper - reduce need for field lookups
+ this.chunkPos = pos; this.coordinateKey = ChunkPos.asLong(locX, locZ); // Paper - cache long key
this.upgradeData = upgradeData;
@@ -103,7 +108,11 @@
this.levelHeightAccessor = heightLimitView;
this.sections = new LevelChunkSection[heightLimitView.getSectionsCount()];
@@ -103,7 +109,11 @@
}
ChunkAccess.replaceMissingSections(biomeRegistry, this.sections);
@@ -24,7 +37,7 @@
private static void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sectionArray) {
for (int i = 0; i < sectionArray.length; ++i) {
@@ -275,6 +284,7 @@
@@ -275,6 +285,7 @@
public boolean tryMarkSaved() {
if (this.unsaved) {
this.unsaved = false;
@@ -32,7 +45,7 @@
return true;
} else {
return false;
@@ -282,7 +292,7 @@
@@ -282,7 +293,7 @@
}
public boolean isUnsaved() {
@@ -41,10 +54,15 @@
}
public abstract ChunkStatus getPersistedStatus();
@@ -463,6 +473,27 @@
}
}
@@ -458,10 +469,31 @@
crashreportsystemdetails.setDetail("Location", () -> {
return CrashReportCategory.formatLocation(this, biomeX, biomeY, biomeZ);
+ });
+ throw new ReportedException(crashreport);
+ }
+ }
+
+ // CraftBukkit start
+ public void setBiome(int i, int j, int k, Holder<Biome> biome) {
+ try {
@@ -60,12 +78,11 @@
+
+ crashreportsystemdetails.setDetail("Location", () -> {
+ return CrashReportCategory.formatLocation(this, i, j, k);
+ });
+ throw new ReportedException(crashreport);
+ }
+ }
});
throw new ReportedException(crashreport);
}
}
+ // CraftBukkit end
+
public void fillBiomesFromNoise(BiomeResolver biomeSupplier, Climate.Sampler sampler) {
ChunkPos chunkcoordintpair = this.getPos();
int i = QuartPos.fromBlock(chunkcoordintpair.getMinBlockX());

View File

@@ -0,0 +1,15 @@
--- a/net/minecraft/world/level/chunk/EmptyLevelChunk.java
+++ b/net/minecraft/world/level/chunk/EmptyLevelChunk.java
@@ -25,6 +25,12 @@
public BlockState getBlockState(BlockPos pos) {
return Blocks.VOID_AIR.defaultBlockState();
}
+ // Paper start
+ @Override
+ public BlockState getBlockState(final int x, final int y, final int z) {
+ return Blocks.VOID_AIR.defaultBlockState();
+ }
+ // Paper end
@Nullable
@Override

View File

@@ -18,7 +18,7 @@
this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap();
Heightmap.Types[] aheightmap_type = Heightmap.Types.values();
int j = aheightmap_type.length;
@@ -116,6 +116,11 @@
@@ -116,6 +116,15 @@
this.fluidTicks = fluidTickScheduler;
}
@@ -26,11 +26,15 @@
+ public boolean mustNotSave;
+ public boolean needsDecoration;
+ // CraftBukkit end
+
+ // Paper start
+ boolean loadedTicketLevel;
+ // Paper end
+
public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor entityLoader) {
this(world, protoChunk.getPos(), protoChunk.getUpgradeData(), protoChunk.unpackBlockTicks(), protoChunk.unpackFluidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), entityLoader, protoChunk.getBlendingData());
if (!Collections.disjoint(protoChunk.pendingBlockEntities.keySet(), protoChunk.blockEntities.keySet())) {
@@ -151,6 +156,10 @@
@@ -151,6 +160,10 @@
this.skyLightSources = protoChunk.skyLightSources;
this.setLightCorrect(protoChunk.isLightCorrect());
this.markUnsaved();
@@ -41,7 +45,53 @@
}
public void setUnsavedListener(LevelChunk.UnsavedListener unsavedListener) {
@@ -272,78 +281,86 @@
@@ -200,8 +213,25 @@
}
}
+ // Paper start - Perf: Reduce instructions and provide final method
+ public BlockState getBlockState(final int x, final int y, final int z) {
+ return this.getBlockStateFinal(x, y, z);
+ }
+ public BlockState getBlockStateFinal(final int x, final int y, final int z) {
+ // Copied and modified from below
+ final int sectionIndex = this.getSectionIndex(y);
+ if (sectionIndex < 0 || sectionIndex >= this.sections.length
+ || this.sections[sectionIndex].nonEmptyBlockCount == 0) {
+ return Blocks.AIR.defaultBlockState();
+ }
+ return this.sections[sectionIndex].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15);
+ }
@Override
public BlockState getBlockState(BlockPos pos) {
+ if (true) {
+ return this.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
+ }
+ // Paper end - Perf: Reduce instructions and provide final method
int i = pos.getX();
int j = pos.getY();
int k = pos.getZ();
@@ -243,7 +273,19 @@
}
}
+ // Paper start - If loaded util
@Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ return this.getFluidState(blockposition);
+ }
+
+ @Override
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
+ return this.getBlockState(blockposition);
+ }
+ // Paper end
+
+ @Override
public FluidState getFluidState(BlockPos pos) {
return this.getFluidState(pos.getX(), pos.getY(), pos.getZ());
}
@@ -272,78 +314,86 @@
}
}
@@ -153,7 +203,7 @@
this.updateBlockEntityTicker(tileentity);
}
}
@@ -375,7 +392,12 @@
@@ -375,7 +425,12 @@
@Nullable
public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) {
@@ -167,7 +217,7 @@
if (tileentity == null) {
CompoundTag nbttagcompound = (CompoundTag) this.pendingBlockEntities.remove(pos);
@@ -447,6 +469,7 @@
@@ -447,6 +502,7 @@
if (!iblockdata.hasBlockEntity()) {
LevelChunk.LOGGER.warn("Trying to set block entity {} at position {}, but state {} does not allow it", new Object[]{blockEntity, blockposition, iblockdata});
@@ -175,7 +225,7 @@
} else {
BlockState iblockdata1 = blockEntity.getBlockState();
@@ -500,6 +523,12 @@
@@ -500,6 +556,12 @@
if (this.isInLevel()) {
BlockEntity tileentity = (BlockEntity) this.blockEntities.remove(pos);
@@ -188,7 +238,7 @@
if (tileentity != null) {
Level world = this.level;
@@ -549,10 +578,61 @@
@@ -549,9 +611,68 @@
if (this.postLoad != null) {
this.postLoad.run(this);
this.postLoad = null;
@@ -198,7 +248,11 @@
+
+ // CraftBukkit start
+ public void loadCallback() {
+ // Paper start
+ this.loadedTicketLevel = true;
+ // Paper end
+ org.bukkit.Server server = this.level.getCraftServer();
+ this.level.getChunkSource().addLoadedChunk(this); // Paper
+ if (server != null) {
+ /*
+ * If it's a new world, the first few chunks are generated inside
@@ -239,18 +293,21 @@
+ server.getPluginManager().callEvent(unloadEvent);
+ // note: saving can be prevented, but not forced if no saving is actually required
+ this.mustNotSave = !unloadEvent.isSaveChunk();
}
+ this.level.getChunkSource().removeLoadedChunk(this); // Paper
+ // Paper start
+ this.loadedTicketLevel = false;
+ // Paper end
+ }
+
+ @Override
+ public boolean isUnsaved() {
+ return super.isUnsaved() && !this.mustNotSave;
+ }
}
+ // CraftBukkit end
+
public boolean isEmpty() {
return false;
}
@@ -750,7 +830,7 @@
@@ -750,7 +871,7 @@
private <T extends BlockEntity> void updateBlockEntityTicker(T blockEntity) {
BlockState iblockdata = blockEntity.getBlockState();
@@ -259,7 +316,7 @@
if (blockentityticker == null) {
this.removeBlockEntityTicker(blockEntity.getBlockPos());
@@ -841,7 +921,7 @@
@@ -841,7 +962,7 @@
private boolean loggedInvalidBlockState;
BoundTickingBlockEntity(final BlockEntity tileentity, final BlockEntityTicker blockentityticker) {
@@ -268,7 +325,7 @@
this.ticker = blockentityticker;
}
@@ -855,6 +935,7 @@
@@ -855,6 +976,7 @@
ProfilerFiller gameprofilerfiller = Profiler.get();
gameprofilerfiller.push(this::getType);
@@ -276,7 +333,7 @@
BlockState iblockdata = LevelChunk.this.getBlockState(blockposition);
if (this.blockEntity.getType().isValid(iblockdata)) {
@@ -872,6 +953,10 @@
@@ -872,6 +994,10 @@
this.blockEntity.fillCrashReportCategory(crashreportsystemdetails);
throw new ReportedException(crashreport);

View File

@@ -1,6 +1,11 @@
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -23,7 +23,7 @@
@@ -19,11 +19,11 @@
public static final int SECTION_HEIGHT = 16;
public static final int SECTION_SIZE = 4096;
public static final int BIOME_CONTAINER_BITS = 2;
- private short nonEmptyBlockCount;
+ short nonEmptyBlockCount; // Paper - package private
private short tickingBlockCount;
private short tickingFluidCount;
public final PalettedContainer<BlockState> states;

View File

@@ -0,0 +1,22 @@
--- a/net/minecraft/world/level/chunk/ProtoChunk.java
+++ b/net/minecraft/world/level/chunk/ProtoChunk.java
@@ -81,7 +81,19 @@
@Override
public ChunkAccess.PackedTicks getTicksForSerialization(long time) {
return new ChunkAccess.PackedTicks(this.blockTicks.pack(time), this.fluidTicks.pack(time));
+ }
+
+ // Paper start - If loaded util
+ @Override
+ public final FluidState getFluidIfLoaded(BlockPos blockposition) {
+ return this.getFluidState(blockposition);
+ }
+
+ @Override
+ public final BlockState getBlockStateIfLoaded(BlockPos blockposition) {
+ return this.getBlockState(blockposition);
}
+ // Paper end
@Override
public BlockState getBlockState(BlockPos pos) {

View File

@@ -18,9 +18,12 @@
ChunkStatusTasks.postLoadProtoChunk(worldserver, protochunk.getEntities());
});
generationchunkholder.replaceProtoChunk(new ImposterProtoChunk(chunk1, false));
@@ -170,7 +170,17 @@
@@ -168,9 +168,19 @@
}, context.mainThreadExecutor());
}
private static void postLoadProtoChunk(ServerLevel world, List<CompoundTag> entities) {
- private static void postLoadProtoChunk(ServerLevel world, List<CompoundTag> entities) {
+ public static void postLoadProtoChunk(ServerLevel world, List<CompoundTag> entities) { // Paper - public
if (!entities.isEmpty()) {
- world.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(entities, world, EntitySpawnReason.LOAD));
+ // CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities

View File

@@ -32,7 +32,24 @@
void removeSectionIfEmpty(long sectionPos, EntitySection<T> section) {
if (section.isEmpty()) {
this.sectionStorage.remove(sectionPos);
@@ -196,27 +211,35 @@
@@ -76,6 +91,16 @@
}
private boolean addEntity(T entity, boolean existing) {
+ // Paper start - chunk system hooks
+ // 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)) {
return false;
} else {
@@ -196,27 +221,35 @@
}
private boolean storeChunkSections(long chunkPos, Consumer<T> action) {
@@ -74,7 +91,7 @@
return true;
}
}
@@ -238,7 +261,7 @@
@@ -238,7 +271,7 @@
private boolean processChunkUnload(long chunkPos) {
boolean flag = this.storeChunkSections(chunkPos, (entityaccess) -> {
entityaccess.getPassengersAndSelf().forEach(this::unloadEntity);
@@ -83,7 +100,7 @@
if (!flag) {
return false;
@@ -249,24 +272,28 @@
@@ -249,24 +282,28 @@
}
private void unloadEntity(EntityAccess entity) {
@@ -115,7 +132,7 @@
}
}
@@ -292,7 +319,7 @@
@@ -292,7 +329,7 @@
}
public void autoSave() {
@@ -124,7 +141,7 @@
boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN;
if (flag) {
@@ -311,7 +338,7 @@
@@ -311,7 +348,7 @@
while (!longset.isEmpty()) {
this.permanentStorage.flush(false);
this.processPendingLoads();
@@ -133,7 +150,7 @@
boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN;
return flag ? this.processChunkUnload(i) : this.storeChunkSections(i, (entityaccess) -> {
@@ -323,7 +350,15 @@
@@ -323,7 +360,15 @@
}
public void close() throws IOException {
@@ -150,7 +167,7 @@
this.permanentStorage.close();
}
@@ -350,7 +385,7 @@
@@ -350,7 +395,7 @@
public void dumpSections(Writer writer) throws IOException {
CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("y").addColumn("z").addColumn("visibility").addColumn("load_status").addColumn("entity_count").build(writer);
@@ -159,7 +176,7 @@
PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(i);
this.sectionStorage.getExistingSectionPositionsInChunk(i).forEach((j) -> {
@@ -394,7 +429,7 @@
@@ -394,7 +439,7 @@
private EntitySection<T> currentSection;
Callback(final EntityAccess entityaccess, final long i, final EntitySection entitysection) {