diff --git a/paper-api/src/main/java/org/bukkit/World.java b/paper-api/src/main/java/org/bukkit/World.java
index e59582f377a7..ace055593195 100644
--- a/paper-api/src/main/java/org/bukkit/World.java
+++ b/paper-api/src/main/java/org/bukkit/World.java
@@ -2094,10 +2094,8 @@ default boolean setSpawnLocation(int x, int y, int z) {
*
* @param time The new absolute time to set this world to
* @see #setTime(long) Sets the relative time of this world
- * @deprecated all overworlds share the same world clock by default now
* @throws IllegalArgumentException if this world does not have a world clock (e.g. the nether)
*/
- @Deprecated // TODO world clock API with links to it
public void setFullTime(long time);
// Paper start
diff --git a/paper-api/src/main/java/org/bukkit/event/world/ClockTimeSkipEvent.java b/paper-api/src/main/java/org/bukkit/event/world/ClockTimeSkipEvent.java
new file mode 100644
index 000000000000..5fe3728726df
--- /dev/null
+++ b/paper-api/src/main/java/org/bukkit/event/world/ClockTimeSkipEvent.java
@@ -0,0 +1,97 @@
+package org.bukkit.event.world;
+
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Called when the time skips for a world clock.
+ *
+ * If the event is cancelled the time will not change.
+ */
+// TODO - snapshot - 26.1 clock
+@ApiStatus.Experimental
+@NullMarked
+public class ClockTimeSkipEvent extends Event implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
+ private final SkipReason skipReason;
+ private long skipAmount;
+
+ private boolean cancelled;
+
+ @ApiStatus.Internal
+ public ClockTimeSkipEvent(final SkipReason skipReason, final long skipAmount) {
+ this.skipReason = skipReason;
+ this.skipAmount = skipAmount;
+ }
+
+ /**
+ * Gets the reason why the time has skipped.
+ *
+ * @return a SkipReason value detailing why the time has skipped
+ */
+ public SkipReason getSkipReason() {
+ return this.skipReason;
+ }
+
+ /**
+ * Gets the amount of time that was skipped.
+ *
+ * @return Amount of time skipped
+ */
+ public long getSkipAmount() {
+ return this.skipAmount;
+ }
+
+ /**
+ * Sets the amount of time to skip.
+ *
+ * @param skipAmount Amount of time to skip
+ */
+ public void setSkipAmount(long skipAmount) {
+ this.skipAmount = skipAmount;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLER_LIST;
+ }
+
+ public static HandlerList getHandlerList() {
+ return HANDLER_LIST;
+ }
+
+ /**
+ * An enum specifying the reason the time skipped.
+ */
+ public enum SkipReason {
+
+ /**
+ * When time is changed using the vanilla /time command.
+ */
+ COMMAND,
+ /**
+ * When time is changed by a plugin.
+ */
+ CUSTOM,
+ /**
+ * When time is changed by all players sleeping in their beds and the
+ * night skips.
+ */
+ NIGHT_SKIP
+ }
+}
diff --git a/paper-api/src/main/java/org/bukkit/event/world/TimeSkipEvent.java b/paper-api/src/main/java/org/bukkit/event/world/TimeSkipEvent.java
index ffcc09589e24..ae68f615de86 100644
--- a/paper-api/src/main/java/org/bukkit/event/world/TimeSkipEvent.java
+++ b/paper-api/src/main/java/org/bukkit/event/world/TimeSkipEvent.java
@@ -1,7 +1,6 @@
package org.bukkit.event.world;
import org.bukkit.World;
-import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@@ -10,60 +9,29 @@
* Called when the time skips in a world.
*
* If the event is cancelled the time will not change.
+ *
+ * @see ClockTimeSkipEvent for changing of clocks that affect all worlds
*/
-// TODO - snapshot - 26.1 API needed for clock!
-public class TimeSkipEvent extends WorldEvent implements Cancellable {
+public class TimeSkipEvent extends ClockTimeSkipEvent {
private static final HandlerList HANDLER_LIST = new HandlerList();
- private final SkipReason skipReason;
- private long skipAmount;
-
- private boolean cancelled;
+ private final World world;
@ApiStatus.Internal
public TimeSkipEvent(@NotNull World world, @NotNull SkipReason skipReason, long skipAmount) {
- super(world);
- this.skipReason = skipReason;
- this.skipAmount = skipAmount;
+ super(skipReason, skipAmount);
+ this.world = world;
}
/**
- * Gets the reason why the time has skipped.
+ * Returns the world that time is skipped in.
*
- * @return a SkipReason value detailing why the time has skipped
+ * @return world that time is skipped in
*/
@NotNull
- public SkipReason getSkipReason() {
- return this.skipReason;
- }
-
- /**
- * Gets the amount of time that was skipped.
- *
- * @return Amount of time skipped
- */
- public long getSkipAmount() {
- return this.skipAmount;
- }
-
- /**
- * Sets the amount of time to skip.
- *
- * @param skipAmount Amount of time to skip
- */
- public void setSkipAmount(long skipAmount) {
- this.skipAmount = skipAmount;
- }
-
- @Override
- public boolean isCancelled() {
- return this.cancelled;
- }
-
- @Override
- public void setCancelled(boolean cancel) {
- this.cancelled = cancel;
+ public World getWorld() {
+ return world;
}
@NotNull
@@ -76,24 +44,4 @@ public HandlerList getHandlers() {
public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
-
- /**
- * An enum specifying the reason the time skipped.
- */
- public enum SkipReason {
-
- /**
- * When time is changed using the vanilla /time command.
- */
- COMMAND,
- /**
- * When time is changed by a plugin.
- */
- CUSTOM,
- /**
- * When time is changed by all players sleeping in their beds and the
- * night skips.
- */
- NIGHT_SKIP
- }
}
diff --git a/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch
index 70ea857d9cc4..7841e0015680 100644
--- a/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch
+++ b/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch
@@ -23838,7 +23838,7 @@ index 3c1490ac7c259da04031db2f170e0c0a5f512191..470d7c770ae9d045b97e2df145cfe3cf
}
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
-index c11e2ce21e43f677bfccb65e6b5ad374912381fa..9aae782f8f9f1c0f7eae394ec0a1bda79e93f6f4 100644
+index aebc47b0ed5c5a47b3e70e0c94ab5f7abaca523d..7c6a23408d7fe9cb11891678af97b5b7761d6bbc 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -191,7 +191,7 @@ import net.minecraft.world.scores.ScoreboardSaveData;
@@ -24079,7 +24079,7 @@ index c11e2ce21e43f677bfccb65e6b5ad374912381fa..9aae782f8f9f1c0f7eae394ec0a1bda7
this.tickFrame.end();
this.recordEndOfTick(); // Paper - improve tick loop
profiler.pop();
-@@ -2610,6 +2729,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop passengers = this.entity.getPassengers();
if (!passengers.equals(this.lastPassengers)) {
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
-index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3bb953056 100644
+index cebead9e2d11f03e3c854113230c3b74dfe9f02e..c26c0e20f788d96cf491ee5cf27c7b19e2e87fc1 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -182,7 +182,7 @@ import net.minecraft.world.waypoints.WaypointTransmitter;
@@ -27025,7 +27025,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
private final GameEventDispatcher gameEventDispatcher;
public boolean noSave;
private final SleepStatus sleepStatus;
-@@ -275,12 +275,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -276,12 +276,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
public final void loadChunksForMoveAsync(AABB box, ca.spottedleaf.concurrentutil.util.Priority priority,
java.util.function.Consumer> onLoad) {
@@ -27039,7 +27039,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
int minBlockX = Mth.floor(box.minX - 1.0E-7) - 3;
int minBlockZ = Mth.floor(box.minZ - 1.0E-7) - 3;
-@@ -299,30 +294,171 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -300,30 +295,171 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
public final void loadChunks(int minChunkX, int minChunkZ, int maxChunkX, int maxChunkZ,
ca.spottedleaf.concurrentutil.util.Priority priority,
java.util.function.Consumer> onLoad) {
@@ -27227,7 +27227,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
}
}
-@@ -336,16 +472,135 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -337,16 +473,135 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
}
}
@@ -27370,7 +27370,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
public ServerLevel(
final MinecraftServer server,
-@@ -409,18 +664,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -416,18 +671,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
// CraftBukkit end
boolean syncWrites = server.forceSynchronousWrites();
DataFixer fixerUpper = server.getFixerUpper();
@@ -27390,7 +27390,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
this.chunkSource = new ServerChunkCache(
this,
levelStorage,
-@@ -431,7 +675,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -438,7 +682,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
this.spigotConfig.viewDistance, // Spigot
this.spigotConfig.simulationDistance, // Spigot
syncWrites,
@@ -27399,7 +27399,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
() -> server.overworld().getDataStorage()
, savedDataStorage // Paper - initialize SavedDataStorage earlier
);
-@@ -471,6 +715,20 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -478,6 +722,20 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
this.waypointManager = new ServerWaypointManager(this); // Paper - optimize ServerWaypointManager with locator bar disabled
this.environmentAttributes = EnvironmentAttributeSystem.builder().addDefaultLayers(this).build();
this.updateSkyBrightness();
@@ -27420,7 +27420,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
}
-@@ -607,8 +865,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -614,8 +872,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
profiler.push("checkDespawn");
entity.checkDespawn();
profiler.pop();
@@ -27430,7 +27430,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
Entity vehicle = entity.getVehicle();
if (vehicle != null) {
if (!vehicle.isRemoved() && vehicle.hasPassenger(entity)) {
-@@ -632,7 +889,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -639,7 +896,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
profiler.push("entityManagement");
@@ -27439,7 +27439,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
profiler.pop();
profiler.push("debugSynchronizers");
if (this.debugSynchronizers.hasAnySubscriberFor(DebugSubscriptions.NEIGHBOR_UPDATES)) {
-@@ -649,7 +906,10 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -656,7 +913,10 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@Override
public boolean shouldTickBlocksAt(final long chunkPos) {
@@ -27451,7 +27451,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
protected void tickTime() {
-@@ -673,7 +933,60 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -680,7 +940,60 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
this.players.stream().filter(LivingEntity::isSleeping).collect(Collectors.toList()).forEach(player -> player.stopSleepInBed(false, false));
}
@@ -27512,7 +27512,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
ChunkPos chunkPos = chunk.getPos();
int minX = chunkPos.getMinBlockX();
int minZ = chunkPos.getMinBlockZ();
-@@ -682,7 +995,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -689,7 +1002,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
if (!this.paperConfig().environment.disableIceAndSnow) { // Paper - Option to disable ice and snow
for (int i = 0; i < tickSpeed; i++) {
@@ -27521,7 +27521,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
this.tickPrecipitation(this.getBlockRandomPos(minX, 0, minZ, 15));
}
}
-@@ -690,31 +1003,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -697,31 +1010,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
profiler.popPush("tickBlocks");
if (tickSpeed > 0) {
@@ -27554,7 +27554,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
profiler.pop();
-@@ -1037,6 +1326,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -1044,6 +1333,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
if (fluidState.is(type)) {
fluidState.tick(this, pos, blockState);
}
@@ -27567,7 +27567,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
private void tickBlock(final BlockPos pos, final Block type) {
-@@ -1044,6 +1339,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -1051,6 +1346,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
if (state.is(type)) {
state.tick(this, pos, this.random);
}
@@ -27580,7 +27580,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
// Paper start - log detailed entity tick information
-@@ -1128,6 +1429,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -1135,6 +1436,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
public void save(final @Nullable ProgressListener progressListener, final boolean flush, final boolean noSave) {
@@ -27592,7 +27592,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
ServerChunkCache chunkSource = this.getChunkSource();
if (!noSave) {
new org.bukkit.event.world.WorldSaveEvent(this.getWorld()).callEvent(); // CraftBukkit
-@@ -1140,13 +1446,18 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -1147,13 +1453,18 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
progressListener.progressStage(Component.translatable("menu.savingChunks"));
}
@@ -27616,7 +27616,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
private void saveLevelData(final boolean sync) {
-@@ -1267,7 +1578,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -1274,7 +1585,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
this.removePlayerImmediately((ServerPlayer)existing, Entity.RemovalReason.DISCARDED);
}
@@ -27625,7 +27625,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
// CraftBukkit start
-@@ -1298,7 +1609,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -1305,7 +1616,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
// CraftBukkit end
@@ -27634,7 +27634,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
}
-@@ -1309,7 +1620,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -1316,7 +1627,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
public boolean tryAddFreshEntityWithPassengers(final Entity entity, final org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
// CraftBukkit end
@@ -27643,7 +27643,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
return false;
} else {
this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit
-@@ -2102,7 +2413,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -2109,7 +2420,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
}
@@ -27652,7 +27652,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
output.write(String.format(Locale.ROOT, "block_entity_tickers: %d\n", this.blockEntityTickers.size()));
output.write(String.format(Locale.ROOT, "block_ticks: %d\n", this.getBlockTicks().count()));
output.write(String.format(Locale.ROOT, "fluid_ticks: %d\n", this.getFluidTicks().count()));
-@@ -2120,13 +2431,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -2127,13 +2438,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
Path chunks = rootDir.resolve("chunks.csv");
try (Writer output = Files.newBufferedWriter(chunks)) {
@@ -27668,7 +27668,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
Path entities = rootDir.resolve("entities.csv");
-@@ -2221,8 +2532,8 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -2228,8 +2539,8 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
Locale.ROOT,
"players: %s, entities: %s [%s], block_entities: %d [%s], block_ticks: %d, fluid_ticks: %d, chunk_source: %s",
this.players.size(),
@@ -27679,7 +27679,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
this.blockEntityTickers.size(),
getTypeCount(this.blockEntityTickers, TickingBlockEntity::getType),
this.getBlockTicks().count(),
-@@ -2255,15 +2566,25 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -2262,15 +2573,25 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@Override
public LevelEntityGetter getEntities() {
org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot
@@ -27708,7 +27708,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
public void startTickingChunk(final LevelChunk levelChunk) {
-@@ -2280,8 +2601,8 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -2287,8 +2608,8 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
public void waitForEntities(final ChunkPos centerChunk, final int radius) {
List chunks = ChunkPos.rangeClosed(centerChunk, radius).toList();
@@ -27719,7 +27719,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
for (ChunkPos chunk : chunks) {
if (!this.areEntitiesLoaded(chunk.pack())) {
-@@ -2302,28 +2623,38 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -2309,28 +2630,38 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@Override
public void close() throws IOException {
super.close();
@@ -27764,7 +27764,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
public boolean anyPlayerCloseEnoughForSpawning(final BlockPos pos) {
-@@ -2340,7 +2671,10 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -2347,7 +2678,10 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
public boolean canSpawnEntitiesInChunk(final ChunkPos pos) {
@@ -27776,7 +27776,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
@Override
-@@ -2388,7 +2722,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -2395,7 +2729,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
public CrashReportCategory fillReportDetails(final CrashReport report) {
CrashReportCategory category = super.fillReportDetails(report);
WeatherData weatherData = this.getWeatherData();
@@ -28487,11 +28487,11 @@ index 83af9ee3ba150da85b9b694cd76a5fabb5b2d8ef..1fb40837bd02672850ec9adc2797190d
PrepareSpawnTask.this.loadListener.updateFocus(this.spawnLevel.dimension(), spawnChunk);
}
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
-index c4f8f0e1013809260977c0874205fbaeebb27e95..b928b58ea5f0b4268b999ce4a23fe2fbc3042f4e 100644
+index eff42b94fd182abace988d9649952e04dc35b268..02605ebe6ef10727badadbf7fc4cec52583df965 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -982,8 +982,8 @@ public abstract class PlayerList {
- player.connection.send(this.server.clockManager().createFullSyncPacket());
+ player.connection.send(level.clockManager().createFullSyncPacket(player)); // Paper - per-world time; per-player time
player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getRespawnData()));
// Paper start - view distances
- player.connection.send(new ClientboundSetChunkCacheRadiusPacket(io.papermc.paper.FeatureHooks.getViewDistance(level)));
diff --git a/paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch b/paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch
index a84ba9c900ca..0811413faa0a 100644
--- a/paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch
+++ b/paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch
@@ -354,10 +354,10 @@ index 0000000000000000000000000000000000000000..ce6b57eeeeb1bd652f4bb53c19dcfbc0
+ }
+}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
-index 3cd2fcc38f3989bb5124ba5bc2f4597103e7a111..6d847ff3646b27fe9bc75e792d813a7f611ab3e5 100644
+index 16ed1b0057e74e2fd84060d5b00bf68c4a887816..3741607fa3ba755b3a9983ced08460053b75e17f 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
-@@ -857,6 +857,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -864,6 +864,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
profiler.pop();
}
@@ -365,7 +365,7 @@ index 3cd2fcc38f3989bb5124ba5bc2f4597103e7a111..6d847ff3646b27fe9bc75e792d813a7f
this.entityTickList
.forEach(
entity -> {
-@@ -1373,12 +1374,15 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -1380,12 +1381,15 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
entity.totalEntityAge++; // Paper - age-like counter for all entities
profiler.push(entity.typeHolder()::getRegisteredName);
profiler.incrementCounter("tickNonPassenger");
@@ -382,7 +382,7 @@ index 3cd2fcc38f3989bb5124ba5bc2f4597103e7a111..6d847ff3646b27fe9bc75e792d813a7f
}
// Paper start - log detailed entity tick information
} finally {
-@@ -1389,7 +1393,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -1396,7 +1400,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
// Paper end - log detailed entity tick information
}
@@ -391,7 +391,7 @@ index 3cd2fcc38f3989bb5124ba5bc2f4597103e7a111..6d847ff3646b27fe9bc75e792d813a7f
if (entity.isRemoved() || entity.getVehicle() != vehicle) {
entity.stopRiding();
} else if (entity instanceof Player || this.entityTickList.contains(entity)) {
-@@ -1399,12 +1403,21 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -1406,12 +1410,21 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
ProfilerFiller profiler = Profiler.get();
profiler.push(entity.typeHolder()::getRegisteredName);
profiler.incrementCounter("tickPassenger");
diff --git a/paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch b/paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch
index f3152b394ec8..5de5e3b8286e 100644
--- a/paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch
+++ b/paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch
@@ -2326,18 +2326,18 @@ index 0000000000000000000000000000000000000000..298076a0db4e6ee6e4775ac43bf749d9
+ }
+}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
-index 26c05173e7fb2bf055afda1717af0dd2e997118d..ffe3ae41dd3d8c4141f81edf0b92001db957ebac 100644
+index f1341c78e90e0f7d6d2b27e6fff57bf6999f7176..12e6162e82dd639ac34da6466fc201623f4682c5 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
-@@ -232,6 +232,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
- public final WorldGenSettings worldGenSettings;
+@@ -233,6 +233,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+ private @Nullable ServerClockManager clockManager;
public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent
+ private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current)
@Override
public @Nullable LevelChunk getChunkIfLoaded(int x, int z) {
-@@ -2765,6 +2766,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -2772,6 +2773,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
return this.debugSynchronizers;
}
diff --git a/paper-server/patches/features/0020-Incremental-chunk-and-player-saving.patch b/paper-server/patches/features/0020-Incremental-chunk-and-player-saving.patch
index 411bbe361674..da4e46704bd3 100644
--- a/paper-server/patches/features/0020-Incremental-chunk-and-player-saving.patch
+++ b/paper-server/patches/features/0020-Incremental-chunk-and-player-saving.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Incremental chunk and player saving
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
-index 1e88021d476710cf4fce9bf50c02993e076e36ee..8c4b40362f77cdea6e57315a6639006ac7ab27c7 100644
+index 248a01f06ec822737a741873166aa4e502a7ba07..c4eb56fc227afd7e9631624537dd8e67ae3a8bea 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -968,7 +968,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - BlockPhysicsEvent
level.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
level.updateLagCompensationTick(); // Paper - lag compensation
diff --git a/paper-server/patches/features/0030-Anti-Xray.patch b/paper-server/patches/features/0030-Anti-Xray.patch
index 3ba9f153e495..f828830ec388 100644
--- a/paper-server/patches/features/0030-Anti-Xray.patch
+++ b/paper-server/patches/features/0030-Anti-Xray.patch
@@ -155,10 +155,10 @@ index a94e6ca1d396b6b0781de5d550c4a804274ee003..a1018e9ca9dfb978d6e6633577abd7d5
private ClientboundLevelChunkWithLightPacket(final RegistryFriendlyByteBuf input) {
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
-index 78021db10860396fef4eb2e01926fbad123916fa..3f02da2014ed8e4169f4bb819b4d9e61154b7b06 100644
+index 4ac7ef5a1ed1fac04a9fd246212f59919deb498c..e562aec4366d7724f915e3dd5ae440a77e0947c5 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
-@@ -630,7 +630,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
+@@ -631,7 +631,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
savedDataStorage.set(io.papermc.paper.world.saveddata.PaperWorldPDC.TYPE, loadedWorldData.pdc() == null ? io.papermc.paper.world.saveddata.PaperWorldPDC.TYPE.constructor().get() : loadedWorldData.pdc());
final GameRules gameRules = new GameRules(server.getWorldData().enabledFeatures(), savedDataStorage.computeIfAbsent(net.minecraft.world.level.gamerules.GameRuleMap.TYPE));
this.gameRules = gameRules;
@@ -196,7 +196,7 @@ index ec40f02032f965f548b0c0a29aa9d9bbad6f439b..373da9d604cfb1614a0618d856aefd2b
if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), connection.getPlayer().getBukkitEntity()).callEvent();
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
-index b69bcaa1e27a4fbe9a9568f3c9e1843167abe1f5..9218322801c41657c00928ef90b0de99df1670f6 100644
+index 5e11abcfd681d86b1c0e282cf901108822766ce2..3020a3208b14bb483b08cf59a796fb83c2403d1c 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -331,7 +331,7 @@ public abstract class PlayerList {
diff --git a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch
index 0dfd995fb01f..dbfb75d16abb 100644
--- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch
+++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch
@@ -1096,7 +1096,7 @@
ObjectArrayList sample = new ObjectArrayList<>(sampleSize);
int offset = Mth.nextInt(this.random, 0, players.size() - sampleSize);
-@@ -1104,6 +_,32 @@
+@@ -1104,12 +_,46 @@
protected void tickChildren(final BooleanSupplier haveTime) {
ProfilerFiller profiler = Profiler.get();
this.getPlayerList().getPlayers().forEach(playerx -> playerx.connection.suspendFlushing());
@@ -1129,25 +1129,31 @@
profiler.push("commandFunctions");
this.getFunctions().tick();
profiler.pop();
-@@ -1115,14 +_,28 @@
-
- if (this.tickCount % 20 == 0) {
- profiler.push("timeSync");
-- this.forceGameTimeSynchronization();
-+ // Paper start - per-world game time
-+ for (final ServerLevel level : this.getAllLevels()) {
-+ this.playerList.broadcastAll(new ClientboundSetTimePacket(level.getGameTime(), Map.of()), level);
+ if (this.tickRateManager.runsNormally()) {
+ profiler.push("clocks");
+- this.clockManager.tick();
++ // Paper start - per-world time
++ if (io.papermc.paper.configuration.GlobalConfiguration.get().time.affectsAllWorlds) {
++ this.clockManager.tick();
++ } else {
++ for (ServerLevel level : this.getAllLevels()) {
++ level.clockManager().tick();
++ }
+ }
-+ // Paper end - per-world game time
++ // Paper end - per-world time
profiler.pop();
-+ }
-+
+ }
+
+@@ -1119,10 +_,20 @@
+ profiler.pop();
+ }
+
+ // CraftBukkit start
+ // Run tasks that are waiting on processing
+ while (!this.processQueue.isEmpty()) {
+ this.processQueue.remove().run();
- }
-
++ }
++
profiler.push("levels");
this.updateEffectiveRespawnData();
@@ -1184,6 +1190,19 @@
this.effectiveRespawnData = respawnLevel.getWorldBorderAdjustedRespawnData(respawnData);
}
+@@ -1179,7 +_,11 @@
+ public void forceGameTimeSynchronization() {
+ ProfilerFiller profiler = Profiler.get();
+ profiler.push("timeSync");
+- this.playerList.broadcastAll(new ClientboundSetTimePacket(this.overworld().getGameTime(), Map.of()));
++ // Paper start - per-world time
++ for (ServerLevel level : this.getAllLevels()) {
++ this.playerList.broadcastAll(new ClientboundSetTimePacket(level.getGameTime(), Map.of()), level);
++ }
++ // Paper end - per-world time
+ profiler.pop();
+ }
+
@@ -1207,6 +_,22 @@
return this.levels.get(dimension);
}
@@ -1544,7 +1563,7 @@
player.connection.send(new ClientboundEntityEventPacket(player, event));
}
} else if (rule == GameRules.LIMITED_CRAFTING || rule == GameRules.IMMEDIATE_RESPAWN) {
-@@ -2131,19 +_,21 @@
+@@ -2131,20 +_,21 @@
? ClientboundGameEventPacket.LIMITED_CRAFTING
: ClientboundGameEventPacket.IMMEDIATE_RESPAWN;
ClientboundGameEventPacket packet = new ClientboundGameEventPacket(eventType, (Boolean)value ? 1.0F : 0.0F);
@@ -1566,10 +1585,11 @@
- this.updateMobSpawningFlags();
+ level.setSpawnSettings(level.isSpawningMonsters()); // Paper - per-world game rules
} else if (rule == GameRules.ADVANCE_TIME) {
-+ // TODO - snapshot - time handling
- this.getPlayerList().broadcastAll(this.clockManager().createFullSyncPacket());
+- this.getPlayerList().broadcastAll(this.clockManager().createFullSyncPacket());
++ level.players().forEach(player -> player.connection.send(level.clockManager().createFullSyncPacket(player))); // Paper - per-world time; per-player time
}
}
+
@@ -2157,12 +_,14 @@
return this.savedDataStorage;
}
diff --git a/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch
index 7dbcf005a8e7..49cecb5c7c9c 100644
--- a/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch
+++ b/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch
@@ -1,67 +1,108 @@
--- a/net/minecraft/server/commands/TimeCommand.java
+++ b/net/minecraft/server/commands/TimeCommand.java
-@@ -170,23 +_,61 @@
+@@ -119,7 +_,7 @@
+ final CommandSourceStack source, final SuggestionsBuilder builder, final Holder clock
+ ) {
+ return SharedSuggestionProvider.suggestResource(
+- source.getServer().clockManager().commandTimeMarkersForClock(clock).map(ResourceKey::identifier), builder
++ source.getLevel().clockManager().commandTimeMarkersForClock(clock).map(ResourceKey::identifier), builder // Paper - per-world time
+ );
}
+@@ -141,7 +_,7 @@
+ }
+
+ private static int queryTime(final CommandSourceStack source, final Holder clock) {
+- ServerClockManager clockManager = source.getServer().clockManager();
++ ServerClockManager clockManager = source.getLevel().clockManager(); // Paper - per-world time
+ long totalTicks = clockManager.getTotalTicks(clock);
+ source.sendSuccess(() -> Component.translatable("commands.time.query.absolute", clock.getRegisteredName(), totalTicks), false);
+ return wrapTime(totalTicks);
+@@ -151,7 +_,7 @@
+ if (!clock.equals(timeline.value().clock())) {
+ throw ERROR_WRONG_TIMELINE_FOR_CLOCK.create(clock.getRegisteredName(), timeline.getRegisteredName());
+ } else {
+- ServerClockManager clockManager = source.getServer().clockManager();
++ ServerClockManager clockManager = source.getLevel().clockManager(); // Paper - per-world time
+ long currentTicks = timeline.value().getCurrentTicks(clockManager);
+ source.sendSuccess(() -> Component.translatable("commands.time.query.timeline", timeline.getRegisteredName(), currentTicks), false);
+ return wrapTime(currentTicks);
+@@ -162,33 +_,53 @@
+ if (!clock.equals(timeline.value().clock())) {
+ throw ERROR_WRONG_TIMELINE_FOR_CLOCK.create(clock.getRegisteredName(), timeline.getRegisteredName());
+ } else {
+- ServerClockManager clockManager = source.getServer().clockManager();
++ ServerClockManager clockManager = source.getLevel().clockManager(); // Paper - per-world time
+ long repetitions = timeline.value().getPeriodCount(clockManager);
+ source.sendSuccess(() -> Component.translatable("commands.time.query.timeline.repetitions", timeline.getRegisteredName(), repetitions), false);
+ return wrapTime(repetitions);
+ }
+ }
+
++ // Paper start - per-world time
private static int setTotalTicks(final CommandSourceStack source, final Holder clock, final int totalTicks) {
-+ // Paper start
-+ // TODO - snapshot - 26.1
-+ for (net.minecraft.server.level.ServerLevel level : io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels() : java.util.List.of(source.getLevel())) {
-+ long currentTime = level.clockManager().getTotalTicks(clock);
-+ org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent(level.getWorld(), org.bukkit.event.world.TimeSkipEvent.SkipReason.COMMAND, totalTicks - currentTime);
-+ if (event.callEvent()) {
-+ level.clockManager().setTotalTicks(clock, currentTime + event.getSkipAmount());
-+ }
-+ }
-+ // Paper end
- ServerClockManager clockManager = source.getServer().clockManager();
+- ServerClockManager clockManager = source.getServer().clockManager();
- clockManager.setTotalTicks(clock, totalTicks);
-+ // clockManager.setTotalTicks(clock, totalTicks);
- source.sendSuccess(() -> Component.translatable("commands.time.set.absolute", clock.getRegisteredName(), totalTicks), true);
- return totalTicks;
+- source.sendSuccess(() -> Component.translatable("commands.time.set.absolute", clock.getRegisteredName(), totalTicks), true);
+- return totalTicks;
++ ServerClockManager clockManager = source.getLevel().clockManager();
++ long currentTotalTicks = clockManager.getTotalTicks(clock);
++ org.bukkit.event.world.ClockTimeSkipEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.createTimeSkipEvent(source, totalTicks - currentTotalTicks);
++ final long newTotalTicks;
++ if (event.callEvent()) {
++ newTotalTicks = currentTotalTicks + event.getSkipAmount();
++ clockManager.setTotalTicks(clock, newTotalTicks);
++ } else {
++ newTotalTicks = totalTicks; // just pass it through
++ }
++ source.sendSuccess(() -> Component.translatable("commands.time.set.absolute", clock.getRegisteredName(), newTotalTicks), true);
++ return wrapTime(newTotalTicks);
}
private static int addTime(final CommandSourceStack source, final Holder clock, final int time) {
-+ // Paper start
-+ // TODO - snapshot - 26.1
-+ for (net.minecraft.server.level.ServerLevel level : io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels() : java.util.List.of(source.getLevel())) {
-+ org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent(level.getWorld(), org.bukkit.event.world.TimeSkipEvent.SkipReason.COMMAND, time);;
-+ if (event.callEvent()) {
-+ level.clockManager().addTicks(clock, event.getSkipAmount());
-+ }
-+ }
-+ // Paper end
- ServerClockManager clockManager = source.getServer().clockManager();
+- ServerClockManager clockManager = source.getServer().clockManager();
- clockManager.addTicks(clock, time);
-+ // Paper - move up
++ ServerClockManager clockManager = source.getLevel().clockManager();
++ org.bukkit.event.world.ClockTimeSkipEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.createTimeSkipEvent(source, time);
++ if (event.callEvent()) {
++ clockManager.addTicks(clock, event.getSkipAmount());
++ }
long totalTicks = clockManager.getTotalTicks(clock);
source.sendSuccess(() -> Component.translatable("commands.time.set.absolute", clock.getRegisteredName(), totalTicks), true);
return wrapTime(totalTicks);
}
private static int setTimeToTimeMarker(final CommandSourceStack source, final Holder clock, final ResourceKey timeMarkerId) throws CommandSyntaxException {
-+ // Paper start
-+ // TODO - snapshot - 26.1
-+ boolean foundMarker = false;
-+ for (net.minecraft.server.level.ServerLevel level : io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels() : java.util.List.of(source.getLevel())) {
-+ java.util.OptionalLong targetTime = level.clockManager().getTotalTicksToTimeMarker(clock, timeMarkerId);
-+ if (targetTime.isEmpty()) {
-+ continue;
-+ }
-+
-+ foundMarker = true;
-+ long currentTime = level.clockManager().getTotalTicks(clock);
-+ long delta = targetTime.getAsLong() - currentTime;
-+ org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent(level.getWorld(), org.bukkit.event.world.TimeSkipEvent.SkipReason.COMMAND, delta);
-+ if (event.callEvent()) {
-+ level.clockManager().setTotalTicks(clock, currentTime + event.getSkipAmount());
-+ }
-+ }
-+ // Paper end
-+
- ServerClockManager clockManager = source.getServer().clockManager();
+- ServerClockManager clockManager = source.getServer().clockManager();
- if (!clockManager.moveToTimeMarker(clock, timeMarkerId)) {
-+ if (!foundMarker) { // Paper
++ // Paper start - per-world time
++ ServerClockManager clockManager = source.getLevel().clockManager();
++ java.util.OptionalLong targetTime = clockManager.getTotalTicksToTimeMarker(clock, timeMarkerId);
++ if (targetTime.isEmpty()) {
throw ERROR_NO_TIME_MARKER_FOUND.create(clock.getRegisteredName(), timeMarkerId);
} else {
++ final long currentTime = clockManager.getTotalTicks(clock);
++ final org.bukkit.event.world.ClockTimeSkipEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.createTimeSkipEvent(source, targetTime.getAsLong() - currentTime);
++ if (event.callEvent()) {
++ clockManager.setTotalTicks(clock, currentTime + event.getSkipAmount());
++ }
++ // Paper end - per-world time
source.sendSuccess(
+ () -> Component.translatable("commands.time.set.time_marker", clock.getRegisteredName(), timeMarkerId.identifier().toString()), true
+ );
+@@ -197,13 +_,13 @@
+ }
+
+ private static int setPaused(final CommandSourceStack source, final Holder clock, final boolean paused) {
+- source.getServer().clockManager().setPaused(clock, paused);
++ source.getLevel().clockManager().setPaused(clock, paused); // Paper - per-world time
+ source.sendSuccess(() -> Component.translatable(paused ? "commands.time.pause" : "commands.time.resume", clock.getRegisteredName()), true);
+ return 1;
+ }
+
+ private static int setRate(final CommandSourceStack source, final Holder clock, final float rate) {
+- source.getServer().clockManager().setRate(clock, rate);
++ source.getLevel().clockManager().setRate(clock, rate); // Paper - per-world time
+ source.sendSuccess(() -> Component.translatable("commands.time.rate", clock.getRegisteredName(), rate), true);
+ return 1;
+ }
diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch
index 5b1161c8ff74..c276288b7821 100644
--- a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch
+++ b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch
@@ -9,7 +9,7 @@
private final EntityTickList entityTickList = new EntityTickList();
private final ServerWaypointManager waypointManager;
private EnvironmentAttributeSystem environmentAttributes;
-@@ -221,24 +_,192 @@
+@@ -221,24 +_,199 @@
private final boolean tickTime;
private final LevelDebugSynchronizers debugSynchronizers = new LevelDebugSynchronizers(this);
@@ -22,6 +22,7 @@
+ private final WeatherData weatherData;
+ public final net.minecraft.world.level.timers.TimerQueue scheduledEvents;
+ public final WorldGenSettings worldGenSettings;
++ private @Nullable ServerClockManager clockManager;
+ public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent
+ public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent
+
@@ -184,6 +185,12 @@
this.serverLevelData = levelData;
ChunkGenerator generator = levelStem.generator();
+ // CraftBukkit start
++ // Paper start - per-world time
++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().time.affectsAllWorlds) {
++ this.clockManager = savedDataStorage.computeIfAbsent(net.minecraft.world.clock.ServerClockManager.TYPE); // Paper - per-world time
++ this.clockManager.init(server, this); // Paper - per-world time
++ }
++ // Paper end - per-world time
+ if (loadedWorldData.pdc() != null) {
+ this.getWorld().readBukkitValues(loadedWorldData.pdc().persistentData().toTagCompound());
+ }
@@ -262,30 +269,39 @@
@Deprecated
@VisibleForTesting
+@@ -322,7 +_,7 @@
+
+ @Override
+ public ServerClockManager clockManager() {
+- return this.server.clockManager();
++ return io.papermc.paper.configuration.GlobalConfiguration.get().time.affectsAllWorlds ? this.server.clockManager() : this.clockManager; // Paper - per-world time
+ }
+
+ @Override
@@ -354,11 +_,24 @@
int percentage = this.getGameRules().get(GameRules.PLAYERS_SLEEPING_PERCENTAGE);
if (this.sleepStatus.areEnoughSleeping(percentage) && this.sleepStatus.areEnoughDeepSleeping(percentage, this.players)) {
Optional> defaultClock = this.dimensionType().defaultClock();
-+ org.bukkit.event.world.TimeSkipEvent event = null; // Paper - time skip event
++ org.bukkit.event.world.ClockTimeSkipEvent event = null; // Paper - per-world time
if (this.getGameRules().get(GameRules.ADVANCE_TIME) && defaultClock.isPresent()) {
- this.server.clockManager().moveToTimeMarker(defaultClock.get(), ClockTimeMarkers.WAKE_UP_FROM_SLEEP);
-+ // Paper start - time skip event
-+ long currentTime = this.server.clockManager().getTotalTicks(defaultClock.get());
-+ long delta = this.server.clockManager().getTotalTicksToTimeMarker(defaultClock.get(), ClockTimeMarkers.WAKE_UP_FROM_SLEEP).orElse(0L) - currentTime;
++ // Paper start - per-world time
++ long currentTime = this.clockManager().getTotalTicks(defaultClock.get());
++ long delta = this.clockManager().getTotalTicksToTimeMarker(defaultClock.get(), ClockTimeMarkers.WAKE_UP_FROM_SLEEP).orElse(0L) - currentTime;
+ event = new org.bukkit.event.world.TimeSkipEvent(
+ this.getWorld(),
-+ org.bukkit.event.world.TimeSkipEvent.SkipReason.NIGHT_SKIP,
++ org.bukkit.event.world.ClockTimeSkipEvent.SkipReason.NIGHT_SKIP,
+ delta
+ );
+
+ if (event.callEvent()) {
-+ this.server.clockManager().setTotalTicks(defaultClock.get(), currentTime + event.getSkipAmount()); // TODO - snapshot - per world time
++ this.clockManager().setTotalTicks(defaultClock.get(), currentTime + event.getSkipAmount());
+ }
-+ // Paper end - time skip event
++ // Paper end - per-world time
}
- this.wakeUpAllPlayers();
-+ if (event == null || !event.isCancelled()) this.wakeUpAllPlayers(); // Paper - time skip event - only wake up players if time skip event is not cancelled
++ if (event == null || !event.isCancelled()) this.wakeUpAllPlayers(); // Paper - per-world time - only wake up players if time skip event is not cancelled
if (this.getGameRules().get(GameRules.ADVANCE_WEATHER) && this.isRaining()) {
this.resetWeatherCycle();
}
diff --git a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch
index 87be55d0e7d8..b6c7894d187b 100644
--- a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch
+++ b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch
@@ -740,9 +740,12 @@
}
public UserWhiteList getWhiteList() {
-@@ -654,10 +_,18 @@
+@@ -652,12 +_,20 @@
+ public void sendLevelInfo(final ServerPlayer player, final ServerLevel level) {
+ WorldBorder worldBorder = level.getWorldBorder();
player.connection.send(new ClientboundInitializeBorderPacket(worldBorder));
- player.connection.send(this.server.clockManager().createFullSyncPacket());
+- player.connection.send(this.server.clockManager().createFullSyncPacket());
++ player.connection.send(level.clockManager().createFullSyncPacket(player)); // Paper - per-world time; per-player time
player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getRespawnData()));
+ // Paper start - view distances
+ player.connection.send(new ClientboundSetChunkCacheRadiusPacket(io.papermc.paper.FeatureHooks.getViewDistance(level)));
diff --git a/paper-server/patches/sources/net/minecraft/world/clock/ServerClockManager.java.patch b/paper-server/patches/sources/net/minecraft/world/clock/ServerClockManager.java.patch
index 7722ffc60843..ab690e14553a 100644
--- a/paper-server/patches/sources/net/minecraft/world/clock/ServerClockManager.java.patch
+++ b/paper-server/patches/sources/net/minecraft/world/clock/ServerClockManager.java.patch
@@ -1,5 +1,35 @@
--- a/net/minecraft/world/clock/ServerClockManager.java
+++ b/net/minecraft/world/clock/ServerClockManager.java
+@@ -30,6 +_,7 @@
+ );
+ private final PackedClockStates packedClockStates;
+ private MinecraftServer server;
++ private @org.jspecify.annotations.Nullable ServerLevel level; // Paper - per-world time
+ private final Map, ServerClockManager.ClockInstance> clocks = new HashMap<>();
+
+ private ServerClockManager(final PackedClockStates packedClockStates) {
+@@ -37,6 +_,12 @@
+ }
+
+ public void init(final MinecraftServer server) {
++ // Paper start - per-world time
++ this.init(server, null);
++ }
++ public void init(final MinecraftServer server, @org.jspecify.annotations.Nullable final ServerLevel level) {
++ this.level = level;
++ // Paper end - per-world time
+ this.server = server;
+ server.registryAccess()
+ .lookupOrThrow(Registries.WORLD_CLOCK)
+@@ -61,7 +_,7 @@
+ }
+
+ public void tick() {
+- boolean advanceTime = this.server.getGlobalGameRules().get(GameRules.ADVANCE_TIME);
++ boolean advanceTime = this.advanceTime(); // Paper - per-world time
+ if (advanceTime) {
+ this.clocks.values().forEach(ServerClockManager.ClockInstance::tick);
+ this.setDirty();
@@ -97,7 +_,16 @@
return set.booleanValue();
}
@@ -18,36 +48,86 @@
this.modifyClock(clock, instance -> instance.totalTicks = Math.max(instance.totalTicks + ticks, 0L));
}
-@@ -113,7 +_,7 @@
+@@ -112,13 +_,18 @@
+ private void modifyClock(final Holder clock, final Consumer super ServerClockManager.ClockInstance> action) {
ServerClockManager.ClockInstance instance = this.getInstance(clock);
action.accept(instance);
- Map, ClockNetworkState> updates = Map.of(clock, instance.packNetworkState(this.server));
+- Map, ClockNetworkState> updates = Map.of(clock, instance.packNetworkState(this.server));
- this.server.getPlayerList().broadcastAll(new ClientboundSetTimePacket(this.getGameTime(), updates));
-+ this.server.getPlayerList().broadcastAll(new ClientboundSetTimePacket(this.getGameTime(), updates)); // TODO 26.1 per-player time
++ // Paper start - per-world time
++ this.broadcastUpdates(clock, instance);
this.setDirty();
++ if (this.level != null) {
++ this.level.environmentAttributes().invalidateTickCache();
++ } else {
for (ServerLevel level : this.server.getAllLevels()) {
-@@ -126,7 +_,23 @@
- return this.getInstance(definition).totalTicks;
+ level.environmentAttributes().invalidateTickCache();
+ }
++ }
++ // Paper end - per-world time
+ }
+
+ @Override
+@@ -127,12 +_,48 @@
}
-+ // Paper start
-+ // TODO - snapshot: just make the inner class, fields and getter public
-+ public boolean isPaused(final Holder definition) {
-+ return this.getInstance(definition).paused;
+ public ClientboundSetTimePacket createFullSyncPacket() {
+- return new ClientboundSetTimePacket(this.getGameTime(), Util.mapValues(this.clocks, clock -> clock.packNetworkState(this.server)));
++ // Paper start - per-player time
++ return this.createFullSyncPacket(null);
+ }
+
-+ public float partialTick(final Holder definition) {
-+ return this.getInstance(definition).partialTick;
++ public ClientboundSetTimePacket createFullSyncPacket(final net.minecraft.server.level.ServerPlayer player) {
++ final Map, ClockNetworkState> updates = new HashMap<>(this.clocks.size());
++ this.clocks.forEach((clock, instance) -> updates.put(clock, this.packNetworkState(clock, instance, player)));
++ return new ClientboundSetTimePacket(this.getGameTime(), updates);
++ // Paper end - per-player time
+ }
+
+ private long getGameTime() {
+- return this.server.overworld().getGameTime();
+- }
++ return this.level != null ? this.level.getGameTime() : this.server.overworld().getGameTime(); // Paper - per-world time
+ }
+
-+ public float rate(final Holder definition) {
-+ return this.getInstance(definition).rate;
++ // Paper start - per-world time; per-player time
++ private void broadcastUpdates(final Holder clock, final ServerClockManager.ClockInstance instance) {
++ for (final net.minecraft.server.level.ServerPlayer player : this.level != null ? this.level.players() : this.server.getPlayerList().getPlayers()) {
++ final var packet = new net.minecraft.network.protocol.game.ClientboundSetTimePacket(
++ this.getGameTime(),
++ java.util.Map.of(clock, this.packNetworkState(clock, instance, player))
++ );
++ player.connection.send(packet);
++ }
+ }
-+ // Paper end
+
- public ClientboundSetTimePacket createFullSyncPacket() {
-+ // TODO - snapshot: 26.1 per-player time
- return new ClientboundSetTimePacket(this.getGameTime(), Util.mapValues(this.clocks, clock -> clock.packNetworkState(this.server)));
- }
++ private ClockNetworkState packNetworkState(
++ final Holder clock,
++ final ServerClockManager.ClockInstance instance,
++ final net.minecraft.server.level.ServerPlayer player
++ ) {
++ if (player != null && player.level().dimensionType().defaultClock().filter(clock::equals).isPresent()) {
++ final boolean paused = !player.relativeTime || instance.paused || !this.advanceTime();
++ return new ClockNetworkState(player.getPlayerTime(), instance.partialTick, paused ? 0.0F : instance.rate);
++ }
++ return instance.packNetworkState(this.advanceTime());
++ }
++
++ private boolean advanceTime() {
++ return this.level != null ? this.level.getGameRules().get(GameRules.ADVANCE_TIME) : this.server.getGlobalGameRules().get(GameRules.ADVANCE_TIME);
++ }
++ // Paper end - per-world time; per-player time
+
+ public boolean isAtTimeMarker(final Holder clock, final ResourceKey timeMarkerId) {
+ ServerClockManager.ClockInstance clockInstance = this.getInstance(clock);
+@@ -171,8 +_,7 @@
+ return new ClockState(this.totalTicks, this.partialTick, this.rate, this.paused);
+ }
+- public ClockNetworkState packNetworkState(final MinecraftServer server) {
+- boolean advanceTime = server.getGlobalGameRules().get(GameRules.ADVANCE_TIME);
++ public ClockNetworkState packNetworkState(final boolean advanceTime) { // Paper - per-world time
+ boolean paused = this.paused || !advanceTime;
+ return new ClockNetworkState(this.totalTicks, this.partialTick, paused ? 0.0F : this.rate);
+ }
diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/paper-server/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
index adfeed35c1f8..232bc5e8b7cb 100644
--- a/paper-server/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
+++ b/paper-server/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
@@ -192,11 +192,16 @@ public class UnsupportedSettings extends ConfigurationPart {
public class Commands extends ConfigurationPart {
public boolean suggestPlayerNamesWhenNullTabCompletions = true;
- public boolean timeCommandAffectsAllWorlds = false;
@Comment("Allow mounting entities to a player in the Vanilla '/ride' command.")
public boolean rideCommandAllowPlayerAsVehicle = false;
}
+ public Time time;
+
+ public class Time extends ConfigurationPart {
+ public boolean affectsAllWorlds = false;
+ }
+
public Scoreboards scoreboards;
public class Scoreboards extends ConfigurationPart {
diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/RemovedConfigurations.java b/paper-server/src/main/java/io/papermc/paper/configuration/RemovedConfigurations.java
index 07baa90527f9..902f19edc9fc 100644
--- a/paper-server/src/main/java/io/papermc/paper/configuration/RemovedConfigurations.java
+++ b/paper-server/src/main/java/io/papermc/paper/configuration/RemovedConfigurations.java
@@ -87,6 +87,7 @@ interface RemovedConfigurations {
path("chunk-system", "gen-parallelism"),
path("logging"), // server is no longer obfuscated since 26.1
path("unsupported-settings", "compression-format"),
+ path("commands", "time-command-affects-all-worlds") // replaced with time.affects-all-worlds
};
}
diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/transformation/global/LegacyPaperConfig.java b/paper-server/src/main/java/io/papermc/paper/configuration/transformation/global/LegacyPaperConfig.java
index 7b984ec88a72..983382332b75 100644
--- a/paper-server/src/main/java/io/papermc/paper/configuration/transformation/global/LegacyPaperConfig.java
+++ b/paper-server/src/main/java/io/papermc/paper/configuration/transformation/global/LegacyPaperConfig.java
@@ -128,7 +128,6 @@ private static ConfigurationTransformation newFormatTransformation() {
moveFromRoot(builder, "track-plugin-scoreboards", "scoreboards");
moveFromRoot(builder, "suggest-player-names-when-null-tab-completions", "commands");
- moveFromRoot(builder, "time-command-affects-all-worlds", "commands");
moveFromRoot(builder, "fix-target-selector-tag-completion", "commands");
moveFromRoot(builder, "log-player-ip-addresses", "loggers");
diff --git a/paper-server/src/main/java/io/papermc/paper/world/migration/LegacyCraftBukkitWorldMigration.java b/paper-server/src/main/java/io/papermc/paper/world/migration/LegacyCraftBukkitWorldMigration.java
index 91f4bb7c2fa4..ba24fda2395f 100644
--- a/paper-server/src/main/java/io/papermc/paper/world/migration/LegacyCraftBukkitWorldMigration.java
+++ b/paper-server/src/main/java/io/papermc/paper/world/migration/LegacyCraftBukkitWorldMigration.java
@@ -14,6 +14,7 @@
import net.minecraft.core.HolderLookup;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.datafix.DataFixers;
+import net.minecraft.world.clock.ServerClockManager;
import net.minecraft.world.entity.raid.Raids;
import net.minecraft.world.level.TicketStorage;
import net.minecraft.world.level.border.WorldBorder;
@@ -107,6 +108,7 @@ private void migrateSharedSavedData() throws IOException {
this.copySavedDataIfPresent(TicketStorage.TYPE);
this.copySavedDataIfPresent(Raids.TYPE);
this.copySavedDataIfPresent(WorldGenSettings.TYPE);
+ this.copySavedDataIfPresent(ServerClockManager.TYPE);
this.migrateLegacyWorldBorder();
if (this.context.stemKey() == LevelStem.END) {
diff --git a/paper-server/src/main/java/io/papermc/paper/world/migration/VanillaWorldMigration.java b/paper-server/src/main/java/io/papermc/paper/world/migration/VanillaWorldMigration.java
index 7e3116e9ac0a..00ab529b50f3 100644
--- a/paper-server/src/main/java/io/papermc/paper/world/migration/VanillaWorldMigration.java
+++ b/paper-server/src/main/java/io/papermc/paper/world/migration/VanillaWorldMigration.java
@@ -12,6 +12,7 @@
import java.util.UUID;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.datafix.DataFixers;
+import net.minecraft.world.clock.ServerClockManager;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.gamerules.GameRuleMap;
import net.minecraft.world.level.levelgen.WorldGenSettings;
@@ -64,6 +65,7 @@ private static void migrateSavedData(final WorldMigrationContext context) throws
WorldMigrationSupport.copySavedDataIfPresent(sourceDataRoots, context.targetDataRoot(), WorldGenSettings.TYPE, false);
WorldMigrationSupport.copySavedDataIfPresent(sourceDataRoots, context.targetDataRoot(), GameRuleMap.TYPE, false);
WorldMigrationSupport.copySavedDataIfPresent(sourceDataRoots, context.targetDataRoot(), WeatherData.TYPE, false);
+ WorldMigrationSupport.copySavedDataIfPresent(sourceDataRoots, context.targetDataRoot(), ServerClockManager.TYPE, false);
if (context.dimensionKey() == Level.OVERWORLD) {
WorldMigrationSupport.copySavedDataIfPresent(sourceDataRoots, context.targetDataRoot(), TimerQueue.TYPE, false);
WorldMigrationSupport.copySavedDataIfPresent(sourceDataRoots, context.targetDataRoot(), WanderingTraderData.TYPE, false);
@@ -71,6 +73,7 @@ private static void migrateSavedData(final WorldMigrationContext context) throws
deleteLegacyRootCopyIfMigrated(context, WorldGenSettings.TYPE);
deleteLegacyRootCopyIfMigrated(context, GameRuleMap.TYPE);
deleteLegacyRootCopyIfMigrated(context, WeatherData.TYPE);
+ deleteLegacyRootCopyIfMigrated(context, ServerClockManager.TYPE);
deleteLegacyRootCopyIfMigrated(context, TimerQueue.TYPE);
deleteLegacyRootCopyIfMigrated(context, WanderingTraderData.TYPE);
}
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index e53cea42596e..885d5fe3ecd4 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -146,6 +146,7 @@
import org.bukkit.event.weather.LightningStrikeEvent;
import org.bukkit.event.weather.ThunderChangeEvent;
import org.bukkit.event.weather.WeatherChangeEvent;
+import org.bukkit.event.world.ClockTimeSkipEvent;
import org.bukkit.event.world.SpawnChangeEvent;
import org.bukkit.event.world.TimeSkipEvent;
import org.bukkit.generator.BiomeProvider;
@@ -814,7 +815,7 @@ public void setFullTime(long time) {
}
final long currentClockTime = this.world.getDefaultClockTime();
- final TimeSkipEvent event = new TimeSkipEvent(this, TimeSkipEvent.SkipReason.CUSTOM, time - currentClockTime);
+ final ClockTimeSkipEvent event = new TimeSkipEvent(this, ClockTimeSkipEvent.SkipReason.CUSTOM, time - currentClockTime);
this.server.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 04533880d438..7c80c93209bd 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -97,7 +97,6 @@
import net.minecraft.network.protocol.game.ClientboundSetHealthPacket;
import net.minecraft.network.protocol.game.ClientboundSetPlayerInventoryPacket;
import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket;
-import net.minecraft.network.protocol.game.ClientboundSetTimePacket;
import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket;
import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket;
import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket;
@@ -118,8 +117,6 @@
import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.InteractionHand;
-import net.minecraft.world.clock.ClockNetworkState;
-import net.minecraft.world.clock.WorldClock;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
@@ -132,7 +129,6 @@
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.level.block.entity.SignText;
import net.minecraft.world.level.border.BorderChangeListener;
-import net.minecraft.world.level.gamerules.GameRules;
import net.minecraft.world.level.saveddata.maps.MapDecoration;
import net.minecraft.world.level.saveddata.maps.MapId;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
@@ -1541,16 +1537,7 @@ public void setPlayerTime(long time, boolean tickTime) {
return;
}
- final long gameTime = level.getGameTime();
- final long playerClockTime = this.getHandle().getPlayerTime();
- final Holder worldClock = level.dimensionType().defaultClock().get();
- final boolean paused = !this.getHandle().relativeTime || !level.getGameRules().get(GameRules.ADVANCE_TIME) || level.clockManager().isPaused(worldClock);
- final ClockNetworkState clockState = new ClockNetworkState(
- playerClockTime,
- level.clockManager().partialTick(worldClock),
- paused ? 0.0F : level.clockManager().rate(worldClock)
- );
- this.getHandle().connection.send(new ClientboundSetTimePacket(gameTime, Map.of(worldClock, clockState)));
+ this.getHandle().connection.send(level.clockManager().createFullSyncPacket(this.getHandle()));
}
@Override
diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 6d485bb4d916..7a42d1810f74 100644
--- a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -23,6 +23,7 @@
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.Connection;
@@ -261,9 +262,11 @@
import org.bukkit.event.raid.RaidTriggerEvent;
import org.bukkit.event.vehicle.VehicleCreateEvent;
import org.bukkit.event.weather.LightningStrikeEvent;
+import org.bukkit.event.world.ClockTimeSkipEvent;
import org.bukkit.event.world.EntitiesLoadEvent;
import org.bukkit.event.world.EntitiesUnloadEvent;
import org.bukkit.event.world.LootGenerateEvent;
+import org.bukkit.event.world.TimeSkipEvent;
import org.bukkit.inventory.CraftingRecipe;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.InventoryView;
@@ -2417,4 +2420,11 @@ public static boolean callPlayerToggleEntityAgeLockEvent(net.minecraft.world.ent
}
return true;
}
+
+ public static ClockTimeSkipEvent createTimeSkipEvent(final CommandSourceStack source, final long skipAmount) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().time.affectsAllWorlds) {
+ return new ClockTimeSkipEvent(ClockTimeSkipEvent.SkipReason.COMMAND, skipAmount);
+ }
+ return new TimeSkipEvent(source.getLevel().getWorld(), ClockTimeSkipEvent.SkipReason.COMMAND, skipAmount);
+ }
}