more patches
This commit is contained in:
parent
123a41d132
commit
27a8d6da9a
32 changed files with 825 additions and 1168 deletions
165
patches/server/0338-Generator-Settings.patch
Normal file
165
patches/server/0338-Generator-Settings.patch
Normal file
|
@ -0,0 +1,165 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Byteflux <byte@byteflux.net>
|
||||
Date: Wed, 2 Mar 2016 02:17:54 -0600
|
||||
Subject: [PATCH] Generator Settings
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 4c177a383b277debe8a7c02a70d029d862e6b048..0c336a794d21d5084b9ea39308379b2ffb4a4330 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -416,5 +416,10 @@ public class PaperWorldConfig {
|
||||
private void disableRelativeProjectileVelocity() {
|
||||
disableRelativeProjectileVelocity = getBoolean("game-mechanics.disable-relative-projectile-velocity", false);
|
||||
}
|
||||
+
|
||||
+ public boolean generateFlatBedrock;
|
||||
+ private void generatorSettings() {
|
||||
+ generateFlatBedrock = getBoolean("generator-settings.flat-bedrock", false);
|
||||
+ }
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index dd7de2c3db10d9d606d47c52eba40e71034fc11a..5473b22d21ea981f245f4826c4d47295890f88ef 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -678,7 +678,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
this.markPositionReplaceable(pos);
|
||||
- return Either.left(new ProtoChunk(pos, UpgradeData.EMPTY, this.level));
|
||||
+ return Either.left(new ProtoChunk(pos, UpgradeData.EMPTY, this.level, this.level)); // Paper - add level
|
||||
// Paper start - Async chunk io
|
||||
};
|
||||
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> ret = new CompletableFuture<>();
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
index 974ab04b08bbd3c27a394b37c1af112be5f28f43..c0075d226331f32e470dae5bf1ce8d79e8b263dc 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
@@ -29,6 +29,18 @@ public interface ChunkAccess extends BlockGetter, FeatureAccess {
|
||||
return GameEventDispatcher.NOOP;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ default boolean generateFlatBedrock() {
|
||||
+ if (this instanceof ProtoChunk) {
|
||||
+ return ((ProtoChunk)this).level.paperConfig.generateFlatBedrock;
|
||||
+ } else if (this instanceof LevelChunk) {
|
||||
+ return ((LevelChunk)this).level.paperConfig.generateFlatBedrock;
|
||||
+ } else {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
BlockState getType(final int x, final int y, final int z); // Paper
|
||||
@Nullable
|
||||
BlockState setBlockState(BlockPos pos, BlockState state, boolean moved);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||
index 452b513e8b89d865a396066adaf4feb1140e1c62..8245c5834ec69beb8e3b95fb3900601009a9273f 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
|
||||
@@ -25,7 +25,7 @@ public class ImposterProtoChunk extends ProtoChunk {
|
||||
private final LevelChunk wrapped;
|
||||
|
||||
public ImposterProtoChunk(LevelChunk wrapped) {
|
||||
- super(wrapped.getPos(), UpgradeData.EMPTY, wrapped);
|
||||
+ super(wrapped.getPos(), UpgradeData.EMPTY, wrapped, wrapped.level); // Paper - add level
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
index da36e6d40ad3e8b7cdbe09ef911d1e5b8c28670f..245998e2cea32cf15ee2659639c647f449704ec0 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
@@ -63,16 +63,24 @@ public class ProtoChunk implements ChunkAccess {
|
||||
private long inhabitedTime;
|
||||
private final Map<GenerationStep.Carving, BitSet> carvingMasks = new Object2ObjectArrayMap<>();
|
||||
private volatile boolean isLightCorrect;
|
||||
+ final net.minecraft.world.level.Level level; // Paper - Add level
|
||||
|
||||
- public ProtoChunk(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor world) {
|
||||
+ // Paper start - add level
|
||||
+ @Deprecated public ProtoChunk(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor world) { this(pos, upgradeData, world, null); }
|
||||
+ public ProtoChunk(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor world, net.minecraft.server.level.ServerLevel level) {
|
||||
+ // Paper end
|
||||
this(pos, upgradeData, (LevelChunkSection[])null, new ProtoTickList<>((block) -> {
|
||||
return block == null || block.defaultBlockState().isAir();
|
||||
}, pos, world), new ProtoTickList<>((fluid) -> {
|
||||
return fluid == null || fluid == Fluids.EMPTY;
|
||||
- }, pos, world), world);
|
||||
+ }, pos, world), world, level); // Paper - add level
|
||||
}
|
||||
|
||||
- public ProtoChunk(ChunkPos pos, UpgradeData upgradeData, @Nullable LevelChunkSection[] levelChunkSections, ProtoTickList<Block> blockTickScheduler, ProtoTickList<Fluid> fluidTickScheduler, LevelHeightAccessor world) {
|
||||
+ // Paper start - add level
|
||||
+ @Deprecated public ProtoChunk(ChunkPos pos, UpgradeData upgradeData, @Nullable LevelChunkSection[] levelChunkSections, ProtoTickList<Block> blockTickScheduler, ProtoTickList<Fluid> fluidTickScheduler, LevelHeightAccessor world) { this(pos, upgradeData, levelChunkSections, blockTickScheduler, fluidTickScheduler, world, null); }
|
||||
+ public ProtoChunk(ChunkPos pos, UpgradeData upgradeData, @Nullable LevelChunkSection[] levelChunkSections, ProtoTickList<Block> blockTickScheduler, ProtoTickList<Fluid> fluidTickScheduler, LevelHeightAccessor world, net.minecraft.server.level.ServerLevel level) {
|
||||
+ this.level = level;
|
||||
+ // Paper end
|
||||
this.chunkPos = pos;
|
||||
this.upgradeData = upgradeData;
|
||||
this.blockTicks = blockTickScheduler;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
index fc320450878279a6aa48019fbde35bb183f5f06e..3cb35f2f47ba841915ac2825d30cc4c3274ce3c4 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
@@ -210,7 +210,7 @@ public class ChunkSerializer {
|
||||
// CraftBukkit end
|
||||
});
|
||||
} else {
|
||||
- ProtoChunk protochunk = new ProtoChunk(pos, chunkconverter, achunksection, protochunkticklist, protochunkticklist1, world);
|
||||
+ ProtoChunk protochunk = new ProtoChunk(pos, chunkconverter, achunksection, protochunkticklist, protochunkticklist1, world, world); // Paper - add level
|
||||
|
||||
protochunk.setBiomes(biomestorage);
|
||||
object = protochunk;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
|
||||
index a0a3cf7655eca5c2b181476b0842d9e8c19dbffd..db0abd275be2df7a4fdeb1d7179bff4d61bab052 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
|
||||
@@ -270,8 +270,8 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
|
||||
int j = chunk.getPos().getMinBlockZ();
|
||||
NoiseGeneratorSettings noiseGeneratorSettings = this.settings.get();
|
||||
int k = noiseGeneratorSettings.noiseSettings().minY();
|
||||
- int l = k + noiseGeneratorSettings.getBedrockFloorPosition();
|
||||
- int m = this.height - 1 + k - noiseGeneratorSettings.getBedrockRoofPosition();
|
||||
+ int l = k + noiseGeneratorSettings.getBedrockFloorPosition(); final int floorHeight = k; // Paper
|
||||
+ int m = this.height - 1 + k - noiseGeneratorSettings.getBedrockRoofPosition(); final int roofHeight = l; // Paper
|
||||
int n = 5;
|
||||
int o = chunk.getMinBuildHeight();
|
||||
int p = chunk.getMaxBuildHeight();
|
||||
@@ -281,7 +281,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
|
||||
for(BlockPos blockPos : BlockPos.betweenClosed(i, 0, j, i + 15, 0, j + 15)) {
|
||||
if (bl) {
|
||||
for(int q = 0; q < 5; ++q) {
|
||||
- if (q <= random.nextInt(5)) {
|
||||
+ if (q <= (chunk.generateFlatBedrock() ? roofHeight : random.nextInt(5))) { // Paper - Configurable flat bedrock roof
|
||||
chunk.setBlockState(mutableBlockPos.set(blockPos.getX(), m - q, blockPos.getZ()), Blocks.BEDROCK.defaultBlockState(), false);
|
||||
}
|
||||
}
|
||||
@@ -289,7 +289,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
|
||||
|
||||
if (bl2) {
|
||||
for(int r = 4; r >= 0; --r) {
|
||||
- if (r <= random.nextInt(5)) {
|
||||
+ if (r <= (chunk.generateFlatBedrock() ? roofHeight : random.nextInt(5))) { // Paper - Configurable flat bedrock floor
|
||||
chunk.setBlockState(mutableBlockPos.set(blockPos.getX(), l + r, blockPos.getZ()), Blocks.BEDROCK.defaultBlockState(), false);
|
||||
}
|
||||
}
|
||||
@@ -309,14 +309,14 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
|
||||
if (l <= 0) {
|
||||
return CompletableFuture.completedFuture(chunk);
|
||||
} else {
|
||||
- int m = chunk.getSectionIndex(l * this.cellHeight - 1 + i);
|
||||
+ int mStart = chunk.getSectionIndex(l * this.cellHeight - 1 + i); // Paper - decompile fix
|
||||
int n = chunk.getSectionIndex(i);
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
Set<LevelChunkSection> set = Sets.newHashSet();
|
||||
|
||||
ChunkAccess var16;
|
||||
try {
|
||||
- for(int m = m; m >= n; --m) {
|
||||
+ for(int m = mStart; m >= n; --m) { // Paper - decompile fix
|
||||
LevelChunkSection levelChunkSection = chunk.getOrCreateSection(m);
|
||||
levelChunkSection.acquire();
|
||||
set.add(levelChunkSection);
|
23
patches/server/0339-Fix-MC-161754.patch
Normal file
23
patches/server/0339-Fix-MC-161754.patch
Normal file
|
@ -0,0 +1,23 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 24 Sep 2019 16:03:00 -0700
|
||||
Subject: [PATCH] Fix MC-161754
|
||||
|
||||
Fixes https://github.com/PaperMC/Paper/issues/2580
|
||||
|
||||
We can use an entity valid check since this method is invoked for
|
||||
each inventory iteraction (thanks to CB) and on player tick (vanilla).
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/HorseInventoryMenu.java b/src/main/java/net/minecraft/world/inventory/HorseInventoryMenu.java
|
||||
index 9da2f9334ea98ecba328c7b0d022321d6194529b..0d145f075798dde27beef80022cd7c0f582f8253 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/HorseInventoryMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/HorseInventoryMenu.java
|
||||
@@ -95,7 +95,7 @@ public class HorseInventoryMenu extends AbstractContainerMenu {
|
||||
|
||||
@Override
|
||||
public boolean stillValid(Player player) {
|
||||
- return !this.horse.hasInventoryChanged(this.horseContainer) && this.horseContainer.stillValid(player) && this.horse.isAlive() && this.horse.distanceTo((Entity) player) < 8.0F;
|
||||
+ return !this.horse.hasInventoryChanged(this.horseContainer) && this.horseContainer.stillValid(player) && (this.horse.isAlive() && this.horse.valid) && this.horse.distanceTo((Entity) player) < 8.0F; // Paper - Fix MC-161754
|
||||
}
|
||||
|
||||
private boolean hasChest(AbstractHorse entityhorseabstract) {
|
|
@ -0,0 +1,25 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MisterErwin <git@askarian.net>
|
||||
Date: Wed, 30 Oct 2019 16:57:54 +0100
|
||||
Subject: [PATCH] Fix spawning of hanging entities that are not ItemFrames and
|
||||
can not face UP or DOWN
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 4841591539fdd5a01f9ded0ee510991602c266a4..f1cbcdb1e409f8544125dde5f24bff5b07cb5082 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -1881,7 +1881,12 @@ public class CraftWorld implements World {
|
||||
height = 9;
|
||||
}
|
||||
|
||||
- BlockFace[] faces = new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN};
|
||||
+ // Paper start - In addition to d65a2576e40e58c8e446b330febe6799d13a604f do not check UP/DOWN for non item frames
|
||||
+ // BlockFace[] faces = new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN};
|
||||
+ BlockFace[] faces = (ItemFrame.class.isAssignableFrom(clazz))
|
||||
+ ? new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN}
|
||||
+ : new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH};
|
||||
+ // Paper end
|
||||
final BlockPos pos = new BlockPos(x, y, z);
|
||||
for (BlockFace dir : faces) {
|
||||
net.minecraft.world.level.block.state.BlockState nmsBlock = this.world.getBlockState(pos.relative(CraftBlock.blockFaceToNotch(dir)));
|
21
patches/server/0341-Expose-the-internal-current-tick.patch
Normal file
21
patches/server/0341-Expose-the-internal-current-tick.patch
Normal file
|
@ -0,0 +1,21 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Sat, 20 Apr 2019 19:47:34 -0500
|
||||
Subject: [PATCH] Expose the internal current tick
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 58d7fec472dd8c8d7775eb6d931be29871102054..9730c701b734eb3491bc1fa5d9bb81ddfefc910a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2364,5 +2364,10 @@ public final class CraftServer implements Server {
|
||||
}
|
||||
return new com.destroystokyo.paper.profile.CraftPlayerProfile(uuid, name);
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public int getCurrentTick() {
|
||||
+ return net.minecraft.server.MinecraftServer.currentTick;
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Wed, 9 Oct 2019 21:51:43 -0500
|
||||
Subject: [PATCH] Fix stuck in sneak when changing worlds (MC-10657)
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 679f1e3ef4c19ab466cf2d06c47b1018aabaa7bf..8da35a7dde494b059e542d049d7ee039deb5833d 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1101,6 +1101,8 @@ public class ServerPlayer extends Player {
|
||||
this.lastSentHealth = -1.0F;
|
||||
this.lastSentFood = -1;
|
||||
|
||||
+ setShiftKeyDown(false); // Paper - fix MC-10657
|
||||
+
|
||||
// CraftBukkit start
|
||||
PlayerChangedWorldEvent changeEvent = new PlayerChangedWorldEvent(this.getBukkitEntity(), worldserver1.getWorld());
|
||||
this.level.getCraftServer().getPluginManager().callEvent(changeEvent);
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 6f9bd5da1504af296e7ee2a69d8afdd3bc4cfd5e..bcc946d2747443c34ee8ac2485a5ab41773c93af 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -820,6 +820,8 @@ public abstract class PlayerList {
|
||||
entityplayer.connection.send(new ClientboundUpdateMobEffectPacket(entityplayer.getId(), mobEffect));
|
||||
}
|
||||
|
||||
+ entityplayer.setShiftKeyDown(false); // Paper - fix MC-10657
|
||||
+
|
||||
// Fire advancement trigger
|
||||
entityplayer.triggerDimensionChangeTriggers(((CraftWorld) fromWorld).getHandle());
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <blake.galbreath@gmail.com>
|
||||
Date: Wed, 9 Oct 2019 21:46:15 -0500
|
||||
Subject: [PATCH] Add option to disable pillager patrols
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 0c336a794d21d5084b9ea39308379b2ffb4a4330..f46731897f4234b27dafa49a5f652535a99d2992 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -421,5 +421,10 @@ public class PaperWorldConfig {
|
||||
private void generatorSettings() {
|
||||
generateFlatBedrock = getBoolean("generator-settings.flat-bedrock", false);
|
||||
}
|
||||
+
|
||||
+ public boolean disablePillagerPatrols = false;
|
||||
+ private void pillagerSettings() {
|
||||
+ disablePillagerPatrols = getBoolean("game-mechanics.disable-pillager-patrols", disablePillagerPatrols);
|
||||
+ }
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
index e0a376617f6b6232591942da0bc9d7b1ee58c2e7..744b58d59a5f34ed3bd6f2d4a0f876acfa6a7135 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
|
||||
@@ -26,6 +26,7 @@ public class PatrolSpawner implements CustomSpawner {
|
||||
|
||||
@Override
|
||||
public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) {
|
||||
+ if (world.paperConfig.disablePillagerPatrols) return 0; // Paper
|
||||
if (!spawnMonsters) {
|
||||
return 0;
|
||||
} else if (!world.getGameRules().getBoolean(GameRules.RULE_DO_PATROL_SPAWNING)) {
|
|
@ -0,0 +1,23 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Lukasz Derlatka <toranktto@gmail.com>
|
||||
Date: Mon, 11 Nov 2019 16:08:13 +0100
|
||||
Subject: [PATCH] Fix AssertionError when player hand set to empty type
|
||||
|
||||
Fixes an AssertionError when setting the player's item in hand to null or a new ItemStack of Air in PlayerInteractEvent
|
||||
Fixes GH-2718
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 377e224acb06bfd5f769b5f75b7f52129394b494..9240064a17e7ac2492fe157b759d1f724105cd0e 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1741,6 +1741,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
||||
this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524
|
||||
return;
|
||||
}
|
||||
+ // Paper start
|
||||
+ itemstack = this.player.getItemInHand(enumhand);
|
||||
+ if (itemstack.isEmpty()) return;
|
||||
+ // Paper end
|
||||
InteractionResult enuminteractionresult = this.player.gameMode.useItem(this.player, worldserver, itemstack, enumhand);
|
||||
|
||||
if (enuminteractionresult.shouldSwing()) {
|
|
@ -0,0 +1,20 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Callahan <mr.callahhh@gmail.com>
|
||||
Date: Mon, 13 Jan 2020 23:47:28 -0600
|
||||
Subject: [PATCH] Prevent sync chunk loads when villagers try to find beds
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/SleepInBed.java b/src/main/java/net/minecraft/world/entity/ai/behavior/SleepInBed.java
|
||||
index 455774a211c679367c6e7845a11159ad84ca07e2..673b6e60731d440cc02b1e86bfba50e6ebeb0da9 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/SleepInBed.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/SleepInBed.java
|
||||
@@ -41,7 +41,8 @@ public class SleepInBed extends Behavior<LivingEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
- BlockState blockState = world.getBlockState(globalPos.pos());
|
||||
+ BlockState blockState = world.getTypeIfLoaded(globalPos.pos()); // Paper
|
||||
+ if (blockState == null) { return false; } // Paper
|
||||
return globalPos.pos().closerThan(entity.position(), 2.0D) && blockState.is(BlockTags.BEDS) && !blockState.getValue(BedBlock.OCCUPIED);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Wed, 18 Dec 2019 22:21:35 -0600
|
||||
Subject: [PATCH] MC-145656 Fix Follow Range Initial Target
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index f46731897f4234b27dafa49a5f652535a99d2992..8190c30346c0fd2d86fb7cbcfc7ce17333e05146 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -426,5 +426,10 @@ public class PaperWorldConfig {
|
||||
private void pillagerSettings() {
|
||||
disablePillagerPatrols = getBoolean("game-mechanics.disable-pillager-patrols", disablePillagerPatrols);
|
||||
}
|
||||
+
|
||||
+ public boolean entitiesTargetWithFollowRange = false;
|
||||
+ private void entitiesTargetWithFollowRange() {
|
||||
+ entitiesTargetWithFollowRange = getBoolean("entities-target-with-follow-range", entitiesTargetWithFollowRange);
|
||||
+ }
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
||||
index 6cbd2fc4a7041f957966e5b09616e70aae63c0d4..b5bbcb9fa6de4c919e4d4fabbab483054d81574e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
|
||||
@@ -32,6 +32,7 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
|
||||
this.randomInterval = reciprocalChance;
|
||||
this.setFlags(EnumSet.of(Goal.Flag.TARGET));
|
||||
this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(targetPredicate);
|
||||
+ if (mob.level.paperConfig.entitiesTargetWithFollowRange) this.targetConditions.useFollowRange(); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
||||
index e45434b844c98c322e1432c2382c1ccb8c3e57a7..3ee691d4caccbc1b3e0f52decb41d436ac0d08ec 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/targeting/TargetingConditions.java
|
||||
@@ -75,7 +75,7 @@ public class TargetingConditions {
|
||||
|
||||
if (this.range > 0.0D) {
|
||||
double d = this.testInvisible ? targetEntity.getVisibilityPercent(baseEntity) : 1.0D;
|
||||
- double e = Math.max(this.range * d, 2.0D);
|
||||
+ double e = Math.max((this.useFollowRange ? this.getFollowRange(baseEntity) : this.range) * d, 2.0D); // Paper
|
||||
double f = baseEntity.distanceToSqr(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ());
|
||||
if (f > e * e) {
|
||||
return false;
|
||||
@@ -90,4 +90,18 @@ public class TargetingConditions {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ private boolean useFollowRange = false;
|
||||
+
|
||||
+ public TargetingConditions useFollowRange() {
|
||||
+ this.useFollowRange = true;
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ private double getFollowRange(LivingEntity entityliving) {
|
||||
+ net.minecraft.world.entity.ai.attributes.AttributeInstance attributeinstance = entityliving.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.FOLLOW_RANGE);
|
||||
+ return attributeinstance == null ? 16.0D : attributeinstance.getValue();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
482
patches/server/0347-Optimize-Hoppers.patch
Normal file
482
patches/server/0347-Optimize-Hoppers.patch
Normal file
|
@ -0,0 +1,482 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 27 Apr 2016 22:09:52 -0400
|
||||
Subject: [PATCH] Optimize Hoppers
|
||||
|
||||
* Removes unnecessary extra calls to .update() that are very expensive
|
||||
* Lots of itemstack cloning removed. Only clone if the item is actually moved
|
||||
* Return true when a plugin cancels inventory move item event instead of false, as false causes pulls to cycle through all items.
|
||||
However, pushes do not exhibit the same behavior, so this is not something plugins could of been relying on.
|
||||
* Add option (Default on) to cooldown hoppers when they fail to move an item due to full inventory
|
||||
* Skip subsequent InventoryMoveItemEvents if a plugin does not use the item after first event fire for an iteration
|
||||
* Don't check for Entities with Inventories if the block above us is also occluding (not just Inventoried)
|
||||
* Remove Streams from Item Suck In and restore restore 1.12 AABB checks which is simpler and no voxel allocations (was doing TWO Item Suck ins)
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 8190c30346c0fd2d86fb7cbcfc7ce17333e05146..041efecbfcd54384d15ebf771cdfa0e711483997 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -431,5 +431,14 @@ public class PaperWorldConfig {
|
||||
private void entitiesTargetWithFollowRange() {
|
||||
entitiesTargetWithFollowRange = getBoolean("entities-target-with-follow-range", entitiesTargetWithFollowRange);
|
||||
}
|
||||
+
|
||||
+ public boolean cooldownHopperWhenFull = true;
|
||||
+ public boolean disableHopperMoveEvents = false;
|
||||
+ private void hopperOptimizations() {
|
||||
+ cooldownHopperWhenFull = getBoolean("hopper.cooldown-when-full", cooldownHopperWhenFull);
|
||||
+ log("Cooldown Hoppers when Full: " + (cooldownHopperWhenFull ? "enabled" : "disabled"));
|
||||
+ disableHopperMoveEvents = getBoolean("hopper.disable-move-event", disableHopperMoveEvents);
|
||||
+ log("Hopper Move Item Events: " + (disableHopperMoveEvents ? "disabled" : "enabled"));
|
||||
+ }
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index f00839eab02277bf10b742c88fadc4aa9e89e7e0..312be2221e1acc44aaf6936533b0eb968f796dc6 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1422,6 +1422,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
while (iterator.hasNext()) {
|
||||
ServerLevel worldserver = (ServerLevel) iterator.next();
|
||||
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
|
||||
+ net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper
|
||||
|
||||
this.profiler.push(() -> {
|
||||
return worldserver + " " + worldserver.dimension().location();
|
||||
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
index dd4deb08eb3ed15a156269a11d3d43abfd61fe5b..10f55ba189d12c46e0ef38b0b96a29894b4fba93 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
|
||||
@@ -601,11 +601,12 @@ public final class ItemStack {
|
||||
return this.getItem().interactLivingEntity(this, user, entity, hand);
|
||||
}
|
||||
|
||||
- public ItemStack copy() {
|
||||
- if (this.isEmpty()) {
|
||||
+ public ItemStack copy() { return cloneItemStack(false); } // Paper
|
||||
+ public ItemStack cloneItemStack(boolean origItem) { // Paper
|
||||
+ if (!origItem && this.isEmpty()) { // Paper
|
||||
return ItemStack.EMPTY;
|
||||
} else {
|
||||
- ItemStack itemstack = new ItemStack(this.getItem(), this.count);
|
||||
+ ItemStack itemstack = new ItemStack(origItem ? this.item : this.getItem(), this.count); // Paper
|
||||
|
||||
itemstack.setPopTime(this.getPopTime());
|
||||
if (this.tag != null) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
index 8a079ee3ed243fd19b1dd7eed2de1dd33785faa1..c3a07ccccd5cc38552363c82398f432c8d624288 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
@@ -63,6 +63,7 @@ public abstract class BlockEntity implements net.minecraft.server.KeyedObject {
|
||||
getMinecraftKey(); // Try to load if it doesn't exists.
|
||||
return tileEntityKeyString;
|
||||
}
|
||||
+ static boolean IGNORE_TILE_UPDATES = false;
|
||||
// Paper end
|
||||
|
||||
@Nullable
|
||||
@@ -145,6 +146,7 @@ public abstract class BlockEntity implements net.minecraft.server.KeyedObject {
|
||||
|
||||
public void setChanged() {
|
||||
if (this.level != null) {
|
||||
+ if (IGNORE_TILE_UPDATES) return; // Paper
|
||||
BlockEntity.setChanged(this.level, this.worldPosition, this.blockState);
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/Hopper.java b/src/main/java/net/minecraft/world/level/block/entity/Hopper.java
|
||||
index a05acf709735b40ca86f978508c63a86065fd405..c1754df6a60ff93d75a28145b9dc4e9174241a21 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/Hopper.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/Hopper.java
|
||||
@@ -14,6 +14,10 @@ public interface Hopper extends Container {
|
||||
return SUCK;
|
||||
}
|
||||
|
||||
+ net.minecraft.world.level.Level getLevel();
|
||||
+
|
||||
+ default net.minecraft.core.BlockPos getBlockPosition() { return new net.minecraft.core.BlockPos(getLevelX(), getLevelY(), getLevelZ()); } // Paper
|
||||
+
|
||||
double getLevelX();
|
||||
|
||||
double getLevelY();
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
index 0ec16d554c2b51a64614c73783505c7b06ff02c7..86c0a477883102e4aebdab7ac28bf9f2ab2f7c48 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
@@ -3,7 +3,6 @@ package net.minecraft.world.level.block.entity;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
-import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -33,7 +32,6 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.shapes.BooleanOp;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
-import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
@@ -192,6 +190,159 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
|
||||
return false;
|
||||
}
|
||||
+ // Paper start - Optimize Hoppers
|
||||
+ private static boolean skipPullModeEventFire = false;
|
||||
+ private static boolean skipPushModeEventFire = false;
|
||||
+ public static boolean skipHopperEvents = false;
|
||||
+
|
||||
+ private static boolean hopperPush(Level level, BlockPos pos, Container iinventory, Direction enumdirection, HopperBlockEntity hopper) {
|
||||
+ skipPushModeEventFire = skipHopperEvents;
|
||||
+ boolean foundItem = false;
|
||||
+ for (int i = 0; i < iinventory.getContainerSize(); ++i) {
|
||||
+ ItemStack item = iinventory.getItem(i);
|
||||
+ if (!item.isEmpty()) {
|
||||
+ foundItem = true;
|
||||
+ ItemStack origItemStack = item;
|
||||
+ ItemStack itemstack = origItemStack;
|
||||
+
|
||||
+ final int origCount = origItemStack.getCount();
|
||||
+ final int moved = Math.min(level.spigotConfig.hopperAmount, origCount);
|
||||
+ origItemStack.setCount(moved);
|
||||
+
|
||||
+ // We only need to fire the event once to give protection plugins a chance to cancel this event
|
||||
+ // Because nothing uses getItem, every event call should end up the same result.
|
||||
+ if (!skipPushModeEventFire) {
|
||||
+ itemstack = callPushMoveEvent(iinventory, itemstack, hopper);
|
||||
+ if (itemstack == null) { // cancelled
|
||||
+ origItemStack.setCount(origCount);
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ final ItemStack itemstack2 = addItem(hopper, iinventory, itemstack, enumdirection);
|
||||
+ final int remaining = itemstack2.getCount();
|
||||
+ if (remaining != moved) {
|
||||
+ origItemStack = origItemStack.cloneItemStack(true);
|
||||
+ origItemStack.setCount(origCount);
|
||||
+ if (!origItemStack.isEmpty()) {
|
||||
+ origItemStack.setCount(origCount - moved + remaining);
|
||||
+ }
|
||||
+ hopper.setItem(i, origItemStack);
|
||||
+ iinventory.setChanged();
|
||||
+ return true;
|
||||
+ }
|
||||
+ origItemStack.setCount(origCount);
|
||||
+ }
|
||||
+ }
|
||||
+ if (foundItem && level.paperConfig.cooldownHopperWhenFull) { // Inventory was full - cooldown
|
||||
+ hopper.setCooldown(level.spigotConfig.hopperTransfer);
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ private static boolean hopperPull(Hopper ihopper, Container iinventory, ItemStack origItemStack, int i) {
|
||||
+ ItemStack itemstack = origItemStack;
|
||||
+ final int origCount = origItemStack.getCount();
|
||||
+ final Level world = ihopper.getLevel();
|
||||
+ final int moved = Math.min(world.spigotConfig.hopperAmount, origCount);
|
||||
+ itemstack.setCount(moved);
|
||||
+
|
||||
+ if (!skipPullModeEventFire) {
|
||||
+ itemstack = callPullMoveEvent(ihopper, iinventory, itemstack);
|
||||
+ if (itemstack == null) { // cancelled
|
||||
+ origItemStack.setCount(origCount);
|
||||
+ // Drastically improve performance by returning true.
|
||||
+ // No plugin could of relied on the behavior of false as the other call
|
||||
+ // site for IMIE did not exhibit the same behavior
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final ItemStack itemstack2 = addItem(iinventory, ihopper, itemstack, null);
|
||||
+ final int remaining = itemstack2.getCount();
|
||||
+ if (remaining != moved) {
|
||||
+ origItemStack = origItemStack.cloneItemStack(true);
|
||||
+ origItemStack.setCount(origCount);
|
||||
+ if (!origItemStack.isEmpty()) {
|
||||
+ origItemStack.setCount(origCount - moved + remaining);
|
||||
+ }
|
||||
+ IGNORE_TILE_UPDATES = true;
|
||||
+ iinventory.setItem(i, origItemStack);
|
||||
+ IGNORE_TILE_UPDATES = false;
|
||||
+ iinventory.setChanged();
|
||||
+ return true;
|
||||
+ }
|
||||
+ origItemStack.setCount(origCount);
|
||||
+
|
||||
+ if (world.paperConfig.cooldownHopperWhenFull) {
|
||||
+ cooldownHopper(ihopper);
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ private static ItemStack callPushMoveEvent(Container iinventory, ItemStack itemstack, HopperBlockEntity hopper) {
|
||||
+ Inventory destinationInventory = getInventory(iinventory);
|
||||
+ InventoryMoveItemEvent event = new InventoryMoveItemEvent(hopper.getOwner(false).getInventory(),
|
||||
+ CraftItemStack.asCraftMirror(itemstack), destinationInventory, true);
|
||||
+ boolean result = event.callEvent();
|
||||
+ if (!event.calledGetItem && !event.calledSetItem) {
|
||||
+ skipPushModeEventFire = true;
|
||||
+ }
|
||||
+ if (!result) {
|
||||
+ cooldownHopper(hopper);
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ if (event.calledSetItem) {
|
||||
+ return CraftItemStack.asNMSCopy(event.getItem());
|
||||
+ } else {
|
||||
+ return itemstack;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static ItemStack callPullMoveEvent(Hopper hopper, Container iinventory, ItemStack itemstack) {
|
||||
+ Inventory sourceInventory = getInventory(iinventory);
|
||||
+ Inventory destination = getInventory(hopper);
|
||||
+
|
||||
+ InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory,
|
||||
+ // Mirror is safe as we no plugins ever use this item
|
||||
+ CraftItemStack.asCraftMirror(itemstack), destination, false);
|
||||
+ boolean result = event.callEvent();
|
||||
+ if (!event.calledGetItem && !event.calledSetItem) {
|
||||
+ skipPullModeEventFire = true;
|
||||
+ }
|
||||
+ if (!result) {
|
||||
+ cooldownHopper(hopper);
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ if (event.calledSetItem) {
|
||||
+ return CraftItemStack.asNMSCopy(event.getItem());
|
||||
+ } else {
|
||||
+ return itemstack;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static Inventory getInventory(Container iinventory) {
|
||||
+ Inventory sourceInventory;// Have to special case large chests as they work oddly
|
||||
+ if (iinventory instanceof CompoundContainer) {
|
||||
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
|
||||
+ } else if (iinventory instanceof BlockEntity) {
|
||||
+ sourceInventory = ((BlockEntity) iinventory).getOwner(false).getInventory();
|
||||
+ } else {
|
||||
+ sourceInventory = iinventory.getOwner().getInventory();
|
||||
+ }
|
||||
+ return sourceInventory;
|
||||
+ }
|
||||
+
|
||||
+ private static void cooldownHopper(Hopper hopper) {
|
||||
+ if (hopper instanceof HopperBlockEntity) {
|
||||
+ ((HopperBlockEntity) hopper).setCooldown(hopper.getLevel().spigotConfig.hopperTransfer);
|
||||
+ } else if (hopper instanceof MinecartHopper) {
|
||||
+ ((MinecartHopper) hopper).setCooldown(hopper.getLevel().spigotConfig.hopperTransfer / 2);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
private static boolean a(Level world, BlockPos blockposition, BlockState iblockdata, Container iinventory, HopperBlockEntity hopper) { // CraftBukkit
|
||||
Container iinventory1 = HopperBlockEntity.getAttachedContainer(world, blockposition, iblockdata);
|
||||
@@ -204,6 +355,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
if (HopperBlockEntity.isFullContainer(iinventory1, enumdirection)) {
|
||||
return false;
|
||||
} else {
|
||||
+ return hopperPush(world, blockposition, iinventory, enumdirection, hopper); /* // Paper - disable rest
|
||||
for (int i = 0; i < iinventory.getContainerSize(); ++i) {
|
||||
if (!iinventory.getItem(i).isEmpty()) {
|
||||
ItemStack itemstack = iinventory.getItem(i).copy();
|
||||
@@ -241,7 +393,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
}
|
||||
}
|
||||
|
||||
- return false;
|
||||
+ return false;*/ // Paper - end commenting out replaced block for Hopper Optimizations
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,27 +403,68 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
}
|
||||
|
||||
private static boolean isFullContainer(Container inventory, Direction direction) {
|
||||
- return HopperBlockEntity.getSlots(inventory, direction).allMatch((i) -> {
|
||||
- ItemStack itemstack = inventory.getItem(i);
|
||||
-
|
||||
- return itemstack.getCount() >= itemstack.getMaxStackSize();
|
||||
- });
|
||||
+ return allMatch(inventory, direction, STACK_SIZE_TEST); // Paper - no streams
|
||||
}
|
||||
|
||||
private static boolean isEmptyContainer(Container inv, Direction facing) {
|
||||
- return HopperBlockEntity.getSlots(inv, facing).allMatch((i) -> {
|
||||
- return inv.getItem(i).isEmpty();
|
||||
- });
|
||||
+ // Paper start
|
||||
+ return allMatch(inv, facing, IS_EMPTY_TEST);
|
||||
+ }
|
||||
+ private static boolean allMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
|
||||
+ if (iinventory instanceof WorldlyContainer) {
|
||||
+ for (int i : ((WorldlyContainer) iinventory).getSlotsForFace(enumdirection)) {
|
||||
+ if (!test.test(iinventory.getItem(i), i)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ int size = iinventory.getContainerSize();
|
||||
+ for (int i = 0; i < size; i++) {
|
||||
+ if (!test.test(iinventory.getItem(i), i)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return true;
|
||||
}
|
||||
|
||||
+ private static boolean anyMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
|
||||
+ if (iinventory instanceof WorldlyContainer) {
|
||||
+ for (int i : ((WorldlyContainer) iinventory).getSlotsForFace(enumdirection)) {
|
||||
+ if (test.test(iinventory.getItem(i), i)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ int size = iinventory.getContainerSize();
|
||||
+ for (int i = 0; i < size; i++) {
|
||||
+ if (test.test(iinventory.getItem(i), i)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ private static final java.util.function.BiPredicate<ItemStack, Integer> STACK_SIZE_TEST = (itemstack, i) -> itemstack.getCount() >= itemstack.getMaxStackSize();
|
||||
+ private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemstack, i) -> itemstack.isEmpty();
|
||||
+ // Paper end
|
||||
+
|
||||
public static boolean suckInItems(Level world, Hopper hopper) {
|
||||
Container iinventory = HopperBlockEntity.getSourceContainer(world, hopper);
|
||||
|
||||
if (iinventory != null) {
|
||||
Direction enumdirection = Direction.DOWN;
|
||||
|
||||
- return HopperBlockEntity.isEmptyContainer(iinventory, enumdirection) ? false : HopperBlockEntity.getSlots(iinventory, enumdirection).anyMatch((i) -> {
|
||||
- return HopperBlockEntity.a(hopper, iinventory, i, enumdirection, world); // Spigot
|
||||
+ // Paper start - optimize hoppers and remove streams
|
||||
+ skipPullModeEventFire = skipHopperEvents;
|
||||
+ return !HopperBlockEntity.isEmptyContainer(iinventory, enumdirection) && anyMatch(iinventory, enumdirection, (item, i) -> {
|
||||
+ // Logic copied from below to avoid extra getItem calls
|
||||
+ if (!item.isEmpty() && canTakeItemFromContainer(iinventory, item, i, enumdirection)) {
|
||||
+ return hopperPull(hopper, iinventory, item, i);
|
||||
+ } else {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
});
|
||||
} else {
|
||||
Iterator iterator = HopperBlockEntity.getItemsAtAndAbove(world, hopper).iterator();
|
||||
@@ -290,10 +483,12 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper - method unused as logic is inlined above
|
||||
private static boolean a(Hopper ihopper, Container iinventory, int i, Direction enumdirection, Level world) { // Spigot
|
||||
ItemStack itemstack = iinventory.getItem(i);
|
||||
|
||||
- if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(iinventory, itemstack, i, enumdirection)) {
|
||||
+ if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(iinventory, itemstack, i, enumdirection)) { // If this logic changes, update above. this is left inused incase reflective plugins
|
||||
+ return hopperPull(ihopper, iinventory, itemstack, i); /* // Paper - disable rest
|
||||
ItemStack itemstack1 = itemstack.copy();
|
||||
// ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.splitStack(i, 1), (EnumDirection) null);
|
||||
// CraftBukkit start - Call event on collection of items from inventories into the hopper
|
||||
@@ -330,7 +525,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
}
|
||||
|
||||
itemstack1.shrink(origCount - itemstack2.getCount()); // Spigot
|
||||
- iinventory.setItem(i, itemstack1);
|
||||
+ iinventory.setItem(i, itemstack1);*/ // Paper - end commenting out replaced block for Hopper Optimizations
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -339,7 +534,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
public static boolean addItem(Container inventory, ItemEntity itemEntity) {
|
||||
boolean flag = false;
|
||||
// CraftBukkit start
|
||||
- InventoryPickupItemEvent event = new InventoryPickupItemEvent(inventory.getOwner().getInventory(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity());
|
||||
+ InventoryPickupItemEvent event = new InventoryPickupItemEvent(getInventory(inventory), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); // Paper - use getInventory() to avoid snapshot creation
|
||||
itemEntity.level.getCraftServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return false;
|
||||
@@ -393,7 +588,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
boolean flag1 = to.isEmpty();
|
||||
|
||||
if (itemstack1.isEmpty()) {
|
||||
+ IGNORE_TILE_UPDATES = true; // Paper
|
||||
to.setItem(slot, stack);
|
||||
+ IGNORE_TILE_UPDATES = false; // Paper
|
||||
stack = ItemStack.EMPTY;
|
||||
flag = true;
|
||||
} else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) {
|
||||
@@ -444,18 +641,23 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
}
|
||||
|
||||
public static List<ItemEntity> getItemsAtAndAbove(Level world, Hopper hopper) {
|
||||
- return (List) hopper.getSuckShape().toAabbs().stream().flatMap((axisalignedbb) -> {
|
||||
- return world.getEntitiesOfClass(ItemEntity.class, axisalignedbb.move(hopper.getLevelX() - 0.5D, hopper.getLevelY() - 0.5D, hopper.getLevelZ() - 0.5D), EntitySelector.ENTITY_STILL_ALIVE).stream();
|
||||
- }).collect(Collectors.toList());
|
||||
+ // Paper start - Optimize item suck in. remove streams, restore 1.12 checks. Seriously checking the bowl?!
|
||||
+ double d0 = hopper.getLevelX();
|
||||
+ double d1 = hopper.getLevelY();
|
||||
+ double d2 = hopper.getLevelZ();
|
||||
+ AABB bb = new AABB(d0 - 0.5D, d1, d2 - 0.5D, d0 + 0.5D, d1 + 1.5D, d2 + 0.5D);
|
||||
+ return world.getEntitiesOfClass(ItemEntity.class, bb, Entity::isAlive);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Container getContainerAt(Level world, BlockPos pos) {
|
||||
- return HopperBlockEntity.getContainerAt(world, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D);
|
||||
+ return HopperBlockEntity.getContainerAt(world, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, true); // Paper
|
||||
}
|
||||
|
||||
+ public static Container getContainerAt(Level world, double x, double y, double z) { return getContainerAt(world, x, y, z, false); } // Paper - overload to default false
|
||||
@Nullable
|
||||
- private static Container getContainerAt(Level world, double x, double y, double z) {
|
||||
+ private static Container getContainerAt(Level world, double x, double y, double z, boolean optimizeEntities) {
|
||||
Object object = null;
|
||||
BlockPos blockposition = new BlockPos(x, y, z);
|
||||
if ( !world.hasChunkAt( blockposition ) ) return null; // Spigot
|
||||
@@ -475,7 +677,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
}
|
||||
}
|
||||
|
||||
- if (object == null) {
|
||||
+ if (object == null && (!optimizeEntities || !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding())) { // Paper
|
||||
List<Entity> list = world.getEntities((Entity) null, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR);
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
index f23fff80d07ac7d06715efe67cb49ebbe704967b..ed3518fe7c841d9e1a9c97626acaa3d765a6d76f 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
@@ -95,12 +95,19 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
this.unpackLootTable((Player)null);
|
||||
- return this.getItems().stream().allMatch(ItemStack::isEmpty);
|
||||
+ // Paper start
|
||||
+ for (ItemStack itemStack : this.getItems()) {
|
||||
+ if (!itemStack.isEmpty()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+ return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int slot) {
|
||||
- this.unpackLootTable((Player)null);
|
||||
+ if (slot == 0) this.unpackLootTable((Player) null); // Paper
|
||||
return this.getItems().get(slot);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Tue, 24 Dec 2019 00:35:42 +0000
|
||||
Subject: [PATCH] PlayerDeathEvent#shouldDropExperience
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 8da35a7dde494b059e542d049d7ee039deb5833d..4fef4c0240be90ddcb9640f5719e292d2d5dbdf8 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -849,7 +849,7 @@ public class ServerPlayer extends Player {
|
||||
this.tellNeutralMobsThatIDied();
|
||||
}
|
||||
// SPIGOT-5478 must be called manually now
|
||||
- this.dropExperience();
|
||||
+ if (event.shouldDropExperience()) this.dropExperience(); // Paper - tie to event
|
||||
// we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory.
|
||||
if (!event.getKeepInventory()) {
|
||||
this.getInventory().clearContent();
|
|
@ -0,0 +1,18 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 5 Jan 2020 17:24:34 -0600
|
||||
Subject: [PATCH] Prevent bees loading chunks checking hive position
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
index 488dd4693dbbc303f0fc6d98667b822304b06c9f..f3ba4b26553915917c79f013ed9dd7c87d9f65a4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -495,6 +495,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
if (!this.hasHive()) {
|
||||
return false;
|
||||
} else {
|
||||
+ if (level.getChunkIfLoadedImmediately(hivePos.getX() >> 4, hivePos.getZ() >> 4) == null) return true; // Paper - just assume the hive is still there, no need to load the chunk(s)
|
||||
BlockEntity tileentity = this.level.getBlockEntity(this.hivePos);
|
||||
|
||||
return tileentity != null && tileentity.getType() == BlockEntityType.BEEHIVE;
|
|
@ -0,0 +1,32 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 3 Nov 2016 20:28:12 -0400
|
||||
Subject: [PATCH] Don't load Chunks from Hoppers and other things
|
||||
|
||||
Hoppers call this to I guess "get the primary side" of a double sided chest.
|
||||
|
||||
If the double sided chest crosses chunk lines, it causes the chunk to load.
|
||||
This will end up causing sync chunk loads, which will unload with Chunk GC,
|
||||
only to be reloaded again the next tick.
|
||||
|
||||
This of course is undesirable, so just return the loaded side as "primary"
|
||||
and treat it as a single chest if the other sides are unloaded
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/DoubleBlockCombiner.java b/src/main/java/net/minecraft/world/level/block/DoubleBlockCombiner.java
|
||||
index ff2a7b08fe70adaecdaa508baadcfe40416519e0..7082bb0b28b6a046e3925f69e18b7c319871128f 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/DoubleBlockCombiner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/DoubleBlockCombiner.java
|
||||
@@ -25,7 +25,12 @@ public class DoubleBlockCombiner {
|
||||
return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity);
|
||||
} else {
|
||||
BlockPos blockPos = pos.relative(function.apply(state));
|
||||
- BlockState blockState = world.getBlockState(blockPos);
|
||||
+ // Paper start
|
||||
+ BlockState blockState = world.getTypeIfLoaded(blockPos);
|
||||
+ if (blockState == null) {
|
||||
+ return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity);
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (blockState.is(state.getBlock())) {
|
||||
DoubleBlockCombiner.BlockType blockType2 = typeMapper.apply(blockState);
|
||||
if (blockType2 != DoubleBlockCombiner.BlockType.SINGLE && blockType != blockType2 && blockState.getValue(directionProperty) == state.getValue(directionProperty)) {
|
|
@ -0,0 +1,54 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 27 Dec 2019 09:42:26 -0800
|
||||
Subject: [PATCH] Guard against serializing mismatching chunk coordinate
|
||||
|
||||
Should help if something dumb happens
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
index 3cb35f2f47ba841915ac2825d30cc4c3274ce3c4..7c04aef3eac54981ca1e34cb87d97104c3c9685b 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
@@ -69,6 +69,13 @@ public class ChunkSerializer {
|
||||
|
||||
public ChunkSerializer() {}
|
||||
|
||||
+ // Paper start - guard against serializing mismatching coordinates
|
||||
+ // TODO Note: This needs to be re-checked each update
|
||||
+ public static ChunkPos getChunkCoordinate(CompoundTag chunkData) {
|
||||
+ CompoundTag levelData = chunkData.getCompound("Level");
|
||||
+ return new ChunkPos(levelData.getInt("xPos"), levelData.getInt("zPos"));
|
||||
+ }
|
||||
+ // Paper end
|
||||
// Paper start
|
||||
public static final class InProgressChunkHolder {
|
||||
|
||||
@@ -95,8 +102,8 @@ public class ChunkSerializer {
|
||||
// Paper end
|
||||
ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator();
|
||||
BiomeSource worldchunkmanager = chunkgenerator.getBiomeSource();
|
||||
- CompoundTag nbttagcompound1 = nbt.getCompound("Level");
|
||||
- ChunkPos chunkcoordintpair1 = new ChunkPos(nbttagcompound1.getInt("xPos"), nbttagcompound1.getInt("zPos"));
|
||||
+ CompoundTag nbttagcompound1 = nbt.getCompound("Level"); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate
|
||||
+ ChunkPos chunkcoordintpair1 = new ChunkPos(nbttagcompound1.getInt("xPos"), nbttagcompound1.getInt("zPos")); // Paper - diff on change, see ChunkSerializer#getChunkCoordinate
|
||||
|
||||
if (!Objects.equals(pos, chunkcoordintpair1)) {
|
||||
ChunkSerializer.LOGGER.error("Chunk file at {} is in the wrong location; relocating. (Expected {}, got {})", pos, pos, chunkcoordintpair1);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
index 6f13c7adce7d4b3d170045ea5ef2a841d34ae7b0..176610b31f66b890afe61f4de46c412382bb8d22 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
@@ -117,6 +117,13 @@ public class ChunkStorage implements AutoCloseable {
|
||||
|
||||
// Paper start - async chunk io
|
||||
public void write(ChunkPos chunkPos, CompoundTag nbt) throws IOException {
|
||||
+ // Paper start
|
||||
+ if (!chunkPos.equals(ChunkSerializer.getChunkCoordinate(nbt))) {
|
||||
+ String world = (this instanceof net.minecraft.server.level.ChunkMap) ? ((net.minecraft.server.level.ChunkMap)this).level.getWorld().getName() : null;
|
||||
+ throw new IllegalArgumentException("Chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + chunkPos.toString()
|
||||
+ + " but compound says coordinate is " + ChunkSerializer.getChunkCoordinate(nbt).toString() + (world == null ? " for an unknown world" : (" for world: " + world)));
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.regionFileCache.write(chunkPos, nbt);
|
||||
// Paper end - Async chunk loading
|
||||
if (this.legacyStructureHandler != null) {
|
|
@ -0,0 +1,26 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 11 Jan 2020 21:50:56 -0800
|
||||
Subject: [PATCH] Optimise IEntityAccess#getPlayerByUUID
|
||||
|
||||
Use the world entity map instead of iterating over all players
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 736521c0925339dc74c2648641932104a947708e..eabf8fa6e8802ebea8dbe124363bb085849af5d9 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -281,6 +281,14 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
public final com.destroystokyo.paper.io.chunk.ChunkTaskManager asyncChunkTaskManager;
|
||||
// Paper end
|
||||
|
||||
+ // Paper start - optimise getPlayerByUUID
|
||||
+ @Nullable
|
||||
+ @Override
|
||||
+ public Player getPlayerByUUID(UUID uuid) {
|
||||
+ return this.getServer().getPlayerList().getPlayer(uuid);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
// Add env and gen to constructor, WorldData -> WorldDataServer
|
||||
public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, ServerLevelData iworlddataserver, ResourceKey<net.minecraft.world.level.Level> resourcekey, DimensionType dimensionmanager, ChunkProgressListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List<CustomSpawner> list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) {
|
||||
// Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error
|
29
patches/server/0353-Fix-items-not-falling-correctly.patch
Normal file
29
patches/server/0353-Fix-items-not-falling-correctly.patch
Normal file
|
@ -0,0 +1,29 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: AJMFactsheets <AJMFactsheets@gmail.com>
|
||||
Date: Fri, 17 Jan 2020 17:17:54 -0600
|
||||
Subject: [PATCH] Fix items not falling correctly
|
||||
|
||||
Since 1.14, Mojang has added an optimization which skips checking if
|
||||
an item should fall every fourth tick.
|
||||
|
||||
However, Spigot's entity activation range class also has an
|
||||
optimization which skips ticking active entities every fourth tick.
|
||||
This can result in a state where an item will never properly fall
|
||||
due to its move method never being called.
|
||||
|
||||
This patch resolves the conflict by offsetting checking an item's
|
||||
move method from Spigot's entity activation range check.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index 82ffe3624943d2e931e2cc2f85ede94f369bd06b..9ee1dc89dd4c6b9453e1f6f92208d454877d23c9 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -135,7 +135,7 @@ public class ItemEntity extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
- if (!this.onGround || this.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D || (this.tickCount + this.getId()) % 4 == 0) {
|
||||
+ if (!this.onGround || this.getDeltaMovement().horizontalDistanceSqr() > 9.999999747378752E-6D || this.tickCount % 4 == 0) { // Paper - Ensure checking item movement is always offset from Spigot's entity activation range check
|
||||
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
float f1 = 0.98F;
|
||||
|
75
patches/server/0354-Lag-compensate-eating.patch
Normal file
75
patches/server/0354-Lag-compensate-eating.patch
Normal file
|
@ -0,0 +1,75 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 14 Jan 2020 15:28:28 -0800
|
||||
Subject: [PATCH] Lag compensate eating
|
||||
|
||||
When the server is lagging, players will wait longer when eating.
|
||||
Change to also use a time check instead if it passes.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 5def2e0379373b126a1b2281b0859b39443fc4ac..f48435dc344fb48feb48e2a141b394829058c5c4 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3492,6 +3492,11 @@ public abstract class LivingEntity extends Entity {
|
||||
return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
|
||||
}
|
||||
|
||||
+ // Paper start - lag compensate eating
|
||||
+ protected long eatStartTime;
|
||||
+ protected int totalEatTimeTicks;
|
||||
+ // Paper end
|
||||
+
|
||||
private void updatingUsingItem() {
|
||||
if (this.isUsingItem()) {
|
||||
if (ItemStack.isSameIgnoreDurability(this.getItemInHand(this.getUsedItemHand()), this.useItem)) {
|
||||
@@ -3509,8 +3514,12 @@ public abstract class LivingEntity extends Entity {
|
||||
if (this.shouldTriggerItemUseEffects()) {
|
||||
this.triggerItemUseEffects(stack, 5);
|
||||
}
|
||||
-
|
||||
- if (--this.useItemRemaining == 0 && !this.level.isClientSide && !stack.useOnRelease()) {
|
||||
+ // Paper start - lag compensate eating
|
||||
+ // we add 1 to the expected time to avoid lag compensating when we should not
|
||||
+ boolean shouldLagCompensate = this.useItem.getItem().isEdible() && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1 + this.totalEatTimeTicks) * 50 * (1000 * 1000));
|
||||
+ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level.isClientSide && !this.useItem.useOnRelease()) {
|
||||
+ this.useItemRemaining = 0;
|
||||
+ // Paper end
|
||||
this.completeUsingItem();
|
||||
}
|
||||
|
||||
@@ -3556,7 +3565,10 @@ public abstract class LivingEntity extends Entity {
|
||||
|
||||
if (!itemstack.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper use override flag
|
||||
this.useItem = itemstack;
|
||||
- this.useItemRemaining = itemstack.getUseDuration();
|
||||
+ // Paper start - lag compensate eating
|
||||
+ this.useItemRemaining = this.totalEatTimeTicks = itemstack.getUseDuration();
|
||||
+ this.eatStartTime = System.nanoTime();
|
||||
+ // Paper end
|
||||
if (!this.level.isClientSide) {
|
||||
this.setLivingEntityFlag(1, true);
|
||||
this.setLivingEntityFlag(2, enumhand == InteractionHand.OFF_HAND);
|
||||
@@ -3580,7 +3592,10 @@ public abstract class LivingEntity extends Entity {
|
||||
}
|
||||
} else if (!this.isUsingItem() && !this.useItem.isEmpty()) {
|
||||
this.useItem = ItemStack.EMPTY;
|
||||
- this.useItemRemaining = 0;
|
||||
+ // Paper start - lag compensate eating
|
||||
+ this.useItemRemaining = this.totalEatTimeTicks = 0;
|
||||
+ this.eatStartTime = -1L;
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3706,7 +3721,10 @@ public abstract class LivingEntity extends Entity {
|
||||
}
|
||||
|
||||
this.useItem = ItemStack.EMPTY;
|
||||
- this.useItemRemaining = 0;
|
||||
+ // Paper start - lag compensate eating
|
||||
+ this.useItemRemaining = this.totalEatTimeTicks = 0;
|
||||
+ this.eatStartTime = -1L;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public boolean isBlocking() {
|
|
@ -0,0 +1,19 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BrodyBeckwith <brody@beckwith.dev>
|
||||
Date: Tue, 14 Jan 2020 17:49:03 -0500
|
||||
Subject: [PATCH] Optimize call to getFluid for explosions
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
index edc0845ae735a9cf3e0f1a3a2b7eabf726d62744..cdf214fca3b0055efa56702470d9d2f890a8aead 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||
@@ -174,7 +174,7 @@ public class Explosion {
|
||||
for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) {
|
||||
BlockPos blockposition = new BlockPos(d4, d5, d6);
|
||||
BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
- FluidState fluid = this.level.getFluidState(blockposition);
|
||||
+ FluidState fluid = iblockdata.getFluidState(); // Paper
|
||||
|
||||
if (!this.level.isInWorldBounds(blockposition)) {
|
||||
break;
|
|
@ -0,0 +1,23 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 17 Jan 2020 18:44:55 -0800
|
||||
Subject: [PATCH] Fix last firework in stack not having effects when dispensed
|
||||
- #2871
|
||||
|
||||
CB used the resulting item in the dispenser rather than the item
|
||||
dispensed. The resulting item would have size == 0 and therefore
|
||||
be convertered to air, hence why the effects disappeared.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
index b665d4293b746b221d469a7b029c1c7f17df6188..92623ae25249d63efb92be8bd6c95228f9155ad2 100644
|
||||
--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
@@ -431,7 +431,7 @@ public interface DispenseItemBehavior {
|
||||
}
|
||||
|
||||
itemstack1 = CraftItemStack.asNMSCopy(event.getItem());
|
||||
- FireworkRocketEntity entityfireworks = new FireworkRocketEntity(pointer.getLevel(), stack, pointer.x(), pointer.y(), pointer.x(), true);
|
||||
+ FireworkRocketEntity entityfireworks = new FireworkRocketEntity(pointer.getLevel(), itemstack1, pointer.x(), pointer.y(), pointer.x(), true); // Paper - GH-2871 - fix last firework in stack having no effects when dispensed
|
||||
|
||||
DispenseItemBehavior.setEntityPokingOutOfBlock(pointer, entityfireworks, enumdirection);
|
||||
entityfireworks.shoot((double) enumdirection.getStepX(), (double) enumdirection.getStepY(), (double) enumdirection.getStepZ(), 0.5F, 1.0F);
|
|
@ -0,0 +1,32 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Thu, 2 Jan 2020 12:25:07 -0600
|
||||
Subject: [PATCH] Add effect to block break naturally
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
index 0a9ed9992a2fc97472a06591a5d129a767ce21af..ca95a6b1b156b37f839c6479733e5184691af66c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
@@ -632,6 +632,13 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean breakNaturally(ItemStack item) {
|
||||
+ // Paper start
|
||||
+ return breakNaturally(item, false);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean breakNaturally(ItemStack item, boolean triggerEffect) {
|
||||
+ // Paper end
|
||||
// Order matters here, need to drop before setting to air so skulls can get their data
|
||||
net.minecraft.world.level.block.state.BlockState iblockdata = this.getNMS();
|
||||
net.minecraft.world.level.block.Block block = iblockdata.getBlock();
|
||||
@@ -641,6 +648,7 @@ public class CraftBlock implements Block {
|
||||
// Modelled off EntityHuman#hasBlock
|
||||
if (block != Blocks.AIR && (item == null || !iblockdata.requiresCorrectToolForDrops() || nmsItem.isCorrectToolForDrops(iblockdata))) {
|
||||
net.minecraft.world.level.block.Block.dropResources(iblockdata, this.world.getMinecraftWorld(), position, this.world.getBlockEntity(position), null, nmsItem);
|
||||
+ if (triggerEffect) world.levelEvent(org.bukkit.Effect.STEP_SOUND.getId(), position, net.minecraft.world.level.block.Block.getId(block.defaultBlockState())); // Paper
|
||||
result = true;
|
||||
}
|
||||
|
774
patches/server/0358-Entity-Activation-Range-2.0.patch
Normal file
774
patches/server/0358-Entity-Activation-Range-2.0.patch
Normal file
|
@ -0,0 +1,774 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 13 May 2016 01:38:06 -0400
|
||||
Subject: [PATCH] Entity Activation Range 2.0
|
||||
|
||||
Optimizes performance of Activation Range
|
||||
|
||||
Adds many new configurations and a new wake up inactive system
|
||||
|
||||
Fixes and adds new Immunities to improve gameplay behavior
|
||||
|
||||
Adds water Mobs to activation range config and nerfs fish
|
||||
Adds flying monsters to control ghast and phantoms
|
||||
Adds villagers as separate config
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index eabf8fa6e8802ebea8dbe124363bb085849af5d9..67b9daee8d7e55fdf2015e6616f393f176b1ca96 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2,7 +2,6 @@ package net.minecraft.server.level;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import co.aikar.timings.TimingHistory; // Paper
|
||||
-import co.aikar.timings.Timings; // Paper
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
@@ -11,7 +10,6 @@ import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSets;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
-import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
@@ -123,7 +121,6 @@ import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.storage.EntityStorage;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.dimension.end.EndDragonFight;
|
||||
-import net.minecraft.world.level.entity.EntityAccess;
|
||||
import net.minecraft.world.level.entity.EntityPersistentStorage;
|
||||
import net.minecraft.world.level.entity.EntityTickList;
|
||||
import net.minecraft.world.level.entity.EntityTypeTest;
|
||||
@@ -888,17 +885,17 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
++TimingHistory.entityTicks; // Paper - timings
|
||||
// Spigot start
|
||||
co.aikar.timings.Timing timer; // Paper
|
||||
- if (!org.spigotmc.ActivationRange.checkIfActive(entity)) {
|
||||
+ /*if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { // Paper - comment out - EAR 2, reimplement below
|
||||
entity.tickCount++;
|
||||
timer = entity.getType().inactiveTickTimer.startTiming(); try { // Paper - timings
|
||||
entity.inactiveTick();
|
||||
} finally { timer.stopTiming(); } // Paper
|
||||
return;
|
||||
- }
|
||||
+ }*/ // Paper - comment out EAR 2
|
||||
// Spigot end
|
||||
// Paper start- timings
|
||||
- TimingHistory.activatedEntityTicks++;
|
||||
- timer = entity.getVehicle() != null ? entity.getType().passengerTickTimer.startTiming() : entity.getType().tickTimer.startTiming();
|
||||
+ final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity);
|
||||
+ timer = isActive ? entity.getType().tickTimer.startTiming() : entity.getType().inactiveTickTimer.startTiming(); // Paper
|
||||
try {
|
||||
// Paper end - timings
|
||||
entity.isInLava();
|
||||
@@ -909,9 +906,13 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
return Registry.ENTITY_TYPE.getKey(entity.getType()).toString();
|
||||
});
|
||||
gameprofilerfiller.incrementCounter("tickNonPassenger");
|
||||
+ if (isActive) { // Paper - EAR 2
|
||||
+ TimingHistory.activatedEntityTicks++;
|
||||
entity.tick();
|
||||
entity.postTick(); // CraftBukkit
|
||||
+ } else { entity.inactiveTick(); } // Paper - EAR 2
|
||||
this.getProfiler().pop();
|
||||
+ } finally { timer.stopTiming(); } // Paper - timings
|
||||
Iterator iterator = entity.getPassengers().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
@@ -920,13 +921,18 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
this.tickPassenger(entity, entity1);
|
||||
}
|
||||
|
||||
- } finally { timer.stopTiming(); } // Paper - timings
|
||||
+ // } finally { timer.stopTiming(); } // Paper - timings - move up
|
||||
|
||||
}
|
||||
|
||||
private void tickPassenger(Entity vehicle, Entity passenger) {
|
||||
if (!passenger.isRemoved() && passenger.getVehicle() == vehicle) {
|
||||
if (passenger instanceof Player || this.entityTickList.contains(passenger)) {
|
||||
+ // Paper - EAR 2
|
||||
+ final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(passenger);
|
||||
+ co.aikar.timings.Timing timer = isActive ? passenger.getType().passengerTickTimer.startTiming() : passenger.getType().passengerInactiveTickTimer.startTiming(); // Paper
|
||||
+ try {
|
||||
+ // Paper end
|
||||
passenger.setOldPosAndRot();
|
||||
++passenger.tickCount;
|
||||
ProfilerFiller gameprofilerfiller = this.getProfiler();
|
||||
@@ -935,8 +941,17 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
return Registry.ENTITY_TYPE.getKey(passenger.getType()).toString();
|
||||
});
|
||||
gameprofilerfiller.incrementCounter("tickPassenger");
|
||||
+ // Paper start - EAR 2
|
||||
+ if (isActive) {
|
||||
passenger.rideTick();
|
||||
passenger.postTick(); // CraftBukkit
|
||||
+ } else {
|
||||
+ passenger.setDeltaMovement(Vec3.ZERO);
|
||||
+ passenger.inactiveTick();
|
||||
+ // copied from inside of if (isPassenger()) of passengerTick, but that ifPassenger is unnecessary
|
||||
+ vehicle.positionRider(passenger);
|
||||
+ }
|
||||
+ // Paper end - EAR 2
|
||||
gameprofilerfiller.pop();
|
||||
Iterator iterator = passenger.getPassengers().iterator();
|
||||
|
||||
@@ -946,6 +961,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
|
||||
this.tickPassenger(passenger, entity2);
|
||||
}
|
||||
|
||||
+ } finally { timer.stopTiming(); }// Paper - EAR2 timings
|
||||
}
|
||||
} else {
|
||||
passenger.stopRiding();
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index a5159198003e43ce272ae73941d2be47d50eedc9..fffeba61e9af5c69876921b48241edb881af2a64 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -275,7 +275,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
|
||||
public boolean noCulling;
|
||||
public boolean hasImpulse;
|
||||
public int portalCooldown;
|
||||
- protected boolean isInsidePortal;
|
||||
+ public boolean isInsidePortal; // Paper - public
|
||||
protected int portalTime;
|
||||
protected BlockPos portalEntrancePos;
|
||||
private boolean invulnerable;
|
||||
@@ -305,6 +305,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
|
||||
public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this);
|
||||
public final boolean defaultActivationState;
|
||||
public long activatedTick = Integer.MIN_VALUE;
|
||||
+ public boolean isTemporarilyActive = false; // Paper
|
||||
public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
|
||||
protected int numCollisions = 0; // Paper
|
||||
public void inactiveTick() { }
|
||||
@@ -746,6 +747,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
|
||||
} else {
|
||||
this.wasOnFire = this.isOnFire();
|
||||
if (movementType == MoverType.PISTON) {
|
||||
+ this.activatedTick = MinecraftServer.currentTick + 20; // Paper
|
||||
movement = this.limitPistonMovement(movement);
|
||||
if (movement.equals(Vec3.ZERO)) {
|
||||
return;
|
||||
@@ -758,6 +760,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
|
||||
this.stuckSpeedMultiplier = Vec3.ZERO;
|
||||
this.setDeltaMovement(Vec3.ZERO);
|
||||
}
|
||||
+ // Paper start - ignore movement changes while inactive.
|
||||
+ if (isTemporarilyActive && !(this instanceof ItemEntity || this instanceof net.minecraft.world.entity.vehicle.AbstractMinecart) && movement == getDeltaMovement() && movementType == MoverType.SELF) {
|
||||
+ setDeltaMovement(Vec3.ZERO);
|
||||
+ this.level.getProfiler().pop();
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
movement = this.maybeBackOffFromEdge(movement, movementType);
|
||||
Vec3 vec3d1 = this.collide(movement);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index f48435dc344fb48feb48e2a141b394829058c5c4..bd1cc5e6fea4b9a171718c1249f652782b7ce13e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -219,7 +219,7 @@ public abstract class LivingEntity extends Entity {
|
||||
protected float rotOffs;
|
||||
protected int deathScore;
|
||||
public float lastHurt;
|
||||
- protected boolean jumping;
|
||||
+ public boolean jumping; // Paper protected -> public
|
||||
public float xxa;
|
||||
public float yya;
|
||||
public float zza;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
index 32e8ae0d2a0f78af671a632c4d1be58a0b38a392..79e10f41b2993a02c4218551b06673f1848325a3 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
@@ -117,7 +117,7 @@ public abstract class Mob extends LivingEntity {
|
||||
public ResourceLocation lootTable;
|
||||
public long lootTableSeed;
|
||||
@Nullable
|
||||
- private Entity leashHolder;
|
||||
+ public Entity leashHolder; // Paper - private -> public
|
||||
private int delayedLeashHolderId;
|
||||
@Nullable
|
||||
private CompoundTag leashInfoTag;
|
||||
@@ -198,6 +198,19 @@ public abstract class Mob extends LivingEntity {
|
||||
return this.lookControl;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ super.inactiveTick();
|
||||
+ if (this.goalSelector.inactiveTick()) {
|
||||
+ this.goalSelector.tick();
|
||||
+ }
|
||||
+ if (this.targetSelector.inactiveTick()) {
|
||||
+ this.targetSelector.tick();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public MoveControl getMoveControl() {
|
||||
if (this.isPassenger() && this.getVehicle() instanceof Mob) {
|
||||
Mob entityinsentient = (Mob) this.getVehicle();
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/PathfinderMob.java b/src/main/java/net/minecraft/world/entity/PathfinderMob.java
|
||||
index 920ae9af8985705a0ada7da5b7085a1ed8ca7f27..7c82d453388a27b69207d051dec316fc14715e2b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/PathfinderMob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/PathfinderMob.java
|
||||
@@ -13,6 +13,7 @@ import org.bukkit.event.entity.EntityUnleashEvent;
|
||||
public abstract class PathfinderMob extends Mob {
|
||||
|
||||
public org.bukkit.craftbukkit.entity.CraftCreature getBukkitCreature() { return (org.bukkit.craftbukkit.entity.CraftCreature) super.getBukkitEntity(); } // Paper
|
||||
+ public BlockPos movingTarget = null; public BlockPos getMovingTarget() { return movingTarget; } // Paper
|
||||
|
||||
protected PathfinderMob(EntityType<? extends PathfinderMob> type, Level world) {
|
||||
super(type, world);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
index 70e5b4446a8485b5995a0ba26af3a86d9b79bcc7..f29ace7b6a27a602102d37d43a6dd0571f218dfe 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
@@ -31,6 +31,7 @@ public class GoalSelector {
|
||||
private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
|
||||
private int tickCount;
|
||||
private int newGoalRate = 3;
|
||||
+ private int curRate;
|
||||
|
||||
public GoalSelector(Supplier<ProfilerFiller> profiler) {
|
||||
this.profiler = profiler;
|
||||
@@ -45,6 +46,20 @@ public class GoalSelector {
|
||||
this.availableGoals.clear();
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public boolean inactiveTick() {
|
||||
+ this.curRate++;
|
||||
+ return this.curRate % this.newGoalRate == 0;
|
||||
+ }
|
||||
+ public boolean hasTasks() {
|
||||
+ for (WrappedGoal task : this.availableGoals) {
|
||||
+ if (task.isRunning()) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
public void removeGoal(Goal goal) {
|
||||
this.availableGoals.stream().filter((wrappedGoal) -> {
|
||||
return wrappedGoal.getGoal() == goal;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
index 065d0752db0e3ae2a89d707aaa2145807f50ecad..c93805ae832d049ea13ca495b778ed52381b1f78 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
|
||||
@@ -14,7 +14,7 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
protected int nextStartTick;
|
||||
protected int tryTicks;
|
||||
private int maxStayTicks;
|
||||
- protected BlockPos blockPos = BlockPos.ZERO; public final BlockPos getTargetPosition() { return this.blockPos; } // Paper - OBFHELPER
|
||||
+ protected BlockPos blockPos = BlockPos.ZERO; public final BlockPos getTargetPosition() { return this.blockPos; } public void setTargetPosition(BlockPos pos) { this.blockPos = pos; mob.movingTarget = pos != BlockPos.ZERO ? pos : null; } // Paper - OBFHELPER
|
||||
private boolean reachedTarget;
|
||||
private final int searchRange;
|
||||
private final int verticalSearchRange;
|
||||
@@ -23,6 +23,13 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
public MoveToBlockGoal(PathfinderMob mob, double speed, int range) {
|
||||
this(mob, speed, range, 1);
|
||||
}
|
||||
+ // Paper start - activation range improvements
|
||||
+ @Override
|
||||
+ public void stop() {
|
||||
+ super.stop();
|
||||
+ setTargetPosition(BlockPos.ZERO);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public MoveToBlockGoal(PathfinderMob mob, double speed, int range, int maxYDifference) {
|
||||
this.mob = mob;
|
||||
@@ -109,6 +116,7 @@ public abstract class MoveToBlockGoal extends Goal {
|
||||
mutableBlockPos.setWithOffset(blockPos, m, k - 1, n);
|
||||
if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level, mutableBlockPos)) {
|
||||
this.blockPos = mutableBlockPos;
|
||||
+ setTargetPosition(mutableBlockPos.immutable()); // Paper
|
||||
return true;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
index 6a9e2105b2d9a4ee83c0a2516d5ef26dc3b99053..a35ce224b11b44567814207c3821d0cd4cdd9ec1 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
@@ -227,17 +227,29 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
@Override
|
||||
public void inactiveTick() {
|
||||
// SPIGOT-3874, SPIGOT-3894, SPIGOT-3846, SPIGOT-5286 :(
|
||||
- if (level.spigotConfig.tickInactiveVillagers && this.isEffectiveAi()) {
|
||||
- this.customServerAiStep();
|
||||
+ // Paper start
|
||||
+ if (this.getUnhappyCounter() > 0) {
|
||||
+ this.setUnhappyCounter(this.getUnhappyCounter() - 1);
|
||||
+ }
|
||||
+ if (this.isEffectiveAi()) {
|
||||
+ if (level.spigotConfig.tickInactiveVillagers) {
|
||||
+ this.customServerAiStep();
|
||||
+ } else {
|
||||
+ this.mobTick(true);
|
||||
+ }
|
||||
}
|
||||
+ maybeDecayGossip();
|
||||
+ // Paper end
|
||||
+
|
||||
super.inactiveTick();
|
||||
}
|
||||
// Spigot End
|
||||
|
||||
@Override
|
||||
- protected void customServerAiStep() {
|
||||
+ protected void customServerAiStep() { mobTick(false); }
|
||||
+ protected void mobTick(boolean inactive) {
|
||||
this.level.getProfiler().push("villagerBrain");
|
||||
- this.getBrain().tick((ServerLevel) this.level, this); // CraftBukkit - decompile error
|
||||
+ if (!inactive) this.getBrain().tick((ServerLevel) this.level, this); // CraftBukkit - decompile error // Paper
|
||||
this.level.getProfiler().pop();
|
||||
if (this.assignProfessionWhenSpawned) {
|
||||
this.assignProfessionWhenSpawned = false;
|
||||
@@ -261,7 +273,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
this.lastTradedPlayer = null;
|
||||
}
|
||||
|
||||
- if (!this.isNoAi() && this.random.nextInt(100) == 0) {
|
||||
+ if (!inactive && !this.isNoAi() && this.random.nextInt(100) == 0) { // Paper
|
||||
Raid raid = ((ServerLevel) this.level).getRaidAt(this.blockPosition());
|
||||
|
||||
if (raid != null && raid.isActive() && !raid.isOver()) {
|
||||
@@ -272,6 +284,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
if (this.getVillagerData().getProfession() == VillagerProfession.NONE && this.isTrading()) {
|
||||
this.stopTrading();
|
||||
}
|
||||
+ if (inactive) return; // Paper
|
||||
|
||||
super.customServerAiStep();
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 9891e40972c1dc6bebe8ccec2bf82123dcdd7e94..ddcde88a8c8b748b4dc2583b4dfd0fb8ea9e201e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -153,6 +153,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public long ticksPerWaterSpawns;
|
||||
public long ticksPerWaterAmbientSpawns;
|
||||
public long ticksPerAmbientSpawns;
|
||||
+ // Paper start
|
||||
+ public int wakeupInactiveRemainingAnimals;
|
||||
+ public int wakeupInactiveRemainingFlying;
|
||||
+ public int wakeupInactiveRemainingMonsters;
|
||||
+ public int wakeupInactiveRemainingVillagers;
|
||||
+ // Paper end
|
||||
public boolean populating;
|
||||
public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
index 84ce3d38d5decb4a2f9fae78e0ef5d715860dc7d..2ab585a018290996e7fa9ca6f3ad7d734cd7beaa 100644
|
||||
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
||||
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
@@ -1,39 +1,51 @@
|
||||
package org.spigotmc;
|
||||
|
||||
-import java.util.Collection;
|
||||
+import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.entity.FlyingMob;
|
||||
import net.minecraft.world.entity.LightningBolt;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
+import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.PathfinderMob;
|
||||
+import net.minecraft.world.entity.ai.Brain;
|
||||
import net.minecraft.world.entity.ambient.AmbientCreature;
|
||||
import net.minecraft.world.entity.animal.Animal;
|
||||
+import net.minecraft.world.entity.animal.Bee;
|
||||
import net.minecraft.world.entity.animal.Sheep;
|
||||
+import net.minecraft.world.entity.animal.WaterAnimal;
|
||||
+import net.minecraft.world.entity.animal.horse.Llama;
|
||||
import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||
import net.minecraft.world.entity.boss.enderdragon.EndCrystal;
|
||||
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||
import net.minecraft.world.entity.boss.wither.WitherBoss;
|
||||
import net.minecraft.world.entity.item.PrimedTnt;
|
||||
import net.minecraft.world.entity.monster.Creeper;
|
||||
-import net.minecraft.world.entity.monster.Monster;
|
||||
-import net.minecraft.world.entity.monster.Slime;
|
||||
+import net.minecraft.world.entity.monster.Enemy;
|
||||
+import net.minecraft.world.entity.monster.Pillager;
|
||||
import net.minecraft.world.entity.npc.Villager;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
|
||||
+import net.minecraft.world.entity.projectile.EyeOfEnder;
|
||||
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
|
||||
import net.minecraft.world.entity.projectile.ThrowableProjectile;
|
||||
import net.minecraft.world.entity.projectile.ThrownTrident;
|
||||
import net.minecraft.world.entity.raid.Raider;
|
||||
+import co.aikar.timings.MinecraftTimings;
|
||||
+import net.minecraft.world.entity.schedule.Activity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
-import co.aikar.timings.MinecraftTimings;
|
||||
|
||||
public class ActivationRange
|
||||
{
|
||||
|
||||
public enum ActivationType
|
||||
{
|
||||
+ WATER, // Paper
|
||||
+ FLYING_MONSTER, // Paper
|
||||
+ VILLAGER, // Paper
|
||||
MONSTER,
|
||||
ANIMAL,
|
||||
RAIDER,
|
||||
@@ -41,6 +53,43 @@ public class ActivationRange
|
||||
|
||||
AABB boundingBox = new AABB( 0, 0, 0, 0, 0, 0 );
|
||||
}
|
||||
+ // Paper start
|
||||
+
|
||||
+ static Activity[] VILLAGER_PANIC_IMMUNITIES = {
|
||||
+ Activity.HIDE,
|
||||
+ Activity.PRE_RAID,
|
||||
+ Activity.RAID,
|
||||
+ Activity.PANIC
|
||||
+ };
|
||||
+
|
||||
+ private static int checkInactiveWakeup(Entity entity) {
|
||||
+ Level world = entity.level;
|
||||
+ SpigotWorldConfig config = world.spigotConfig;
|
||||
+ long inactiveFor = MinecraftServer.currentTick - entity.activatedTick;
|
||||
+ if (entity.activationType == ActivationType.VILLAGER) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveVillagersEvery && world.wakeupInactiveRemainingVillagers > 0) {
|
||||
+ world.wakeupInactiveRemainingVillagers--;
|
||||
+ return config.wakeUpInactiveVillagersFor;
|
||||
+ }
|
||||
+ } else if (entity.activationType == ActivationType.ANIMAL) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveAnimalsEvery && world.wakeupInactiveRemainingAnimals > 0) {
|
||||
+ world.wakeupInactiveRemainingAnimals--;
|
||||
+ return config.wakeUpInactiveAnimalsFor;
|
||||
+ }
|
||||
+ } else if (entity.activationType == ActivationType.FLYING_MONSTER) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveFlyingEvery && world.wakeupInactiveRemainingFlying > 0) {
|
||||
+ world.wakeupInactiveRemainingFlying--;
|
||||
+ return config.wakeUpInactiveFlyingFor;
|
||||
+ }
|
||||
+ } else if (entity.activationType == ActivationType.MONSTER || entity.activationType == ActivationType.RAIDER) {
|
||||
+ if (inactiveFor > config.wakeUpInactiveMonstersEvery && world.wakeupInactiveRemainingMonsters > 0) {
|
||||
+ world.wakeupInactiveRemainingMonsters--;
|
||||
+ return config.wakeUpInactiveMonstersFor;
|
||||
+ }
|
||||
+ }
|
||||
+ return -1;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
static AABB maxBB = new AABB( 0, 0, 0, 0, 0, 0 );
|
||||
|
||||
@@ -53,10 +102,13 @@ public class ActivationRange
|
||||
*/
|
||||
public static ActivationType initializeEntityActivationType(Entity entity)
|
||||
{
|
||||
+ if (entity instanceof WaterAnimal) { return ActivationType.WATER; } // Paper
|
||||
+ else if (entity instanceof Villager) { return ActivationType.VILLAGER; } // Paper
|
||||
+ else if (entity instanceof FlyingMob && entity instanceof Enemy) { return ActivationType.FLYING_MONSTER; } // Paper - doing & Monster incase Flying no longer includes monster in future
|
||||
if ( entity instanceof Raider )
|
||||
{
|
||||
return ActivationType.RAIDER;
|
||||
- } else if ( entity instanceof Monster || entity instanceof Slime )
|
||||
+ } else if ( entity instanceof Enemy ) // Paper - correct monster check
|
||||
{
|
||||
return ActivationType.MONSTER;
|
||||
} else if ( entity instanceof PathfinderMob || entity instanceof AmbientCreature )
|
||||
@@ -77,10 +129,14 @@ public class ActivationRange
|
||||
*/
|
||||
public static boolean initializeEntityActivationState(Entity entity, SpigotWorldConfig config)
|
||||
{
|
||||
- if ( ( entity.activationType == ActivationType.MISC && config.miscActivationRange == 0 )
|
||||
- || ( entity.activationType == ActivationType.RAIDER && config.raiderActivationRange == 0 )
|
||||
- || ( entity.activationType == ActivationType.ANIMAL && config.animalActivationRange == 0 )
|
||||
- || ( entity.activationType == ActivationType.MONSTER && config.monsterActivationRange == 0 )
|
||||
+ if ( ( entity.activationType == ActivationType.MISC && config.miscActivationRange <= 0 )
|
||||
+ || ( entity.activationType == ActivationType.RAIDER && config.raiderActivationRange <= 0 )
|
||||
+ || ( entity.activationType == ActivationType.ANIMAL && config.animalActivationRange <= 0 )
|
||||
+ || ( entity.activationType == ActivationType.MONSTER && config.monsterActivationRange <= 0 )
|
||||
+ || ( entity.activationType == ActivationType.VILLAGER && config.villagerActivationRange <= 0 ) // Paper
|
||||
+ || ( entity.activationType == ActivationType.WATER && config.waterActivationRange <= 0 ) // Paper
|
||||
+ || ( entity.activationType == ActivationType.FLYING_MONSTER && config.flyingMonsterActivationRange <= 0 ) // Paper
|
||||
+ || entity instanceof EyeOfEnder // Paper
|
||||
|| entity instanceof Player
|
||||
|| entity instanceof ThrowableProjectile
|
||||
|| entity instanceof EnderDragon
|
||||
@@ -113,10 +169,25 @@ public class ActivationRange
|
||||
final int raiderActivationRange = world.spigotConfig.raiderActivationRange;
|
||||
final int animalActivationRange = world.spigotConfig.animalActivationRange;
|
||||
final int monsterActivationRange = world.spigotConfig.monsterActivationRange;
|
||||
+ // Paper start
|
||||
+ final int waterActivationRange = world.spigotConfig.waterActivationRange;
|
||||
+ final int flyingActivationRange = world.spigotConfig.flyingMonsterActivationRange;
|
||||
+ final int villagerActivationRange = world.spigotConfig.villagerActivationRange;
|
||||
+ world.wakeupInactiveRemainingAnimals = Math.min(world.wakeupInactiveRemainingAnimals + 1, world.spigotConfig.wakeUpInactiveAnimals);
|
||||
+ world.wakeupInactiveRemainingVillagers = Math.min(world.wakeupInactiveRemainingVillagers + 1, world.spigotConfig.wakeUpInactiveVillagers);
|
||||
+ world.wakeupInactiveRemainingMonsters = Math.min(world.wakeupInactiveRemainingMonsters + 1, world.spigotConfig.wakeUpInactiveMonsters);
|
||||
+ world.wakeupInactiveRemainingFlying = Math.min(world.wakeupInactiveRemainingFlying + 1, world.spigotConfig.wakeUpInactiveFlying);
|
||||
+ final ServerChunkCache chunkProvider = (ServerChunkCache) world.getChunkSource();
|
||||
+ // Paper end
|
||||
|
||||
int maxRange = Math.max( monsterActivationRange, animalActivationRange );
|
||||
maxRange = Math.max( maxRange, raiderActivationRange );
|
||||
maxRange = Math.max( maxRange, miscActivationRange );
|
||||
+ // Paper start
|
||||
+ maxRange = Math.max( maxRange, flyingActivationRange );
|
||||
+ maxRange = Math.max( maxRange, waterActivationRange );
|
||||
+ maxRange = Math.max( maxRange, villagerActivationRange );
|
||||
+ // Paper end
|
||||
maxRange = Math.min( ( world.spigotConfig.viewDistance << 4 ) - 8, maxRange );
|
||||
|
||||
for ( Player player : world.players() )
|
||||
@@ -128,6 +199,11 @@ public class ActivationRange
|
||||
ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate( raiderActivationRange, 256, raiderActivationRange );
|
||||
ActivationType.ANIMAL.boundingBox = player.getBoundingBox().inflate( animalActivationRange, 256, animalActivationRange );
|
||||
ActivationType.MONSTER.boundingBox = player.getBoundingBox().inflate( monsterActivationRange, 256, monsterActivationRange );
|
||||
+ // Paper start
|
||||
+ ActivationType.WATER.boundingBox = player.getBoundingBox().inflate( waterActivationRange, 256, waterActivationRange );
|
||||
+ ActivationType.FLYING_MONSTER.boundingBox = player.getBoundingBox().inflate( flyingActivationRange, 256, flyingActivationRange );
|
||||
+ ActivationType.VILLAGER.boundingBox = player.getBoundingBox().inflate( villagerActivationRange, 256, waterActivationRange );
|
||||
+ // Paper end
|
||||
|
||||
world.getEntities().get(maxBB, ActivationRange::activateEntity);
|
||||
}
|
||||
@@ -162,56 +238,105 @@ public class ActivationRange
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
- public static boolean checkEntityImmunities(Entity entity)
|
||||
+ public static int checkEntityImmunities(Entity entity) // Paper - return # of ticks to get immunity
|
||||
{
|
||||
+ // Paper start
|
||||
+ SpigotWorldConfig config = entity.level.spigotConfig;
|
||||
+ int inactiveWakeUpImmunity = checkInactiveWakeup(entity);
|
||||
+ if (inactiveWakeUpImmunity > -1) {
|
||||
+ return inactiveWakeUpImmunity;
|
||||
+ }
|
||||
+ if (entity.remainingFireTicks > 0) {
|
||||
+ return 2;
|
||||
+ }
|
||||
+ long inactiveFor = MinecraftServer.currentTick - entity.activatedTick;
|
||||
+ // Paper end
|
||||
// quick checks.
|
||||
- if ( entity.wasTouchingWater || entity.remainingFireTicks > 0 )
|
||||
+ if ( (entity.activationType != ActivationType.WATER && entity.wasTouchingWater && entity.isPushedByFluid()) ) // Paper
|
||||
{
|
||||
- return true;
|
||||
+ return 100; // Paper
|
||||
}
|
||||
if ( !( entity instanceof AbstractArrow ) )
|
||||
{
|
||||
- if ( !entity.isOnGround() || !entity.passengers.isEmpty() || entity.isPassenger() )
|
||||
+ if ( (!entity.isOnGround() && !(entity instanceof FlyingMob)) ) // Paper - remove passengers logic
|
||||
{
|
||||
- return true;
|
||||
+ return 10; // Paper
|
||||
}
|
||||
} else if ( !( (AbstractArrow) entity ).inGround )
|
||||
{
|
||||
- return true;
|
||||
+ return 1; // Paper
|
||||
}
|
||||
// special cases.
|
||||
if ( entity instanceof LivingEntity )
|
||||
{
|
||||
LivingEntity living = (LivingEntity) entity;
|
||||
- if ( /*TODO: Missed mapping? living.attackTicks > 0 || */ living.hurtTime > 0 || living.activeEffects.size() > 0 )
|
||||
+ if ( living.onClimbable() || living.jumping || living.hurtTime > 0 || living.activeEffects.size() > 0 ) // Paper
|
||||
{
|
||||
- return true;
|
||||
+ return 1; // Paper
|
||||
}
|
||||
- if ( entity instanceof PathfinderMob && ( (PathfinderMob) entity ).getTarget() != null )
|
||||
+ if ( entity instanceof Mob && ((Mob) entity ).getTarget() != null) // Paper
|
||||
{
|
||||
- return true;
|
||||
+ return 20; // Paper
|
||||
+ }
|
||||
+ // Paper start
|
||||
+ if (entity instanceof Bee) {
|
||||
+ Bee bee = (Bee)entity;
|
||||
+ BlockPos movingTarget = bee.getMovingTarget();
|
||||
+ if (bee.isAngry() ||
|
||||
+ (bee.getHivePos() != null && bee.getHivePos().equals(movingTarget)) ||
|
||||
+ (bee.getSavedFlowerPos() != null && bee.getSavedFlowerPos().equals(movingTarget))
|
||||
+ ) {
|
||||
+ return 20;
|
||||
+ }
|
||||
+ }
|
||||
+ if ( entity instanceof Villager ) {
|
||||
+ Brain<Villager> behaviorController = ((Villager) entity).getBrain();
|
||||
+
|
||||
+ if (config.villagersActiveForPanic) {
|
||||
+ for (Activity activity : VILLAGER_PANIC_IMMUNITIES) {
|
||||
+ if (behaviorController.isActive(activity)) {
|
||||
+ return 20*5;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (config.villagersWorkImmunityAfter > 0 && inactiveFor >= config.villagersWorkImmunityAfter) {
|
||||
+ if (behaviorController.isActive(Activity.WORK)) {
|
||||
+ return config.villagersWorkImmunityFor;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() )
|
||||
+ if ( entity instanceof Llama && ( (Llama) entity ).inCaravan() )
|
||||
{
|
||||
- return true;
|
||||
+ return 1;
|
||||
}
|
||||
+ // Paper end
|
||||
if ( entity instanceof Animal )
|
||||
{
|
||||
Animal animal = (Animal) entity;
|
||||
if ( animal.isBaby() || animal.isInLove() )
|
||||
{
|
||||
- return true;
|
||||
+ return 5; // Paper
|
||||
}
|
||||
if ( entity instanceof Sheep && ( (Sheep) entity ).isSheared() )
|
||||
{
|
||||
- return true;
|
||||
+ return 1; // Paper
|
||||
}
|
||||
}
|
||||
if (entity instanceof Creeper && ((Creeper) entity).isIgnited()) { // isExplosive
|
||||
- return true;
|
||||
+ return 20; // Paper
|
||||
+ }
|
||||
+ // Paper start
|
||||
+ if (entity instanceof Mob && ((Mob) entity).targetSelector.hasTasks() ) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if (entity instanceof Pillager) {
|
||||
+ Pillager pillager = (Pillager) entity;
|
||||
+ // TODO:?
|
||||
}
|
||||
+ // Paper end
|
||||
}
|
||||
- return false;
|
||||
+ return -1; // Paper
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,8 +351,19 @@ public class ActivationRange
|
||||
if ( entity instanceof FireworkRocketEntity ) {
|
||||
return true;
|
||||
}
|
||||
+ // Paper start - special case always immunities
|
||||
+ // immunize brand new entities, dead entities, and portal scenarios
|
||||
+ if (entity.defaultActivationState || entity.tickCount < 20*10 || !entity.isAlive() || entity.isInsidePortal || entity.portalCooldown > 0) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // immunize leashed entities
|
||||
+ if (entity instanceof Mob && ((Mob)entity).leashHolder instanceof Player) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
- boolean isActive = entity.activatedTick >= MinecraftServer.currentTick || entity.defaultActivationState;
|
||||
+ boolean isActive = entity.activatedTick >= MinecraftServer.currentTick;
|
||||
+ entity.isTemporarilyActive = false; // Paper
|
||||
|
||||
// Should this entity tick?
|
||||
if ( !isActive )
|
||||
@@ -235,15 +371,19 @@ public class ActivationRange
|
||||
if ( ( MinecraftServer.currentTick - entity.activatedTick - 1 ) % 20 == 0 )
|
||||
{
|
||||
// Check immunities every 20 ticks.
|
||||
- if ( ActivationRange.checkEntityImmunities( entity ) )
|
||||
- {
|
||||
- // Triggered some sort of immunity, give 20 full ticks before we check again.
|
||||
- entity.activatedTick = MinecraftServer.currentTick + 20;
|
||||
+ // Paper start
|
||||
+ int immunity = checkEntityImmunities(entity);
|
||||
+ if (immunity >= 0) {
|
||||
+ entity.activatedTick = MinecraftServer.currentTick + immunity;
|
||||
+ } else {
|
||||
+ entity.isTemporarilyActive = true;
|
||||
}
|
||||
+ // Paper end
|
||||
isActive = true;
|
||||
+
|
||||
}
|
||||
// Add a little performance juice to active entities. Skip 1/4 if not immune.
|
||||
- } else if ( !entity.defaultActivationState && entity.tickCount % 4 == 0 && !ActivationRange.checkEntityImmunities( entity ) )
|
||||
+ } else if ( entity.tickCount % 4 == 0 && ActivationRange.checkEntityImmunities( entity ) < 0 ) // Paper
|
||||
{
|
||||
isActive = false;
|
||||
}
|
||||
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
index 8e6eae7cc27f66faede9a3dc74571e1814df3652..308de0757c219c1e5fa8bde182343c4095301cde 100644
|
||||
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
@@ -180,13 +180,59 @@ public class SpigotWorldConfig
|
||||
public int monsterActivationRange = 32;
|
||||
public int raiderActivationRange = 48;
|
||||
public int miscActivationRange = 16;
|
||||
+ // Paper start
|
||||
+ public int flyingMonsterActivationRange = 32;
|
||||
+ public int waterActivationRange = 16;
|
||||
+ public int villagerActivationRange = 32;
|
||||
+ public int wakeUpInactiveAnimals = 4;
|
||||
+ public int wakeUpInactiveAnimalsEvery = 60*20;
|
||||
+ public int wakeUpInactiveAnimalsFor = 5*20;
|
||||
+ public int wakeUpInactiveMonsters = 8;
|
||||
+ public int wakeUpInactiveMonstersEvery = 20*20;
|
||||
+ public int wakeUpInactiveMonstersFor = 5*20;
|
||||
+ public int wakeUpInactiveVillagers = 4;
|
||||
+ public int wakeUpInactiveVillagersEvery = 30*20;
|
||||
+ public int wakeUpInactiveVillagersFor = 5*20;
|
||||
+ public int wakeUpInactiveFlying = 8;
|
||||
+ public int wakeUpInactiveFlyingEvery = 10*20;
|
||||
+ public int wakeUpInactiveFlyingFor = 5*20;
|
||||
+ public int villagersWorkImmunityAfter = 5*20;
|
||||
+ public int villagersWorkImmunityFor = 20;
|
||||
+ public boolean villagersActiveForPanic = true;
|
||||
+ // Paper end
|
||||
public boolean tickInactiveVillagers = true;
|
||||
private void activationRange()
|
||||
{
|
||||
+ boolean hasAnimalsConfig = config.getInt("entity-activation-range.animals", this.animalActivationRange) != this.animalActivationRange; // Paper
|
||||
this.animalActivationRange = this.getInt( "entity-activation-range.animals", this.animalActivationRange );
|
||||
this.monsterActivationRange = this.getInt( "entity-activation-range.monsters", this.monsterActivationRange );
|
||||
this.raiderActivationRange = this.getInt( "entity-activation-range.raiders", this.raiderActivationRange );
|
||||
this.miscActivationRange = this.getInt( "entity-activation-range.misc", this.miscActivationRange );
|
||||
+ // Paper start
|
||||
+ this.waterActivationRange = this.getInt( "entity-activation-range.water", this.waterActivationRange );
|
||||
+ this.villagerActivationRange = this.getInt( "entity-activation-range.villagers", hasAnimalsConfig ? this.animalActivationRange : this.villagerActivationRange );
|
||||
+ this.flyingMonsterActivationRange = this.getInt( "entity-activation-range.flying-monsters", this.flyingMonsterActivationRange );
|
||||
+
|
||||
+ this.wakeUpInactiveAnimals = this.getInt("entity-activation-range.wake-up-inactive.animals-max-per-tick", this.wakeUpInactiveAnimals);
|
||||
+ this.wakeUpInactiveAnimalsEvery = this.getInt("entity-activation-range.wake-up-inactive.animals-every", this.wakeUpInactiveAnimalsEvery);
|
||||
+ this.wakeUpInactiveAnimalsFor = this.getInt("entity-activation-range.wake-up-inactive.animals-for", this.wakeUpInactiveAnimalsFor);
|
||||
+
|
||||
+ this.wakeUpInactiveMonsters = this.getInt("entity-activation-range.wake-up-inactive.monsters-max-per-tick", this.wakeUpInactiveMonsters);
|
||||
+ this.wakeUpInactiveMonstersEvery = this.getInt("entity-activation-range.wake-up-inactive.monsters-every", this.wakeUpInactiveMonstersEvery);
|
||||
+ this.wakeUpInactiveMonstersFor = this.getInt("entity-activation-range.wake-up-inactive.monsters-for", this.wakeUpInactiveMonstersFor);
|
||||
+
|
||||
+ this.wakeUpInactiveVillagers = this.getInt("entity-activation-range.wake-up-inactive.villagers-max-per-tick", this.wakeUpInactiveVillagers);
|
||||
+ this.wakeUpInactiveVillagersEvery = this.getInt("entity-activation-range.wake-up-inactive.villagers-every", this.wakeUpInactiveVillagersEvery);
|
||||
+ this.wakeUpInactiveVillagersFor = this.getInt("entity-activation-range.wake-up-inactive.villagers-for", this.wakeUpInactiveVillagersFor);
|
||||
+
|
||||
+ this.wakeUpInactiveFlying = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-max-per-tick", this.wakeUpInactiveFlying);
|
||||
+ this.wakeUpInactiveFlyingEvery = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-every", this.wakeUpInactiveFlyingEvery);
|
||||
+ this.wakeUpInactiveFlyingFor = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-for", this.wakeUpInactiveFlyingFor);
|
||||
+
|
||||
+ this.villagersWorkImmunityAfter = this.getInt( "entity-activation-range.villagers-work-immunity-after", this.villagersWorkImmunityAfter );
|
||||
+ this.villagersWorkImmunityFor = this.getInt( "entity-activation-range.villagers-work-immunity-for", this.villagersWorkImmunityFor );
|
||||
+ this.villagersActiveForPanic = this.getBoolean( "entity-activation-range.villagers-active-for-panic", this.villagersActiveForPanic );
|
||||
+ // Paper end
|
||||
this.tickInactiveVillagers = this.getBoolean( "entity-activation-range.tick-inactive-villagers", this.tickInactiveVillagers );
|
||||
this.log( "Entity Activation Range: An " + this.animalActivationRange + " / Mo " + this.monsterActivationRange + " / Ra " + this.raiderActivationRange + " / Mi " + this.miscActivationRange + " / Tiv " + this.tickInactiveVillagers );
|
||||
}
|
43
patches/server/0359-Increase-Light-Queue-Size.patch
Normal file
43
patches/server/0359-Increase-Light-Queue-Size.patch
Normal file
|
@ -0,0 +1,43 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 8 Apr 2020 21:24:05 -0400
|
||||
Subject: [PATCH] Increase Light Queue Size
|
||||
|
||||
Wiz mentioned that large WorldEdit operations cause light to run on
|
||||
main thread. The queue was small, set to 5.. this bumps it to 20
|
||||
but makes it configurable per-world.
|
||||
|
||||
The main risk of increasing this higher is during shutdown, some
|
||||
queued light updates may be lost because mojang did not flush the
|
||||
light engine on shutdown...
|
||||
|
||||
The queue size only puts a cap on max loss, doesn't solve that problem.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 041efecbfcd54384d15ebf771cdfa0e711483997..e29566cad2647da4d9288e912188b57f00e8dd0c 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -440,5 +440,10 @@ public class PaperWorldConfig {
|
||||
disableHopperMoveEvents = getBoolean("hopper.disable-move-event", disableHopperMoveEvents);
|
||||
log("Hopper Move Item Events: " + (disableHopperMoveEvents ? "disabled" : "enabled"));
|
||||
}
|
||||
+
|
||||
+ public int lightQueueSize = 20;
|
||||
+ private void lightQueueSize() {
|
||||
+ lightQueueSize = getInt("light-queue-size", lightQueueSize);
|
||||
+ }
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 312be2221e1acc44aaf6936533b0eb968f796dc6..494a3afaaa0e3496d30e8d97edbab62b21610dfe 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -832,7 +832,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.executeModerately();
|
||||
// CraftBukkit end
|
||||
if (worldserver.getWorld().getKeepSpawnInMemory()) worldloadlistener.stop(); // Paper
|
||||
- chunkproviderserver.getLightEngine().setTaskPerBatch(5);
|
||||
+ chunkproviderserver.getLightEngine().setTaskPerBatch(worldserver.paperConfig.lightQueueSize); // Paper - increase light queue size
|
||||
// CraftBukkit start
|
||||
// this.updateSpawnFlags();
|
||||
worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
|
179
patches/server/0360-Fix-Light-Command.patch
Normal file
179
patches/server/0360-Fix-Light-Command.patch
Normal file
|
@ -0,0 +1,179 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 7 May 2020 19:17:36 -0400
|
||||
Subject: [PATCH] Fix Light Command
|
||||
|
||||
This lets you run /paper fixlight <chunkRadius> (max 5) to automatically
|
||||
fix all light data in the chunks.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
index 71ffa66973d8994e2a480435ac1ada3fe61600a4..7b5afc5d34b78e6404c1a5c6bb823d9589471f13 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
@@ -10,7 +10,8 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
-import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
+import net.minecraft.server.level.ThreadedLevelLightEngine;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
@@ -25,15 +26,18 @@ import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
+import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
+import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
+import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -43,7 +47,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class PaperCommand extends Command {
|
||||
private static final String BASE_PERM = "bukkit.command.paper.";
|
||||
- private static final ImmutableSet<String> SUBCOMMANDS = ImmutableSet.<String>builder().add("heap", "entity", "reload", "version", "debug", "chunkinfo").build();
|
||||
+ private static final ImmutableSet<String> SUBCOMMANDS = ImmutableSet.<String>builder().add("heap", "entity", "reload", "version", "debug", "chunkinfo", "fixlight").build();
|
||||
|
||||
public PaperCommand(String name) {
|
||||
super(name);
|
||||
@@ -158,6 +162,9 @@ public class PaperCommand extends Command {
|
||||
case "chunkinfo":
|
||||
doChunkInfo(sender, args);
|
||||
break;
|
||||
+ case "fixlight":
|
||||
+ this.doFixLight(sender, args);
|
||||
+ break;
|
||||
case "ver":
|
||||
if (!testPermission(sender, "version")) break; // "ver" needs a special check because it's an alias. All other commands are checked up before the switch statement (because they are present in the SUBCOMMANDS set)
|
||||
case "version":
|
||||
@@ -413,4 +420,74 @@ public class PaperCommand extends Command {
|
||||
|
||||
Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Paper config reload complete.");
|
||||
}
|
||||
+ private void doFixLight(CommandSender sender, String[] args) {
|
||||
+ if (!(sender instanceof Player)) {
|
||||
+ sender.sendMessage("Only players can use this command");
|
||||
+ return;
|
||||
+ }
|
||||
+ int radius = 2;
|
||||
+ if (args.length > 1) {
|
||||
+ try {
|
||||
+ radius = Math.min(5, Integer.parseInt(args[1]));
|
||||
+ } catch (Exception e) {
|
||||
+ sender.sendMessage("Not a number");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ CraftPlayer player = (CraftPlayer) sender;
|
||||
+ ServerPlayer handle = player.getHandle();
|
||||
+ ServerLevel world = (ServerLevel) handle.level;
|
||||
+ ThreadedLevelLightEngine lightengine = world.getChunkSource().getLightEngine();
|
||||
+
|
||||
+ net.minecraft.core.BlockPos center = MCUtil.toBlockPosition(player.getLocation());
|
||||
+ Deque<ChunkPos> queue = new ArrayDeque<>(MCUtil.getSpiralOutChunks(center, radius));
|
||||
+ updateLight(sender, world, lightengine, queue);
|
||||
+ }
|
||||
+
|
||||
+ private void updateLight(CommandSender sender, ServerLevel world, ThreadedLevelLightEngine lightengine, Deque<ChunkPos> queue) {
|
||||
+ ChunkPos coord = queue.poll();
|
||||
+ if (coord == null) {
|
||||
+ sender.sendMessage("All Chunks Light updated");
|
||||
+ return;
|
||||
+ }
|
||||
+ world.getChunkSource().getChunkAtAsynchronously(coord.x, coord.z, false, false).whenCompleteAsync((either, ex) -> {
|
||||
+ if (ex != null) {
|
||||
+ sender.sendMessage("Error loading chunk " + coord);
|
||||
+ updateLight(sender, world, lightengine, queue);
|
||||
+ return;
|
||||
+ }
|
||||
+ net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) either.left().orElse(null);
|
||||
+ if (chunk == null) {
|
||||
+ updateLight(sender, world, lightengine, queue);
|
||||
+ return;
|
||||
+ }
|
||||
+ lightengine.setTaskPerBatch(world.paperConfig.lightQueueSize + 16 * 256); // ensure full chunk can fit into queue
|
||||
+ sender.sendMessage("Updating Light " + coord);
|
||||
+ int cx = chunk.getPos().x << 4;
|
||||
+ int cz = chunk.getPos().z << 4;
|
||||
+ for (int y = 0; y < world.getHeight(); y++) {
|
||||
+ for (int x = 0; x < 16; x++) {
|
||||
+ for (int z = 0; z < 16; z++) {
|
||||
+ net.minecraft.core.BlockPos pos = new net.minecraft.core.BlockPos(cx + x, y, cz + z);
|
||||
+ lightengine.checkBlock(pos);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ lightengine.tryScheduleUpdate();
|
||||
+ ChunkHolder visibleChunk = world.getChunkSource().chunkMap.getVisibleChunkIfPresent(chunk.coordinateKey);
|
||||
+ if (visibleChunk != null) {
|
||||
+ world.getChunkSource().chunkMap.addLightTask(visibleChunk, () -> {
|
||||
+ MinecraftServer.getServer().processQueue.add(() -> {
|
||||
+ visibleChunk.broadcast(new net.minecraft.network.protocol.game.ClientboundLightUpdatePacket(chunk.getPos(), lightengine, null, null, true), false);
|
||||
+ updateLight(sender, world, lightengine, queue);
|
||||
+ });
|
||||
+ });
|
||||
+ } else {
|
||||
+ updateLight(sender, world, lightengine, queue);
|
||||
+ }
|
||||
+ lightengine.setTaskPerBatch(world.paperConfig.lightQueueSize);
|
||||
+ }, MinecraftServer.getServer());
|
||||
+ }
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
index 56e292e6550b19d0cae9ebad369da730ca1cabd8..3653ec6f93d627092e63cede51f4db2e12b10613 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -312,7 +312,7 @@ public class ChunkHolder {
|
||||
|
||||
}
|
||||
|
||||
- private void broadcast(Packet<?> packet, boolean onlyOnWatchDistanceEdge) {
|
||||
+ public void broadcast(Packet<?> packet, boolean onlyOnWatchDistanceEdge) { // Paper - private -> public
|
||||
this.playerProvider.getPlayers(this.pos, onlyOnWatchDistanceEdge).forEach((entityplayer) -> {
|
||||
entityplayer.connection.send(packet);
|
||||
});
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 5473b22d21ea981f245f4826c4d47295890f88ef..480c361c919bbfbebacf9ac94418eac5ed38e233 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -123,6 +123,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
private final ChunkTaskPriorityQueueSorter queueSorter;
|
||||
private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> worldgenMailbox;
|
||||
private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mainThreadMailbox;
|
||||
+ // Paper start
|
||||
+ final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mailboxLight;
|
||||
+ public void addLightTask(ChunkHolder playerchunk, Runnable run) {
|
||||
+ this.mailboxLight.tell(ChunkTaskPriorityQueueSorter.message(playerchunk, run));
|
||||
+ }
|
||||
+ // Paper end
|
||||
public final ChunkProgressListener progressListener;
|
||||
private final ChunkStatusUpdateListener chunkStatusListener;
|
||||
public final ChunkMap.ChunkDistanceManager distanceManager;
|
||||
@@ -199,11 +205,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
this.progressListener = worldGenerationProgressListener;
|
||||
this.chunkStatusListener = chunkStatusChangeListener;
|
||||
- ProcessorMailbox<Runnable> threadedmailbox1 = ProcessorMailbox.create(executor, "light");
|
||||
+ ProcessorMailbox<Runnable> lightthreaded; ProcessorMailbox<Runnable> threadedmailbox1 = lightthreaded = ProcessorMailbox.create(executor, "light"); // Paper
|
||||
|
||||
this.queueSorter = new ChunkTaskPriorityQueueSorter(ImmutableList.of(threadedmailbox, mailbox, threadedmailbox1), executor, Integer.MAX_VALUE);
|
||||
this.worldgenMailbox = this.queueSorter.getProcessor(threadedmailbox, false);
|
||||
this.mainThreadMailbox = this.queueSorter.getProcessor(mailbox, false);
|
||||
+ this.mailboxLight = this.queueSorter.getProcessor(lightthreaded, false);// Paper
|
||||
this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), threadedmailbox1, this.queueSorter.getProcessor(threadedmailbox1, false));
|
||||
this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor);
|
||||
this.overworldDataStorage = persistentStateManagerFactory;
|
710
patches/server/0361-No-Tick-view-distance-implementation.patch
Normal file
710
patches/server/0361-No-Tick-view-distance-implementation.patch
Normal file
|
@ -0,0 +1,710 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 5 May 2020 21:23:34 -0700
|
||||
Subject: [PATCH] No-Tick view distance implementation
|
||||
|
||||
Implements world view distance getters/setters
|
||||
|
||||
Per-Player is absent due to difficulty of maintaining
|
||||
the diff required to make it happen.
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
index f27fadc15cb7f5c782e45885ec6a5a69963beade..2ff4d4921e2076abf415bd3c8f5173ecd6222168 100644
|
||||
--- a/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
@@ -152,7 +152,8 @@ public class TimingsExport extends Thread {
|
||||
pair("gamerules", toObjectMapper(world.getWorld().getGameRules(), rule -> {
|
||||
return pair(rule, world.getWorld().getGameRuleValue(rule));
|
||||
})),
|
||||
- pair("ticking-distance", world.getChunkSource().chunkMap.getEffectiveViewDistance())
|
||||
+ pair("ticking-distance", world.getChunkSource().chunkMap.getEffectiveViewDistance()),
|
||||
+ pair("notick-viewdistance", world.getChunkSource().chunkMap.getEffectiveNoTickViewDistance())
|
||||
));
|
||||
}));
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index e29566cad2647da4d9288e912188b57f00e8dd0c..3cd8895adecd345c3bdfb8b5e3e9fdf0ef9097db 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -445,5 +445,10 @@ public class PaperWorldConfig {
|
||||
private void lightQueueSize() {
|
||||
lightQueueSize = getInt("light-queue-size", lightQueueSize);
|
||||
}
|
||||
+
|
||||
+ public int noTickViewDistance;
|
||||
+ private void viewDistance() {
|
||||
+ this.noTickViewDistance = this.getInt("viewdistances.no-tick-view-distance", -1);
|
||||
+ }
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
|
||||
index bb0a07a280c7d4885165e9d6488e7741aaa7b47c..9c88426ab1275ee5fb6e28be8b213533dc4ab859 100644
|
||||
--- a/src/main/java/net/minecraft/server/MCUtil.java
|
||||
+++ b/src/main/java/net/minecraft/server/MCUtil.java
|
||||
@@ -636,7 +636,8 @@ public final class MCUtil {
|
||||
});
|
||||
|
||||
worldData.addProperty("name", world.getWorld().getName());
|
||||
- worldData.addProperty("view-distance", world.spigotConfig.viewDistance);
|
||||
+ worldData.addProperty("view-distance", world.getChunkSource().chunkMap.getEffectiveViewDistance());
|
||||
+ worldData.addProperty("no-view-distance", world.getChunkSource().chunkMap.getRawNoTickViewDistance());
|
||||
worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory);
|
||||
worldData.addProperty("keep-spawn-loaded-range", world.paperConfig.keepLoadedRange);
|
||||
worldData.addProperty("visible-chunk-count", visibleChunks.size());
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
index 3653ec6f93d627092e63cede51f4db2e12b10613..995d7977233f0d7683c00a75c3833f9a1eba7f92 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -75,6 +75,17 @@ public class ChunkHolder {
|
||||
|
||||
boolean isUpdateQueued = false; // Paper
|
||||
private final ChunkMap chunkMap; // Paper
|
||||
+ // Paper start - no-tick view distance
|
||||
+ public final LevelChunk getSendingChunk() {
|
||||
+ // it's important that we use getChunkAtIfLoadedImmediately to mirror the chunk sending logic used
|
||||
+ // in Chunk's neighbour callback
|
||||
+ LevelChunk ret = this.chunkMap.level.getChunkSource().getChunkAtIfLoadedImmediately(this.pos.x, this.pos.z);
|
||||
+ if (ret != null && ret.areNeighboursLoaded(1)) {
|
||||
+ return ret;
|
||||
+ }
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end - no-tick view distance
|
||||
|
||||
public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) {
|
||||
this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size());
|
||||
@@ -207,7 +218,7 @@ public class ChunkHolder {
|
||||
}
|
||||
|
||||
public void blockChanged(BlockPos pos) {
|
||||
- LevelChunk chunk = this.getTickingChunk();
|
||||
+ LevelChunk chunk = this.getSendingChunk(); // Paper - no-tick view distance
|
||||
|
||||
if (chunk != null) {
|
||||
int i = this.levelHeightAccessor.getSectionIndex(pos.getY());
|
||||
@@ -223,7 +234,7 @@ public class ChunkHolder {
|
||||
}
|
||||
|
||||
public void sectionLightChanged(LightLayer lightType, int y) {
|
||||
- LevelChunk chunk = this.getTickingChunk();
|
||||
+ LevelChunk chunk = this.getSendingChunk(); // Paper - no-tick view distance
|
||||
|
||||
if (chunk != null) {
|
||||
chunk.setUnsaved(true);
|
||||
@@ -313,9 +324,48 @@ public class ChunkHolder {
|
||||
}
|
||||
|
||||
public void broadcast(Packet<?> packet, boolean onlyOnWatchDistanceEdge) { // Paper - private -> public
|
||||
- this.playerProvider.getPlayers(this.pos, onlyOnWatchDistanceEdge).forEach((entityplayer) -> {
|
||||
- entityplayer.connection.send(packet);
|
||||
- });
|
||||
+ // Paper start - per player view distance
|
||||
+ // there can be potential desync with player's last mapped section and the view distance map, so use the
|
||||
+ // view distance map here.
|
||||
+ com.destroystokyo.paper.util.misc.PlayerAreaMap viewDistanceMap = this.chunkMap.playerViewDistanceBroadcastMap;
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> players = viewDistanceMap.getObjectsInRange(this.pos);
|
||||
+ if (players == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (onlyOnWatchDistanceEdge) { // flag -> border only
|
||||
+ Object[] backingSet = players.getBackingSet();
|
||||
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||
+ Object temp = backingSet[i];
|
||||
+ if (!(temp instanceof ServerPlayer)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ ServerPlayer player = (ServerPlayer)temp;
|
||||
+
|
||||
+ int viewDistance = viewDistanceMap.getLastViewDistance(player);
|
||||
+ long lastPosition = viewDistanceMap.getLastCoordinate(player);
|
||||
+
|
||||
+ int distX = Math.abs(net.minecraft.server.MCUtil.getCoordinateX(lastPosition) - this.pos.x);
|
||||
+ int distZ = Math.abs(net.minecraft.server.MCUtil.getCoordinateZ(lastPosition) - this.pos.z);
|
||||
+
|
||||
+ if (Math.max(distX, distZ) == viewDistance) {
|
||||
+ player.connection.send(packet);
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ Object[] backingSet = players.getBackingSet();
|
||||
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||
+ Object temp = backingSet[i];
|
||||
+ if (!(temp instanceof ServerPlayer)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ ServerPlayer player = (ServerPlayer)temp;
|
||||
+ player.connection.send(packet);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return;
|
||||
+ // Paper end - per player view distance
|
||||
}
|
||||
|
||||
public CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getOrScheduleFuture(ChunkStatus targetStatus, ChunkMap chunkStorage) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 480c361c919bbfbebacf9ac94418eac5ed38e233..fdf5d8ede4b01e399272ddebfbd49258b166f00b 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -122,7 +122,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
private boolean modified;
|
||||
private final ChunkTaskPriorityQueueSorter queueSorter;
|
||||
private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> worldgenMailbox;
|
||||
- private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mainThreadMailbox;
|
||||
+ public final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mainThreadMailbox; // Paper - private -> public
|
||||
// Paper start
|
||||
final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mailboxLight;
|
||||
public void addLightTask(ChunkHolder playerchunk, Runnable run) {
|
||||
@@ -164,21 +164,68 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
// Paper start - distance maps
|
||||
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
|
||||
+ // Paper start - no-tick view distance
|
||||
+ int noTickViewDistance;
|
||||
+ public final int getRawNoTickViewDistance() {
|
||||
+ return this.noTickViewDistance;
|
||||
+ }
|
||||
+ public final int getEffectiveNoTickViewDistance() {
|
||||
+ return this.noTickViewDistance == -1 ? this.getEffectiveViewDistance() : this.noTickViewDistance;
|
||||
+ }
|
||||
+ public final int getLoadViewDistance() {
|
||||
+ return Math.max(this.getEffectiveViewDistance(), this.getEffectiveNoTickViewDistance());
|
||||
+ }
|
||||
+
|
||||
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerViewDistanceBroadcastMap;
|
||||
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerViewDistanceTickMap;
|
||||
+ public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerViewDistanceNoTickMap;
|
||||
+ // Paper end - no-tick view distance
|
||||
|
||||
void addPlayerToDistanceMaps(ServerPlayer player) {
|
||||
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
||||
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
||||
// Note: players need to be explicitly added to distance maps before they can be updated
|
||||
+ // Paper start - no-tick view distance
|
||||
+ int effectiveTickViewDistance = this.getEffectiveViewDistance();
|
||||
+ int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance);
|
||||
+
|
||||
+ if (!this.skipPlayer(player)) {
|
||||
+ this.playerViewDistanceTickMap.add(player, chunkX, chunkZ, effectiveTickViewDistance);
|
||||
+ this.playerViewDistanceNoTickMap.add(player, chunkX, chunkZ, effectiveNoTickViewDistance + 2); // clients need chunk 1 neighbour, and we need another 1 for sending those extra neighbours (as we require neighbours to send)
|
||||
+ }
|
||||
+
|
||||
+ player.needsChunkCenterUpdate = true;
|
||||
+ this.playerViewDistanceBroadcastMap.add(player, chunkX, chunkZ, effectiveNoTickViewDistance + 1); // clients need an extra neighbour to render the full view distance configured
|
||||
+ player.needsChunkCenterUpdate = false;
|
||||
+ // Paper end - no-tick view distance
|
||||
}
|
||||
|
||||
void removePlayerFromDistanceMaps(ServerPlayer player) {
|
||||
|
||||
+ // Paper start - no-tick view distance
|
||||
+ this.playerViewDistanceBroadcastMap.remove(player);
|
||||
+ this.playerViewDistanceTickMap.remove(player);
|
||||
+ this.playerViewDistanceNoTickMap.remove(player);
|
||||
+ // Paper end - no-tick view distance
|
||||
}
|
||||
|
||||
void updateMaps(ServerPlayer player) {
|
||||
int chunkX = MCUtil.getChunkCoordinate(player.getX());
|
||||
int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
|
||||
// Note: players need to be explicitly added to distance maps before they can be updated
|
||||
+ // Paper start - no-tick view distance
|
||||
+ int effectiveTickViewDistance = this.getEffectiveViewDistance();
|
||||
+ int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance);
|
||||
+
|
||||
+ if (!this.skipPlayer(player)) {
|
||||
+ this.playerViewDistanceTickMap.update(player, chunkX, chunkZ, effectiveTickViewDistance);
|
||||
+ this.playerViewDistanceNoTickMap.update(player, chunkX, chunkZ, effectiveNoTickViewDistance + 2); // clients need chunk 1 neighbour, and we need another 1 for sending those extra neighbours (as we require neighbours to send)
|
||||
+ }
|
||||
+
|
||||
+ player.needsChunkCenterUpdate = true;
|
||||
+ this.playerViewDistanceBroadcastMap.update(player, chunkX, chunkZ, effectiveNoTickViewDistance + 1); // clients need an extra neighbour to render the full view distance configured
|
||||
+ player.needsChunkCenterUpdate = false;
|
||||
+ // Paper end - no-tick view distance
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -216,6 +263,45 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.overworldDataStorage = persistentStateManagerFactory;
|
||||
this.poiManager = new PoiManager(new File(this.storageFolder, "poi"), dataFixer, dsync, world);
|
||||
this.setViewDistance(viewDistance);
|
||||
+ // Paper start - no-tick view distance
|
||||
+ this.setNoTickViewDistance(this.level.paperConfig.noTickViewDistance);
|
||||
+ this.playerViewDistanceTickMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||
+ if (newState.size() != 1) {
|
||||
+ return;
|
||||
+ }
|
||||
+ LevelChunk chunk = ChunkMap.this.level.getChunkSource().getChunkAtIfLoadedMainThreadNoCache(rangeX, rangeZ);
|
||||
+ if (chunk == null || !chunk.areNeighboursLoaded(2)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ChunkPos chunkPos = new ChunkPos(rangeX, rangeZ);
|
||||
+ ChunkMap.this.level.getChunkSource().addTicketAtLevel(TicketType.PLAYER, chunkPos, 31, chunkPos); // entity ticking level, TODO check on update
|
||||
+ },
|
||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||
+ if (newState != null) {
|
||||
+ return;
|
||||
+ }
|
||||
+ ChunkPos chunkPos = new ChunkPos(rangeX, rangeZ);
|
||||
+ ChunkMap.this.level.getChunkSource().removeTicketAtLevel(TicketType.PLAYER, chunkPos, 31, chunkPos); // entity ticking level, TODO check on update
|
||||
+ });
|
||||
+ this.playerViewDistanceNoTickMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
|
||||
+ this.playerViewDistanceBroadcastMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
|
||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||
+ if (player.needsChunkCenterUpdate) {
|
||||
+ player.needsChunkCenterUpdate = false;
|
||||
+ player.connection.send(new ClientboundSetChunkCacheCenterPacket(currPosX, currPosZ));
|
||||
+ }
|
||||
+ ChunkMap.this.updateChunkTracking(player, new ChunkPos(rangeX, rangeZ), new Packet[2], false, true); // unloaded, loaded
|
||||
+ },
|
||||
+ (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
|
||||
+ ChunkMap.this.updateChunkTracking(player, new ChunkPos(rangeX, rangeZ), null, true, false); // unloaded, loaded
|
||||
+ });
|
||||
+ // Paper end - no-tick view distance
|
||||
}
|
||||
|
||||
private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) {
|
||||
@@ -863,14 +949,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
completablefuture1.thenAcceptAsync((either) -> {
|
||||
either.ifLeft((chunk) -> {
|
||||
this.tickingGenerated.getAndIncrement();
|
||||
- Packet<?>[] apacket = new Packet[2];
|
||||
-
|
||||
- this.getPlayers(chunkcoordintpair, false).forEach((entityplayer) -> {
|
||||
- this.playerLoadedChunk(entityplayer, apacket, chunk);
|
||||
- });
|
||||
+ // Paper - no-tick view distance - moved to Chunk neighbour update
|
||||
});
|
||||
}, (runnable) -> {
|
||||
- this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable));
|
||||
+ this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable)); // Paper - diff on change, this is the scheduling method copied in Chunk used to schedule chunk broadcasts (on change it needs to be copied again)
|
||||
});
|
||||
return completablefuture1;
|
||||
}
|
||||
@@ -962,28 +1044,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
}
|
||||
|
||||
- protected void setViewDistance(int watchDistance) {
|
||||
- int j = Mth.clamp(watchDistance + 1, 3, 33);
|
||||
+ public void setViewDistance(int watchDistance) { // Paper - public
|
||||
+ int j = Mth.clamp(watchDistance + 1, 3, 33); // Paper - diff on change, these make the lower view distance limit 2 and the upper 32
|
||||
|
||||
if (j != this.viewDistance) {
|
||||
int k = this.viewDistance;
|
||||
|
||||
this.viewDistance = j;
|
||||
- this.distanceManager.updatePlayerTickets(this.viewDistance);
|
||||
- ObjectIterator objectiterator = this.updatingChunkMap.values().iterator();
|
||||
+ this.setNoTickViewDistance(this.getRawNoTickViewDistance()); //Paper - no-tick view distance - propagate changes to no-tick, which does the actual chunk loading/sending
|
||||
+ }
|
||||
|
||||
- while (objectiterator.hasNext()) {
|
||||
- ChunkHolder playerchunk = (ChunkHolder) objectiterator.next();
|
||||
- ChunkPos chunkcoordintpair = playerchunk.getPos();
|
||||
- Packet<?>[] apacket = new Packet[2];
|
||||
+ }
|
||||
|
||||
- this.getPlayers(chunkcoordintpair, false).forEach((entityplayer) -> {
|
||||
- int l = ChunkMap.checkerboardDistance(chunkcoordintpair, entityplayer, true);
|
||||
- boolean flag = l <= k;
|
||||
- boolean flag1 = l <= this.viewDistance;
|
||||
+ // Paper start - no-tick view distance
|
||||
+ public final void setNoTickViewDistance(int viewDistance) {
|
||||
+ viewDistance = viewDistance == -1 ? -1 : Mth.clamp(viewDistance, 2, 32);
|
||||
|
||||
- this.updateChunkTracking(entityplayer, chunkcoordintpair, apacket, flag, flag1);
|
||||
- });
|
||||
+ this.noTickViewDistance = viewDistance;
|
||||
+ int loadViewDistance = this.getLoadViewDistance();
|
||||
+ this.distanceManager.setNoTickViewDistance(loadViewDistance + 2 + 2); // add 2 to account for the change to 31 -> 33 tickets // see notes in the distance map updating for the other + 2
|
||||
+
|
||||
+ if (this.level != null && this.level.players != null) { // this can be called from constructor, where these aren't set
|
||||
+ for (ServerPlayer player : this.level.players) {
|
||||
+ net.minecraft.server.network.ServerGamePacketListenerImpl connection = player.connection;
|
||||
+ if (connection != null) {
|
||||
+ // moved in from PlayerList
|
||||
+ connection.send(new net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket(loadViewDistance));
|
||||
+ }
|
||||
+ this.updateMaps(player);
|
||||
+ // Paper end - no-tick view distance
|
||||
}
|
||||
}
|
||||
|
||||
@@ -995,7 +1084,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong());
|
||||
|
||||
if (playerchunk != null) {
|
||||
- LevelChunk chunk = playerchunk.getTickingChunk();
|
||||
+ LevelChunk chunk = playerchunk.getSendingChunk(); // Paper - no-tick view distance
|
||||
|
||||
if (chunk != null) {
|
||||
this.playerLoadedChunk(player, packets, chunk);
|
||||
@@ -1202,13 +1291,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.removePlayerFromDistanceMaps(player); // Paper - distance maps
|
||||
}
|
||||
|
||||
- for (int k = i - this.viewDistance; k <= i + this.viewDistance; ++k) {
|
||||
- for (int l = j - this.viewDistance; l <= j + this.viewDistance; ++l) {
|
||||
- ChunkPos chunkcoordintpair = new ChunkPos(k, l);
|
||||
-
|
||||
- this.updateChunkTracking(player, chunkcoordintpair, new Packet[2], !added, added);
|
||||
- }
|
||||
- }
|
||||
+ // Paper - broadcast view distance map handles this (see remove/add calls above)
|
||||
|
||||
}
|
||||
|
||||
@@ -1216,7 +1299,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
SectionPos sectionposition = SectionPos.of((Entity) player);
|
||||
|
||||
player.setLastSectionPos(sectionposition);
|
||||
- player.connection.send(new ClientboundSetChunkCacheCenterPacket(sectionposition.x(), sectionposition.z()));
|
||||
+ // player.connection.send(new ClientboundSetChunkCacheCenterPacket(sectionposition.x(), sectionposition.z())); // Paper - distance map handles this now
|
||||
return sectionposition;
|
||||
}
|
||||
|
||||
@@ -1271,6 +1354,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
int k1;
|
||||
int l1;
|
||||
|
||||
+ /* // Paper start - replaced by distance map
|
||||
if (Math.abs(i1 - i) <= this.viewDistance * 2 && Math.abs(j1 - j) <= this.viewDistance * 2) {
|
||||
k1 = Math.min(i, i1) - this.viewDistance;
|
||||
l1 = Math.min(j, j1) - this.viewDistance;
|
||||
@@ -1309,6 +1393,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
}
|
||||
}
|
||||
+ */ // Paper end - replaced by distance map
|
||||
|
||||
this.updateMaps(player); // Paper - distance maps
|
||||
|
||||
@@ -1316,11 +1401,46 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
@Override
|
||||
public Stream<ServerPlayer> getPlayers(ChunkPos chunkPos, boolean onlyOnWatchDistanceEdge) {
|
||||
- return this.playerMap.getPlayers(chunkPos.toLong()).filter((entityplayer) -> {
|
||||
- int i = ChunkMap.checkerboardDistance(chunkPos, entityplayer, true);
|
||||
+ // Paper start - per player view distance
|
||||
+ // there can be potential desync with player's last mapped section and the view distance map, so use the
|
||||
+ // view distance map here.
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> inRange = this.playerViewDistanceBroadcastMap.getObjectsInRange(chunkPos);
|
||||
|
||||
- return i > this.viewDistance ? false : !onlyOnWatchDistanceEdge || i == this.viewDistance;
|
||||
- });
|
||||
+ if (inRange == null) {
|
||||
+ return Stream.empty();
|
||||
+ }
|
||||
+ // all current cases are inlined so we wont hit this code, it's just in case plugins or future updates use it
|
||||
+ List<ServerPlayer> players = new java.util.ArrayList<>();
|
||||
+ Object[] backingSet = inRange.getBackingSet();
|
||||
+
|
||||
+ if (onlyOnWatchDistanceEdge) { // flag -> border only
|
||||
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||
+ Object temp = backingSet[i];
|
||||
+ if (!(temp instanceof ServerPlayer)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ ServerPlayer player = (ServerPlayer)temp;
|
||||
+ int viewDistance = this.playerViewDistanceBroadcastMap.getLastViewDistance(player);
|
||||
+ long lastPosition = this.playerViewDistanceBroadcastMap.getLastCoordinate(player);
|
||||
+
|
||||
+ int distX = Math.abs(MCUtil.getCoordinateX(lastPosition) - chunkPos.x);
|
||||
+ int distZ = Math.abs(MCUtil.getCoordinateZ(lastPosition) - chunkPos.z);
|
||||
+ if (Math.max(distX, distZ) == viewDistance) {
|
||||
+ players.add(player);
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ for (int i = 0, len = backingSet.length; i < len; ++i) {
|
||||
+ Object temp = backingSet[i];
|
||||
+ if (!(temp instanceof ServerPlayer)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ ServerPlayer player = (ServerPlayer)temp;
|
||||
+ players.add(player);
|
||||
+ }
|
||||
+ }
|
||||
+ return players.stream();
|
||||
+ // Paper end - per player view distance
|
||||
}
|
||||
|
||||
protected void addEntity(Entity entity) {
|
||||
@@ -1442,7 +1562,48 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
}
|
||||
|
||||
- private void playerLoadedChunk(ServerPlayer player, Packet<?>[] packets, LevelChunk chunk) {
|
||||
+ // Paper start
|
||||
+ private static int getLightMask(final LevelChunk chunk) {
|
||||
+ final net.minecraft.world.level.chunk.LevelChunkSection[] chunkSections = chunk.getSections();
|
||||
+ int mask = 0;
|
||||
+
|
||||
+ for (int i = 0; i < chunkSections.length; ++i) {
|
||||
+ /*
|
||||
+
|
||||
+
|
||||
+Lightmasks have 18 bits, from the -1 (void) section until the 17th (air) section.
|
||||
+Sections go from 0..16. Now whenever a section is not empty, it can potentially change lighting for the section itself, the section below and the section above, hence the bitmask 111b, which is 7d.
|
||||
+
|
||||
+ */
|
||||
+ mask |= (net.minecraft.world.level.chunk.LevelChunkSection.isEmpty(chunkSections[i]) ? 0 : 7) << i;
|
||||
+ }
|
||||
+
|
||||
+ return mask;
|
||||
+ }
|
||||
+
|
||||
+ private static int getCeilingLightMask(final LevelChunk chunk) {
|
||||
+ int mask = getLightMask(chunk);
|
||||
+
|
||||
+ /*
|
||||
+ It is similar to get highest bit, it would turn an 001010 into an 001111 so basically the highest bit and all below.
|
||||
+ We then invert this, so we'd have 110000 and compare that to the "main" chunk.
|
||||
+ This is because the bug only appears when the current chunks lightmaps are higher than those of the neighbors, thus we can omit sending neighbors which are lower than the current chunks lights.
|
||||
+
|
||||
+ so TLDR is that getCeilingLightMask returns a light mask with all bits set below the highest affected section. We could also count the number of leading zeros and invert them, somehow.
|
||||
+ @TODO: Implement Leafs suggestion
|
||||
+ either use Integer#numberOfLeadingZeros or document what this bithack is supposed to be doing then
|
||||
+ */
|
||||
+ mask |= mask >> 1;
|
||||
+ mask |= mask >> 2;
|
||||
+ mask |= mask >> 4;
|
||||
+ mask |= mask >> 8;
|
||||
+ mask |= mask >> 16;
|
||||
+
|
||||
+ return mask;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
+ public void playerLoadedChunk(ServerPlayer player, Packet<?>[] packets, LevelChunk chunk) { // Paper - private -> public
|
||||
if (packets[0] == null) {
|
||||
packets[0] = new ClientboundLevelChunkPacket(chunk);
|
||||
packets[1] = new ClientboundLightUpdatePacket(chunk.getPos(), this.lightEngine, (BitSet) null, (BitSet) null, true);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
index 45c7ebe67019cdbe88b6617a95d5c40d3a68286c..38eebda226e007c8910e04f502ce218cdfe1d456 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -275,8 +275,8 @@ public abstract class DistanceManager {
|
||||
return s;
|
||||
}
|
||||
|
||||
- protected void updatePlayerTickets(int viewDistance) {
|
||||
- this.playerTicketManager.updateViewDistance(viewDistance);
|
||||
+ protected void setNoTickViewDistance(int i) { // Paper - force abi breakage on usage change
|
||||
+ this.playerTicketManager.updateViewDistance(i);
|
||||
}
|
||||
|
||||
public int getNaturalSpawnChunkCount() {
|
||||
@@ -503,7 +503,7 @@ public abstract class DistanceManager {
|
||||
|
||||
private void onLevelChange(long pos, int distance, boolean oldWithinViewDistance, boolean withinViewDistance) {
|
||||
if (oldWithinViewDistance != withinViewDistance) {
|
||||
- Ticket<?> ticket = new Ticket<>(TicketType.PLAYER, DistanceManager.PLAYER_TICKET_LEVEL, new ChunkPos(pos));
|
||||
+ Ticket<?> ticket = new Ticket<>(TicketType.PLAYER, 33, new ChunkPos(pos)); // Paper - no-tick view distance
|
||||
|
||||
if (withinViewDistance) {
|
||||
DistanceManager.this.ticketThrottlerInput.tell(ChunkTaskPriorityQueueSorter.message(() -> {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 4fef4c0240be90ddcb9640f5719e292d2d5dbdf8..bffc897cb88a54c36432c98264f3416051aeab17 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -241,6 +241,7 @@ public class ServerPlayer extends Player {
|
||||
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
|
||||
|
||||
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
||||
+ boolean needsChunkCenterUpdate; // Paper - no-tick view distance
|
||||
|
||||
public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile) {
|
||||
super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile);
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index bcc946d2747443c34ee8ac2485a5ab41773c93af..2730923bd0bf3b0f928765b9e09e2299fa9a393d 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -241,7 +241,7 @@ public abstract class PlayerList {
|
||||
boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO);
|
||||
|
||||
// Spigot - view distance
|
||||
- playerconnection.send(new ClientboundLoginPacket(player.getId(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), worlddata.isHardcore(), this.server.levelKeys(), this.registryHolder, worldserver1.dimensionType(), worldserver1.dimension(), this.getMaxPlayers(), worldserver1.spigotConfig.viewDistance, flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat()));
|
||||
+ playerconnection.send(new ClientboundLoginPacket(player.getId(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), worlddata.isHardcore(), this.server.levelKeys(), this.registryHolder, worldserver1.dimensionType(), worldserver1.dimension(), this.getMaxPlayers(), worldserver1.getChunkSource().chunkMap.getLoadViewDistance(), flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat())); // Paper - no-tick view distance
|
||||
player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit
|
||||
playerconnection.send(new ClientboundCustomPayloadPacket(ClientboundCustomPayloadPacket.BRAND, (new FriendlyByteBuf(Unpooled.buffer())).writeUtf(this.getServer().getServerModName())));
|
||||
playerconnection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked()));
|
||||
@@ -789,7 +789,7 @@ public abstract class PlayerList {
|
||||
// CraftBukkit start
|
||||
LevelData worlddata = worldserver1.getLevelData();
|
||||
entityplayer1.connection.send(new ClientboundRespawnPacket(worldserver1.dimensionType(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), entityplayer1.gameMode.getGameModeForPlayer(), entityplayer1.gameMode.getPreviousGameModeForPlayer(), worldserver1.isDebug(), worldserver1.isFlat(), flag));
|
||||
- entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.spigotConfig.viewDistance)); // Spigot
|
||||
+ entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.getChunkSource().chunkMap.getLoadViewDistance())); // Spigot // Paper - no-tick view distance
|
||||
entityplayer1.setLevel(worldserver1);
|
||||
entityplayer1.unsetRemoved();
|
||||
entityplayer1.connection.teleport(new Location(worldserver1.getWorld(), entityplayer1.getX(), entityplayer1.getY(), entityplayer1.getZ(), entityplayer1.getYRot(), entityplayer1.getXRot()));
|
||||
@@ -1273,7 +1273,7 @@ public abstract class PlayerList {
|
||||
|
||||
public void setViewDistance(int viewDistance) {
|
||||
this.viewDistance = viewDistance;
|
||||
- this.broadcastAll(new ClientboundSetChunkCacheRadiusPacket(viewDistance));
|
||||
+ //this.sendAll(new PacketPlayOutViewDistance(i)); // Paper - move into setViewDistance
|
||||
Iterator iterator = this.server.getAllLevels().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index ddcde88a8c8b748b4dc2583b4dfd0fb8ea9e201e..07e81fa1119bba4981e34e70b9e67f43280f8071 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -521,8 +521,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
this.setBlocksDirty(blockposition, iblockdata1, iblockdata2);
|
||||
}
|
||||
|
||||
- if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || (chunk.getFullStatus() != null && chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement
|
||||
+ if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || (chunk.getFullStatus() != null && chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement // Paper - diff on change, see below
|
||||
this.sendBlockUpdated(blockposition, iblockdata1, iblockdata, i);
|
||||
+ // Paper start - per player view distance - allow block updates for non-ticking chunks in player view distance
|
||||
+ // if copied from above
|
||||
+ } else if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || ((ServerLevel)this).getChunkSource().chunkMap.playerViewDistanceBroadcastMap.getObjectsInRange(MCUtil.getCoordinateKey(blockposition)) != null)) {
|
||||
+ ((ServerLevel)this).getChunkSource().blockChanged(blockposition);
|
||||
+ // Paper end - per player view distance
|
||||
}
|
||||
|
||||
if ((i & 1) != 0) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 521f199e495f3bec232cc9ca36e51e0392afe737..922026da8c234427e0322443004d3c32993adfce 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -33,7 +33,10 @@ import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
+import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
+import net.minecraft.server.level.ChunkMap;
|
||||
+import net.minecraft.server.level.ChunkTaskPriorityQueueSorter;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
@@ -227,7 +230,51 @@ public class LevelChunk implements ChunkAccess {
|
||||
}
|
||||
|
||||
protected void onNeighbourChange(final long bitsetBefore, final long bitsetAfter) {
|
||||
+ // Paper start - no-tick view distance
|
||||
+ ServerChunkCache chunkProviderServer = ((ServerLevel)this.level).getChunkSource();
|
||||
+ ChunkMap chunkMap = chunkProviderServer.chunkMap;
|
||||
+ // this code handles the addition of ticking tickets - the distance map handles the removal
|
||||
+ if (!areNeighboursLoaded(bitsetBefore, 2) && areNeighboursLoaded(bitsetAfter, 2)) {
|
||||
+ if (chunkMap.playerViewDistanceTickMap.getObjectsInRange(this.coordinateKey) != null) {
|
||||
+ // now we're ready for entity ticking
|
||||
+ chunkProviderServer.mainThreadProcessor.execute(() -> {
|
||||
+ // double check that this condition still holds.
|
||||
+ if (LevelChunk.this.areNeighboursLoaded(2) && chunkMap.playerViewDistanceTickMap.getObjectsInRange(LevelChunk.this.coordinateKey) != null) {
|
||||
+ chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.PLAYER, LevelChunk.this.chunkPos, 31, LevelChunk.this.chunkPos); // 31 -> entity ticking, TODO check on update
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+ }
|
||||
|
||||
+ // this code handles the chunk sending
|
||||
+ if (!areNeighboursLoaded(bitsetBefore, 1) && areNeighboursLoaded(bitsetAfter, 1)) {
|
||||
+ if (chunkMap.playerViewDistanceBroadcastMap.getObjectsInRange(this.coordinateKey) != null) {
|
||||
+ // now we're ready to send
|
||||
+ chunkMap.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(chunkMap.getUpdatingChunkIfPresent(this.coordinateKey), (() -> { // Copied frm PlayerChunkMap
|
||||
+ // double check that this condition still holds.
|
||||
+ if (!LevelChunk.this.areNeighboursLoaded(1)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<net.minecraft.server.level.ServerPlayer> inRange = chunkMap.playerViewDistanceBroadcastMap.getObjectsInRange(LevelChunk.this.coordinateKey);
|
||||
+ if (inRange == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // broadcast
|
||||
+ Object[] backingSet = inRange.getBackingSet();
|
||||
+ Packet[] chunkPackets = new Packet[2];
|
||||
+ for (int index = 0, len = backingSet.length; index < len; ++index) {
|
||||
+ Object temp = backingSet[index];
|
||||
+ if (!(temp instanceof net.minecraft.server.level.ServerPlayer)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)temp;
|
||||
+ chunkMap.playerLoadedChunk(player, chunkPackets, LevelChunk.this);
|
||||
+ }
|
||||
+ })));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - no-tick view distance
|
||||
}
|
||||
|
||||
public final boolean isAnyNeighborsLoaded() {
|
||||
@@ -1005,7 +1052,7 @@ public class LevelChunk implements ChunkAccess {
|
||||
BlockState iblockdata = this.getBlockState(blockposition);
|
||||
BlockState iblockdata1 = Block.updateFromNeighbourShapes(iblockdata, (LevelAccessor) this.level, blockposition);
|
||||
|
||||
- this.level.setBlock(blockposition, iblockdata1, 20);
|
||||
+ this.level.setBlock(blockposition, iblockdata1, 20 | 2); // Paper - We send chunks before they're ticking ready, so we need to notify here
|
||||
}
|
||||
|
||||
this.postProcessing[i].clear();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index f1cbcdb1e409f8544125dde5f24bff5b07cb5082..1d22119b962840dff789a0619fd2188958f924d0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -2540,10 +2540,39 @@ public class CraftWorld implements World {
|
||||
// Spigot start
|
||||
@Override
|
||||
public int getViewDistance() {
|
||||
- return world.spigotConfig.viewDistance;
|
||||
+ return getHandle().getChunkSource().chunkMap.getEffectiveViewDistance(); // Paper - no-tick view distance
|
||||
}
|
||||
// Spigot end
|
||||
|
||||
+ // Paper start - per player view distance
|
||||
+ @Override
|
||||
+ public void setViewDistance(int viewDistance) {
|
||||
+ if (viewDistance < 2 || viewDistance > 32) {
|
||||
+ throw new IllegalArgumentException("View distance " + viewDistance + " is out of range of [2, 32]");
|
||||
+ }
|
||||
+ net.minecraft.server.level.ChunkMap chunkMap = getHandle().getChunkSource().chunkMap;
|
||||
+ if (viewDistance != chunkMap.getEffectiveViewDistance()) {
|
||||
+ chunkMap.setViewDistance(viewDistance);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getNoTickViewDistance() {
|
||||
+ return getHandle().getChunkSource().chunkMap.getEffectiveNoTickViewDistance();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setNoTickViewDistance(int viewDistance) {
|
||||
+ if ((viewDistance < 2 || viewDistance > 32) && viewDistance != -1) {
|
||||
+ throw new IllegalArgumentException("View distance " + viewDistance + " is out of range of [2, 32]");
|
||||
+ }
|
||||
+ net.minecraft.server.level.ChunkMap chunkMap = getHandle().getChunkSource().chunkMap;
|
||||
+ if (viewDistance != chunkMap.getRawNoTickViewDistance()) {
|
||||
+ chunkMap.setNoTickViewDistance(viewDistance);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - per player view distance
|
||||
+
|
||||
// Spigot start
|
||||
private final org.bukkit.World.Spigot spigot = new org.bukkit.World.Spigot()
|
||||
{
|
||||
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
index 2ab585a018290996e7fa9ca6f3ad7d734cd7beaa..a08583863f9fa08016bdfc7949a273eaa4429927 100644
|
||||
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
||||
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
||||
@@ -188,7 +188,7 @@ public class ActivationRange
|
||||
maxRange = Math.max( maxRange, waterActivationRange );
|
||||
maxRange = Math.max( maxRange, villagerActivationRange );
|
||||
// Paper end
|
||||
- maxRange = Math.min( ( world.spigotConfig.viewDistance << 4 ) - 8, maxRange );
|
||||
+ maxRange = Math.min( ( ((net.minecraft.server.level.ServerLevel)world).getChunkSource().chunkMap.getEffectiveViewDistance() << 4 ) - 8, maxRange ); // Paper - no-tick view distance
|
||||
|
||||
for ( Player player : world.players() )
|
||||
{
|
Loading…
Add table
Add a link
Reference in a new issue