MC Utils
== 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:
@@ -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 @@
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user