More patches
This commit is contained in:
@@ -1,105 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Tue, 20 Feb 2024 18:24:16 -0800
|
||||
Subject: [PATCH] Fix entity tracker desync when new players are added to the
|
||||
tracker
|
||||
|
||||
The delta position packet instructs the client to update
|
||||
the entity position by a position difference. However, this position
|
||||
difference is relative to the last position in the entity tracker
|
||||
state, not the last position which has been sent to the player. As
|
||||
a result, if the last position the player has recorded is different
|
||||
than the one stored in the entity tracker (which occurs when a new
|
||||
player is added to an existing entity tracker state) then the sent
|
||||
position difference will cause a position desync for the client.
|
||||
|
||||
We can resolve this problem by either tracking the last position
|
||||
sent per-player, or by simply resetting the last sent position
|
||||
in the entity tracker state every time a new player is added.
|
||||
Resetting the last sent position every time a new player is
|
||||
added to the tracker is just easier to do, so that is what
|
||||
this patch does.
|
||||
|
||||
This patch also fixes entities appearing to disappear when
|
||||
teleporting to players by changing the initial position
|
||||
in the spawn packet to the entities current tracking position.
|
||||
When teleporting, the spawn packet will contain the old position
|
||||
which is most likely in an unloaded chunk - which means that the
|
||||
client will not tick the entity and thus not lerp the entity
|
||||
from its old position to its new position.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
@@ -0,0 +0,0 @@ public class ClientboundAddEntityPacket implements Packet<ClientGamePacketListen
|
||||
this(
|
||||
entity.getId(),
|
||||
entity.getUUID(),
|
||||
- entityTrackerEntry.getPositionBase().x(),
|
||||
- entityTrackerEntry.getPositionBase().y(),
|
||||
- entityTrackerEntry.getPositionBase().z(),
|
||||
+ // Paper start - fix entity tracker desync
|
||||
+ entity.trackingPosition().x(),
|
||||
+ entity.trackingPosition().y(),
|
||||
+ entity.trackingPosition().z(),
|
||||
+ // Paper end - fix entity tracker desync
|
||||
entityTrackerEntry.getLastSentXRot(),
|
||||
entityTrackerEntry.getLastSentYRot(),
|
||||
entity.getType(),
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.serverEntity.addPairing(player);
|
||||
}
|
||||
// Paper end - entity tracking events
|
||||
+ this.serverEntity.onPlayerAdd(); // Paper - fix desync when a player is added to the tracker
|
||||
}
|
||||
} else if (this.seenBy.remove(player.connection)) {
|
||||
this.serverEntity.removePairing(player);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
this.trackedDataValues = entity.getEntityData().getNonDefaultValues();
|
||||
}
|
||||
|
||||
+ // Paper start - fix desync when a player is added to the tracker
|
||||
+ private boolean forceStateResync;
|
||||
+ public void onPlayerAdd() {
|
||||
+ this.forceStateResync = true;
|
||||
+ }
|
||||
+ // Paper end - fix desync when a player is added to the tracker
|
||||
+
|
||||
public void sendChanges() {
|
||||
// Paper start - optimise collisions
|
||||
if (((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)this.entity).moonrise$isHardColliding()) {
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
}
|
||||
}
|
||||
|
||||
- if (this.tickCount % this.updateInterval == 0 || this.entity.hasImpulse || this.entity.getEntityData().isDirty()) {
|
||||
+ if (this.forceStateResync || this.tickCount % this.updateInterval == 0 || this.entity.hasImpulse || this.entity.getEntityData().isDirty()) { // Paper - fix desync when a player is added to the tracker
|
||||
int i;
|
||||
int j;
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
long i1 = this.positionCodec.encodeZ(vec3d);
|
||||
boolean flag6 = k < -32768L || k > 32767L || l < -32768L || l > 32767L || i1 < -32768L || i1 > 32767L;
|
||||
|
||||
- if (!flag6 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()) {
|
||||
+ if (!this.forceStateResync && !flag6 && this.teleportDelay <= 400 && !this.wasRiding && this.wasOnGround == this.entity.onGround()) { // Paper - fix desync when a player is added to the tracker
|
||||
if ((!flag2 || !flag3) && !(this.entity instanceof AbstractArrow)) {
|
||||
if (flag2) {
|
||||
packet1 = new ClientboundMoveEntityPacket.Pos(this.entity.getId(), (short) ((int) k), (short) ((int) l), (short) ((int) i1), this.entity.onGround());
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
}
|
||||
|
||||
this.entity.hasImpulse = false;
|
||||
+ this.forceStateResync = false; // Paper - fix desync when a player is added to the tracker
|
||||
}
|
||||
|
||||
++this.tickCount;
|
||||
@@ -1,145 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 9 Jun 2019 03:53:22 +0100
|
||||
Subject: [PATCH] Incremental chunk and player saving
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
try {
|
||||
this.isSaving = true;
|
||||
- this.getPlayerList().saveAll();
|
||||
+ this.getPlayerList().saveAll(); // Paper - Incremental chunk and player saving; diff on change
|
||||
flag3 = this.saveAllChunks(suppressLogs, flush, force);
|
||||
} finally {
|
||||
this.isSaving = false;
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
--this.ticksUntilAutosave;
|
||||
- // CraftBukkit start
|
||||
- if (this.autosavePeriod > 0 && this.ticksUntilAutosave <= 0) {
|
||||
- this.ticksUntilAutosave = this.autosavePeriod;
|
||||
- // CraftBukkit end
|
||||
- MinecraftServer.LOGGER.debug("Autosave started");
|
||||
- this.profiler.push("save");
|
||||
- this.saveEverything(true, false, false);
|
||||
- this.profiler.pop();
|
||||
- MinecraftServer.LOGGER.debug("Autosave finished");
|
||||
+ // Paper start - Incremental chunk and player saving
|
||||
+ int playerSaveInterval = io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.rate;
|
||||
+ if (playerSaveInterval < 0) {
|
||||
+ playerSaveInterval = autosavePeriod;
|
||||
+ }
|
||||
+ this.profiler.push("save");
|
||||
+ final boolean fullSave = autosavePeriod > 0 && this.tickCount % autosavePeriod == 0;
|
||||
+ try {
|
||||
+ this.isSaving = true;
|
||||
+ if (playerSaveInterval > 0) {
|
||||
+ this.playerList.saveAll(playerSaveInterval);
|
||||
+ }
|
||||
+ for (ServerLevel level : this.getAllLevels()) {
|
||||
+ if (level.paperConfig().chunks.autoSaveInterval.value() > 0) {
|
||||
+ level.saveIncrementally(fullSave);
|
||||
+ }
|
||||
+ }
|
||||
+ } finally {
|
||||
+ this.isSaving = false;
|
||||
}
|
||||
+ this.profiler.pop();
|
||||
+ // Paper end - Incremental chunk and player saving
|
||||
// Paper start - move executeAll() into full server tick timing
|
||||
try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) {
|
||||
this.runAllTasks();
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.
|
||||
return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos);
|
||||
}
|
||||
|
||||
+ // Paper start - Incremental chunk and player saving
|
||||
+ public void saveIncrementally(boolean doFull) {
|
||||
+ ServerChunkCache chunkproviderserver = this.getChunkSource();
|
||||
+
|
||||
+ if (doFull) {
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld()));
|
||||
+ }
|
||||
+
|
||||
+ try (co.aikar.timings.Timing ignored = this.timings.worldSave.startTiming()) {
|
||||
+ if (doFull) {
|
||||
+ this.saveLevelData(true);
|
||||
+ }
|
||||
+
|
||||
+ // chunk autosave is already called by the ChunkSystem during unload processing (ChunkMap#processUnloads)
|
||||
+
|
||||
+ // Copied from save()
|
||||
+ // CraftBukkit start - moved from MinecraftServer.saveChunks
|
||||
+ if (doFull) { // Paper
|
||||
+ ServerLevel worldserver1 = this;
|
||||
+
|
||||
+ this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings());
|
||||
+ this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save(this.registryAccess()));
|
||||
+ this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Incremental chunk and player saving
|
||||
+
|
||||
public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) {
|
||||
// Paper start - add close param
|
||||
this.save(progressListener, flush, savingDisabled, false);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.inventory.MainHand;
|
||||
public class ServerPlayer extends net.minecraft.world.entity.player.Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
+ public long lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
|
||||
private static final int FLY_STAT_RECORDING_SPEED = 25;
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||
|
||||
protected void save(ServerPlayer player) {
|
||||
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
|
||||
+ player.lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving
|
||||
this.playerIo.save(player);
|
||||
ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit
|
||||
|
||||
@@ -0,0 +0,0 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void saveAll() {
|
||||
+ // Paper start - Incremental chunk and player saving
|
||||
+ this.saveAll(-1);
|
||||
+ }
|
||||
+
|
||||
+ public void saveAll(int interval) {
|
||||
io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
|
||||
MinecraftTimings.savePlayers.startTiming(); // Paper
|
||||
+ int numSaved = 0;
|
||||
+ long now = MinecraftServer.currentTick;
|
||||
for (int i = 0; i < this.players.size(); ++i) {
|
||||
- this.save(this.players.get(i));
|
||||
+ ServerPlayer entityplayer = this.players.get(i);
|
||||
+ if (interval == -1 || now - entityplayer.lastSave >= interval) {
|
||||
+ this.save(entityplayer);
|
||||
+ if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; }
|
||||
+ }
|
||||
+ // Paper end - Incremental chunk and player saving
|
||||
}
|
||||
MinecraftTimings.savePlayers.stopTiming(); // Paper
|
||||
return null; }); // Paper - ensure main
|
||||
@@ -1,129 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 23 Sep 2023 22:05:35 -0700
|
||||
Subject: [PATCH] Lag compensation ticks
|
||||
|
||||
Areas affected by lag comepnsation:
|
||||
- Block breaking and destroying
|
||||
- Eating food items
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
public volatile Thread shutdownThread; // Paper
|
||||
public volatile boolean abnormalExit = false; // Paper
|
||||
+ public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
||||
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
|
||||
AtomicReference<S> atomicreference = new AtomicReference();
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
|
||||
worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
|
||||
net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
|
||||
+ worldserver.updateLagCompensationTick(); // Paper - lag compensation
|
||||
|
||||
this.profiler.push(() -> {
|
||||
String s = String.valueOf(worldserver);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.
|
||||
return this.entityTickingChunks;
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
+ // Paper start - lag compensation
|
||||
+ private long lagCompensationTick = net.minecraft.server.MinecraftServer.SERVER_INIT;
|
||||
+
|
||||
+ public long getLagCompensationTick() {
|
||||
+ return this.lagCompensationTick;
|
||||
+ }
|
||||
+
|
||||
+ public void updateLagCompensationTick() {
|
||||
+ this.lagCompensationTick = (System.nanoTime() - net.minecraft.server.MinecraftServer.SERVER_INIT) / (java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(50L));
|
||||
+ }
|
||||
+ // Paper end - lag compensation
|
||||
|
||||
// Add env and gen to constructor, IWorldDataServer -> WorldDataServer
|
||||
public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -0,0 +0,0 @@ public class ServerPlayerGameMode {
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
- this.gameTicks = MinecraftServer.currentTick; // CraftBukkit;
|
||||
+ this.gameTicks = (int)this.level.getLagCompensationTick(); // CraftBukkit; // Paper - lag compensation
|
||||
BlockState iblockdata;
|
||||
|
||||
if (this.hasDelayedDestroy) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
this.resendPossiblyDesyncedDataValues(java.util.List.of(DATA_LIVING_ENTITY_FLAGS), serverPlayer);
|
||||
}
|
||||
// Paper end - Properly cancel usable items
|
||||
+ // Paper start - lag compensate eating
|
||||
+ protected long eatStartTime;
|
||||
+ protected int totalEatTimeTicks;
|
||||
+ // Paper end - lag compensate eating
|
||||
private void updatingUsingItem() {
|
||||
if (this.isUsingItem()) {
|
||||
if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) {
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
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.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L));
|
||||
+ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide && !stack.useOnRelease()) {
|
||||
+ this.useItemRemaining = 0;
|
||||
+ // Paper end - lag compensate eating
|
||||
this.completeUsingItem();
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
if (!itemstack.isEmpty() && !this.isUsingItem() || forceUpdate) { // Paper - Prevent consuming the wrong itemstack
|
||||
this.useItem = itemstack;
|
||||
- this.useItemRemaining = itemstack.getUseDuration(this);
|
||||
+ // Paper start - lag compensate eating
|
||||
+ this.useItemRemaining = this.totalEatTimeTicks = itemstack.getUseDuration(this);
|
||||
+ this.eatStartTime = System.nanoTime();
|
||||
+ // Paper end - lag compensate eating
|
||||
if (!this.level().isClientSide) {
|
||||
this.setLivingEntityFlag(1, true);
|
||||
this.setLivingEntityFlag(2, hand == InteractionHand.OFF_HAND);
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
} 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 - lag compensate eating
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
this.useItem = ItemStack.EMPTY;
|
||||
- this.useItemRemaining = 0;
|
||||
+ // Paper start - lag compensate eating
|
||||
+ this.useItemRemaining = this.totalEatTimeTicks = 0;
|
||||
+ this.eatStartTime = -1L;
|
||||
+ // Paper end - lag compensate eating
|
||||
}
|
||||
|
||||
public boolean isBlocking() {
|
||||
@@ -1,168 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 2 Jul 2020 12:02:43 -0700
|
||||
Subject: [PATCH] Optimise collision checking in player move packet handling
|
||||
|
||||
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
return;
|
||||
}
|
||||
|
||||
- boolean flag = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D));
|
||||
+ AABB oldBox = entity.getBoundingBox(); // Paper - copy from player movement packet
|
||||
|
||||
d6 = d3 - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d7 = d4 - this.vehicleLastGoodY - 1.0E-6D; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
|
||||
entity.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
|
||||
+ boolean didCollide = toX != entity.getX() || toY != entity.getY() || toZ != entity.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||
double d11 = d7;
|
||||
|
||||
d6 = d3 - entity.getX();
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
boolean flag2 = false;
|
||||
|
||||
if (d10 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
|
||||
- flag2 = true;
|
||||
+ flag2 = true; // Paper - diff on change, this should be moved wrongly
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", new Object[]{entity.getName().getString(), this.player.getName().getString(), Math.sqrt(d10)});
|
||||
}
|
||||
|
||||
entity.absMoveTo(d3, d4, d5, f, f1);
|
||||
this.player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
- boolean flag3 = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D));
|
||||
|
||||
- if (flag && (flag2 || !flag3)) {
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ boolean teleportBack = flag2; // violating this is always a fail
|
||||
+ if (!teleportBack) {
|
||||
+ // note: only call after setLocation, or else getBoundingBox is wrong
|
||||
+ AABB newBox = entity.getBoundingBox();
|
||||
+ if (didCollide || !oldBox.equals(newBox)) {
|
||||
+ teleportBack = this.hasNewCollision(worldserver, entity, oldBox, newBox);
|
||||
+ } // else: no collision at all detected, why do we care?
|
||||
+ }
|
||||
+ if (teleportBack) { // Paper end - optimise out extra getCubes
|
||||
entity.absMoveTo(d0, d1, d2, f, f1);
|
||||
this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
this.send(new ClientboundMoveVehiclePacket(entity));
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
|
||||
private boolean noBlocksAround(Entity entity) {
|
||||
- return entity.level().getBlockStates(entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D)).allMatch(BlockBehaviour.BlockStateBase::isAir);
|
||||
+ // Paper start - stop using streams, this is already a known fixed problem in Entity#move
|
||||
+ AABB box = entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D);
|
||||
+ int minX = Mth.floor(box.minX);
|
||||
+ int minY = Mth.floor(box.minY);
|
||||
+ int minZ = Mth.floor(box.minZ);
|
||||
+ int maxX = Mth.floor(box.maxX);
|
||||
+ int maxY = Mth.floor(box.maxY);
|
||||
+ int maxZ = Mth.floor(box.maxZ);
|
||||
+
|
||||
+ Level world = entity.level();
|
||||
+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
+
|
||||
+ for (int y = minY; y <= maxY; ++y) {
|
||||
+ for (int z = minZ; z <= maxZ; ++z) {
|
||||
+ for (int x = minX; x <= maxX; ++x) {
|
||||
+ pos.set(x, y, z);
|
||||
+ BlockState type = world.getBlockStateIfLoaded(pos);
|
||||
+ if (type != null && !type.isAir()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ // Paper end - stop using streams, this is already a known fixed problem in Entity#move
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
- AABB axisalignedbb = this.player.getBoundingBox();
|
||||
+ AABB axisalignedbb = this.player.getBoundingBox(); // Paper - diff on change, should be old AABB
|
||||
|
||||
d6 = d0 - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d7 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
|
||||
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
||||
+ boolean didCollide = toX != this.player.getX() || toY != this.player.getY() || toZ != this.player.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||
// Paper start - prevent position desync
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
return; // ... thanks Mojang for letting move calls teleport across dimensions.
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
|
||||
// Paper start - Add fail move event
|
||||
- boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && (movedWrongly && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb, d0, d1, d2));
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ boolean teleportBack = !this.player.noPhysics && !this.player.isSleeping() && movedWrongly;
|
||||
+ this.player.absMoveTo(d0, d1, d2, f, f1); // prevent desync by tping to the set position, dropped for unknown reasons by mojang
|
||||
+ if (!this.player.noPhysics && !this.player.isSleeping() && !teleportBack) {
|
||||
+ AABB newBox = this.player.getBoundingBox();
|
||||
+ if (didCollide || !axisalignedbb.equals(newBox)) {
|
||||
+ // note: only call after setLocation, or else getBoundingBox is wrong
|
||||
+ teleportBack = this.hasNewCollision(worldserver, this.player, axisalignedbb, newBox);
|
||||
+ } // else: no collision at all detected, why do we care?
|
||||
+ }
|
||||
+ // Paper end - optimise out extra getCubes
|
||||
if (teleportBack) {
|
||||
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
|
||||
toX, toY, toZ, toYaw, toPitch, false);
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
private boolean updateAwaitingTeleport() {
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
- if (this.tickCount - this.awaitingTeleportTime > 20) {
|
||||
+ if (false && this.tickCount - this.awaitingTeleportTime > 20) { // Paper - this will greatly screw with clients with > 1000ms RTT
|
||||
this.awaitingTeleportTime = this.tickCount;
|
||||
this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot());
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ private boolean hasNewCollision(final ServerLevel world, final Entity entity, final AABB oldBox, final AABB newBox) {
|
||||
+ final List<AABB> collisionsBB = new java.util.ArrayList<>();
|
||||
+ final List<VoxelShape> collisionsVoxel = new java.util.ArrayList<>();
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getCollisions(
|
||||
+ world, entity, newBox, collisionsVoxel, collisionsBB,
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_COLLIDE_WITH_UNLOADED_CHUNKS | ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER,
|
||||
+ null, null
|
||||
+ );
|
||||
+
|
||||
+ for (int i = 0, len = collisionsBB.size(); i < len; ++i) {
|
||||
+ final AABB box = collisionsBB.get(i);
|
||||
+ if (!ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.voxelShapeIntersect(box, oldBox)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0, len = collisionsVoxel.size(); i < len; ++i) {
|
||||
+ final VoxelShape voxel = collisionsVoxel.get(i);
|
||||
+ if (!ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.voxelShapeIntersectNoEmpty(voxel, oldBox)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - optimise out extra getCubes
|
||||
private boolean isPlayerCollidingWithAnythingNew(LevelReader world, AABB box, double newX, double newY, double newZ) {
|
||||
AABB axisalignedbb1 = this.player.getBoundingBox().move(newX - this.player.getX(), newY - this.player.getY(), newZ - this.player.getZ());
|
||||
Iterable<VoxelShape> iterable = world.getCollisions(this.player, axisalignedbb1.deflate(9.999999747378752E-6D));
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,164 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Cryptite <cryptite@gmail.com>
|
||||
Date: Tue, 27 Jun 2023 11:35:52 -0500
|
||||
Subject: [PATCH] Write SavedData IO async
|
||||
|
||||
Co-Authored-By: Shane Freeder <theboyetronic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
|
||||
public void close(boolean save) throws IOException {
|
||||
((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.close(save, true); // Paper - rewrite chunk system
|
||||
+ // Paper start - Write SavedData IO async
|
||||
+ try {
|
||||
+ this.dataStorage.close();
|
||||
+ } catch (final IOException e) {
|
||||
+ LOGGER.error("Failed to close persistent world data", e);
|
||||
+ }
|
||||
+ // Paper end - Write SavedData IO async
|
||||
}
|
||||
|
||||
// CraftBukkit start - modelled on below
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.
|
||||
progressListener.progressStartNoAbort(Component.translatable("menu.savingLevel"));
|
||||
}
|
||||
|
||||
- this.saveLevelData();
|
||||
+ this.saveLevelData(!close); // Paper - Write SavedData IO async
|
||||
if (progressListener != null) {
|
||||
progressListener.progressStage(Component.translatable("menu.savingChunks"));
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf.
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
- private void saveLevelData() {
|
||||
+ private void saveLevelData(boolean async) { // Paper - Write SavedData IO async
|
||||
if (this.dragonFight != null) {
|
||||
this.serverLevelData.setEndDragonFightData(this.dragonFight.saveData()); // CraftBukkit
|
||||
}
|
||||
|
||||
- this.getChunkSource().getDataStorage().save();
|
||||
+ this.getChunkSource().getDataStorage().save(async); // Paper - Write SavedData IO async
|
||||
}
|
||||
|
||||
public <T extends Entity> List<? extends T> getEntities(EntityTypeTest<Entity, T> filter, Predicate<? super T> predicate) {
|
||||
diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
@@ -0,0 +0,0 @@ public class WorldUpgrader {
|
||||
(new WorldUpgrader.PoiUpgrader(this)).upgrade();
|
||||
WorldUpgrader.LOGGER.info("Upgrading blocks");
|
||||
(new WorldUpgrader.ChunkUpgrader()).upgrade();
|
||||
- this.overworldDataStorage.save();
|
||||
+ // Paper start - Write SavedData IO async
|
||||
+ try {
|
||||
+ this.overworldDataStorage.close();
|
||||
+ } catch (final IOException e) {
|
||||
+ LOGGER.error("Failed to close persistent world data", e);
|
||||
+ }
|
||||
+ // Paper end - Write SavedData IO async
|
||||
i = Util.getMillis() - i;
|
||||
WorldUpgrader.LOGGER.info("World optimizaton finished after {} seconds", i / 1000L);
|
||||
this.finished = true;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
|
||||
@@ -0,0 +0,0 @@ public abstract class SavedData {
|
||||
return this.dirty;
|
||||
}
|
||||
|
||||
+ // Paper start - Write SavedData IO async - joining is evil, but we assume the old blocking behavior here just for safety
|
||||
+ @io.papermc.paper.annotation.DoNotUse
|
||||
public void save(File file, HolderLookup.Provider registryLookup) {
|
||||
+ save(file, registryLookup, null).join();
|
||||
+ }
|
||||
+
|
||||
+ public java.util.concurrent.CompletableFuture<Void> save(File file, HolderLookup.Provider registryLookup, @org.jetbrains.annotations.Nullable java.util.concurrent.ExecutorService ioExecutor) {
|
||||
+ // Paper end - Write SavedData IO async
|
||||
if (this.isDirty()) {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.put("data", this.save(new CompoundTag(), registryLookup));
|
||||
NbtUtils.addCurrentDataVersion(compoundTag);
|
||||
|
||||
+ Runnable writeRunnable = () -> { // Paper - Write SavedData IO async
|
||||
try {
|
||||
NbtIo.writeCompressed(compoundTag, file.toPath());
|
||||
} catch (IOException var5) {
|
||||
LOGGER.error("Could not save data {}", this, var5);
|
||||
}
|
||||
+ }; // Paper - Write SavedData IO async
|
||||
|
||||
this.setDirty(false);
|
||||
+ // Paper start - Write SavedData IO async
|
||||
+ if (ioExecutor == null) {
|
||||
+ return java.util.concurrent.CompletableFuture.runAsync(writeRunnable); // No executor, just use common pool
|
||||
+ }
|
||||
+ return java.util.concurrent.CompletableFuture.runAsync(writeRunnable, ioExecutor);
|
||||
}
|
||||
+ return java.util.concurrent.CompletableFuture.completedFuture(null);
|
||||
+ // Paper end - Write SavedData IO async
|
||||
}
|
||||
|
||||
public static record Factory<T extends SavedData>(
|
||||
diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.util.datafix.DataFixTypes;
|
||||
import net.minecraft.world.level.saveddata.SavedData;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
-public class DimensionDataStorage {
|
||||
+public class DimensionDataStorage implements java.io.Closeable { // Paper - Write SavedData IO async
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public final Map<String, SavedData> cache = Maps.newHashMap();
|
||||
private final DataFixer fixerUpper;
|
||||
private final HolderLookup.Provider registries;
|
||||
private final File dataFolder;
|
||||
+ protected final java.util.concurrent.ExecutorService ioExecutor; // Paper - Write SavedData IO async
|
||||
|
||||
public DimensionDataStorage(File directory, DataFixer dataFixer, HolderLookup.Provider registryLookup) {
|
||||
this.fixerUpper = dataFixer;
|
||||
this.dataFolder = directory;
|
||||
this.registries = registryLookup;
|
||||
+ this.ioExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("DimensionDataIO - " + dataFolder.getParent() + " - %d").setDaemon(true).build()); // Paper - Write SavedData IO async
|
||||
}
|
||||
|
||||
private File getDataFile(String id) {
|
||||
@@ -0,0 +0,0 @@ public class DimensionDataStorage {
|
||||
return bl;
|
||||
}
|
||||
|
||||
- public void save() {
|
||||
+ // Paper start - Write SavedData IO async
|
||||
+ @Override
|
||||
+ public void close() throws IOException {
|
||||
+ save(false);
|
||||
+ this.ioExecutor.shutdown();
|
||||
+ }
|
||||
+ // Paper end - Write SavedData IO async
|
||||
+
|
||||
+ public void save(boolean async) { // Paper - Write SavedData IO async
|
||||
this.cache.forEach((id, state) -> {
|
||||
if (state != null) {
|
||||
- state.save(this.getDataFile(id), this.registries);
|
||||
+ // Paper start - Write SavedData IO async
|
||||
+ final java.util.concurrent.CompletableFuture<Void> save = state.save(this.getDataFile(id), this.registries, this.ioExecutor);
|
||||
+ if (!async) {
|
||||
+ save.join();
|
||||
+ }
|
||||
+ // Paper end - Write SavedData IO async
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user