Compare commits

...
Author SHA1 Message Date
Jake Potrebic 592f013c5c Add RegistryRetriever for future use in registry API 2026-05-08 21:56:30 +02:00
Alejandro Nieto b4682bfef6 Fix clicked items disappearing when player dies (#13002) 2026-05-04 08:23:40 +02:00
Warrior b685281d74 [ci skip] Mention documenting new config options in CONTRIBUTING.md (#13664) 2026-05-03 16:43:03 -04:00
Lulu13022002 b8b4a1c7cd Update Player#getClientViewDistance (#13530) 2026-05-03 16:40:33 -04:00
Lulu13022002 11dbf11014 Call BlockRedstoneEvent for more interactions (#12206) 2026-05-03 16:38:16 -04:00
Nassim Jahnke 39bd1bac06 [ci skip] Rebuild patches 2026-05-03 21:23:19 +02:00
Harry afea65c2d2 Fix leash event for boats and elytra (#13697) 2026-05-03 12:47:36 -04:00
masmc05 1835b0468f Call AsyncPlayerPreLoginEvent/AsyncPlayerConnectionConfigureEvent on virtual threads (#13816) 2026-05-03 12:46:14 -04:00
Owen b80b604636 fix: Attack strength ticker cooldown incorrectly reset (#13856) 2026-05-03 12:38:13 -04:00
Pedro 6048c2d97c Fix LivingEntity#knockback ignored when its Player (#13842) 2026-05-03 12:38:02 -04:00
Lulu13022002 2e7bb166b1 Deprecate dyes custom tag in favour of vanilla tag (#13855) 2026-05-03 12:14:01 -04:00
Nassim Jahnke 39a1aa5c7f Promote build channel to stable 2026-04-30 18:21:45 +02:00
𝑩𝒊𝒒𝒖𝒂𝒕𝒆𝒓𝒏𝒊𝒐𝒏𝒔 174eab0192 Update Improve exact choice recipe ingredients (#13788) 2026-04-29 08:08:28 +00:00
masmc05 5d62ec0ed9 Prevent spawn location getters from allowing making the location invalid (#13831) 2026-04-27 17:52:49 +01:00
masmc05 17524d0ee0 Add precondition to spawn location setter in spawn events (#13830) 2026-04-27 16:56:47 +01:00
Jason Penilla 7799bf28ae Update Paperclip to v3.0.4
Updates Java runtime version check
2026-04-26 13:58:31 -07:00
Coredex 55be6c0ef5 Fix boat and minecart inventories on region switch [ci skip] (#13826) 2026-04-26 16:01:07 -04:00
Nassim Jahnke 5dc4afc1dd Promote build channel to BETA 2026-04-26 20:20:48 +02:00
PedroandLulu13022002 f4e769a74d Improvements checks for arguments numbers (#13290)
Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
2026-04-26 17:55:35 +02:00
Lulu13022002 651d8481b7 Finish world key initial migration (#13824) 2026-04-26 17:26:40 +02:00
Nassim Jahnke acfe105b9d Add options to disable chunk and block entity ticking (#13821) 2026-04-26 17:09:05 +02:00
Nassim Jahnke a64ea13e8e Re-implement per-world and per-player time (#13814) 2026-04-26 13:37:46 +02:00
Warrior 1f8197327f Allow ServerboundChangeGameModePacket if player has /gamemode permissions (#13507) 2026-04-26 01:00:30 -04:00
Owen 8021488ef4 Disconnect State Fixes (#13616)
Replaces the processedDisconnect flag and executeBlocking cleanup with a force kill flag processed by the connection listener tick. executeBlocking(connection::handleDisconnection) did not actually Work, as the the channel is still open at that point because the disconnect packet hasn't been flushed. Replaced with handleConnectionDisconnectOnNextTick, which the connection listener processes on the next tick.

processedDisconnect was an old flag preventing double disconnect.

The same protection is now provided by vanilla's disconnectionHandled check on Connection.

Drops the SPIGOT-924 player.doTick() call on quit. This is an ancient spigot bug fix that causes issues and weird event fires whilst the player is disconnected.

Removes the login side disconnecting flag and the matching tick guard, since the connection now closes properly on its own. The login disconnect path moves to disconnectAsync so it doesn't block on IO.
2026-04-25 18:06:21 -04:00
156 changed files with 1747 additions and 1282 deletions

No files matched your search

+12 -3
View File
@@ -420,13 +420,19 @@ int maxPlayers = GlobalConfiguration.get().misc.maxNumOfPlayers;
Generally for global config values you will use the fully qualified class name,
`io.papermc.paper.configuration.GlobalConfiguration` since it's not imported in
most places.
---
If you are adding a new world config value, you must have access to an instance
of the `net.minecraft.world.level.Level` which you can then access the config by doing
```java
int maxPlayers = level.paperConfig().misc.maxNumOfPlayers;
```
#### Documentation
When adding or removing a config option, you should open a pull request in our [documentation repository](https://github.com/PaperMC/docs)
to keep it in sync and accurate. If you're unsure whether your original change will be accepted, then it's fine to wait with making the documentation
pull request until a maintainer has reviewed your changes. Once everything is done, the documentation pull request will be merged at the same time
that your original pull request is.
## Testing API changes
### Using the Paper Test Plugin
@@ -470,10 +476,13 @@ If you use Maven to build your plugin:
### My commit doesn't need a build, what do I do?
Quite simple: You add `[ci skip]` to the start of your commit subject.
Quite simple: You add `[ci skip]` to the start of your pull request title.
This case most often applies to changes to files like `README.md`, this very
file (`CONTRIBUTING.md`), the `LICENSE.md` file, and so forth.
file (`CONTRIBUTING.md`), the `LICENSE.md` file, and also small updates to Javadocs or other documentation.
Do *not* add [ci skip] to the start of your individual commit subjects, as your
pull request will not be mergeable until a new commit is added due to status check requirements.
### Patching and building is *really* slow, what can I do?
+1 -1
View File
@@ -3,7 +3,7 @@ mcVersion=26.1.2
# This is the current API version for use in (paper-)plugin.yml files
# During snapshot cycles this should be the anticipated version of the release target
apiVersion=26.1.2
channel=ALPHA
channel=STABLE
# Set to true while updating Minecraft version
updatingMinecraft=false
@@ -134,7 +134,7 @@ public class TimingHistory {
}
}
return pair(
worldMap.get(world.getKey().toString()),
worldMap.get(world.key().asString()),
toArrayMapper(regions.values(),new Function<RegionData, Object>() {
@NotNull
@Override
@@ -125,10 +125,11 @@ public class MaterialTags {
/**
* Covers all dyes.
*
* @deprecated in favour of {@link Tag#ITEMS_DYES}
*/
public static final MaterialSetTag DYES = new MaterialSetTag(keyFor("dyes"))
.endsWith("_DYE")
.ensureSize("DYES", 16).lock();
@Deprecated(since = "26.1")
public static final MaterialSetTag DYES = replacedBy(Tag.ITEMS_DYES);
/**
* Covers all variants of gates.
@@ -9,9 +9,16 @@ import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Called when processing a player's attack on an entity when the player's attack strength cooldown is reset
* Called when processing a player's attack on an entity when the player's attack strength cooldown is reset.
*
* @deprecated In modern Minecraft, this does not properly represent spear attacks and additionally does not
* cover the wide range of ways that the cooldown may be reset.
* <p>
* Additionally, the cancellation of event is misleading as the client will reset the cooldown manually.
* So there is no way for the server to control this.
*/
@NullMarked
@Deprecated(since = "26.1", forRemoval = true)
public class PlayerAttackEntityCooldownResetEvent extends PlayerEvent implements Cancellable {
private static final HandlerList HANDLER_LIST = new HandlerList();
@@ -2,6 +2,7 @@ package io.papermc.paper.datacomponent.item;
import io.papermc.paper.datacomponent.DataComponentBuilder;
import net.kyori.adventure.key.Key;
import org.checkerframework.checker.index.qual.Positive;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jspecify.annotations.NullMarked;
@@ -23,7 +24,7 @@ public interface UseCooldown {
* @return builder
*/
@Contract(value = "_ -> new", pure = true)
static UseCooldown.Builder useCooldown(final float seconds) {
static UseCooldown.Builder useCooldown(final @Positive float seconds) {
return ItemComponentTypesBridge.bridge().useCooldown(seconds);
}
@@ -33,7 +34,7 @@ public interface UseCooldown {
* @return cooldown seconds
*/
@Contract(pure = true)
float seconds();
@Positive float seconds();
/**
* The unique resource location to identify this cooldown group.
@@ -1,6 +1,7 @@
package io.papermc.paper.datacomponent.item;
import io.papermc.paper.datacomponent.DataComponentBuilder;
import org.checkerframework.checker.index.qual.NonNegative;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@@ -23,7 +24,7 @@ public interface Weapon {
*
* @return durability
*/
int itemDamagePerAttack();
@NonNegative int itemDamagePerAttack();
/**
* The number of seconds that blocking is disabled.
@@ -46,7 +47,7 @@ public interface Weapon {
* @return the builder for chaining
* @see #itemDamagePerAttack()
*/
Builder itemDamagePerAttack(int damage);
Builder itemDamagePerAttack(@NonNegative int damage);
/**
* Sets the disable blocking duration (in seconds).
@@ -27,8 +27,7 @@ public interface ItemDamageFunction {
*
* @return the threshold
*/
@NonNegative
float threshold();
@NonNegative float threshold();
/**
* Get the constant amount of damage applied to the item, if threshold is passed.
@@ -60,7 +59,7 @@ public interface ItemDamageFunction {
interface Builder extends DataComponentBuilder<ItemDamageFunction> {
@Contract(value = "_ -> this", mutates = "this")
ItemDamageFunction.Builder threshold(@NonNegative final float threshold);
ItemDamageFunction.Builder threshold(final @NonNegative float threshold);
@Contract(value = "_ -> this", mutates = "this")
ItemDamageFunction.Builder base(final float base);
@@ -1,5 +1,6 @@
package io.papermc.paper.event.player;
import com.google.common.base.Preconditions;
import io.papermc.paper.connection.PlayerConfigurationConnection;
import org.bukkit.Location;
import org.bukkit.Server;
@@ -52,7 +53,7 @@ public class AsyncPlayerSpawnLocationEvent extends Event {
* @return the spawn location
*/
public Location getSpawnLocation() {
return this.spawnLocation;
return this.spawnLocation.clone();
}
/**
@@ -61,6 +62,8 @@ public class AsyncPlayerSpawnLocationEvent extends Event {
* @param location the spawn location
*/
public void setSpawnLocation(final Location location) {
Preconditions.checkArgument(location != null, "Location cannot be null");
Preconditions.checkArgument(location.getWorld() != null, "World cannot be null");
this.spawnLocation = location.clone();
}
@@ -12,6 +12,7 @@ import net.kyori.adventure.text.Component;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.EquipmentSlotGroup;
import org.bukkit.inventory.ItemType;
import org.checkerframework.checker.index.qual.NonNegative;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Range;
@@ -99,7 +100,7 @@ public interface EnchantmentRegistryEntry {
*
* @return the anvil cost of this enchantment
*/
@Range(from = 0, to = Integer.MAX_VALUE) int anvilCost();
@NonNegative int anvilCost();
/**
* Provides a list of slot groups this enchantment may be active in.
@@ -245,7 +246,7 @@ public interface EnchantmentRegistryEntry {
* @see Enchantment#getAnvilCost()
*/
@Contract(value = "_ -> this", mutates = "this")
Builder anvilCost(@Range(from = 0, to = Integer.MAX_VALUE) int anvilCost);
Builder anvilCost(@NonNegative int anvilCost);
/**
* Configures the list of slot groups this enchantment may be active in.
@@ -2,9 +2,9 @@ package io.papermc.paper.registry.data;
import io.papermc.paper.registry.RegistryBuilder;
import org.bukkit.GameEvent;
import org.checkerframework.checker.index.qual.NonNegative;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Range;
/**
* A data-centric version-specific registry entry for the {@link GameEvent} type.
@@ -19,7 +19,7 @@ public interface GameEventRegistryEntry {
* @return the range of blocks, represented as an int.
* @see GameEvent#getRange()
*/
@Range(from = 0, to = Integer.MAX_VALUE) int range();
@NonNegative int range();
/**
* A mutable builder for the {@link GameEventRegistryEntry} plugins may change in applicable registry events.
@@ -42,6 +42,6 @@ public interface GameEventRegistryEntry {
* @see GameEvent#getRange()
*/
@Contract(value = "_ -> this", mutates = "this")
Builder range(@Range(from = 0, to = Integer.MAX_VALUE) int range);
Builder range(@NonNegative int range);
}
}
@@ -5,6 +5,7 @@ import io.papermc.paper.registry.tag.Tag;
import io.papermc.paper.registry.tag.TagKey;
import org.bukkit.Keyed;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
/**
* Event object for {@link RegistryEventProvider#compose()}. This
@@ -32,6 +33,19 @@ public interface RegistryComposeEvent<T, B extends RegistryBuilder<T>> extends R
* @param tagKey the tag key
* @return the tag
* @param <V> the tag value type
* @deprecated use {@link #retriever()}
*/
<V extends Keyed> Tag<V> getOrCreateTag(TagKey<V> tagKey); // TODO remove Keyed
@Deprecated(forRemoval = true)
default <V extends Keyed> Tag<V> getOrCreateTag(TagKey<V> tagKey) { // TODO remove Keyed
return this.retriever().getOrCreateTag(tagKey);
}
/**
* Gets the registry retriever, which can be used to retrieve or create
* entries in the registry.
*
* @return the registry retriever
*/
@Contract(pure = true)
RegistryRetriever retriever();
}
@@ -6,6 +6,7 @@ import io.papermc.paper.registry.tag.Tag;
import io.papermc.paper.registry.tag.TagKey;
import org.bukkit.Keyed;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
/**
* Event object for {@link RegistryEventProvider#entryAdd()}. This
@@ -40,6 +41,19 @@ public interface RegistryEntryAddEvent<T, B extends RegistryBuilder<T>> extends
* @param tagKey the tag key
* @return the tag
* @param <V> the tag value type
* @deprecated use {@link #retriever()}
*/
<V extends Keyed> Tag<V> getOrCreateTag(TagKey<V> tagKey);
@Deprecated(forRemoval = true)
default <V extends Keyed> Tag<V> getOrCreateTag(final TagKey<V> tagKey) { // TODO remove Keyed
return this.retriever().getOrCreateTag(tagKey);
}
/**
* Gets the registry retriever, which can be used to retrieve or create
* entries in the registry.
*
* @return the registry retriever
*/
@Contract(pure = true)
RegistryRetriever retriever();
}
@@ -0,0 +1,35 @@
package io.papermc.paper.registry.event;
import io.papermc.paper.registry.TypedKey;
import io.papermc.paper.registry.tag.Tag;
import io.papermc.paper.registry.tag.TagKey;
import org.bukkit.Keyed;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.NonExtendable
public interface RegistryRetriever {
/**
* Gets or creates a tag for the given tag key. This tag
* is then required to be filled either from the built-in or
* custom datapack.
*
* @param tagKey the tag key
* @param <V> the tag value type
* @return the tag
*/
<V extends Keyed> Tag<V> getOrCreateTag(TagKey<V> tagKey); // TODO remove Keyed
/**
* Gets or creates an empty instance of the given {@link TypedKey}.
* <br>
* Can only create instances if the applicable registry still supports adding
* new references. If the registry doesn't, this method will throw an exception.
*
* @param key the key to get or create an instance for
* @param <V> the type of the value associated with the key
* @return an instance of the given key, or a new instance if it does not exist
* @throws IllegalStateException if this registry does not support adding new references and the key does not exist
*/
<V extends Keyed> V getOrCreate(TypedKey<V> key); // TODO remove Keyed
}
@@ -857,13 +857,13 @@ public final class Bukkit {
}
/**
* Gets the world with the given name.
* Gets the world with the given legacy Bukkit name.
*
* <p>This method is considered obsolete and is a candidate for future deprecation.
* Prefer using {@link #getWorld(NamespacedKey)}.</p>
*
* @param name the name of the world to retrieve
* @return a world with the given name, or null if none exists
* @param name the legacy Bukkit name of the world to retrieve
* @return a world with the given legacy Bukkit name, or null if none exists
*/
@ApiStatus.Obsolete
@Nullable
@@ -1,14 +1,14 @@
package org.bukkit;
import com.google.common.base.Preconditions;
import io.papermc.paper.math.FinePosition;
import io.papermc.paper.math.Rotation;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
import io.papermc.paper.math.FinePosition;
import io.papermc.paper.math.Rotation;
import org.bukkit.block.Block;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.Entity;
@@ -574,7 +574,7 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm
} else if (o.getWorld() == null || getWorld() == null) {
throw new IllegalArgumentException("Cannot measure distance to a null world");
} else if (o.getWorld() != getWorld()) {
throw new IllegalArgumentException("Cannot measure distance between " + getWorld().getKey() + " and " + o.getWorld().getKey());
throw new IllegalArgumentException("Cannot measure distance between " + getWorld().key().asString() + " and " + o.getWorld().key().asString());
}
return NumberConversions.square(x - o.x) + NumberConversions.square(y - o.y) + NumberConversions.square(z - o.z);
@@ -1186,10 +1186,11 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm
@Utility
@NotNull
public Map<String, Object> serialize() {
Map<String, Object> data = new HashMap<String, Object>();
Map<String, Object> data = new HashMap<>();
if (this.world != null) {
data.put("world_key", getWorld().getKey().toString());
World world = this.getWorld();
if (world != null) {
data.put("world_key", world.key().asString());
}
data.put("x", this.x);
@@ -1219,7 +1220,8 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm
requiresWorld = true;
}
if (args.containsKey("world_key")) {
world = Bukkit.getWorld(NamespacedKey.fromString((String) args.get("world_key")));
NamespacedKey key = NamespacedKey.fromString((String) args.get("world_key"));
world = key == null ? null : Bukkit.getWorld(key);
requiresWorld = true;
}
@@ -1227,7 +1229,6 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm
throw new IllegalArgumentException("unknown world");
}
return new Location(world, NumberConversions.toDouble(args.get("x")), NumberConversions.toDouble(args.get("y")), NumberConversions.toDouble(args.get("z")), NumberConversions.toFloat(args.get("yaw")), NumberConversions.toFloat(args.get("pitch")));
}
@@ -2094,10 +2094,8 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
*
* @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
@@ -3349,8 +3349,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
/**
* Get the player's current client side view distance.
* <br>
* Will default to the server view distance if the client has not yet
* communicated this information,
* Will default to 2 if the client has not yet communicated this information.
*
* @return client view distance as above
*/
@@ -1,13 +1,22 @@
package org.bukkit.event.block;
import com.google.common.base.Preconditions;
import org.bukkit.block.Block;
import org.bukkit.event.HandlerList;
import org.checkerframework.common.value.qual.IntRange;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.NullMarked;
/**
* Called when a redstone current changes
* Called when a redstone current changes.
* <p>
* It includes the relevant mutation of the {@code powered} and {@code power}
* properties even if the block is not able to produce a redstone signal.
* For the {@code powered} property, a high state will be considered as
* a current of 15 and a low state as 0. Setting the new current to a different
* value will prevent most action in this case.
*/
@NullMarked
public class BlockRedstoneEvent extends BlockEvent {
private static final HandlerList HANDLER_LIST = new HandlerList();
@@ -16,46 +25,45 @@ public class BlockRedstoneEvent extends BlockEvent {
private int newCurrent;
@ApiStatus.Internal
public BlockRedstoneEvent(@NotNull final Block block, final int oldCurrent, final int newCurrent) {
public BlockRedstoneEvent(final Block block, final int oldCurrent, final int newCurrent) {
super(block);
this.oldCurrent = oldCurrent;
this.newCurrent = newCurrent;
}
/**
* Gets the old current of this block
* Gets the old current of this block.
*
* @return The previous current
* @return the previous current
*/
public int getOldCurrent() {
public @IntRange(from = 0, to = 15) int getOldCurrent() {
return this.oldCurrent;
}
/**
* Gets the new current of this block
* Gets the new current of this block.
*
* @return The new current
* @return the new current
*/
public int getNewCurrent() {
public @IntRange(from = 0, to = 15) int getNewCurrent() {
return this.newCurrent;
}
/**
* Sets the new current of this block
* Sets the new current of this block.
*
* @param newCurrent The new current to set
* @param newCurrent the new current to set
*/
public void setNewCurrent(int newCurrent) {
public void setNewCurrent(@IntRange(from = 0, to = 15) int newCurrent) {
Preconditions.checkArgument(newCurrent >= 0 && newCurrent <= 15, "New current must be a redstone signal between 0 and 15 (was %s)", newCurrent);
this.newCurrent = newCurrent;
}
@NotNull
@Override
public HandlerList getHandlers() {
return HANDLER_LIST;
}
@NotNull
public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
@@ -102,6 +102,10 @@ public class EntityUnleashEvent extends EntityEvent implements Cancellable {
* When the entity's leashholder is more than 10 blocks away
*/
DISTANCE,
/**
* When the leashed entity is removed from the game
*/
LEASHED_GONE,
UNKNOWN;
}
}
@@ -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.
* <p>
* 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
}
}
@@ -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 @@ import org.jetbrains.annotations.NotNull;
* Called when the time skips in a world.
* <p>
* 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 class TimeSkipEvent extends WorldEvent implements Cancellable {
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
}
}
@@ -1,6 +1,7 @@
package org.bukkit.inventory.meta.components;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.checkerframework.checker.index.qual.NonNegative;
import org.jetbrains.annotations.ApiStatus;
/**
@@ -14,14 +15,14 @@ public interface FoodComponent extends ConfigurationSerializable {
*
* @return nutrition value
*/
int getNutrition();
@NonNegative int getNutrition();
/**
* Sets the food restored by this item when eaten.
*
* @param nutrition new nutrition value, must be non-negative
*/
void setNutrition(int nutrition);
void setNutrition(@NonNegative int nutrition);
/**
* Gets the saturation restored by this item when eaten.
@@ -1,5 +1,6 @@
package org.spigotmc.event.player;
import com.google.common.base.Preconditions;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.Warning;
@@ -49,6 +50,8 @@ public class PlayerSpawnLocationEvent extends PlayerEvent {
* @param location the spawn location
*/
public void setSpawnLocation(@NotNull Location location) {
Preconditions.checkArgument(location != null, "Location cannot be null");
Preconditions.checkArgument(location.getWorld() != null, "World cannot be null");
this.spawnLocation = location.clone();
}
+1 -1
View File
@@ -15,7 +15,7 @@ val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
dependencies {
mache("io.papermc:mache:26.1.2+build.1")
paperclip("io.papermc:paperclip:3.0.3")
paperclip("io.papermc:paperclip:3.0.4")
}
paperweight {
@@ -23277,10 +23277,10 @@ index 1cd5901c8e4eb4114ab347a393fc37095c8642d2..fadce1c051e6c7bc0c3d041c0cc8ecd7
+}
diff --git a/io/papermc/paper/command/subcommands/ChunkDebugCommand.java b/io/papermc/paper/command/subcommands/ChunkDebugCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..09f1a74740f898559edc8892ae59aca9b89a6fb3
index 0000000000000000000000000000000000000000..d86bd11e0155f767c3bf66ac05fa4acf6d2bfccb
--- /dev/null
+++ b/io/papermc/paper/command/subcommands/ChunkDebugCommand.java
@@ -0,0 +1,277 @@
@@ -0,0 +1,269 @@
+package io.papermc.paper.command.subcommands;
+
+import ca.spottedleaf.moonrise.common.util.JsonUtil;
@@ -23301,6 +23301,8 @@ index 0000000000000000000000000000000000000000..09f1a74740f898559edc8892ae59aca9
+import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.level.chunk.ProtoChunk;
+import org.bukkit.Bukkit;
+import org.bukkit.NamespacedKey;
+import org.bukkit.World;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.checkerframework.checker.nullness.qual.NonNull;
@@ -23327,44 +23329,33 @@ index 0000000000000000000000000000000000000000..09f1a74740f898559edc8892ae59aca9
+
+ @Override
+ public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
+ switch (subCommand) {
+ case "debug" -> {
+ return switch (subCommand) {
+ case "debug":
+ if (args.length == 1) {
+ return CommandUtil.getListMatchingLast(sender, args, "help", "chunks");
+ yield CommandUtil.getListMatchingLast(sender, args, "help", "chunks");
+ }
+ }
+ case "holderinfo" -> {
+ List<String> worldNames = new ArrayList<>();
+ worldNames.add("*");
+ for (org.bukkit.World world : Bukkit.getWorlds()) {
+ worldNames.add(world.getKey().toString());
+ case "chunkinfo", "holderinfo":
+ if (args.length >= 1 && (args.length == 1 || !args[0].equals("*"))) {
+ yield CommandUtil.getListMatchingLast(
+ sender,
+ args,
+ CommandUtil.getWorldSuggestions(sender.getServer(), args.length == 1)
+ );
+ }
+ if (args.length == 1) {
+ return CommandUtil.getListMatchingLast(sender, args, worldNames);
+ }
+ }
+ case "chunkinfo" -> {
+ List<String> worldNames = new ArrayList<>();
+ worldNames.add("*");
+ for (org.bukkit.World world : Bukkit.getWorlds()) {
+ worldNames.add(world.getKey().toString());
+ }
+ if (args.length == 1) {
+ return CommandUtil.getListMatchingLast(sender, args, worldNames);
+ }
+ }
+ }
+ return Collections.emptyList();
+ default:
+ yield Collections.emptyList();
+ };
+ }
+
+ private void doChunkInfo(final CommandSender sender, final String[] args) {
+ List<org.bukkit.World> worlds;
+ List<World> worlds;
+ if (args.length < 1 || args[0].equals("*")) {
+ worlds = Bukkit.getWorlds();
+ worlds = Bukkit.getServer().getWorlds();
+ } else {
+ worlds = new ArrayList<>(args.length);
+ for (final String arg : args) {
+ org.bukkit.@Nullable World world = Bukkit.getWorld(arg);
+ @Nullable NamespacedKey key = NamespacedKey.fromString(arg);
+ @Nullable World world = key == null ? null : sender.getServer().getWorld(key);
+ if (world == null) {
+ sender.sendMessage(text("World '" + arg + "' is invalid", RED));
+ return;
@@ -23379,7 +23370,7 @@ index 0000000000000000000000000000000000000000..09f1a74740f898559edc8892ae59aca9
+ int accumulatedTicking = 0;
+ int accumulatedEntityTicking = 0;
+
+ for (final org.bukkit.World bukkitWorld : worlds) {
+ for (final World bukkitWorld : worlds) {
+ final ServerLevel world = ((CraftWorld) bukkitWorld).getHandle();
+
+ int total = 0;
@@ -23390,7 +23381,7 @@ index 0000000000000000000000000000000000000000..09f1a74740f898559edc8892ae59aca9
+
+ for (final NewChunkHolder holder : ((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolders()) {
+ final NewChunkHolder.ChunkCompletion completion = holder.getLastChunkCompletion();
+ final ChunkAccess chunk = completion == null ? null : completion.chunk();
+ final @Nullable ChunkAccess chunk = completion == null ? null : completion.chunk();
+
+ if (!(chunk instanceof LevelChunk fullChunk)) {
+ continue;
@@ -23424,7 +23415,7 @@ index 0000000000000000000000000000000000000000..09f1a74740f898559edc8892ae59aca9
+ accumulatedTicking += blockTicking;
+ accumulatedEntityTicking += entityTicking;
+
+ sender.sendMessage(text().append(text("Chunks in ", BLUE), text(bukkitWorld.key().toString(), GREEN), text(":")));
+ sender.sendMessage(text().append(text("Chunks in ", BLUE), text(bukkitWorld.key().asString(), GREEN), text(":")));
+ sender.sendMessage(text().color(DARK_AQUA).append(
+ text("Total: ", BLUE), text(total),
+ text(" Inactive: ", BLUE), text(inactive),
@@ -23446,13 +23437,14 @@ index 0000000000000000000000000000000000000000..09f1a74740f898559edc8892ae59aca9
+ }
+
+ private void doHolderInfo(final CommandSender sender, final String[] args) {
+ List<org.bukkit.World> worlds;
+ List<World> worlds;
+ if (args.length < 1 || args[0].equals("*")) {
+ worlds = Bukkit.getWorlds();
+ worlds = Bukkit.getServer().getWorlds();
+ } else {
+ worlds = new ArrayList<>(args.length);
+ for (final String arg : args) {
+ org.bukkit.@Nullable World world = Bukkit.getWorld(arg);
+ @Nullable NamespacedKey key = NamespacedKey.fromString(arg);
+ @Nullable World world = key == null ? null : sender.getServer().getWorld(key);
+ if (world == null) {
+ sender.sendMessage(text("World '" + arg + "' is invalid", RED));
+ return;
@@ -23468,7 +23460,7 @@ index 0000000000000000000000000000000000000000..09f1a74740f898559edc8892ae59aca9
+ int accumulatedProtoChunk = 0;
+ int accumulatedFullChunk = 0;
+
+ for (final org.bukkit.World bukkitWorld : worlds) {
+ for (final World bukkitWorld : worlds) {
+ final ServerLevel world = ((CraftWorld) bukkitWorld).getHandle();
+
+ int total = 0;
@@ -23480,7 +23472,7 @@ index 0000000000000000000000000000000000000000..09f1a74740f898559edc8892ae59aca9
+
+ for (final NewChunkHolder holder : ((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolders()) {
+ final NewChunkHolder.ChunkCompletion completion = holder.getLastChunkCompletion();
+ final ChunkAccess chunk = completion == null ? null : completion.chunk();
+ final @Nullable ChunkAccess chunk = completion == null ? null : completion.chunk();
+
+ ++total;
+
@@ -23506,7 +23498,7 @@ index 0000000000000000000000000000000000000000..09f1a74740f898559edc8892ae59aca9
+ accumulatedProtoChunk += protoChunk;
+ accumulatedFullChunk += fullChunk;
+
+ sender.sendMessage(text().append(text("Chunks in ", BLUE), text(bukkitWorld.getKey().toString(), GREEN), text(":")));
+ sender.sendMessage(text().append(text("Chunks in ", BLUE), text(bukkitWorld.key().asString(), GREEN), text(":")));
+ sender.sendMessage(text().color(DARK_AQUA).append(
+ text("Total: ", BLUE), text(total),
+ text(" Unloadable: ", BLUE), text(canUnload),
@@ -23838,7 +23830,7 @@ index 3c1490ac7c259da04031db2f170e0c0a5f512191..470d7c770ae9d045b97e2df145cfe3cf
}
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896c81fc2ef 100644
index d22f55c63eb950e1b979280612eb9f155e986406..93690b360e5eb1b8d2f8ab2198aa087c9be7ffe2 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -191,7 +191,7 @@ import net.minecraft.world.scores.ScoreboardSaveData;
@@ -23943,7 +23935,7 @@ index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896
public MinecraftServer(
// CraftBukkit start
@@ -843,7 +929,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -853,7 +939,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
level.setSpawnSettings(level.isSpawningMonsters()); // Paper - per level difficulty (from setDifficulty(ServerLevel, Difficulty, boolean))
this.updateEffectiveRespawnData();
this.forceTicks = false; // CraftBukkit
@@ -23952,7 +23944,7 @@ index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896
new org.bukkit.event.world.WorldLoadEvent(level.getWorld()).callEvent(); // Paper - call WorldLoadEvent
}
@@ -866,6 +952,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -876,6 +962,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public abstract boolean shouldRconBroadcast();
public boolean saveAllChunks(final boolean silent, final boolean flush, final boolean force) {
@@ -23964,7 +23956,7 @@ index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896
this.scoreboard.storeToSaveDataIfDirty(this.getDataStorage().computeIfAbsent(ScoreboardSaveData.TYPE));
boolean result = false;
@@ -874,7 +965,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -884,7 +975,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
LOGGER.info("Saving chunks for level '{}'/{}", level, level.dimension().identifier());
}
@@ -23973,7 +23965,7 @@ index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896
result = true;
}
@@ -971,7 +1062,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -981,7 +1072,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
@@ -23982,7 +23974,7 @@ index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896
this.nextTickTimeNanos = Util.getNanos() + TimeUtil.NANOSECONDS_PER_MILLISECOND;
for (ServerLevel levelx : this.getAllLevels()) {
@@ -982,17 +1073,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -992,17 +1083,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.waitUntilNextTick();
}
@@ -24007,7 +23999,7 @@ index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896
this.isSaving = false;
this.savedDataStorage.close();
@@ -1013,6 +1101,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1023,6 +1111,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.services().nameToIdCache().save(false); // Paper - Perf: Async GameProfileCache saving
}
// Spigot end
@@ -24022,7 +24014,7 @@ index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896
// Paper start - Improved watchdog support - move final shutdown items here
Util.shutdownExecutors();
this.onServerExit();
@@ -1107,16 +1203,31 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1117,16 +1213,31 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// execute small amounts of other tasks just in case the number of tasks we are
// draining is large - chunk system and packet processing may be latency sensitive
@@ -24057,7 +24049,7 @@ index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896
profiler.pop(); // moonrise:run_all_chunk
profiler.pop(); // moonrise:run_all_tasks
@@ -1417,6 +1528,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1427,6 +1538,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
private boolean pollTaskInternal() {
if (super.pollTask()) {
@@ -24065,7 +24057,7 @@ index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896
return true;
} else {
boolean ret = false; // Paper - force execution of all worlds, do not just bias the first
@@ -1558,6 +1670,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1568,6 +1680,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Paper - improve tick loop - moved into runAllTasksAtTickStart
this.runAllTasksAtTickStart(); // Paper - improve tick loop
this.tickServer(sprinting ? () -> false : this::haveTime);
@@ -24079,7 +24071,7 @@ index e5925d778c28bd19ee4cb911fb115edc6351c26b..b4d7ccc2fd9e6c928445b09dbc6ac896
this.tickFrame.end();
this.recordEndOfTick(); // Paper - improve tick loop
profiler.pop();
@@ -2600,6 +2719,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2618,6 +2737,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
@@ -26479,7 +26471,7 @@ index 045d4b0ab26622e2763d1583e1e8fcb83ba44427..ddffd36d8213a40dc3f6cbb0ef0f33a0
}
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
index 319335341617051c5b78578465f2224f78c3ea3d..fcb23814c2539f4e31ed5191e03cc28f4e7f9c2d 100644
index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e749a73f93 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -54,7 +54,7 @@ import net.minecraft.world.level.storage.SavedDataStorage;
@@ -27004,7 +26996,7 @@ index de75dda2e6f17f0ae6e7f6a5620fd3eac9d389e5..6774d12d04fa848624fb8bf7a3c2b8bc
List<Entity> 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 f39d48821d728232472ebc5bd6868e6a0d644721..91d27b90a9c9c348d3f93624ff8dbff8a70f522c 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 +27017,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<List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) {
@@ -27039,7 +27031,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<List<net.minecraft.world.level.chunk.ChunkAccess>> onLoad) {
@@ -27227,7 +27219,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 +27362,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 +27382,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 +27391,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 +27412,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 +27422,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
@@ -642,7 +899,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
profiler.push("entityManagement");
@@ -27439,7 +27431,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
@@ -659,7 +916,10 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@Override
public boolean shouldTickBlocksAt(final long chunkPos) {
@@ -27451,7 +27443,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
protected void tickTime() {
@@ -673,7 +933,60 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -683,7 +943,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 +27504,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
@@ -692,7 +1005,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 +27513,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
this.tickPrecipitation(this.getBlockRandomPos(minX, 0, minZ, 15));
}
}
@@ -690,31 +1003,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -700,31 +1013,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
profiler.popPush("tickBlocks");
if (tickSpeed > 0) {
@@ -27554,7 +27546,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
profiler.pop();
@@ -1037,6 +1326,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -1047,6 +1336,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
if (fluidState.is(type)) {
fluidState.tick(this, pos, blockState);
}
@@ -27567,7 +27559,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
@@ -1054,6 +1349,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
if (state.is(type)) {
state.tick(this, pos, this.random);
}
@@ -27580,7 +27572,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
// Paper start - log detailed entity tick information
@@ -1128,6 +1429,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -1138,6 +1439,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
public void save(final @Nullable ProgressListener progressListener, final boolean flush, final boolean noSave) {
@@ -27592,7 +27584,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
@@ -1150,13 +1456,18 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
progressListener.progressStage(Component.translatable("menu.savingChunks"));
}
@@ -27616,7 +27608,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
private void saveLevelData(final boolean sync) {
@@ -1267,7 +1578,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -1277,7 +1588,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
this.removePlayerImmediately((ServerPlayer)existing, Entity.RemovalReason.DISCARDED);
}
@@ -27625,7 +27617,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
// CraftBukkit start
@@ -1298,7 +1609,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -1308,7 +1619,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
// CraftBukkit end
@@ -27634,7 +27626,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
}
@@ -1309,7 +1620,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -1319,7 +1630,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 +27635,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
return false;
} else {
this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit
@@ -2102,7 +2413,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -2112,7 +2423,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
}
@@ -27652,7 +27644,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
@@ -2130,13 +2441,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
Path chunks = rootDir.resolve("chunks.csv");
try (Writer output = Files.newBufferedWriter(chunks)) {
@@ -27668,7 +27660,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
Path entities = rootDir.resolve("entities.csv");
@@ -2221,8 +2532,8 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -2231,8 +2542,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 +27671,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
@@ -2265,15 +2576,25 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@Override
public LevelEntityGetter<Entity> getEntities() {
org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot
@@ -27708,7 +27700,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
public void startTickingChunk(final LevelChunk levelChunk) {
@@ -2280,8 +2601,8 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -2290,8 +2611,8 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
public void waitForEntities(final ChunkPos centerChunk, final int radius) {
List<ChunkPos> chunks = ChunkPos.rangeClosed(centerChunk, radius).toList();
@@ -27719,7 +27711,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
@@ -2312,28 +2633,38 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@Override
public void close() throws IOException {
super.close();
@@ -27764,7 +27756,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
public boolean anyPlayerCloseEnoughForSpawning(final BlockPos pos) {
@@ -2340,7 +2671,10 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -2350,7 +2681,10 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
}
public boolean canSpawnEntitiesInChunk(final ChunkPos pos) {
@@ -27776,7 +27768,7 @@ index 5dc8f5d3738bb3b97e0a0d98fcec4fda44d741a3..0b7fb9e17a43d2eddd96a55e422626c3
}
@Override
@@ -2388,7 +2722,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -2398,7 +2732,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 +28479,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 0c4de29676732f5e84d7584e1f89d508addc1cc4..0613b053f4a75c0884280011ee092d9d108b3857 100644
index eff42b94fd182abace988d9649952e04dc35b268..02605ebe6ef10727badadbf7fc4cec52583df965 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -983,8 +983,8 @@ public abstract class PlayerList {
player.connection.send(this.server.clockManager().createFullSyncPacket());
@@ -982,8 +982,8 @@ public abstract class PlayerList {
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)));
@@ -28501,7 +28493,7 @@ index 0c4de29676732f5e84d7584e1f89d508addc1cc4..0613b053f4a75c0884280011ee092d9d
// Paper end - view distances
if (level.isRaining()) {
// CraftBukkit start - handle player weather
@@ -1201,7 +1201,7 @@ public abstract class PlayerList {
@@ -1200,7 +1200,7 @@ public abstract class PlayerList {
public void setViewDistance(final int viewDistance) {
this.viewDistance = viewDistance;
@@ -28510,7 +28502,7 @@ index 0c4de29676732f5e84d7584e1f89d508addc1cc4..0613b053f4a75c0884280011ee092d9d
for (ServerLevel level : this.server.getAllLevels()) {
level.getChunkSource().setViewDistance(viewDistance);
@@ -1210,7 +1210,7 @@ public abstract class PlayerList {
@@ -1209,7 +1209,7 @@ public abstract class PlayerList {
public void setSimulationDistance(final int simulationDistance) {
this.simulationDistance = simulationDistance;
@@ -30053,7 +30045,7 @@ index e07a7bda45146686a6ac2d20507df9fc8630514f..f84e651e2a34e76a0a71993332e4be1b
// Paper start - Affects Spawning API
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003ef8bb694 100644
index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669b111f4c0 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -87,6 +87,7 @@ import net.minecraft.world.level.storage.LevelData;
@@ -30725,10 +30717,10 @@ index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003
+ this.maxSectionY = this.maxY >> 4;
+ this.sectionsCount = this.maxSectionY - this.minSectionY + 1;
+ // Paper end - getblock optimisations - cache world height/sections
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, CraftNamespacedKey.fromMinecraft(dimension.identifier())); // Spigot
final org.bukkit.NamespacedKey worldKey = CraftNamespacedKey.fromMinecraft(dimension.identifier()); // Paper
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, worldKey); // Spigot
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
this.generator = generator;
@@ -230,6 +863,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -231,6 +864,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
this.registryAccess = registryAccess;
this.palettedContainerFactory = PalettedContainerFactory.create(registryAccess);
this.damageSources = new DamageSources(registryAccess);
@@ -30736,7 +30728,7 @@ index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003
}
// Paper start - Cancel hit for vanished players
@@ -511,7 +1145,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -512,7 +1146,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
this.setBlocksDirty(pos, blockState, blockState1);
}
@@ -30745,7 +30737,7 @@ index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003
this.sendBlockUpdated(pos, blockState, state, flags);
}
@@ -844,6 +1478,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -846,6 +1480,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Paper - Fix MC-117075 use removeAll - remove iterator in favour of indexed for loop, ensuring compile error if something uses iter incorrectly
boolean tickBlockEntities = this.tickRateManager().runsNormally();
@@ -30753,7 +30745,7 @@ index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003
// Paper start - Fix MC-117075 use removeAll
final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<@Nullable TickingBlockEntity> toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>();
toRemove.add(null);
@@ -854,6 +1489,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -856,6 +1491,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
toRemove.add(ticker); // Paper - Fix MC-117075 use removeAll
} else if (tickBlockEntities && this.shouldTickBlocksAt(ticker.getPos())) {
ticker.tick();
@@ -30765,7 +30757,7 @@ index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003
}
}
@@ -873,6 +1513,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -874,6 +1514,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
// Paper end - Prevent block entity and entity crashes
}
@@ -30773,7 +30765,7 @@ index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003
}
// Paper start - Option to prevent armor stands from doing entity lookups
@@ -880,7 +1521,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -881,7 +1522,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public boolean noCollision(@Nullable Entity entity, AABB box) {
if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups)
return false;
@@ -30789,7 +30781,7 @@ index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003
}
// Paper end - Option to prevent armor stands from doing entity lookups
@@ -1025,7 +1673,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -1026,7 +1674,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
if (!this.isInValidBounds(pos)) {
return null;
} else {
@@ -30798,7 +30790,7 @@ index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003
? null
: this.getChunkAt(pos).getBlockEntity(pos, LevelChunk.EntityCreationType.IMMEDIATE);
}
@@ -1105,20 +1753,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -1106,20 +1754,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@Override
public List<Entity> getEntities(final @Nullable Entity except, final AABB bb, final Predicate<? super Entity> selector) {
Profiler.get().incrementCounter("getEntities");
@@ -30826,7 +30818,7 @@ index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003
}
@Override
@@ -1134,33 +1777,94 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -1135,33 +1778,94 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
this.getEntities(type, bb, selector, output, Integer.MAX_VALUE);
}
@@ -30941,7 +30933,7 @@ index 81c3f9f04040b6cfa014ce55e517bd9b374ec252..0958fe0438c3e934b885acf78a0f8003
public <T extends Entity> boolean hasEntities(final EntityTypeTest<Entity, T> type, final AABB bb, final Predicate<? super T> selector) {
Profiler.get().incrementCounter("hasEntities");
@@ -1465,13 +2169,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -1466,13 +2170,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Paper start - allow patching this logic
public final int getEntityCount() {
@@ -32693,7 +32685,7 @@ index 54d57f80b1cca351cac2aa59477a0e57334816e7..94652b00e18ffcbe02f1ad0578d671e2
public @Nullable BlockEntity getBlockEntity(final BlockPos pos) {
return this.wrapped.getBlockEntity(pos);
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index 1bbb8ca0c4a5087cf35c8af8362d867ef868cbd3..b5b514b292f9fdbe410aba5facec1638682c9075 100644
index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d40d82229e 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -64,7 +64,7 @@ import net.minecraft.world.ticks.TickContainerAccess;
@@ -28,7 +28,7 @@ and then catch exceptions and close if they fire.
Part of this commit was authored by: Spottedleaf, sandtechnology
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6b33beff8 100644
index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c647b1cde27 100644
--- a/net/minecraft/network/Connection.java
+++ b/net/minecraft/network/Connection.java
@@ -65,7 +65,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -40,7 +40,7 @@ index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6
public Channel channel;
public SocketAddress address;
// Spigot start
@@ -123,6 +123,10 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -124,6 +124,10 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public boolean handledLegacyLoginEvent; // Paper - playerloginevent
public net.minecraft.server.level.@Nullable ServerPlayer savedPlayerForLegacyEvents; // Paper - playerloginevent & PlayerSpawnLocationEvent
public org.bukkit.event.player.PlayerResourcePackStatusEvent.@Nullable Status resourcePackStatus; // Paper
@@ -51,7 +51,7 @@ index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6
public Connection(final PacketFlow receiving) {
this.receiving = receiving;
@@ -393,11 +397,38 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -394,11 +398,38 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
}
public void send(final Packet<?> packet, final @Nullable ChannelFutureListener listener, final boolean flush) {
@@ -93,7 +93,7 @@ index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6
}
}
@@ -406,7 +437,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -407,7 +438,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
this.flushQueue();
action.accept(this);
} else {
@@ -102,7 +102,7 @@ index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6
}
}
@@ -420,21 +451,41 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -421,21 +452,42 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
}
private void doSendPacket(final Packet<?> packet, final @Nullable ChannelFutureListener listener, final boolean flush) {
@@ -133,7 +133,8 @@ index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6
+ }
+ } catch (final Exception e) {
+ LOGGER.error("NetworkException: {}", player, e);
+ this.disconnect(Component.translatable("disconnect.genericReason", "Internal Exception: " + e.getMessage()));
+ Component reason = Component.translatable("disconnect.genericReason", "Internal Exception: " + e.getMessage());
+ this.send(new ClientboundDisconnectPacket(reason), PacketSendListener.thenRun(() -> this.disconnect(reason)));
+ packet.onPacketDispatchFinish(player, null);
}
+ // Paper end - Optimize network
@@ -148,7 +149,7 @@ index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6
}
}
@@ -446,16 +497,57 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -447,16 +499,57 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
}
}
@@ -211,7 +212,7 @@ index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6
private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world
private static int joinAttemptsThisTick; // Paper - Buffer joins to world
@@ -525,6 +617,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -526,6 +619,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void disconnect(final DisconnectionDetails details) {
this.preparing = false; // Spigot
@@ -219,7 +220,7 @@ index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6
if (this.channel == null) {
this.delayedDisconnect = details;
}
@@ -714,7 +807,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -715,7 +809,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void handleDisconnection() {
if (this.channel != null && !this.channel.isOpen()) {
if (this.disconnectionHandled) {
@@ -228,7 +229,7 @@ index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6
} else {
this.disconnectionHandled = true;
PacketListener packetListener = this.getPacketListener();
@@ -725,7 +818,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -726,7 +820,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
);
disconnectListener.onDisconnect(details);
}
@@ -237,7 +238,7 @@ index 0bc6ab5e498f82c5b3cbdf8dddfed6c8406ad511..9cd6ec17981da310be1d35054af080d6
// Paper start - Add PlayerConnectionCloseEvent
if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) {
/* Player was logged in, either game listener or configuration listener */
@@ -760,4 +853,96 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -761,4 +855,96 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void setBandwidthLogger(final LocalSampleLogger bandwidthLogger) {
this.bandwidthDebugMonitor = new BandwidthDebugMonitor(bandwidthLogger);
}
@@ -371,7 +372,7 @@ index 1480d0db90f5797e3dee19503e52d1e783493ac3..bd76e55ea56dd7c1e232806d1d13a747
+ // Paper end
}
diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java
index b0445b4ad9adb6d2dec08537559d2ed243ca69bb..b266e4f7b437578356568d86910e3b428ee66523 100644
index 387ac8a4e67ef07df73ce98d0add0937314ee497..9ae7c79e5088d9e1e3fb7e0dca00bb15fee118b6 100644
--- a/net/minecraft/server/network/ServerConnectionListener.java
+++ b/net/minecraft/server/network/ServerConnectionListener.java
@@ -52,11 +52,13 @@ public class ServerConnectionListener {
@@ -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 91d27b90a9c9c348d3f93624ff8dbff8a70f522c..f4bbccee849ee3711a3b838884e4bcf4e24da039 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
@@ -1383,12 +1384,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
@@ -1399,7 +1403,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
@@ -1409,12 +1413,21 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
ProfilerFiller profiler = Profiler.get();
profiler.push(entity.typeHolder()::getRegisteredName);
profiler.incrementCounter("tickPassenger");
@@ -521,10 +521,10 @@ index e087d5596979044fe7fbcf7f2cccdae4e81a3d3a..fea6c3b48c4eb162fbdc099fa775bc31
delta = this.maybeBackOffFromEdge(delta, moverType);
Vec3 movement = this.collide(delta);
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index c4da41f3b5ba6d8492d3776654b1ce62a5015895..6a0ebbdfcc0bc07915574c1cf87463e82213ca7e 100644
index 8b0abe9c7a3907419f6e4d55ea22fb9bc749f28b..36c0081e3e8f8776293ae619156cd0828fe5b21d 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -3385,6 +3385,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
@@ -3372,6 +3372,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
protected void playAttackSound() {
}
@@ -817,7 +817,7 @@ index 3a590d4dc980a2912e9cc043d8c8db4cf9d60803..06ab7c48b18c03af494ab10fc2b584ce
+
}
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 0958fe0438c3e934b885acf78a0f8003ef8bb694..31c7223d2d01573c24d4ad83737fa2c2752db028 100644
index c0f901c4ac61a0aa2b480f102feb3669b111f4c0..07c301ba02c7f2c032a29a0ae3bdf95fc522c03b 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -155,6 +155,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -266,10 +266,10 @@ index 319325e741cc314b84844bb49ea569aaf014f319..20b5cfe1ce36d74cd6b2f95566a1bc34
+ // Paper end - Use Velocity cipher
}
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
index 9cd6ec17981da310be1d35054af080d6b33beff8..d7ed1621709c491525daaf7adc8e9f0d781c93e1 100644
index 104976b3eb04d80e5be5bd020cf16c647b1cde27..5a23f95aff982ecc58d2e2bc994f4e495285069c 100644
--- a/net/minecraft/network/Connection.java
+++ b/net/minecraft/network/Connection.java
@@ -738,11 +738,22 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -740,11 +740,22 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
return connection;
}
@@ -296,7 +296,7 @@ index 9cd6ec17981da310be1d35054af080d6b33beff8..d7ed1621709c491525daaf7adc8e9f0d
public boolean isEncrypted() {
return this.encrypted;
@@ -780,16 +791,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -782,16 +793,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void setupCompression(final int threshold, final boolean validateDecompressed) {
if (threshold >= 0) {
@@ -318,7 +318,7 @@ index 9cd6ec17981da310be1d35054af080d6b33beff8..d7ed1621709c491525daaf7adc8e9f0d
this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners
} else {
diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java
index b266e4f7b437578356568d86910e3b428ee66523..0b57e3bcd0319e4e9571fddbcb85db5a3105b8b2 100644
index 391435cf3d279c8f5a889702b50f57626864c7bb..19a77c8269c3f1998985d533d9099c7e6cf76af4 100644
--- a/net/minecraft/server/network/ServerConnectionListener.java
+++ b/net/minecraft/server/network/ServerConnectionListener.java
@@ -77,6 +77,10 @@ public class ServerConnectionListener {
@@ -333,10 +333,10 @@ index b266e4f7b437578356568d86910e3b428ee66523..0b57e3bcd0319e4e9571fddbcb85db5a
.add(
new ServerBootstrap()
diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 8203765d5570644b4c8f6790f361bca2c7066b25..718f00ad9c587a4b0c12f351c10d462113f16ac3 100644
index c1edad046cbdd1627edba58bc06aef5c058e79eb..3a0d47a716ce5c5345640ed67ac306101791892b 100644
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -245,11 +245,9 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
@@ -251,11 +251,9 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
}
SecretKey secretKey = packet.getSecretKey(serverPrivateKey);
@@ -19,12 +19,14 @@ Co-authored-by: egg82 <eggys82@gmail.com>
diff --git a/io/papermc/paper/redstone/RedstoneWireTurbo.java b/io/papermc/paper/redstone/RedstoneWireTurbo.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff747a1ecdf3c888bca0d69de4f85dcd810b6139
index 0000000000000000000000000000000000000000..8e03419df1469c6fecfaa82fcb319a58635b39f3
--- /dev/null
+++ b/io/papermc/paper/redstone/RedstoneWireTurbo.java
@@ -0,0 +1,954 @@
@@ -0,0 +1,949 @@
+package io.papermc.paper.redstone;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
@@ -36,11 +38,7 @@ index 0000000000000000000000000000000000000000..ff747a1ecdf3c888bca0d69de4f85dcd
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.RedStoneWireBlock;
+import net.minecraft.world.level.block.state.BlockState;
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.event.block.BlockRedstoneEvent;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+
+public final class RedstoneWireTurbo {
+ /*
@@ -914,12 +912,9 @@ index 0000000000000000000000000000000000000000..ff747a1ecdf3c888bca0d69de4f85dcd
+ // always be in the range of 0 to 15, the following if will correct that.
+ if (k > j) j = k;
+
+ // egg82's amendment
+ // Adding Bukkit's BlockRedstoneEvent - er.. event.
+ // [egg82] Adding Bukkit's BlockRedstoneEvent.
+ if (i != j) {
+ BlockRedstoneEvent event = new BlockRedstoneEvent(CraftBlock.at(worldIn, upd.self), i, j);
+ worldIn.getCraftServer().getPluginManager().callEvent(event);
+ j = event.getNewCurrent();
+ j = CraftEventFactory.callRedstoneChange(worldIn, upd.self, i, j).getNewCurrent();
+ }
+
+ if (i != j) {
@@ -978,10 +973,10 @@ index 0000000000000000000000000000000000000000..ff747a1ecdf3c888bca0d69de4f85dcd
+ }
+}
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
index 0ee7bc3a10896a4f59fa94df158bce741aea0464..a677c3bfddfa0b7947394a3975ec43794be07d7e 100644
index 0ee7bc3a10896a4f59fa94df158bce741aea0464..a00002774755eb90a0b772fe742b30a5e09452cf 100644
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
@@ -269,6 +269,60 @@ public class RedStoneWireBlock extends Block {
@@ -269,6 +269,56 @@ public class RedStoneWireBlock extends Block {
return relativeState.isFaceSturdy(level, relativePos, Direction.UP) || relativeState.is(Blocks.HOPPER);
}
@@ -1021,12 +1016,8 @@ index 0ee7bc3a10896a4f59fa94df158bce741aea0464..a677c3bfddfa0b7947394a3975ec4379
+ int oldPower = state.getValue(POWER);
+ int newPower = ((DefaultRedstoneWireEvaluator) evaluator).calculateTargetStrength(level, pos);
+ if (oldPower != newPower) {
+ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), oldPower, newPower);
+ level.getCraftServer().getPluginManager().callEvent(event);
+
+ newPower = event.getNewCurrent();
+
+ if (level.getBlockState(pos) == state) {
+ newPower = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, oldPower, newPower).getNewCurrent();
+ state = state.setValue(POWER, newPower);
+ // [Space Walker] suppress shape updates and emit those manually to
+ // bypass the new neighbor update stack.
@@ -1042,7 +1033,7 @@ index 0ee7bc3a10896a4f59fa94df158bce741aea0464..a677c3bfddfa0b7947394a3975ec4379
private void updatePowerStrength(
final Level level,
final BlockPos pos,
@@ -303,7 +357,7 @@ public class RedStoneWireBlock extends Block {
@@ -303,7 +353,7 @@ public class RedStoneWireBlock extends Block {
@Override
protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) {
if (!oldState.is(state.getBlock()) && !level.isClientSide()) {
@@ -1051,7 +1042,7 @@ index 0ee7bc3a10896a4f59fa94df158bce741aea0464..a677c3bfddfa0b7947394a3975ec4379
for (Direction direction : Direction.Plane.VERTICAL) {
level.updateNeighborsAt(pos.relative(direction), this);
@@ -320,7 +374,7 @@ public class RedStoneWireBlock extends Block {
@@ -320,7 +370,7 @@ public class RedStoneWireBlock extends Block {
level.updateNeighborsAt(pos.relative(direction), this);
}
@@ -1060,7 +1051,7 @@ index 0ee7bc3a10896a4f59fa94df158bce741aea0464..a677c3bfddfa0b7947394a3975ec4379
this.updateNeighborsOfNeighboringWires(level, pos);
}
}
@@ -347,7 +401,7 @@ public class RedStoneWireBlock extends Block {
@@ -347,7 +397,7 @@ public class RedStoneWireBlock extends Block {
if (!level.isClientSide()) {
if (block != this || !useExperimentalEvaluator(level)) {
if (state.canSurvive(level, pos)) {
@@ -1070,10 +1061,10 @@ index 0ee7bc3a10896a4f59fa94df158bce741aea0464..a677c3bfddfa0b7947394a3975ec4379
dropResources(state, level, pos);
level.removeBlock(pos, false);
diff --git a/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java b/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
index fe52dd304bc03b172654b89acb382c7f410d7946..afdcbb9e5a4c859d82bfb33a1d253514c17eed39 100644
index 45c3586a653f4ec22b9fb859b2869503d0b6c5b3..81b7b625dbfe69f2a9d74dac000a0e60a75db839 100644
--- a/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
+++ b/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
@@ -47,7 +47,7 @@ public class DefaultRedstoneWireEvaluator extends RedstoneWireEvaluator {
@@ -44,7 +44,7 @@ public class DefaultRedstoneWireEvaluator extends RedstoneWireEvaluator {
}
}
@@ -22,30 +22,25 @@ Alternate Current's wire handler.
diff --git a/alternate/current/wire/LevelHelper.java b/alternate/current/wire/LevelHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff663d3089627e75221aa128aff4bf5cc459addb
index 0000000000000000000000000000000000000000..dd533953f33aacfc91a8acad6c9a9d601df0bd86
--- /dev/null
+++ b/alternate/current/wire/LevelHelper.java
@@ -0,0 +1,66 @@
@@ -0,0 +1,61 @@
+package alternate.current.wire;
+
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.event.block.BlockRedstoneEvent;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+import net.minecraft.world.level.chunk.LevelChunkSection;
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+
+class LevelHelper {
+
+ static int doRedstoneEvent(ServerLevel level, BlockPos pos, int prevPower, int newPower) {
+ BlockRedstoneEvent event = new BlockRedstoneEvent(CraftBlock.at(level, pos), prevPower, newPower);
+ level.getCraftServer().getPluginManager().callEvent(event);
+
+ return event.getNewCurrent();
+ return CraftEventFactory.callRedstoneChange(level, pos, prevPower, newPower).getNewCurrent();
+ }
+
+ /**
@@ -2326,18 +2321,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 f4bbccee849ee3711a3b838884e4bcf4e24da039..0b9fbf0ae658f0b3e9c6106a42fb70948b6fb9be 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
@@ -2775,6 +2776,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
return this.debugSynchronizers;
}
@@ -2352,10 +2347,10 @@ index 26c05173e7fb2bf055afda1717af0dd2e997118d..ffe3ae41dd3d8c4141f81edf0b92001d
return toLevel.dimension() != Level.NETHER || this.getGameRules().get(GameRules.ALLOW_ENTERING_NETHER_USING_PORTALS);
}
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 31c7223d2d01573c24d4ad83737fa2c2752db028..8df070a7135411806d42ea692b566c4d8389a47b 100644
index 07c301ba02c7f2c032a29a0ae3bdf95fc522c03b..7e4cf8a13e0ff2198cb7b6d80fb3fa343339943b 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -2152,6 +2152,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -2153,6 +2153,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
return this.palettedContainerFactory;
}
@@ -2374,7 +2369,7 @@ index 31c7223d2d01573c24d4ad83737fa2c2752db028..8df070a7135411806d42ea692b566c4d
NONE("none"),
BLOCK("block"),
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
index a677c3bfddfa0b7947394a3975ec43794be07d7e..ed471efa3ab705de62aec81c3940c1b9c5acdbc5 100644
index a00002774755eb90a0b772fe742b30a5e09452cf..1e863e97bd1dc99ed6e2c0602f78f457ac618965 100644
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
@@ -269,7 +269,7 @@ public class RedStoneWireBlock extends Block {
@@ -2386,7 +2381,7 @@ index a677c3bfddfa0b7947394a3975ec43794be07d7e..ed471efa3ab705de62aec81c3940c1b9
// The bulk of the new functionality is found in RedstoneWireTurbo.java
io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this);
@@ -357,7 +357,13 @@ public class RedStoneWireBlock extends Block {
@@ -353,7 +353,13 @@ public class RedStoneWireBlock extends Block {
@Override
protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) {
if (!oldState.is(state.getBlock()) && !level.isClientSide()) {
@@ -2401,7 +2396,7 @@ index a677c3bfddfa0b7947394a3975ec43794be07d7e..ed471efa3ab705de62aec81c3940c1b9
for (Direction direction : Direction.Plane.VERTICAL) {
level.updateNeighborsAt(pos.relative(direction), this);
@@ -374,7 +380,13 @@ public class RedStoneWireBlock extends Block {
@@ -370,7 +376,13 @@ public class RedStoneWireBlock extends Block {
level.updateNeighborsAt(pos.relative(direction), this);
}
@@ -2416,7 +2411,7 @@ index a677c3bfddfa0b7947394a3975ec43794be07d7e..ed471efa3ab705de62aec81c3940c1b9
this.updateNeighborsOfNeighboringWires(level, pos);
}
}
@@ -399,9 +411,15 @@ public class RedStoneWireBlock extends Block {
@@ -395,9 +407,15 @@ public class RedStoneWireBlock extends Block {
final BlockState state, final Level level, final BlockPos pos, final Block block, final @Nullable Orientation orientation, final boolean movedByPiston
) {
if (!level.isClientSide()) {
@@ -5,10 +5,10 @@ Subject: [PATCH] Incremental chunk and player saving
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 40a500011e7fcb6f5b07ff289f737ed9d3550296..da8c04aa02032c4c582709727f8f7f0b66b697b1 100644
index 248a01f06ec822737a741873166aa4e502a7ba07..c4eb56fc227afd7e9631624537dd8e67ae3a8bea 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -958,7 +958,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -968,7 +968,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
public boolean saveAllChunks(final boolean silent, final boolean flush, final boolean force, final boolean close) {
// Paper end - add close param
@@ -17,7 +17,7 @@ index 40a500011e7fcb6f5b07ff289f737ed9d3550296..da8c04aa02032c4c582709727f8f7f0b
boolean result = false;
for (ServerLevel level : this.getAllLevels()) {
@@ -970,13 +970,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -980,13 +980,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
result = true;
}
@@ -32,7 +32,7 @@ index 40a500011e7fcb6f5b07ff289f737ed9d3550296..da8c04aa02032c4c582709727f8f7f0b
if (flush) {
for (ServerLevel level : this.getAllLevels()) {
@@ -990,11 +984,25 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1000,11 +994,25 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return result;
}
@@ -59,7 +59,7 @@ index 40a500011e7fcb6f5b07ff289f737ed9d3550296..da8c04aa02032c4c582709727f8f7f0b
boolean result = this.saveAllChunks(silent, flush, force);
this.warnOnLowDiskSpace();
var5 = result;
@@ -1641,9 +1649,31 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1651,9 +1659,31 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
this.ticksUntilAutosave--;
@@ -94,10 +94,10 @@ index 40a500011e7fcb6f5b07ff289f737ed9d3550296..da8c04aa02032c4c582709727f8f7f0b
ProfilerFiller profiler = Profiler.get();
this.server.spark.executeMainThreadTasks(); // Paper - spark
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index ffe3ae41dd3d8c4141f81edf0b92001db957ebac..98461e8468a7eeaef2544ee907ff64de1fd42a49 100644
index 0b9fbf0ae658f0b3e9c6106a42fb70948b6fb9be..bbeb0f673f2b23d1748e33364dc12ac16528d4c4 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1441,6 +1441,15 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
@@ -1451,6 +1451,15 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
public boolean mayInteract(final Entity entity, final BlockPos pos) {
return !(entity instanceof Player player && (this.server.isUnderSpawnProtection(this, pos, player) || !this.getWorldBorder().isWithinBounds(pos)));
}
@@ -126,7 +126,7 @@ index 41816ca8d4ef3d959d2b88cd4b2eedaaa541e612..82e87270d1ad89ad7aa56e028ced6b99
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
private static final int FLY_STAT_RECORDING_SPEED = 25;
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 0613b053f4a75c0884280011ee092d9d108b3857..b69bcaa1e27a4fbe9a9568f3c9e1843167abe1f5 100644
index 02605ebe6ef10727badadbf7fc4cec52583df965..3d62e4d275f32c8604a1bdaefb6b9b1d4ea6e21f 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -418,6 +418,7 @@ public abstract class PlayerList {
@@ -137,7 +137,7 @@ index 0613b053f4a75c0884280011ee092d9d108b3857..b69bcaa1e27a4fbe9a9568f3c9e18431
this.playerIo.save(player);
ServerStatsCounter stats = player.getStats(); // CraftBukkit
if (stats != null) {
@@ -951,10 +952,24 @@ public abstract class PlayerList {
@@ -950,10 +951,24 @@ public abstract class PlayerList {
}
public void saveAll() {
@@ -6,10 +6,10 @@ 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/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 0b86c393b041607278c1b712a62ec9ae3640f4de..80162ffef5d54d00663dcb58a087884ec8a3eaaa 100644
index fad017de5d9fc31988aa4edf97fb3f9bcbee56c8..06132bde0aed9dd9088c884ee31056b9176b6f90 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -634,6 +634,7 @@ public class ServerGamePacketListenerImpl
@@ -633,6 +633,7 @@ public class ServerGamePacketListenerImpl
}
vehicle.move(MoverType.PLAYER, new Vec3(xDist, yDist, zDist));
@@ -17,7 +17,7 @@ index 0b86c393b041607278c1b712a62ec9ae3640f4de..80162ffef5d54d00663dcb58a087884e
double oyDist = yDist;
xDist = targetX - vehicle.getX();
yDist = targetY - vehicle.getY();
@@ -649,7 +650,17 @@ public class ServerGamePacketListenerImpl
@@ -648,7 +649,17 @@ public class ServerGamePacketListenerImpl
LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", vehicle.getPlainTextName(), this.player.getPlainTextName(), Math.sqrt(movedDist));
}
@@ -36,7 +36,7 @@ index 0b86c393b041607278c1b712a62ec9ae3640f4de..80162ffef5d54d00663dcb58a087884e
vehicle.absSnapTo(oldX, oldY, oldZ, targetYRot, targetXRot);
this.send(ClientboundMoveVehiclePacket.fromEntity(vehicle));
vehicle.removeLatestMovementRecording();
@@ -728,9 +739,32 @@ public class ServerGamePacketListenerImpl
@@ -727,9 +738,32 @@ public class ServerGamePacketListenerImpl
}
private boolean noBlocksAround(final Entity entity) {
@@ -72,7 +72,7 @@ index 0b86c393b041607278c1b712a62ec9ae3640f4de..80162ffef5d54d00663dcb58a087884e
}
@Override
@@ -1542,7 +1576,7 @@ public class ServerGamePacketListenerImpl
@@ -1541,7 +1575,7 @@ public class ServerGamePacketListenerImpl
}
}
@@ -81,7 +81,7 @@ index 0b86c393b041607278c1b712a62ec9ae3640f4de..80162ffef5d54d00663dcb58a087884e
xDist = targetX - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
yDist = targetY - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
zDist = targetZ - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
@@ -1581,6 +1615,7 @@ public class ServerGamePacketListenerImpl
@@ -1580,6 +1614,7 @@ public class ServerGamePacketListenerImpl
boolean playerStandsOnSomething = this.player.verticalCollisionBelow;
this.player.move(MoverType.PLAYER, new Vec3(xDist, yDist, zDist));
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
@@ -89,7 +89,7 @@ index 0b86c393b041607278c1b712a62ec9ae3640f4de..80162ffef5d54d00663dcb58a087884e
// Paper start - prevent position desync
if (this.awaitingPositionFromClient != null) {
return; // ... thanks Mojang for letting move calls teleport across dimensions.
@@ -1614,7 +1649,17 @@ public class ServerGamePacketListenerImpl
@@ -1613,7 +1648,17 @@ public class ServerGamePacketListenerImpl
}
// Paper start - Add fail move event
@@ -108,7 +108,7 @@ index 0b86c393b041607278c1b712a62ec9ae3640f4de..80162ffef5d54d00663dcb58a087884e
if (!allowMovement) {
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
targetX, targetY, targetZ, targetYRot, targetXRot, false);
@@ -1752,7 +1797,7 @@ public class ServerGamePacketListenerImpl
@@ -1751,7 +1796,7 @@ public class ServerGamePacketListenerImpl
private boolean updateAwaitingTeleport() {
if (this.awaitingPositionFromClient != null) {
@@ -117,7 +117,7 @@ index 0b86c393b041607278c1b712a62ec9ae3640f4de..80162ffef5d54d00663dcb58a087884e
this.awaitingTeleportTime = this.tickCount;
this.teleport(
this.awaitingPositionFromClient.x,
@@ -1771,6 +1816,34 @@ public class ServerGamePacketListenerImpl
@@ -1770,6 +1815,34 @@ public class ServerGamePacketListenerImpl
}
}
@@ -117,7 +117,7 @@ index d87a00ee3cd04ce25dbe46ae6b386b7f0799102c..ace440c2b82a6368aa27a85ff433ba2c
}
}
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
index 079ab378920c0e52ef4e42ef20b37bd389f40870..dc9020f210c21a626c948d013cc6c972cbc093f3 100644
index abeca4714053fd0a4fa489d496e2e0b844de40a8..7ed50fc00c58c7781c958df1d828a67adf696f3e 100644
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -39,12 +39,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -138,7 +138,7 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..dc9020f210c21a626c948d013cc6c972
private volatile boolean suspendFlushingOnServerThread = false;
// CraftBukkit start
public final org.bukkit.craftbukkit.CraftServer cserver;
@@ -61,13 +62,14 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -60,13 +61,14 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
public ServerCommonPacketListenerImpl(final MinecraftServer server, final Connection connection, final CommonListenerCookie cookie) {
this.server = server;
this.connection = connection;
@@ -154,7 +154,7 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..dc9020f210c21a626c948d013cc6c972
// Paper end
}
@@ -100,13 +102,41 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -99,13 +101,35 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@Override
public void handleKeepAlive(final ServerboundKeepAlivePacket packet) {
@@ -184,25 +184,19 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..dc9020f210c21a626c948d013cc6c972
+ if (ka.challengeId() == packet.getId()) {
+ itr.remove();
+
+ if (!this.processedDisconnect) {
+ LOGGER.info("Disconnecting {} for sending keepalive response ({}) out-of-order!", this.playerProfile().name(), packet.getId());
+ this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT);
+ return;
+ }
+ break;
+ LOGGER.info("Disconnecting {} for sending keepalive response ({}) out-of-order!", this.playerProfile().name(), packet.getId());
+ this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT);
+ return;
+ }
}
+
+ if (!this.processedDisconnect) {
+ LOGGER.info("Disconnecting {} for sending keepalive response ({}) without matching challenge!", this.playerProfile().name(), packet.getId());
+ this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT);
+ return;
+ }
+ LOGGER.info("Disconnecting {} for sending keepalive response ({}) without matching challenge!", this.playerProfile().name(), packet.getId());
+ this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT);
+ // Paper end - improve keepalives
}
@Override
@@ -233,20 +263,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -232,20 +256,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
protected void keepConnectionAlive() {
Profiler.get().push("keepAlive");
long now = Util.getMillis();
@@ -221,7 +215,7 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..dc9020f210c21a626c948d013cc6c972
- this.keepAliveChallenge = now;
- this.send(new ClientboundKeepAlivePacket(this.keepAliveChallenge));
+ // Paper start - improve keepalives
+ if (this.checkIfClosed(now) && !this.processedDisconnect) {
+ if (this.checkIfClosed(now)) {
+ long currTime = System.nanoTime();
+
+ if ((currTime - this.keepAlive.lastKeepAliveTx) >= java.util.concurrent.TimeUnit.SECONDS.toNanos(1L)) {
@@ -240,11 +234,12 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..dc9020f210c21a626c948d013cc6c972
}
}
@@ -424,6 +457,14 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@@ -420,6 +447,16 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
}
protected CommonListenerCookie createCookie(final ClientInformation clientInformation) {
- return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred, this.playerBrand, this.pluginMessagerChannels); // Paper
+ // Paper start - listener handoff should reset pending keepalive expectations
+ return new CommonListenerCookie(
+ this.playerProfile(),
+ this.latency,
@@ -253,6 +248,7 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..dc9020f210c21a626c948d013cc6c972
+ this.playerBrand,
+ this.pluginMessagerChannels,
+ this.keepAlive.copyForListenerHandoff()
+ ); // Paper - listener handoff should reset pending keepalive expectations
+ );
+ // Paper end - listener handoff should reset pending keepalive expectations
}
}
@@ -20,10 +20,10 @@ index 2bc436cdf5180a7943c45fabb9fbbedae6f7db56..f312a7f5b1b2a777ab36b94ce7cbf387
@Override
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index da8c04aa02032c4c582709727f8f7f0b66b697b1..3923f21c67165e2ecd2c9cecd5266758435a6806 100644
index 8c4b40362f77cdea6e57315a6639006ac7ab27c7..a5217deb236ee922d020a7a6a03141a5f67acd77 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1784,32 +1784,22 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1794,32 +1794,22 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
@@ -42,10 +42,10 @@ index d2877c20f389d0131e1dd208b464f590671e5d82..27bdc70d861ca39487ad16cb3afb89d6
updateComponent(root, "minecraft:trim", hiddenComponents);
updateComponent(root, "minecraft:unbreakable", hiddenComponents);
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index ae140a514e1e3200f52c5933f886cc9e820b818a..4a1146cc54bd9272466ffc9bb64f600c40f0c0f4 100644
index 06132bde0aed9dd9088c884ee31056b9176b6f90..08374da2d9b84e8ff13c670d7f45867fb0bdd897 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1820,9 +1820,14 @@ public class ServerGamePacketListenerImpl
@@ -1819,9 +1819,14 @@ public class ServerGamePacketListenerImpl
private boolean hasNewCollision(final ServerLevel level, 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<>();
@@ -62,10 +62,10 @@ index ae140a514e1e3200f52c5933f886cc9e820b818a..4a1146cc54bd9272466ffc9bb64f600c
);
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 8df070a7135411806d42ea692b566c4d8389a47b..06451a21c4bfbcd95063f96246013d63f65af8a3 100644
index fa3809be5c0488c5a1d2639579d68619b0a55de9..c332d48f5cac2f3be93201c66f4f7cdba916cbac 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -1528,7 +1528,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -1529,7 +1529,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups)
return false;
// Paper start - optimise collisions
@@ -48,10 +48,10 @@ index 0000000000000000000000000000000000000000..24a2090e068ad3c0d08705050944abdf
+ }
+}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 3923f21c67165e2ecd2c9cecd5266758435a6806..92acd256fdf815dfb8dd743cf8ecd0eb377d996e 100644
index af1f5e83bd24e671399af2a9aadc8e11959ec5f4..b9efed1df74651c894a416f1d3db320d4ab20401 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1836,6 +1836,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1850,6 +1850,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
level.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
level.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
level.updateLagCompensationTick(); // Paper - lag compensation
@@ -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 {
@@ -209,7 +209,7 @@ index b69bcaa1e27a4fbe9a9568f3c9e1843167abe1f5..9218322801c41657c00928ef90b0de99
}
// Paper end - Send empty chunk
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 06451a21c4bfbcd95063f96246013d63f65af8a3..e34e901dce06c6bc6060418593010dcfb38e9396 100644
index 829bb616e5d72b955248bbc150254c239176ce64..4b228b5c563e40b6f301df22b5c8a7f7988cb072 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -145,6 +145,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -230,7 +230,7 @@ index 06451a21c4bfbcd95063f96246013d63f65af8a3..e34e901dce06c6bc6060418593010dcf
) {
// Paper start - getblock optimisations - cache world height/sections
final DimensionType dimType = dimensionTypeRegistration.value();
@@ -870,6 +872,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -871,6 +873,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
this.palettedContainerFactory = PalettedContainerFactory.create(registryAccess);
this.damageSources = new DamageSources(registryAccess);
this.entityLookup = new ca.spottedleaf.moonrise.patches.chunk_system.level.entity.dfl.DefaultEntityLookup(this); // Paper - rewrite chunk system
@@ -238,7 +238,7 @@ index 06451a21c4bfbcd95063f96246013d63f65af8a3..e34e901dce06c6bc6060418593010dcf
}
// Paper start - Cancel hit for vanished players
@@ -1084,6 +1087,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -1085,6 +1088,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
}
// CraftBukkit end - capture blockstates
BlockState oldState = chunk.setBlockState(pos, blockState, updateFlags);
@@ -46,7 +46,7 @@ index 81a293cc13653a9a0336cb25d75273969fee4d16..8ebcce4c4971a11d367fb39e9c7fd280
protected void onOpen(final Level level, final BlockPos pos, final BlockState blockState) {
if (blockState.getBlock() instanceof ChestBlock chestBlock) {
diff --git a/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java b/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
index 9af046cbe2c5024040057118a0e9ecd539815781..aa8b384b05738139fa3492b3c09084cda09448ce 100644
index baa8b5aba0500981a191626553d66650c7304b88..52737172ccfa0c7c977e4f2fe1db242e0bb92d25 100644
--- a/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
+++ b/net/minecraft/world/level/block/entity/ContainerOpenersCounter.java
@@ -37,11 +37,23 @@ public abstract class ContainerOpenersCounter {
@@ -70,9 +70,9 @@ index 9af046cbe2c5024040057118a0e9ecd539815781..aa8b384b05738139fa3492b3c09084cd
+ return;
+ }
+ // Paper end - delay open/close callbacks
int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added
int previous = this.openCount++;
// Paper start - Call BlockRedstoneEvent
@@ -66,6 +78,12 @@ public abstract class ContainerOpenersCounter {
}
@@ -83,9 +83,9 @@ index 9af046cbe2c5024040057118a0e9ecd539815781..aa8b384b05738139fa3492b3c09084cd
+ return;
+ }
+ // Paper end - delay open/close callbacks
int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added
if (this.openCount == 0) return; // Paper - Prevent ContainerOpenersCounter openCount from going negative
int previous = this.openCount--;
@@ -151,6 +169,11 @@ public abstract class ContainerOpenersCounter {
}
@@ -8,13 +8,14 @@ and shapeless recipes.
diff --git a/io/papermc/paper/inventory/recipe/ItemOrExact.java b/io/papermc/paper/inventory/recipe/ItemOrExact.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce745e49cd54fe3ae187785563a1bd311d14b5b2
index 0000000000000000000000000000000000000000..9e621873454cc2edc2e59e6c7554d8116cd32bc1
--- /dev/null
+++ b/io/papermc/paper/inventory/recipe/ItemOrExact.java
@@ -0,0 +1,63 @@
@@ -0,0 +1,64 @@
+package io.papermc.paper.inventory.recipe;
+
+import net.minecraft.core.Holder;
+import net.minecraft.core.component.DataComponents;
+import net.minecraft.world.item.ItemStack;
+
+public sealed interface ItemOrExact permits ItemOrExact.Item, ItemOrExact.Exact {
@@ -26,12 +27,12 @@ index 0000000000000000000000000000000000000000..ce745e49cd54fe3ae187785563a1bd31
+ record Item(Holder<net.minecraft.world.item.Item> item) implements ItemOrExact {
+
+ public Item(final ItemStack stack) {
+ this(stack.getItemHolder());
+ this(stack.typeHolder());
+ }
+
+ @Override
+ public int getMaxStackSize() {
+ return this.item.value().getDefaultMaxStackSize();
+ return this.item.components().getOrDefault(DataComponents.MAX_STACK_SIZE, 1);
+ }
+
+ @Override
@@ -150,119 +151,119 @@ index 0000000000000000000000000000000000000000..f47c12e9dd6cfa857ca07a764edc22de
+ }
+}
diff --git a/net/minecraft/recipebook/ServerPlaceRecipe.java b/net/minecraft/recipebook/ServerPlaceRecipe.java
index 6d3e3ec045d5b15a435f7217369968b33e082724..b7a3758af337270737041f84d10eb43784e42279 100644
index 31f8aa58b48aeb64e57480490a449b6c46913880..b7ee9fe694ea37eeb58b5dded7967e7d0f338d0d 100644
--- a/net/minecraft/recipebook/ServerPlaceRecipe.java
+++ b/net/minecraft/recipebook/ServerPlaceRecipe.java
@@ -40,6 +40,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
@@ -41,6 +41,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
return RecipeBookMenu.PostPlaceAction.NOTHING;
} else {
StackedItemContents stackedItemContents = new StackedItemContents();
+ stackedItemContents.initializeExtras(recipe.value(), null); // Paper - Improve exact choice recipe ingredients
inventory.fillStackedContents(stackedItemContents);
menu.fillCraftSlotsStackedContents(stackedItemContents);
return serverPlaceRecipe.tryPlaceRecipe(recipe, stackedItemContents);
@@ -99,7 +100,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
StackedItemContents availableItems = new StackedItemContents();
+ availableItems.initializeExtras(recipe.value(), null); // Paper - Improve exact choice recipe ingredients
inventory.fillStackedContents(availableItems);
menu.fillCraftSlotsStackedContents(availableItems);
return placer.tryPlaceRecipe(recipe, availableItems);
@@ -100,7 +101,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
}
int i = this.calculateAmountToCraft(biggestCraftableStack, flag);
- List<Holder<Item>> list = new ArrayList<>();
+ List<io.papermc.paper.inventory.recipe.ItemOrExact> list = new ArrayList<>(); // Paper - Improve exact choice recipe ingredients
if (stackedItemContents.canCraft(recipe.value(), i, list::add)) {
int i1 = clampToMaxStackSize(i, list);
if (i1 != i) {
@@ -114,7 +115,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
this.gridWidth, this.gridHeight, recipe.value(), recipe.value().placementInfo().slotsToIngredientIndex(), (item1, slot1, x, y) -> {
if (item1 != -1) {
Slot slot2 = this.inputGridSlots.get(slot1);
- Holder<Item> holder = list.get(item1);
+ io.papermc.paper.inventory.recipe.ItemOrExact holder = list.get(item1); // Paper - Improve exact choice recipe ingredients
int i2 = i1;
int amountToCraft = this.calculateAmountToCraft(biggestCraftableStack, recipeMatchesPlaced);
- List<Holder<Item>> itemsUsedPerIngredient = new ArrayList<>();
+ List<io.papermc.paper.inventory.recipe.ItemOrExact> itemsUsedPerIngredient = new ArrayList<>(); // Paper - Improve exact choice recipe ingredients
if (availableItems.canCraft(recipe.value(), amountToCraft, itemsUsedPerIngredient::add)) {
int adjustedAmountToCraft = clampToMaxStackSize(amountToCraft, itemsUsedPerIngredient);
if (adjustedAmountToCraft != amountToCraft) {
@@ -119,7 +120,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
(ingredientIndex, gridIndex, gridXPos, gridYPos) -> {
if (ingredientIndex != -1) {
Slot targetGridSlot = this.inputGridSlots.get(gridIndex);
- Holder<Item> itemUsed = itemsUsedPerIngredient.get(ingredientIndex);
+ io.papermc.paper.inventory.recipe.ItemOrExact itemUsed = itemsUsedPerIngredient.get(ingredientIndex); // Paper - Improve exact choice recipe ingredients
int remainingCount = adjustedAmountToCraft;
while (i2 > 0) {
@@ -129,9 +130,11 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
while (remainingCount > 0) {
@@ -134,9 +135,11 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
}
}
- private static int clampToMaxStackSize(int amount, List<Holder<Item>> items) {
- for (Holder<Item> holder : items) {
- amount = Math.min(amount, holder.value().getDefaultMaxStackSize());
- private static int clampToMaxStackSize(int value, final List<Holder<Item>> items) {
- for (Holder<Item> item : items) {
- value = Math.min(value, item.components().getOrDefault(DataComponents.MAX_STACK_SIZE, 1));
+ // Paper start - Improve exact choice recipe ingredients
+ private static int clampToMaxStackSize(int amount, List<io.papermc.paper.inventory.recipe.ItemOrExact> items) {
+ for (io.papermc.paper.inventory.recipe.ItemOrExact holder : items) {
+ amount = Math.min(amount, holder.getMaxStackSize());
+ private static int clampToMaxStackSize(int value, final List<io.papermc.paper.inventory.recipe.ItemOrExact> items) {
+ for (io.papermc.paper.inventory.recipe.ItemOrExact item : items) {
+ value = Math.min(value, item.getMaxStackSize());
+ // Paper end - Improve exact choice recipe ingredients
}
return amount;
@@ -160,7 +163,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
return value;
@@ -165,7 +168,7 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
}
}
- private int moveItemToGrid(Slot slot, Holder<Item> item, int count) {
+ private int moveItemToGrid(Slot slot, io.papermc.paper.inventory.recipe.ItemOrExact item, int count) { // Paper - Improve exact choice recipe ingredients
ItemStack item1 = slot.getItem();
int i = this.inventory.findSlotMatchingCraftingIngredient(item, item1);
if (i == -1) {
- private int moveItemToGrid(final Slot targetSlot, final Holder<Item> itemInInventory, final int count) {
+ private int moveItemToGrid(final Slot targetSlot, final io.papermc.paper.inventory.recipe.ItemOrExact itemInInventory, final int count) { // Paper - Improve exact choice recipe ingredients
ItemStack itemInTargetSlot = targetSlot.getItem();
int inventorySlotId = this.inventory.findSlotMatchingCraftingIngredient(itemInInventory, itemInTargetSlot);
if (inventorySlotId == Inventory.NOT_FOUND_INDEX) {
diff --git a/net/minecraft/world/entity/player/Inventory.java b/net/minecraft/world/entity/player/Inventory.java
index 76eda3bd8c513c7e42ceedf1aa605fb6df8b7019..41e59f3739945ca7f6ab710c993b5c0f15fcd529 100644
index da8bab81e135a9b240fbeac0e9e1d2aa12c6212d..f004911c438e6f89d6e079437e3f4104d6cbacbd 100644
--- a/net/minecraft/world/entity/player/Inventory.java
+++ b/net/minecraft/world/entity/player/Inventory.java
@@ -252,12 +252,12 @@ public class Inventory implements Container, Nameable {
return !stack.isDamaged() && !stack.isEnchanted() && !stack.has(DataComponents.CUSTOM_NAME);
return !item.isDamaged() && !item.isEnchanted() && !item.has(DataComponents.CUSTOM_NAME);
}
- public int findSlotMatchingCraftingIngredient(Holder<Item> item, ItemStack stack) {
+ public int findSlotMatchingCraftingIngredient(io.papermc.paper.inventory.recipe.ItemOrExact item, ItemStack stack) { // Paper - Improve exact choice recipe ingredients
- public int findSlotMatchingCraftingIngredient(final Holder<Item> item, final ItemStack existingItem) {
+ public int findSlotMatchingCraftingIngredient(final io.papermc.paper.inventory.recipe.ItemOrExact item, final ItemStack existingItem) { // Paper - Improve exact choice recipe ingredients
for (int i = 0; i < this.items.size(); i++) {
ItemStack itemStack = this.items.get(i);
if (!itemStack.isEmpty()
- && itemStack.is(item)
- && isUsableForCrafting(itemStack)
+ && item.matches(itemStack) // Paper - Improve exact choice recipe ingredients
+ && (!(item instanceof io.papermc.paper.inventory.recipe.ItemOrExact.Item) || Inventory.isUsableForCrafting(itemStack)) // Paper - Improve exact choice recipe ingredients
&& (stack.isEmpty() || ItemStack.isSameItemSameComponents(stack, itemStack))) {
ItemStack inventoryItemStack = this.items.get(i);
if (!inventoryItemStack.isEmpty()
- && inventoryItemStack.is(item)
- && isUsableForCrafting(inventoryItemStack)
+ && item.matches(inventoryItemStack) // Paper - Improve exact choice recipe ingredients
+ && (!(item instanceof io.papermc.paper.inventory.recipe.ItemOrExact.Item) || Inventory.isUsableForCrafting(inventoryItemStack)) // Paper - Improve exact choice recipe ingredients
&& (existingItem.isEmpty() || ItemStack.isSameItemSameComponents(existingItem, inventoryItemStack))) {
return i;
}
diff --git a/net/minecraft/world/entity/player/StackedContents.java b/net/minecraft/world/entity/player/StackedContents.java
index bc4f7d16365dffc87b1eef8aa5791a5cb595ee78..cbb37480c19b210cf83999247c1d670c9df2d150 100644
index 889b8e6c3762203deccf657b505f6f29cc893526..6710653d033a48c4b3fc267496f93a2548b5c966 100644
--- a/net/minecraft/world/entity/player/StackedContents.java
+++ b/net/minecraft/world/entity/player/StackedContents.java
@@ -13,7 +13,7 @@ import java.util.List;
@@ -14,7 +14,7 @@ import java.util.Objects;
import org.jspecify.annotations.Nullable;
public class StackedContents<T> {
- public final Reference2IntOpenHashMap<T> amounts = new Reference2IntOpenHashMap<>();
+ public final it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap<T> amounts = new it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap<>(); // Paper - Improve exact choice recipe ingredients (don't use "reference" map)
boolean hasAtLeast(T item, int amount) {
return this.amounts.getInt(item) >= amount;
@@ -49,7 +49,7 @@ public class StackedContents<T> {
List<T> getUniqueAvailableIngredientItems(Iterable<? extends StackedContents.IngredientInfo<T>> ingredients) {
List<T> list = new ArrayList<>();
private boolean hasAtLeast(final T item, final int count) {
return this.amounts.getInt(item) >= count;
@@ -54,7 +54,7 @@ public class StackedContents<T> {
private List<T> getUniqueAvailableIngredientItems(final Iterable<? extends StackedContents.IngredientInfo<T>> ingredients) {
List<T> result = new ArrayList<>();
- for (Entry<T> entry : Reference2IntMaps.fastIterable(this.amounts)) {
+ for (it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<T> entry : it.unimi.dsi.fastutil.objects.Object2IntMaps.fastIterable(this.amounts)) { // Paper - Improve exact choice recipe ingredients (don't use "reference" map)
if (entry.getIntValue() > 0 && anyIngredientMatches(ingredients, entry.getKey())) {
list.add(entry.getKey());
- for (Entry<T> availableItem : Reference2IntMaps.fastIterable(this.amounts)) {
+ for (it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<T> availableItem : it.unimi.dsi.fastutil.objects.Object2IntMaps.fastIterable(this.amounts)) { // Paper - Improve exact choice recipe ingredients (don't use "reference" map)
if (availableItem.getIntValue() > 0 && anyIngredientMatches(ingredients, availableItem.getKey())) {
result.add(availableItem.getKey());
}
@@ -71,13 +71,13 @@ public class StackedContents<T> {
@@ -76,13 +76,13 @@ public class StackedContents<T> {
@VisibleForTesting
public int getResultUpperBound(List<? extends StackedContents.IngredientInfo<T>> ingredients) {
int i = Integer.MAX_VALUE;
- ObjectIterable<Entry<T>> objectIterable = Reference2IntMaps.fastIterable(this.amounts);
+ ObjectIterable<it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<T>> objectIterable = it.unimi.dsi.fastutil.objects.Object2IntMaps.fastIterable(this.amounts); // Paper - Improve exact choice recipe ingredients (don't use "reference" map)
public int getResultUpperBound(final List<? extends StackedContents.IngredientInfo<T>> ingredients) {
int min = Integer.MAX_VALUE;
- ObjectIterable<Entry<T>> availableItems = Reference2IntMaps.fastIterable(this.amounts);
+ ObjectIterable<it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<T>> availableItems = it.unimi.dsi.fastutil.objects.Object2IntMaps.fastIterable(this.amounts); // Paper - Improve exact choice recipe ingredients (don't use "reference" map)
label31:
for (StackedContents.IngredientInfo<T> ingredientInfo : ingredients) {
int i1 = 0;
for (StackedContents.IngredientInfo<T> ingredient : ingredients) {
int max = 0;
- for (Entry<T> entry : objectIterable) {
+ for (it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<T> entry : objectIterable) { // Paper - Improve exact choice recipe ingredients (don't use "reference" map)
int intValue = entry.getIntValue();
if (intValue > i1) {
if (ingredientInfo.acceptsItem(entry.getKey())) {
- for (Entry<T> entry : availableItems) {
+ for (it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<T> entry : availableItems) { // Paper - Improve exact choice recipe ingredients (don't use "reference" map)
int itemCount = entry.getIntValue();
if (itemCount > max) {
if (ingredient.acceptsItem(entry.getKey())) {
diff --git a/net/minecraft/world/entity/player/StackedItemContents.java b/net/minecraft/world/entity/player/StackedItemContents.java
index e0121e9c8439e32b7ef064c06942ccd5dd74987d..00dbc0d125b2c8c208ffa46f9084c6317efaba90 100644
index ffaa8e450a11a01060b6847d1b66a76323f9d8ba..1ace17d8fc7e7b8b4722a1889d49233c0ec55e20 100644
--- a/net/minecraft/world/entity/player/StackedItemContents.java
+++ b/net/minecraft/world/entity/player/StackedItemContents.java
@@ -9,9 +9,27 @@ import net.minecraft.world.item.crafting.Recipe;
@@ -289,115 +290,119 @@ index e0121e9c8439e32b7ef064c06942ccd5dd74987d..00dbc0d125b2c8c208ffa46f9084c631
+ }
+ // Paper end - Improve exact choice recipe ingredients
public void accountSimpleStack(ItemStack stack) {
+ if (this.extrasMap != null && this.extrasMap.accountStack(stack, Math.min(64, stack.getCount()))) return; // Paper - Improve exact choice recipe ingredients; max of 64 due to accountStack method below
if (Inventory.isUsableForCrafting(stack)) {
this.accountStack(stack);
public void accountSimpleStack(final ItemStack itemStack) {
+ if (this.extrasMap != null && this.extrasMap.accountStack(itemStack, Math.min(itemStack.getMaxStackSize(), itemStack.getCount()))) return; // Paper - Improve exact choice recipe ingredients; Referenced from the accountStack method below
if (Inventory.isUsableForCrafting(itemStack)) {
this.accountStack(itemStack);
}
@@ -24,34 +42,35 @@ public class StackedItemContents {
public void accountStack(ItemStack stack, int maxStackSize) {
if (!stack.isEmpty()) {
int min = Math.min(maxStackSize, stack.getCount());
- this.raw.account(stack.getItemHolder(), min);
+ if (this.extrasMap != null && !stack.getComponentsPatch().isEmpty() && this.extrasMap.accountStack(stack, min)) return; // Paper - Improve exact choice recipe ingredients; if an exact ingredient, don't include it
+ this.raw.account(new io.papermc.paper.inventory.recipe.ItemOrExact.Item(stack.getItemHolder()), min);
@@ -24,38 +42,39 @@ public class StackedItemContents {
public void accountStack(final ItemStack itemStack, final int maxCount) {
if (!itemStack.isEmpty()) {
int count = Math.min(maxCount, itemStack.getCount());
- this.raw.account(itemStack.typeHolder(), count);
+ if (this.extrasMap != null && !itemStack.getComponentsPatch().isEmpty() && this.extrasMap.accountStack(itemStack, count)) return; // Paper - Improve exact choice recipe ingredients; if an exact ingredient, don't include it
+ this.raw.account(new io.papermc.paper.inventory.recipe.ItemOrExact.Item(itemStack.typeHolder()), count);
}
}
- public boolean canCraft(Recipe<?> recipe, StackedContents.@Nullable Output<Holder<Item>> output) {
+ public boolean canCraft(Recipe<?> recipe, StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
- public boolean canCraft(final Recipe<?> recipe, final StackedContents.@Nullable Output<Holder<Item>> output) {
+ public boolean canCraft(final Recipe<?> recipe, final StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
return this.canCraft(recipe, 1, output);
}
- public boolean canCraft(Recipe<?> recipe, int maxCount, StackedContents.@Nullable Output<Holder<Item>> output) {
+ public boolean canCraft(Recipe<?> recipe, int maxCount, StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
- public boolean canCraft(final Recipe<?> recipe, final int amount, final StackedContents.@Nullable Output<Holder<Item>> output) {
+ public boolean canCraft(final Recipe<?> recipe, final int amount, final StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
PlacementInfo placementInfo = recipe.placementInfo();
return !placementInfo.isImpossibleToPlace() && this.canCraft(placementInfo.ingredients(), maxCount, output);
return !placementInfo.isImpossibleToPlace() && this.canCraft(placementInfo.ingredients(), amount, output);
}
- public boolean canCraft(List<? extends StackedContents.IngredientInfo<Holder<Item>>> ingredients, StackedContents.@Nullable Output<Holder<Item>> output) {
+ public boolean canCraft(List<? extends StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact>> ingredients, StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
return this.canCraft(ingredients, 1, output);
public boolean canCraft(
- final List<? extends StackedContents.IngredientInfo<Holder<Item>>> contents, final StackedContents.@Nullable Output<Holder<Item>> output
+ final List<? extends StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact>> contents, final StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output // Paper - Improve exact choice recipe ingredients
) {
return this.canCraft(contents, 1, output);
}
private boolean canCraft(
- List<? extends StackedContents.IngredientInfo<Holder<Item>>> ingredients, int maxCount, StackedContents.@Nullable Output<Holder<Item>> output
+ List<? extends StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact>> ingredients, int maxCount, StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output // Paper - Improve exact choice recipe ingredients
- final List<? extends StackedContents.IngredientInfo<Holder<Item>>> contents,
+ final List<? extends StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact>> contents, // Paper - Improve exact choice recipe ingredients
final int amount,
- final StackedContents.@Nullable Output<Holder<Item>> output
+ final StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output // Paper - Improve exact choice recipe ingredients
) {
return this.raw.tryPick(ingredients, maxCount, output);
return this.raw.tryPick(contents, amount, output);
}
- public int getBiggestCraftableStack(Recipe<?> recipe, StackedContents.@Nullable Output<Holder<Item>> output) {
+ public int getBiggestCraftableStack(Recipe<?> recipe, StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
- public int getBiggestCraftableStack(final Recipe<?> recipe, final StackedContents.@Nullable Output<Holder<Item>> output) {
+ public int getBiggestCraftableStack(final Recipe<?> recipe, final StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
return this.getBiggestCraftableStack(recipe, Integer.MAX_VALUE, output);
}
- public int getBiggestCraftableStack(Recipe<?> recipe, int maxCount, StackedContents.@Nullable Output<Holder<Item>> output) {
+ public int getBiggestCraftableStack(Recipe<?> recipe, int maxCount, StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
return this.raw.tryPickAll(recipe.placementInfo().ingredients(), maxCount, output);
- public int getBiggestCraftableStack(final Recipe<?> recipe, final int maxSize, final StackedContents.@Nullable Output<Holder<Item>> output) {
+ public int getBiggestCraftableStack(final Recipe<?> recipe, final int maxSize, final StackedContents.@Nullable Output<io.papermc.paper.inventory.recipe.ItemOrExact> output) { // Paper - Improve exact choice recipe ingredients
return this.raw.tryPickAll(recipe.placementInfo().ingredients(), maxSize, output);
}
diff --git a/net/minecraft/world/item/crafting/Ingredient.java b/net/minecraft/world/item/crafting/Ingredient.java
index ac4520afe510df9b1dd256d13dcb0768c83edb70..da95f40503f3696c8daa8fd0e947508fe43060ba 100644
index 3a8a07712a15167dabd12d4bfd258de11706ce93..1deeb3fd148c5d59250346147681b7e8f2147574 100644
--- a/net/minecraft/world/item/crafting/Ingredient.java
+++ b/net/minecraft/world/item/crafting/Ingredient.java
@@ -21,7 +21,7 @@ import net.minecraft.world.item.Items;
@@ -22,7 +22,7 @@ import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.display.SlotDisplay;
import net.minecraft.world.level.ItemLike;
-public final class Ingredient implements StackedContents.IngredientInfo<Holder<Item>>, Predicate<ItemStack> {
+public final class Ingredient implements StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact>, Predicate<ItemStack> { // Paper - Improve exact choice recipe ingredients
-public final class Ingredient implements Predicate<ItemStack>, StackedContents.IngredientInfo<Holder<Item>> {
+public final class Ingredient implements Predicate<ItemStack>, StackedContents.IngredientInfo<io.papermc.paper.inventory.recipe.ItemOrExact> { // Paper - Improve exact choice recipe ingredients
public static final StreamCodec<RegistryFriendlyByteBuf, Ingredient> CONTENTS_STREAM_CODEC = ByteBufCodecs.holderSet(Registries.ITEM)
.map(Ingredient::new, ingredient -> ingredient.values);
.map(Ingredient::new, i -> i.values);
public static final StreamCodec<RegistryFriendlyByteBuf, Optional<Ingredient>> OPTIONAL_CONTENTS_STREAM_CODEC = ByteBufCodecs.holderSet(Registries.ITEM)
@@ -35,20 +35,24 @@ public final class Ingredient implements StackedContents.IngredientInfo<Holder<I
@@ -34,19 +34,23 @@ public final class Ingredient implements Predicate<ItemStack>, StackedContents.I
public static final Codec<Ingredient> CODEC = ExtraCodecs.nonEmptyHolderSet(NON_AIR_HOLDER_SET_CODEC).xmap(Ingredient::new, i -> i.values);
public final HolderSet<Item> values;
// CraftBukkit start
@javax.annotation.Nullable
- private java.util.List<ItemStack> itemStacks;
+ private java.util.Set<ItemStack> itemStacks; // Paper - Improve exact choice recipe ingredients
- private java.util.@org.jspecify.annotations.Nullable List<ItemStack> itemStacks;
+ private java.util.@org.jspecify.annotations.Nullable Set<ItemStack> itemStacks; // Paper - Improve exact choice recipe ingredients
public boolean isExact() {
return this.itemStacks != null;
}
@javax.annotation.Nullable
- public java.util.List<ItemStack> itemStacks() {
+ public java.util.Set<ItemStack> itemStacks() { // Paper - Improve exact choice recipe ingredients
- public java.util.@org.jspecify.annotations.Nullable List<ItemStack> itemStacks() {
+ public java.util.@org.jspecify.annotations.Nullable Set<ItemStack> itemStacks() { // Paper - Improve exact choice recipe ingredients
return this.itemStacks;
}
public static Ingredient ofStacks(java.util.List<ItemStack> stacks) {
Ingredient recipe = Ingredient.of(stacks.stream().map(ItemStack::getItem));
- recipe.itemStacks = stacks;
Ingredient ingredient = Ingredient.of(stacks.stream().map(ItemStack::getItem));
- ingredient.itemStacks = stacks;
+ // Paper start - Improve exact choice recipe ingredients
+ recipe.itemStacks = net.minecraft.world.item.ItemStackLinkedSet.createTypeAndComponentsSet();
+ recipe.itemStacks.addAll(stacks);
+ recipe.itemStacks = java.util.Collections.unmodifiableSet(recipe.itemStacks);
+ ingredient.itemStacks = net.minecraft.world.item.ItemStackLinkedSet.createTypeAndComponentsSet();
+ ingredient.itemStacks.addAll(stacks);
+ ingredient.itemStacks = java.util.Collections.unmodifiableSet(ingredient.itemStacks);
+ // Paper end - Improve exact choice recipe ingredients
return recipe;
return ingredient;
}
// CraftBukkit end
@@ -81,21 +85,22 @@ public final class Ingredient implements StackedContents.IngredientInfo<Holder<I
public boolean test(ItemStack stack) {
@@ -79,21 +83,22 @@ public final class Ingredient implements Predicate<ItemStack>, StackedContents.I
public boolean test(final ItemStack input) {
// CraftBukkit start
if (this.isExact()) {
- for (ItemStack itemstack1 : this.itemStacks()) {
- if (itemstack1.getItem() == stack.getItem() && ItemStack.isSameItemSameComponents(stack, itemstack1)) {
- for (ItemStack item : this.itemStacks()) {
- if (item.getItem() == input.getItem() && ItemStack.isSameItemSameComponents(input, item)) {
- return true;
- }
- }
-
- return false;
+ return this.itemStacks.contains(stack); // Paper - Improve exact choice recipe ingredients (hashing FTW!)
+ return this.itemStacks.contains(input); // Paper - Improve exact choice recipe ingredients (hashing FTW!)
}
// CraftBukkit end
return stack.is(this.values);
return input.is(this.values);
}
+ // Paper start - Improve exact choice recipe ingredients
@Override
- public boolean acceptsItem(Holder<Item> item) {
- public boolean acceptsItem(final Holder<Item> item) {
- return this.values.contains(item);
+ public boolean acceptsItem(final io.papermc.paper.inventory.recipe.ItemOrExact itemOrExact) {
+ return switch (itemOrExact) {
@@ -410,26 +415,26 @@ index ac4520afe510df9b1dd256d13dcb0768c83edb70..da95f40503f3696c8daa8fd0e947508f
}
@Override
@@ -120,6 +125,11 @@ public final class Ingredient implements StackedContents.IngredientInfo<Holder<I
@@ -118,6 +123,11 @@ public final class Ingredient implements Predicate<ItemStack>, StackedContents.I
}
public SlotDisplay display() {
+ // Paper start - show exact ingredients in recipe book
+ if (this.isExact()) {
+ return new SlotDisplay.Composite(this.itemStacks().stream().<SlotDisplay>map(SlotDisplay.ItemStackSlotDisplay::new).toList());
+ return new SlotDisplay.Composite(this.itemStacks().stream().map(ItemStackTemplate::fromNonEmptyStack).<SlotDisplay>map(SlotDisplay.ItemStackSlotDisplay::new).toList());
+ }
+ // Paper end - show exact ingredients in recipe book
return (SlotDisplay)this.values
.unwrap()
.map(SlotDisplay.TagSlotDisplay::new, list -> new SlotDisplay.Composite(list.stream().map(Ingredient::displayForSingleItem).toList()));
.map(SlotDisplay.TagSlotDisplay::new, l -> new SlotDisplay.Composite(l.stream().map(Ingredient::displayForSingleItem).toList()));
diff --git a/net/minecraft/world/item/crafting/ShapelessRecipe.java b/net/minecraft/world/item/crafting/ShapelessRecipe.java
index 43c8b7a027c519196852602d136a31f8c392b786..28d085fce206634ee88c492e06fdbf63a618ee12 100644
index d4d4fad66be0f0c0225993026602dc61e10c6bce..53a818f14709d1978dbbc4aa7367be733a8ee47f 100644
--- a/net/minecraft/world/item/crafting/ShapelessRecipe.java
+++ b/net/minecraft/world/item/crafting/ShapelessRecipe.java
@@ -71,13 +71,18 @@ public class ShapelessRecipe implements CraftingRecipe {
@@ -74,13 +74,18 @@ public class ShapelessRecipe extends NormalCraftingRecipe {
@Override
public boolean matches(CraftingInput input, Level level) {
public boolean matches(final CraftingInput input, final Level level) {
+ // Paper start - Improve exact choice recipe ingredients & unwrap ternary
if (input.ingredientCount() != this.ingredients.size()) {
return false;
@@ -12,11 +12,12 @@
private volatile @Nullable PacketListener disconnectListener;
private volatile @Nullable PacketListener packetListener;
private @Nullable DisconnectionDetails disconnectionDetails;
@@ -81,6 +_,43 @@
@@ -81,6 +_,44 @@
private boolean handlingFault;
private volatile @Nullable DisconnectionDetails delayedDisconnect;
private @Nullable BandwidthDebugMonitor bandwidthDebugMonitor;
+ public String hostname = ""; // CraftBukkit - add field
+ public boolean handleConnectionDisconnectOnNextTick = false; // Paper - Force kill connection ticking
+ // Paper start - NetworkClient implementation
+ public int protocolVersion;
+ public java.net.InetSocketAddress virtualHost;
@@ -220,7 +221,7 @@
}
if (this.tickCount++ % 20 == 0) {
@@ -391,12 +_,13 @@
@@ -391,6 +_,7 @@
}
public void disconnect(final DisconnectionDetails details) {
@@ -228,13 +229,6 @@
if (this.channel == null) {
this.delayedDisconnect = details;
}
if (this.isConnected()) {
- this.channel.close().awaitUninterruptibly();
+ this.channel.close(); // We can't wait as this may be called from an event loop.
this.disconnectionDetails = details;
}
}
@@ -543,6 +_,14 @@
}
}
@@ -45,7 +45,7 @@
}
}
@@ -44,8 +_,29 @@
@@ -44,8 +_,28 @@
this.closed = true;
}
@@ -71,7 +71,6 @@
public void handle() {
+ packetProcessing.push(this.listener); // Paper - detailed watchdog information
+ try { // Paper - detailed watchdog information
+ if (this.listener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // Paper - Don't handle sync packets for kicked players
if (this.listener.shouldHandleMessage(this.packet)) {
try {
this.packet.handle(this.listener);
@@ -501,9 +501,9 @@
+ java.util.Random rand = new java.util.Random(level.getSeed());
+ org.bukkit.Location spawn = level.generator.getFixedSpawnLocation(level.getWorld(), rand);
+
+ if (spawn != null) {
+ if (spawn != null && spawn.getWorld() != null) {
+ if (spawn.getWorld() != level.getWorld()) {
+ throw new IllegalStateException("Cannot set spawn point for " + levelData.getLevelName() + " to be in another world (" + (spawn.getWorld() != null ? spawn.getWorld().key() : null) + ")");
+ throw new IllegalStateException("Cannot set spawn point for " + levelData.getLevelName() + " to be in another world (" + spawn.getWorld().key().asString() + ")");
+ } else {
+ levelData.setSpawn(
+ net.minecraft.world.level.storage.LevelData.RespawnData.of(
@@ -1096,7 +1096,7 @@
ObjectArrayList<NameAndId> 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;
}
@@ -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<WorldClock> 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<WorldClock> 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<WorldClock> 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<WorldClock> 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<WorldClock> clock, final ResourceKey<ClockTimeMarker> 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<WorldClock> 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<WorldClock> 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;
}
@@ -189,6 +189,15 @@
this.ticketStorage.purgeStaleTickets(this.chunkMap);
}
@@ -344,7 +_,7 @@
if (!this.level.isDebug()) {
ProfilerFiller profiler = Profiler.get();
profiler.push("pollingChunks");
- if (this.level.tickRateManager().runsNormally()) {
+ if (this.level.tickRateManager().runsNormally() && this.level.paperConfig().unsupportedSettings.ticking.chunks) { // Paper - option to disable ticking
profiler.push("tickingChunks");
this.tickChunks(profiler, timeDiff);
profiler.pop();
@@ -376,12 +_,20 @@
chunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap)
);
@@ -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<net.minecraft.server.MinecraftServer> 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<Holder<WorldClock>> 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();
}
@@ -310,6 +326,19 @@
if (isActive) {
this.resetEmptyTime();
}
@@ -437,9 +_,12 @@
}
}
);
+ if (this.paperConfig().unsupportedSettings.ticking.blockEntities) { // Paper - option to disable ticking
profiler.popPush("blockEntities");
this.tickBlockEntities();
profiler.pop();
+ } // Paper - option to disable ticking
+ this.spigotConfig.currentPrimedTnt = 0; // Spigot
}
profiler.push("entityManagement");
@@ -468,7 +_,7 @@
long time = this.levelData.getGameTime() + 1L;
this.serverLevelData.setGameTime(time);
@@ -9,13 +9,12 @@
private final boolean transferred;
private long keepAliveTime;
private boolean keepAlivePending;
@@ -46,6 +_,17 @@
@@ -46,6 +_,16 @@
private boolean closed = false;
private int latency;
private volatile boolean suspendFlushingOnServerThread = false;
+ // CraftBukkit start
+ public final org.bukkit.craftbukkit.CraftServer cserver;
+ public boolean processedDisconnect;
+ // CraftBukkit end
+ public final java.util.Map<java.util.UUID, net.kyori.adventure.resource.ResourcePackCallback> packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks
+ private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit
@@ -210,7 +209,7 @@
public void send(final Packet<?> packet, final @Nullable ChannelFutureListener listener) {
+ // CraftBukkit start
+ if (packet == null || this.processedDisconnect) { // Spigot
+ if (packet == null) {
+ return;
+ } else if (packet instanceof net.minecraft.network.protocol.game.ClientboundSetDefaultSpawnPositionPacket defaultSpawnPositionPacket && this instanceof ServerGamePacketListenerImpl serverGamePacketListener) {
+ serverGamePacketListener.player.compassTarget = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(defaultSpawnPositionPacket.respawnData().pos(), serverGamePacketListener.getPlayer().level());
@@ -219,7 +218,7 @@
if (packet.isTerminal()) {
this.close();
}
@@ -174,15 +_,111 @@
@@ -174,15 +_,108 @@
}
}
@@ -237,7 +236,7 @@
public void disconnect(final DisconnectionDetails details) {
+ // CraftBukkit start - fire PlayerKickEvent
+ if (this.processedDisconnect) {
+ if (!this.connection.isConnected()) {
+ return;
+ }
+ if (!this.cserver.isPrimaryThread()) {
@@ -303,14 +302,11 @@
+ }
+
+ private void disconnect0(final DisconnectionDetails details) {
+ // CraftBukkit end
this.connection.send(new ClientboundDisconnectPacket(details.reason()), PacketSendListener.thenRun(() -> this.connection.disconnect(details)));
+ this.onDisconnect(details); // CraftBukkit - fire quit instantly
this.connection.setReadOnly();
- this.server.executeBlocking(this.connection::handleDisconnection);
- }
+ // CraftBukkit - Don't wait
+ this.server.scheduleOnMain(this.connection::handleDisconnection); // Paper
+ this.connection.handleConnectionDisconnectOnNextTick = true; // Paper - Force kill connection ticking. Let this close the connection
+ }
+
+ // Paper start - add proper async disconnect
@@ -100,7 +100,7 @@
public SocketAddress startMemoryChannel() {
ChannelFuture newChannel;
synchronized (this.channels) {
@@ -151,6 +_,13 @@
@@ -151,12 +_,26 @@
public void tick() {
synchronized (this.connections) {
@@ -114,6 +114,19 @@
Iterator<Connection> iterator = this.connections.iterator();
while (iterator.hasNext()) {
Connection connection = iterator.next();
if (!connection.isConnecting()) {
if (connection.isConnected()) {
+ // Paper start - Force kill connection ticking
+ // also call this multiple times, doesnt matter
+ // See MC-307764
+ if (connection.handleConnectionDisconnectOnNextTick) {
+ continue;
+ }
+ // Paper end - Force kill connection ticking
try {
connection.tick();
} catch (Exception var7) {
@@ -170,6 +_,7 @@
connection.setReadOnly();
}
@@ -83,7 +83,7 @@
public ServerGamePacketListenerImpl(final MinecraftServer server, final Connection connection, final ServerPlayer player, final CommonListenerCookie cookie) {
super(server, connection, cookie);
@@ -284,11 +_,26 @@
@@ -284,8 +_,22 @@
player.connection = this;
player.getTextFilter().join();
this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(player.getUUID(), server::enforceSecureProfile);
@@ -108,10 +108,6 @@
@Override
public void tick() {
+ if (this.isDisconnected()) return; // Paper
if (this.ackBlockChangesUpTo > -1) {
this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo));
this.ackBlockChangesUpTo = -1;
@@ -298,11 +_,13 @@
this.keepConnectionAlive();
this.chatSpamThrottler.tick();
@@ -1356,17 +1352,9 @@
return;
}
}
@@ -1453,24 +_,50 @@
@@ -1454,23 +_,42 @@
@Override
public void onDisconnect(final DisconnectionDetails details) {
+ // CraftBukkit start - Rarely it would send a disconnect line twice
+ if (this.processedDisconnect) {
+ return;
+ } else {
+ this.processedDisconnect = true;
+ }
+ // CraftBukkit end
LOGGER.info("{} lost connection: {}", this.player.getPlainTextName(), details.reason().getString());
- this.removePlayerFromWorld();
+ // Paper start - Fix kick event leave message not being sent
@@ -2510,7 +2498,7 @@
if (this.player.isModelPartShown(PlayerModelPart.HAT) != wasHatShown) {
this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT, this.player));
}
@@ -2082,7 +_,7 @@
@@ -2082,21 +_,21 @@
packet.difficulty().getDisplayName()
);
} else {
@@ -2519,7 +2507,14 @@
}
}
@@ -2096,7 +_,7 @@
@Override
public void handleChangeGameMode(final ServerboundChangeGameModePacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level());
- if (!GameModeCommand.PERMISSION_CHECK.check(this.player.permissions())) {
+ if (!GameModeCommand.PERMISSION_CHECK.check(this.player.permissions()) && !this.player.getBukkitEntity().hasPermission("minecraft.command.gamemode")) { // Paper - add permission check
LOGGER.warn(
"Player {} tried to change game mode to {} without required permissions",
this.player.getGameProfile().name(),
packet.mode().getShortDisplayName().getString()
);
} else {
@@ -2664,7 +2659,7 @@
+ }
+
+ public final boolean isDisconnected() {
+ return (!this.player.joining && !this.connection.isConnected()) || this.processedDisconnect; // Paper - Fix duplication bugs
+ return (!this.player.joining && !this.connection.isConnected());
+ }
+
+ @Override
@@ -13,11 +13,11 @@
public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, TickablePacketListener {
private static final AtomicInteger UNIQUE_THREAD_ID = new AtomicInteger(0);
private static final Logger LOGGER = LogUtils.getLogger();
+ private static final java.util.concurrent.ExecutorService authenticatorPool = java.util.concurrent.Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("User Authenticator #%d").setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).build()); // Paper - Cache authenticator threads
+ private static final java.util.concurrent.ExecutorService authenticatorPool = java.util.concurrent.Executors.newThreadPerTaskExecutor(Thread.ofVirtual().name("User Authenticator #", 0).uncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).factory()); // Paper - Virtual authenticator threads
private static final int MAX_TICKS_BEFORE_LOGIN = 600;
private final byte[] challenge;
private final MinecraftServer server;
@@ -56,10 +_,15 @@
@@ -56,10 +_,14 @@
private final ServerActivityMonitor serverActivityMonitor;
public volatile ServerLoginPacketListenerImpl.State state = ServerLoginPacketListenerImpl.State.HELLO;
private int tick;
@@ -31,11 +31,10 @@
+ private int velocityLoginMessageId = -1; // Paper - Add Velocity IP Forwarding Support
+ public java.util.@Nullable UUID requestedUuid; // Paper
+ private final io.papermc.paper.connection.PaperPlayerLoginConnection paperLoginConnection; // Paper - Config API
+ private volatile boolean disconnecting = false; // Paper - Fix disconnect still ticking login
public ServerLoginPacketListenerImpl(final MinecraftServer minecraftserver, final Connection connection, final boolean transferred) {
this.server = minecraftserver;
@@ -67,10 +_,20 @@
@@ -67,10 +_,19 @@
this.serverActivityMonitor = this.server.getServerActivityMonitor();
this.challenge = Ints.toByteArray(RandomSource.create().nextInt());
this.transferred = transferred;
@@ -44,7 +43,6 @@
@Override
public void tick() {
+ if (this.disconnecting) return; // Paper - Fix disconnect being called multiple times due to not awaiting for disconnect
+ // Paper start - login cookie API
+ // Don't block the connection
+ if (this.paperLoginConnection.isAwaitingCookies()) {
@@ -56,7 +54,7 @@
if (this.state == ServerLoginPacketListenerImpl.State.VERIFYING) {
this.verifyLoginAndFinishConnectionSetup(Objects.requireNonNull(this.authenticatedProfile));
}
@@ -80,11 +_,23 @@
@@ -80,16 +_,39 @@
this.finishLoginAndWaitForClient(this.authenticatedProfile);
}
@@ -66,28 +64,37 @@
+ public void tickTimeout() {
+ // Paper end - login cookie API
if (this.tick++ == 600) {
this.disconnect(Component.translatable("multiplayer.disconnect.slow_login"));
- this.disconnect(Component.translatable("multiplayer.disconnect.slow_login"));
+ this.disconnectAsync(Component.translatable("multiplayer.disconnect.slow_login")); // Paper
}
}
+
+ // CraftBukkit start
+ @Deprecated
+ public void disconnect(String reason) {
+ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(reason))); // Paper - Fix hex colors not working in some kick messages
+ }
+ // CraftBukkit end
+
@Override
public boolean isAcceptingMessages() {
return this.connection.isConnected();
@@ -95,6 +_,7 @@
}
+ // Paper start
+ public void disconnectAsync(Component reason) {
+ try {
+ LOGGER.info("Disconnecting {}: {}", this.getUserName(), reason.getString());
+ this.connection.send(new ClientboundLoginDisconnectPacket(reason), PacketSendListener.thenRun(() -> this.connection.disconnect(reason)));
+ this.connection.handleConnectionDisconnectOnNextTick = true;
+ } catch (Exception var3) {
+ LOGGER.error("Error whilst disconnecting player", (Throwable)var3);
+ }
+ }
+ // Paper end
public void disconnect(final Component component) {
try {
LOGGER.info("Disconnecting {}: {}", this.getUserName(), component.getString());
this.connection.send(new ClientboundLoginDisconnectPacket(component));
this.connection.disconnect(component);
+ this.disconnecting = true; // Paper - Fix disconnect still ticking login
} catch (Exception var3) {
LOGGER.error("Error whilst disconnecting player", (Throwable)var3);
}
@@ -117,7 +_,14 @@
@Override
public void handleHello(final ServerboundHelloPacket packet) {
@@ -104,7 +111,7 @@
this.requestedUsername = packet.name();
GameProfile singleplayerProfile = this.server.getSingleplayerProfile();
if (singleplayerProfile != null && this.requestedUsername.equalsIgnoreCase(singleplayerProfile.name())) {
@@ -127,7 +_,32 @@
@@ -127,7 +_,30 @@
this.state = ServerLoginPacketListenerImpl.State.KEY;
this.connection.send(new ClientboundHelloPacket("", this.server.getKeyPair().getPublic().getEncoded(), this.challenge, true));
} else {
@@ -119,8 +126,7 @@
+ return;
+ }
+ // Paper end - Add Velocity IP Forwarding Support
+ // CraftBukkit start
+ // Paper start - Cache authenticator threads
+ // Paper start - Virtual authenticator threads
+ authenticatorPool.execute(() -> {
+ try {
+ GameProfile gameprofile = ServerLoginPacketListenerImpl.this.createOfflineProfile(ServerLoginPacketListenerImpl.this.requestedUsername); // Spigot
@@ -133,20 +139,22 @@
+ ServerLoginPacketListenerImpl.this.server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.requestedUsername, ex);
+ }
+ });
+ // Paper end - Cache authenticator threads
+ // CraftBukkit end
+ // Paper end - Virtual authenticator threads
}
}
}
@@ -139,7 +_,7 @@
@@ -139,9 +_,9 @@
private void verifyLoginAndFinishConnectionSetup(final GameProfile profile) {
PlayerList playerList = this.server.getPlayerList();
- Component error = playerList.canPlayerLogin(this.connection.getRemoteAddress(), new NameAndId(profile));
+ Component error = org.bukkit.craftbukkit.event.CraftEventFactory.handleLoginResult(playerList.canPlayerLogin(this.connection.getRemoteAddress(), new NameAndId(profile)), this.paperLoginConnection, this.connection, profile, this.server, true); // Paper
if (error != null) {
this.disconnect(error);
- this.disconnect(error);
+ this.disconnectAsync(error); // Paper
} else {
if (this.server.getCompressionThreshold() >= 0 && !this.connection.isMemoryConnection()) {
this.connection
@@ -151,7 +_,7 @@
);
}
@@ -169,7 +177,7 @@
}
- Thread thread = new Thread("User Authenticator #" + UNIQUE_THREAD_ID.incrementAndGet()) {
+ // Paper start - Cache authenticator threads
+ // Paper start - Virtual authenticator threads
+ authenticatorPool.execute(new Runnable() {
{
Objects.requireNonNull(ServerLoginPacketListenerImpl.this);
@@ -222,7 +230,7 @@
- thread.start();
- }
+ });
+ // Paper end - Cache authenticator threads
+ // Paper end - Virtual authenticator threads
+ }
+
+ // CraftBukkit start
@@ -125,7 +125,7 @@
+ );
+ ev.callEvent();
+ spawnPosition = io.papermc.paper.util.MCUtil.toVec3(ev.getSpawnLocation());
+ this.spawnLevel = ((org.bukkit.craftbukkit.CraftWorld) ev.getSpawnLocation().getWorld()).getHandle();
+ if (ev.getSpawnLocation().getWorld() != null) this.spawnLevel = ((org.bukkit.craftbukkit.CraftWorld) ev.getSpawnLocation().getWorld()).getHandle();
+ this.spawnPosition = CompletableFuture.completedFuture(spawnPosition);
+ this.spawnAngle = new Vec2(ev.getSpawnLocation().getYaw(), ev.getSpawnLocation().getPitch());
+ }
@@ -272,7 +272,7 @@
}
@Override
@@ -296,64 +_,148 @@
@@ -296,64 +_,147 @@
}
protected void save(final ServerPlayer player) {
@@ -310,7 +310,6 @@
+ this.cserver.getPluginManager().callEvent(playerQuitEvent);
+ player.getBukkitEntity().disconnect();
+
+ if (this.server.isSameThread()) player.doTick(); // SPIGOT-924 // Paper - Improved watchdog support; don't tick during emergency shutdowns
+ // CraftBukkit end
+
+ // Paper start - Configurable player collision; Remove from collideRule team if needed
@@ -741,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)));
@@ -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<Holder<WorldClock>, 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<WorldClock> clock, final Consumer<? super ServerClockManager.ClockInstance> action) {
ServerClockManager.ClockInstance instance = this.getInstance(clock);
action.accept(instance);
Map<Holder<WorldClock>, ClockNetworkState> updates = Map.of(clock, instance.packNetworkState(this.server));
- Map<Holder<WorldClock>, 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<WorldClock> definition) {
+ return this.getInstance(definition).paused;
+ }
+
+ public float partialTick(final Holder<WorldClock> definition) {
+ return this.getInstance(definition).partialTick;
+ }
+
+ public float rate(final Holder<WorldClock> definition) {
+ return this.getInstance(definition).rate;
+ }
+ // 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)));
- return new ClientboundSetTimePacket(this.getGameTime(), Util.mapValues(this.clocks, clock -> clock.packNetworkState(this.server)));
+ // Paper start - per-player time
+ return this.createFullSyncPacket(null);
+ }
+
+ public ClientboundSetTimePacket createFullSyncPacket(final net.minecraft.server.level.ServerPlayer player) {
+ final Map<Holder<WorldClock>, 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
+ }
+
+ // Paper start - per-world time; per-player time
+ private void broadcastUpdates(final Holder<WorldClock> 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);
+ }
+ }
+
+ private ClockNetworkState packNetworkState(
+ final Holder<WorldClock> 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<WorldClock> clock, final ResourceKey<ClockTimeMarker> 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);
}
@@ -40,7 +40,7 @@
+ // Paper start - Expand EntityUnleashEvent
+ final org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(
+ entity.getBukkitEntity(),
+ !entity.isAlive() ? org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.PLAYER_UNLEASH : org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.HOLDER_GONE,
+ !entity.isAlive() ? org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.LEASHED_GONE : org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.HOLDER_GONE,
+ level.getGameRules().get(GameRules.ENTITY_DROPS) && !entity.pluginRemoved
+ );
+ event.callEvent();
@@ -1053,7 +1053,7 @@
int absorbValue = (this.getEffect(MobEffects.RESISTANCE).getAmplifier() + 1) * 5;
int absorb = 25 - absorbValue;
float v = damage * absorb;
@@ -1915,24 +_,194 @@
@@ -1915,24 +_,181 @@
}
}
@@ -1147,19 +1147,6 @@
+ return false;
+ }
+
+ if (source.getEntity() instanceof net.minecraft.world.entity.player.Player) {
+ // Paper start - PlayerAttackEntityCooldownResetEvent
+ //((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetOnlyAttackStrengthTicker(); // Moved from Player in order to make the cooldown reset get called after the damage event is fired
+ if (source.getEntity() instanceof ServerPlayer player) {
+ if (new com.destroystokyo.paper.event.player.PlayerAttackEntityCooldownResetEvent(player.getBukkitEntity(), this.getBukkitEntity(), player.getAttackStrengthScale(0F)).callEvent()) {
+ player.resetOnlyAttackStrengthTicker();
+ }
+ } else {
+ ((net.minecraft.world.entity.player.Player)source.getEntity()).resetOnlyAttackStrengthTicker();
+ }
+ // Paper end - PlayerAttackEntityCooldownResetEvent
+ }
+
+ // Resistance
+ if (event.getDamage(DamageModifier.RESISTANCE) < 0) {
+ float damageResisted = (float)-event.getDamage(DamageModifier.RESISTANCE);
@@ -1405,6 +1392,18 @@
profiler.pop();
if (this.isFallFlying()) {
@@ -2865,6 +_,11 @@
}
public void onAttack() {
+ // Paper start
+ onAttack(null);
+ }
+ public void onAttack(Entity entity) {
+ // Paper end
}
public void detectEquipmentUpdates() {
@@ -2879,16 +_,39 @@
private @Nullable Map<EquipmentSlot, ItemStack> collectEquipmentChanges() {
@@ -240,8 +240,9 @@
float attackStrengthScale = this.getAttackStrengthScale(0.5F);
float magicBoost = attackStrengthScale * (this.getEnchantedDamage(entity, baseDamage, damageSource) - baseDamage);
baseDamage *= this.baseDamageScaleFactor();
this.onAttack();
- this.onAttack();
- if (!this.deflectProjectile(entity)) {
+ this.onAttack(entity); // Paper
+ final float dmgFinal = magicBoost; // Paper - damage events
+ if (!this.deflectProjectile(entity, () -> !org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(entity, dmgSourceFinal, dmgFinal, false))) {
if (baseDamage > 0.0F || magicBoost > 0.0F) {
@@ -480,15 +481,27 @@
}
}
}
@@ -1808,10 +_,31 @@
@Override
public void onAttack() {
- this.resetOnlyAttackStrengthTicker();
+ // this.resetOnlyAttackStrengthTicker(); // CraftBukkit - Moved to EntityLiving to reset the cooldown after the damage is dealt
super.onAttack();
@@ -1807,10 +_,39 @@
}
@Override
- public void onAttack() {
- this.resetOnlyAttackStrengthTicker();
- super.onAttack();
- }
+ // Paper start
+ public void onAttack(@Nullable Entity entity) {
+ if (entity != null) {
+ if (new com.destroystokyo.paper.event.player.PlayerAttackEntityCooldownResetEvent((org.bukkit.entity.Player) this.getBukkitEntity(), entity.getBukkitEntity(), this.getAttackStrengthScale(0F)).callEvent()) {
+ this.resetOnlyAttackStrengthTicker();
+ }
+ } else {
+ this.resetOnlyAttackStrengthTicker();
+ }
+ super.onAttack(entity);
+ // Paper end
+ }
+
+ // Paper start - Force update attributes.
+ @Override
+ public void detectEquipmentUpdates() {
@@ -509,10 +522,9 @@
+ }
+ }
+ // Paper end - Force update attributes.
+
public void resetOnlyAttackStrengthTicker() {
this.attackStrengthTicker = 0;
}
@@ -1843,17 +_,32 @@
return ImmutableList.of(Pose.STANDING, Pose.CROUCHING, Pose.SWIMMING);
}
@@ -84,14 +84,23 @@
this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, 0.0, 1.0));
this.lastYd = 0.0;
}
@@ -704,12 +_,12 @@
@@ -704,12 +_,20 @@
}
@Override
- public void remove(final Entity.RemovalReason reason) {
+ public void remove(final Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause eventCause) { // CraftBukkit - add Bukkit remove cause
if (!this.level().isClientSide() && reason.shouldDestroy() && this.isLeashed()) {
this.dropLeash();
- this.dropLeash();
+ // Paper start - Fire EntityUnleashEvent on boat destruction
+ final org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(this.getBukkitEntity(), org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.LEASHED_GONE, true);
+ event.callEvent();
+ if (event.isDropLeash()) {
+ this.dropLeash();
+ } else {
+ this.removeLeash();
+ }
+ // Paper end - Fire EntityUnleashEvent on boat destruction
}
- super.remove(reason);
@@ -201,7 +201,7 @@
player.handleCreativeModeItemDrop(itemStack);
}
}
@@ -595,8 +_,9 @@
@@ -595,14 +_,15 @@
if (player instanceof ServerPlayer) {
ItemStack carried = this.getCarried();
if (!carried.isEmpty()) {
@@ -212,6 +212,13 @@
}
}
}
private static void dropOrPlaceInInventory(final Player player, final ItemStack carried) {
- boolean playerRemovedNotChangingDimension = player.isRemoved() && player.getRemovalReason() != Entity.RemovalReason.CHANGED_DIMENSION;
+ boolean playerRemovedNotChangingDimension = !player.isAlive() && player.getRemovalReason() != Entity.RemovalReason.CHANGED_DIMENSION; // Paper - Make sure player is dead (https://github.com/PaperMC/Paper/pull/13002)
boolean serverPlayerHasDisconnected = player instanceof ServerPlayer serverPlayer && serverPlayer.hasDisconnected();
if (playerRemovedNotChangingDimension || serverPlayerHasDisconnected) {
player.drop(carried, false);
@@ -642,6 +_,14 @@
public abstract boolean stillValid(Player player);
@@ -37,7 +37,7 @@
+ com.destroystokyo.paper.event.player.PlayerElytraBoostEvent event = new com.destroystokyo.paper.event.player.PlayerElytraBoostEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) delayed.projectile().getBukkitEntity(), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand));
+ if (event.callEvent() && delayed.attemptSpawn()) {
+ player.awardStat(Stats.ITEM_USED.get(this)); // Moved up from below
+ if (player.dropAllLeashConnections(null)) {
+ if (player.dropAllLeashConnections(player, hand)) { // Paper - PlayerUnleashEntityEvent
+ level.playSound(null, player, SoundEvents.LEAD_BREAK, SoundSource.NEUTRAL, 1.0F, 1.0F);
+ }
+ if (event.shouldConsume() && !player.hasInfiniteMaterials()) {
@@ -76,7 +76,7 @@
protected Level(
final WritableLevelData levelData,
final ResourceKey<Level> dimension,
@@ -141,7 +_,24 @@
@@ -141,7 +_,25 @@
final boolean isDebug,
final long biomeZoomSeed,
final int maxChainedNeighborUpdates
@@ -87,10 +87,11 @@
+ java.util.function.Function<org.spigotmc.SpigotWorldConfig, // Spigot - create per world config
+ io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator // Paper - create paper world config
) {
+ this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, CraftNamespacedKey.fromMinecraft(dimension.identifier())); // Spigot
+ final org.bukkit.NamespacedKey worldKey = CraftNamespacedKey.fromMinecraft(dimension.identifier()); // Paper
+ this.spigotConfig = new org.spigotmc.SpigotWorldConfig(bukkitName, worldKey); // Spigot
+ this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
+ this.generator = generator;
+ this.world = new CraftWorld((ServerLevel) this, dimension.identifier(), biomeProvider, environment);
+ this.world = new CraftWorld((ServerLevel) this, worldKey, biomeProvider, environment);
+
+ for (SpawnCategory spawnCategory : SpawnCategory.values()) {
+ if (org.bukkit.craftbukkit.util.CraftSpawnCategory.isValidForLimits(spawnCategory)) {
@@ -445,7 +446,15 @@
return chunk.getBlockState(pos);
}
}
@@ -533,31 +_,48 @@
@@ -523,6 +_,7 @@
}
public void addBlockEntityTicker(final TickingBlockEntity ticker) {
+ if (!this.paperConfig().unsupportedSettings.ticking.blockEntities) return; // Paper - option to disable ticking
(this.tickingBlockEntities ? this.pendingBlockEntityTickers : this.blockEntityTickers).add(ticker);
}
@@ -533,18 +_,23 @@
this.pendingBlockEntityTickers.clear();
}
@@ -471,10 +480,9 @@
+ this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 use removeAll
this.tickingBlockEntities = false;
+ this.spigotConfig.currentPrimedTnt = 0; // Spigot
}
public <T extends Entity> void guardEntityTick(final Consumer<T> tick, final T entity) {
@@ -552,12 +_,23 @@
try {
tick.accept(entity);
} catch (Throwable var6) {
@@ -0,0 +1,14 @@
--- a/net/minecraft/world/level/block/AbstractSkullBlock.java
+++ b/net/minecraft/world/level/block/AbstractSkullBlock.java
@@ -76,6 +_,11 @@
if (!level.isClientSide()) {
boolean signal = level.hasNeighborSignal(pos);
if (signal != state.getValue(POWERED)) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, signal)) {
+ return;
+ }
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, signal), Block.UPDATE_CLIENTS);
}
}
@@ -13,15 +13,15 @@
boolean wasPressed = oldSignal > 0;
boolean isPressed = signal > 0;
+
+ // CraftBukkit start - Interact Pressure Plate
+ if (wasPressed != isPressed) {
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), oldSignal, signal);
+ eventRedstone.callEvent();
+ // Paper start - Call BlockRedstoneEvent
+ if (oldSignal != signal) {
+ org.bukkit.event.block.BlockRedstoneEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, oldSignal, signal);
+
+ isPressed = eventRedstone.getNewCurrent() > 0;
+ signal = eventRedstone.getNewCurrent();
+ signal = event.getNewCurrent();
+ isPressed = signal > 0;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
+
if (oldSignal != signal) {
BlockState newState = this.setSignalForState(state, signal);
level.setBlock(pos, newState, Block.UPDATE_CLIENTS);
@@ -1,5 +1,17 @@
--- a/net/minecraft/world/level/block/BellBlock.java
+++ b/net/minecraft/world/level/block/BellBlock.java
@@ -73,6 +_,11 @@
) {
boolean signal = level.hasNeighborSignal(pos);
if (signal != state.getValue(POWERED)) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, signal)) {
+ return;
+ }
+ // Paper end - Call BlockRedstoneEvent
if (signal) {
this.attemptToRing(level, pos, null);
}
@@ -143,6 +_,11 @@
direction = level.getBlockState(pos).getValue(FACING);
}
@@ -1,25 +1,27 @@
--- a/net/minecraft/world/level/block/ButtonBlock.java
+++ b/net/minecraft/world/level/block/ButtonBlock.java
@@ -92,6 +_,19 @@
@@ -92,6 +_,11 @@
if (state.getValue(POWERED)) {
return InteractionResult.CONSUME;
} else {
+ // CraftBukkit start
+ boolean powered = state.getValue(ButtonBlock.POWERED);
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+ int old = (powered) ? 15 : 0;
+ int current = (!powered) ? 15 : 0;
+
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(block, old, current);
+ level.getCraftServer().getPluginManager().callEvent(eventRedstone);
+
+ if ((eventRedstone.getNewCurrent() > 0) != (!powered)) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, true)) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
this.press(state, level, pos, player);
return InteractionResult.SUCCESS;
}
@@ -102,7 +_,9 @@
final BlockState state, final ServerLevel level, final BlockPos pos, final Explosion explosion, final BiConsumer<ItemStack, BlockPos> onHit
) {
if (explosion.canTriggerBlocks() && !state.getValue(POWERED)) {
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, true)) { // Paper - Call BlockRedstoneEvent
this.press(state, level, pos, null);
+ } // Paper - Call BlockRedstoneEvent
}
super.onExplosionHit(state, level, pos, explosion, onHit);
@@ -162,6 +_,7 @@
final InsideBlockEffectApplier effectApplier,
final boolean isPrecise
@@ -28,7 +30,7 @@
if (!level.isClientSide() && this.type.canButtonBeActivatedByArrows() && !state.getValue(POWERED)) {
this.checkPressed(state, level, pos);
}
@@ -173,7 +_,31 @@
@@ -173,7 +_,21 @@
: null;
boolean shouldBePressed = firstArrow != null;
boolean wasPressed = state.getValue(POWERED);
@@ -36,27 +38,17 @@
+ if (wasPressed != shouldBePressed && shouldBePressed) {
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+ org.bukkit.event.entity.EntityInteractEvent event = new org.bukkit.event.entity.EntityInteractEvent(firstArrow.getBukkitEntity(), block);
+ level.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ if (!event.callEvent()) {
+ return;
+ }
+ }
+ // CraftBukkit end
if (shouldBePressed != wasPressed) {
+ // CraftBukkit start
+ boolean powered = wasPressed;
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+ int old = (powered) ? 15 : 0;
+ int current = (!powered) ? 15 : 0;
+
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(block, old, current);
+ level.getCraftServer().getPluginManager().callEvent(eventRedstone);
+
+ if ((shouldBePressed && eventRedstone.getNewCurrent() <= 0) || (!shouldBePressed && eventRedstone.getNewCurrent() > 0)) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, shouldBePressed)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, shouldBePressed), Block.UPDATE_ALL);
this.updateNeighbours(state, level, pos);
this.playSound(null, level, pos, shouldBePressed);
@@ -1,24 +1,21 @@
--- a/net/minecraft/world/level/block/CommandBlock.java
+++ b/net/minecraft/world/level/block/CommandBlock.java
@@ -69,8 +_,17 @@
@@ -69,9 +_,14 @@
}
}
- private void setPoweredAndUpdate(final Level level, final BlockPos pos, final CommandBlockEntity commandBlock, final boolean isPowered) {
+ private void setPoweredAndUpdate(final Level level, final BlockPos pos, final CommandBlockEntity commandBlock, boolean isPowered) { // Paper - remove final from isPowered
boolean wasPowered = commandBlock.isPowered();
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+ int old = wasPowered ? 15 : 0;
+ int current = isPowered ? 15 : 0;
+
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(bukkitBlock, old, current);
+ level.getCraftServer().getPluginManager().callEvent(eventRedstone);
+ isPowered = eventRedstone.getNewCurrent() > 0;
+ // CraftBukkit end
if (isPowered != wasPowered) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, isPowered)) {
+ return;
+ }
+ // Paper end - Call BlockRedstoneEvent
commandBlock.setPowered(isPowered);
if (isPowered) {
if (commandBlock.isAutomatic() || commandBlock.getMode() == CommandBlockEntity.Mode.SEQUENCE) {
@@ -129,7 +_,7 @@
final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult
) {
@@ -13,18 +13,18 @@
boolean sourceOn = this.shouldTurnOn(level, pos, state);
boolean isOn = state.getValue(POWERED);
if (isOn && !sourceOn) {
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 15, 0).getNewCurrent() != 0) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, false)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, false), Block.UPDATE_CLIENTS);
} else if (!isOn && sourceOn) {
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 0, 15).getNewCurrent() != 15) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, true)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, true), Block.UPDATE_CLIENTS);
}
@@ -0,0 +1,14 @@
--- a/net/minecraft/world/level/block/CopperBulbBlock.java
+++ b/net/minecraft/world/level/block/CopperBulbBlock.java
@@ -49,6 +_,11 @@
public void checkAndFlip(final BlockState state, final ServerLevel level, final BlockPos pos) {
boolean signal = level.hasNeighborSignal(pos);
if (signal != state.getValue(POWERED)) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, signal)) {
+ return;
+ }
+ // Paper end - Call BlockRedstoneEvent
BlockState newState = state;
if (!state.getValue(POWERED)) {
newState = state.cycle(LIT);
@@ -4,7 +4,7 @@
target = Mth.clamp(target, 0, 15);
if (state.getValue(POWER) != target) {
+ target = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, state.getValue(DaylightDetectorBlock.POWER), target).getNewCurrent(); // CraftBukkit - Call BlockRedstoneEvent
+ target = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, state.getValue(POWER), target).getNewCurrent(); // Paper - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWER, target), Block.UPDATE_ALL);
}
}
@@ -8,7 +8,7 @@
if (!level.isClientSide()) {
if (!state.getValue(POWERED)) {
this.checkPressed(level, pos, state);
@@ -87,6 +_,7 @@
@@ -87,12 +_,21 @@
private void checkPressed(final Level level, final BlockPos pos, final BlockState state) {
if (this.canSurvive(state, level, pos)) {
@@ -16,20 +16,17 @@
boolean wasPressed = state.getValue(POWERED);
boolean shouldBePressed = false;
List<AbstractMinecart> entities = this.getInteractingMinecartOfType(level, pos, AbstractMinecart.class, e -> true);
@@ -94,6 +_,16 @@
if (!entities.isEmpty()) {
shouldBePressed = true;
}
+ // CraftBukkit start
+
+ // Paper start - Call BlockRedstoneEvent
+ if (wasPressed != shouldBePressed) {
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(block, shouldBePressed ? 15 : 0, shouldBePressed ? 15 : 0);
+ level.getCraftServer().getPluginManager().callEvent(eventRedstone);
+
+ shouldBePressed = eventRedstone.getNewCurrent() > 0;
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, shouldBePressed)) {
+ return;
+ }
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
if (shouldBePressed && !wasPressed) {
BlockState newState = state.setValue(POWERED, true);
level.setBlock(pos, newState, Block.UPDATE_ALL);
@@ -4,18 +4,18 @@
boolean on = state.getValue(POWERED);
boolean shouldTurnOn = this.shouldTurnOn(level, pos, state);
if (on && !shouldTurnOn) {
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 15, 0).getNewCurrent() != 0) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, false)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, false), Block.UPDATE_CLIENTS);
} else if (!on) {
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 0, 15).getNewCurrent() != 15) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, true)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, true), Block.UPDATE_CLIENTS);
if (!shouldTurnOn) {
level.scheduleTick(pos, this, this.getDelay(state), TickPriority.VERY_HIGH);
@@ -1,28 +1,14 @@
--- a/net/minecraft/world/level/block/DoorBlock.java
+++ b/net/minecraft/world/level/block/DoorBlock.java
@@ -225,9 +_,22 @@
protected void neighborChanged(
final BlockState state, final Level level, final BlockPos pos, final Block block, final @Nullable Orientation orientation, final boolean movedByPiston
) {
- boolean signal = level.hasNeighborSignal(pos)
- || level.hasNeighborSignal(pos.relative(state.getValue(HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN));
- if (!this.defaultBlockState().is(block) && signal != state.getValue(POWERED)) {
+ // CraftBukkit start
+ BlockPos otherHalf = pos.relative(state.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN);
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+ org.bukkit.block.Block blockTop = org.bukkit.craftbukkit.block.CraftBlock.at(level, otherHalf);
+
+ int power = bukkitBlock.getBlockPower();
+ int powerTop = blockTop.getBlockPower();
+ if (powerTop > power) power = powerTop;
+ int oldPower = state.getValue(DoorBlock.POWERED) ? net.minecraft.world.level.redstone.Redstone.SIGNAL_MAX : net.minecraft.world.level.redstone.Redstone.SIGNAL_MIN;
+
+ if (oldPower == 0 ^ power == 0) {
+ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(bukkitBlock, oldPower, power);
+ event.callEvent();
+
+ boolean signal = event.getNewCurrent() > 0;
+ // CraftBukkit end
@@ -228,6 +_,11 @@
boolean signal = level.hasNeighborSignal(pos)
|| level.hasNeighborSignal(pos.relative(state.getValue(HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN));
if (!this.defaultBlockState().is(block) && signal != state.getValue(POWERED)) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, signal)) {
+ return;
+ }
+ // Paper end - Call BlockRedstoneEvent
if (signal != state.getValue(OPEN)) {
this.playSound(null, level, pos, signal);
level.gameEvent(null, signal ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos);
@@ -1,20 +1,14 @@
--- a/net/minecraft/world/level/block/FenceGateBlock.java
+++ b/net/minecraft/world/level/block/FenceGateBlock.java
@@ -188,6 +_,17 @@
) {
@@ -189,6 +_,11 @@
if (!level.isClientSide()) {
boolean hasPower = level.hasNeighborSignal(pos);
+ // CraftBukkit start
+ boolean oldPowered = state.getValue(FenceGateBlock.POWERED);
+ if (oldPowered != hasPower) {
+ int newPower = hasPower ? 15 : 0;
+ int oldPower = oldPowered ? 15 : 0;
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(bukkitBlock, oldPower, newPower);
+ level.getCraftServer().getPluginManager().callEvent(eventRedstone);
+ hasPower = eventRedstone.getNewCurrent() > 0;
+ }
+ // CraftBukkit end
if (state.getValue(POWERED) != hasPower) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, hasPower)) {
+ return;
+ }
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, hasPower).setValue(OPEN, hasPower), Block.UPDATE_CLIENTS);
if (state.getValue(OPEN) != hasPower) {
level.playSound(
@@ -26,20 +26,17 @@
resetBookState(sourceEntity, level, pos, state, true);
level.playSound(null, pos, SoundEvents.BOOK_PUT, SoundSource.BLOCKS, 1.0F, 1.0F);
}
@@ -162,6 +_,16 @@
@@ -162,6 +_,13 @@
}
private static void changePowered(final Level level, final BlockPos pos, final BlockState state, final boolean isPowered) {
+ // Paper start - Call BlockRedstoneEvent properly
+ final int currentRedstoneLevel = state.getValue(LecternBlock.POWERED) ? 15 : 0, targetRedstoneLevel = isPowered ? 15 : 0;
+ if (currentRedstoneLevel != targetRedstoneLevel) {
+ final org.bukkit.event.block.BlockRedstoneEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, currentRedstoneLevel, targetRedstoneLevel);
+
+ if (event.getNewCurrent() != targetRedstoneLevel) {
+ // Paper start - Call BlockRedstoneEvent
+ if (state.getValue(POWERED) != isPowered) {
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, isPowered)) {
+ return;
+ }
+ }
+ // Paper end - Call BlockRedstoneEvent properly
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, isPowered), Block.UPDATE_ALL);
updateBelow(level, pos, state);
}
@@ -1,22 +1,28 @@
--- a/net/minecraft/world/level/block/LeverBlock.java
+++ b/net/minecraft/world/level/block/LeverBlock.java
@@ -70,6 +_,19 @@
@@ -70,6 +_,12 @@
makeParticle(stateAfter, level, pos, 1.0F);
}
} else {
+ // CraftBukkit start - Interact Lever
+ boolean powered = stateBefore.getValue(LeverBlock.POWERED); // Old powered state
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+ int old = (powered) ? 15 : 0;
+ int current = (!powered) ? 15 : 0;
+
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(block, old, current);
+ level.getCraftServer().getPluginManager().callEvent(eventRedstone);
+
+ if ((eventRedstone.getNewCurrent() > 0) != (!powered)) {
+ // Paper start - Call BlockRedstoneEvent
+ boolean wasPowered = stateBefore.getValue(POWERED);
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, !wasPowered)) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
this.pull(stateBefore, level, pos, null);
}
@@ -81,7 +_,12 @@
final BlockState state, final ServerLevel level, final BlockPos pos, final Explosion explosion, final BiConsumer<ItemStack, BlockPos> onHit
) {
if (explosion.canTriggerBlocks()) {
+ // Paper start - Call BlockRedstoneEvent
+ boolean wasPowered = state.getValue(POWERED);
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, !wasPowered)) {
+ // Paper end - Call BlockRedstoneEvent
this.pull(state, level, pos, null);
+ } // Paper - Call BlockRedstoneEvent
}
super.onExplosionHit(state, level, pos, explosion, onHit);
@@ -1,21 +1,30 @@
--- a/net/minecraft/world/level/block/LightningRodBlock.java
+++ b/net/minecraft/world/level/block/LightningRodBlock.java
@@ -83,6 +_,18 @@
@@ -83,6 +_,13 @@
}
public void onLightningStrike(final BlockState state, final Level level, final BlockPos pos) {
+ // CraftBukkit start
+ boolean powered = state.getValue(LightningRodBlock.POWERED);
+ int old = (powered) ? 15 : 0;
+ int current = (!powered) ? 15 : 0;
+
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), old, current);
+ level.getCraftServer().getPluginManager().callEvent(eventRedstone);
+
+ if (eventRedstone.getNewCurrent() <= 0) {
+ return;
+ // Paper start - Call BlockRedstoneEvent
+ if (!state.getValue(POWERED)) {
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, true)) {
+ return;
+ }
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, true), Block.UPDATE_ALL);
this.updateNeighbours(state, level, pos);
level.scheduleTick(pos, this, 8);
@@ -96,6 +_,13 @@
@Override
protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) {
+ // Paper start - Call BlockRedstoneEvent
+ if (state.getValue(POWERED)) {
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, false)) {
+ return;
+ }
+ }
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, false), Block.UPDATE_ALL);
this.updateNeighbours(state, level, pos);
}
@@ -16,7 +16,7 @@
boolean neighborDirectionSetsInstrument = directionToNeighbour.getAxis() == Direction.Axis.Y;
return neighborDirectionSetsInstrument
? this.setInstrument(level, pos, state)
@@ -86,12 +_,14 @@
@@ -86,12 +_,19 @@
@Override
protected void neighborChanged(
@@ -26,6 +26,11 @@
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return; // Paper - prevent noteblock powered-state from updating
boolean signal = level.hasNeighborSignal(pos);
if (signal != state.getValue(POWERED)) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, signal)) {
+ return;
+ }
+ // Paper end - Call BlockRedstoneEvent
if (signal) {
this.playNote(null, state, level, pos);
+ state = level.getBlockState(pos); // CraftBukkit - SPIGOT-5617: update in case changed in event
@@ -4,18 +4,18 @@
@Override
protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) {
if (state.getValue(POWERED)) {
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 15, 0).getNewCurrent() != 0) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, false)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, false), Block.UPDATE_CLIENTS);
} else {
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 0, 15).getNewCurrent() != 15) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, true)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, true), Block.UPDATE_CLIENTS);
level.scheduleTick(pos, this, 2);
}
@@ -1,16 +1,14 @@
--- a/net/minecraft/world/level/block/PoweredRailBlock.java
+++ b/net/minecraft/world/level/block/PoweredRailBlock.java
@@ -127,6 +_,13 @@
@@ -127,6 +_,11 @@
|| this.findPoweredRailSignal(level, pos, state, true, 0)
|| this.findPoweredRailSignal(level, pos, state, false, 0);
if (shouldPower != isPowered) {
+ // CraftBukkit start
+ int power = shouldPower ? 15 : 0;
+ int newPower = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, power, 15 - power).getNewCurrent();
+ if (newPower == power) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, shouldPower)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(POWERED, shouldPower), Block.UPDATE_ALL);
level.updateNeighborsAt(pos.below(), this);
if (state.getValue(SHAPE).isSlope()) {
@@ -4,11 +4,11 @@
if (isLit) {
level.scheduleTick(pos, this, 4);
} else {
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 0, 15).getNewCurrent() != 15) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, true)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.cycle(LIT), Block.UPDATE_CLIENTS);
}
}
@@ -16,11 +16,11 @@
@Override
protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) {
if (state.getValue(LIT) && !level.hasNeighborSignal(pos)) {
+ // CraftBukkit start
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, 15, 0).getNewCurrent() != 0) {
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, false)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.cycle(LIT), Block.UPDATE_CLIENTS);
}
}
@@ -9,7 +9,7 @@
public static final int RECENT_TOGGLE_TIMER = 60;
public static final int MAX_RECENT_TOGGLES = 8;
public static final int RESTART_DELAY = 160;
@@ -73,14 +_,32 @@
@@ -73,14 +_,23 @@
@Override
protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) {
boolean neighborSignal = this.hasNeighborSignal(level, pos, state);
@@ -26,39 +26,26 @@
+ }
}
+ // Paper end - Faster redstone torch rapid clock removal
+ // CraftBukkit start
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+ int oldCurrent = state.getValue(LIT) ? 15 : 0;
+ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(block, oldCurrent, oldCurrent);
+ // CraftBukkit end
if (state.getValue(LIT)) {
if (neighborSignal) {
+ // CraftBukkit start
+ if (oldCurrent != 0) {
+ event.setNewCurrent(0);
+ event.callEvent();
+ if (event.getNewCurrent() != 0) {
+ return;
+ }
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, false)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(LIT, false), Block.UPDATE_ALL);
if (isToggledTooFrequently(level, pos, true)) {
level.levelEvent(LevelEvent.REDSTONE_TORCH_BURNOUT, pos, 0);
@@ -88,6 +_,15 @@
@@ -88,6 +_,11 @@
}
}
} else if (!neighborSignal && !isToggledTooFrequently(level, pos, false)) {
+ // CraftBukkit start
+ if (oldCurrent != 15) {
+ event.setNewCurrent(15);
+ event.callEvent();
+ if (event.getNewCurrent() != 15) {
+ return;
+ }
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, true)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(LIT, true), Block.UPDATE_ALL);
}
}
@@ -19,7 +19,7 @@
sculkSensor.getListener().forceScheduleVibration(serverLevel, GameEvent.STEP, GameEvent.Context.of(entity), entity.position());
}
@@ -189,10 +_,19 @@
@@ -189,10 +_,17 @@
}
public static boolean canActivate(final BlockState state) {
@@ -28,35 +28,30 @@
}
public static void deactivate(final Level level, final BlockPos pos, final BlockState state) {
+ // CraftBukkit start
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), state.getValue(SculkSensorBlock.POWER), 0);
+ level.getCraftServer().getPluginManager().callEvent(eventRedstone);
+
+ if (eventRedstone.getNewCurrent() > 0) {
+ level.setBlock(pos, state.setValue(SculkSensorBlock.POWER, eventRedstone.getNewCurrent()), Block.UPDATE_ALL);
+ // Paper start - Call BlockRedstoneEvent
+ int newCurrent = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, state.getValue(POWER), 0).getNewCurrent();
+ if (newCurrent > 0) {
+ level.setBlock(pos, state.setValue(POWER, newCurrent), Block.UPDATE_ALL);
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(PHASE, SculkSensorPhase.COOLDOWN).setValue(POWER, 0), Block.UPDATE_ALL);
level.scheduleTick(pos, state.getBlock(), 10);
updateNeighbours(level, pos, state);
@@ -208,9 +_,18 @@
@@ -208,9 +_,15 @@
final Level level,
final BlockPos pos,
final BlockState state,
- final int calculatedPower,
+ int calculatedPower, // CraftBukkit
+ int calculatedPower, // Paper - remove final
final int vibrationFrequency
) {
+ // CraftBukkit start
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), state.getValue(SculkSensorBlock.POWER), calculatedPower);
+ level.getCraftServer().getPluginManager().callEvent(eventRedstone);
+
+ if (eventRedstone.getNewCurrent() <= 0) {
+ // Paper start - Call BlockRedstoneEvent
+ calculatedPower = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, state.getValue(POWER), calculatedPower).getNewCurrent();
+ if (calculatedPower == 0) {
+ return;
+ }
+ calculatedPower = eventRedstone.getNewCurrent();
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(PHASE, SculkSensorPhase.ACTIVE).setValue(POWER, calculatedPower), Block.UPDATE_ALL);
level.scheduleTick(pos, state.getBlock(), this.getActiveTicks());
updateNeighbours(level, pos, state);
@@ -11,7 +11,7 @@
if (projectile.getOwner() instanceof ServerPlayer playerOwner) {
playerOwner.awardStat(Stats.TARGET_HIT);
CriteriaTriggers.TARGET_BLOCK_HIT.trigger(playerOwner, projectile, hitResult.getLocation(), outputStrength);
@@ -51,9 +_,29 @@
@@ -51,10 +_,29 @@
private static int updateRedstoneOutput(final LevelAccessor level, final BlockState state, final BlockHitResult hitResult, final Entity entity) {
int redstoneStrength = getRedstoneStrength(hitResult, hitResult.getLocation());
int duration = entity instanceof AbstractArrow ? 20 : 8;
@@ -32,12 +32,39 @@
if (!level.getBlockTicks().hasScheduledTick(hitResult.getBlockPos(), state.getBlock())) {
setOutputPower(level, state, redstoneStrength, hitResult.getBlockPos(), duration);
}
+
+ // Paper start - Award Hit Criteria after Block Update
+ if (shouldAward) {
+ awardTargetHitCriteria((Projectile) entity, hitResult, redstoneStrength);
+ }
+ // Paper end - Award Hit Criteria after Block Update
return redstoneStrength;
}
@@ -76,7 +_,12 @@
return Math.max(1, Mth.ceil(15.0 * Mth.clamp((0.5 - distance) / 0.5, 0.0, 1.0)));
}
- private static void setOutputPower(final LevelAccessor level, final BlockState state, final int outputStrength, final BlockPos pos, final int duration) {
+ private static void setOutputPower(final LevelAccessor level, final BlockState state, int outputStrength, final BlockPos pos, final int duration) { // Paper - remove final
+ // Paper start - Call BlockRedstoneEvent
+ if (state.getValue(OUTPUT_POWER) != outputStrength) {
+ outputStrength = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, state.getValue(OUTPUT_POWER), outputStrength).getNewCurrent();
+ }
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(OUTPUT_POWER, outputStrength), Block.UPDATE_ALL);
level.scheduleTick(pos, state.getBlock(), duration);
}
@@ -84,6 +_,12 @@
@Override
protected void tick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) {
if (state.getValue(OUTPUT_POWER) != 0) {
+ // Paper start - Call BlockRedstoneEvent
+ org.bukkit.event.block.BlockRedstoneEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, state.getValue(OUTPUT_POWER), 0);
+ if (event.getNewCurrent() > 0) {
+ return;
+ }
+ // Paper end - Call BlockRedstoneEvent
level.setBlock(pos, state.setValue(OUTPUT_POWER, 0), Block.UPDATE_ALL);
}
}
@@ -1,21 +1,15 @@
--- a/net/minecraft/world/level/block/TrapDoorBlock.java
+++ b/net/minecraft/world/level/block/TrapDoorBlock.java
@@ -133,7 +_,37 @@
@@ -133,7 +_,31 @@
if (!level.isClientSide()) {
boolean signal = level.hasNeighborSignal(pos);
if (signal != state.getValue(POWERED)) {
- if (state.getValue(OPEN) != signal) {
+ // CraftBukkit start
+ org.bukkit.block.Block bblock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
+ int power = bblock.getBlockPower();
+ int oldPower = state.getValue(TrapDoorBlock.OPEN) ? 15 : 0;
+
+ if (oldPower == 0 ^ power == 0 || block.defaultBlockState().isSignalSource()) {
+ org.bukkit.event.block.BlockRedstoneEvent eventRedstone = new org.bukkit.event.block.BlockRedstoneEvent(bblock, oldPower, power);
+ level.getCraftServer().getPluginManager().callEvent(eventRedstone);
+ signal = eventRedstone.getNewCurrent() > 0;
+ // Paper start - Call BlockRedstoneEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, signal)) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
+ // Paper start - break redstone on trapdoors early
+ boolean open = state.getValue(TrapDoorBlock.OPEN) != signal;
+ // note: this must run before any state for this block/its neighbours are written to the world
@@ -26,7 +20,7 @@
+ BlockState above = level.getBlockState(abovePos);
+ if (above.getBlock() instanceof RedStoneWireBlock) {
+ level.setBlock(abovePos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_NEIGHBORS);
+ Block.popResource(level, abovePos, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.REDSTONE));
+ Block.popResource(level, abovePos, new ItemStack(net.minecraft.world.item.Items.REDSTONE));
+ // now check that this didn't change our state
+ if (level.getBlockState(pos) != state) {
+ // our state was changed, so we cannot propagate this update
@@ -13,7 +13,7 @@
int receiverPos = 0;
BlockState[] wireStates = new BlockState[42];
@@ -158,8 +_,20 @@
@@ -158,8 +_,15 @@
attached &= receiverPos > 1;
powered &= attached;
BlockState newState = block.defaultBlockState().trySetValue(ATTACHED, attached).trySetValue(POWERED, powered);
@@ -22,19 +22,14 @@
BlockPos testPosx = pos.relative(direction, receiverPos);
+ // Paper start - Call BlockRedstoneEvent
+ if (wasPowered != powered) {
+ int newCurrent = powered ? 15 : 0;
+ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(
+ org.bukkit.craftbukkit.block.CraftBlock.at(level, testPosx), wasPowered ? 15 : 0, newCurrent
+ );
+ event.callEvent();
+ cancelledReceiverHook = event.getNewCurrent() != newCurrent;
+ cancelledReceiverHook = !org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, testPosx, powered);
+ }
+ if (!cancelledReceiverHook) { // always trigger two events even when the first hook current change is cancelled
+ // Paper end - Call BlockRedstoneEvent
Direction opposite = direction.getOpposite();
level.setBlock(testPosx, newState.setValue(FACING, opposite), Block.UPDATE_ALL);
notifyNeighbors(block, level, testPosx, opposite);
@@ -169,15 +_,29 @@
@@ -169,15 +_,24 @@
}
emitState(level, testPosx, attached, powered, wasAttached, wasPowered);
@@ -43,12 +38,7 @@
+ }
+ // Paper start - Call BlockRedstoneEvent
+ if (wasPowered != powered) {
+ int newCurrent = powered ? 15 : 0;
+ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(
+ org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), wasPowered ? 15 : 0, newCurrent
+ );
+ event.callEvent();
+ cancelledEmitterHook = event.getNewCurrent() != newCurrent;
+ cancelledEmitterHook = !org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, powered);
+ }
+ // Paper end - Call BlockRedstoneEvent
@@ -21,22 +21,21 @@
protected abstract void onOpen(final Level level, final BlockPos pos, final BlockState blockState);
@@ -28,7 +_,19 @@
public void incrementOpeners(
@@ -29,6 +_,18 @@
final LivingEntity entity, final Level level, final BlockPos pos, final BlockState blockState, final double maxInteractionRange
) {
+ int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added
int previous = this.openCount++;
+
+ // CraftBukkit start - Call redstone event
+ if (level.getBlockState(pos).is(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST)) {
+ int newPower = Math.max(0, Math.min(15, this.openCount));
+ // Paper start - Call BlockRedstoneEvent
+ if (blockState.is(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST)) {
+ int oldCurrent = Math.clamp(previous, 0, 15);
+ int newCurrent = Math.clamp(this.openCount, 0, 15);
+
+ if (oldPower != newPower) {
+ org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, oldPower, newPower);
+ if (oldCurrent != newCurrent) {
+ org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, oldCurrent, newCurrent);
+ }
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
+
if (previous == 0) {
this.onOpen(level, pos, blockState);
@@ -45,19 +44,19 @@
}
public void decrementOpeners(final LivingEntity entity, final Level level, final BlockPos pos, final BlockState blockState) {
+ int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added
+ if (this.openCount == 0) return; // Paper - Prevent ContainerOpenersCounter openCount from going negative
int previous = this.openCount--;
+
+ // CraftBukkit start - Call redstone event
+ if (level.getBlockState(pos).is(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST)) {
+ int newPower = Math.max(0, Math.min(15, this.openCount));
+ // Paper start - Call BlockRedstoneEvent
+ if (blockState.is(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST)) {
+ int oldCurrent = Math.clamp(previous, 0, 15);
+ int newCurrent = Math.clamp(this.openCount, 0, 15);
+
+ if (oldPower != newPower) {
+ org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, oldPower, newPower);
+ if (oldCurrent != newCurrent) {
+ org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, oldCurrent, newCurrent);
+ }
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
+
if (this.openCount == 0) {
this.onClose(level, pos, blockState);
@@ -69,16 +68,16 @@
+ if (this.opened) openCount++; // CraftBukkit - add dummy count from API
int prevCount = this.openCount;
if (prevCount != openCount) {
+ // CraftBukkit start - Call redstone event
+ if (level.getBlockState(pos).is(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST)) {
+ int oldPower = net.minecraft.util.Mth.clamp(prevCount, 0, 15);
+ int newPower = net.minecraft.util.Mth.clamp(openCount, 0, 15);
+ // Paper start - Call BlockRedstoneEvent
+ if (blockState.is(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST)) {
+ int oldCurrent = Math.clamp(prevCount, 0, 15);
+ int newCurrent = Math.clamp(openCount, 0, 15);
+
+ if (oldPower != newPower) {
+ org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, oldPower, newPower);
+ if (oldCurrent != newCurrent) {
+ org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, oldCurrent, newCurrent);
+ }
+ }
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
+
boolean isOpen = openCount != 0;
boolean wasOpen = prevCount != 0;
@@ -246,6 +246,14 @@
public boolean isEmpty() {
return false;
}
@@ -703,6 +_,7 @@
}
private <T extends BlockEntity> void updateBlockEntityTicker(final T blockEntity) {
+ if (!this.level.paperConfig().unsupportedSettings.ticking.blockEntities) return; // Paper - option to disable ticking
BlockState state = blockEntity.getBlockState();
BlockEntityTicker<T> ticker = state.getTicker(this.level, (BlockEntityType<T>)blockEntity.getType());
if (ticker == null) {
@@ -752,23 +_,24 @@
if (this.blockEntity.getType().isValid(blockState)) {
this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), blockState, this.blockEntity);
@@ -1,20 +1,17 @@
--- a/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
+++ b/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java
@@ -20,7 +_,16 @@
@@ -20,7 +_,13 @@
final Level level, final BlockPos pos, final BlockState state, final @Nullable Orientation orientation, final boolean skipShapeUpdates
) {
int targetStrength = this.calculateTargetStrength(level, pos);
- if (state.getValue(RedStoneWireBlock.POWER) != targetStrength) {
+ // CraftBukkit start
+ int oldPower = state.getValue(RedStoneWireBlock.POWER);
+ if (oldPower != targetStrength) {
+ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), oldPower, targetStrength);
+ level.getCraftServer().getPluginManager().callEvent(event);
+
+ targetStrength = event.getNewCurrent();
+ // Paper start - Call BlockRedstoneEvent
+ int previousStrength = state.getValue(RedStoneWireBlock.POWER);
+ if (previousStrength != targetStrength && level.getBlockState(pos) == state) {
+ targetStrength = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, previousStrength, targetStrength).getNewCurrent();
+ }
+ if (oldPower != targetStrength) {
+ // CraftBukkit end
+ if (previousStrength != targetStrength) {
+ // Paper end - Call BlockRedstoneEvent
if (level.getBlockState(pos) == state) {
level.setBlock(pos, state.setValue(RedStoneWireBlock.POWER, targetStrength), Block.UPDATE_CLIENTS);
}
@@ -1,20 +1,14 @@
--- a/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java
+++ b/net/minecraft/world/level/redstone/ExperimentalRedstoneWireEvaluator.java
@@ -45,7 +_,16 @@
@@ -45,6 +_,11 @@
int packed = next.getIntValue();
int newLevel = unpackPower(packed);
BlockState state = level.getBlockState(pos);
- if (state.is(this.wireBlock) && !state.getValue(RedStoneWireBlock.POWER).equals(newLevel)) {
+ // CraftBukkit start
+ int oldPower = state.getValue(RedStoneWireBlock.POWER); // Paper - Call BlockRedstoneEvent properly; get the previous power from the right state
+ if (oldPower != newLevel) {
+ org.bukkit.event.block.BlockRedstoneEvent event = new org.bukkit.event.block.BlockRedstoneEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), oldPower, newLevel);
+ level.getCraftServer().getPluginManager().callEvent(event);
+
+ newLevel = event.getNewCurrent();
+ // Paper start - Call BlockRedstoneEvent
+ if (state.is(this.wireBlock) && !state.getValue(RedStoneWireBlock.POWER).equals(newLevel)) {
+ newLevel = org.bukkit.craftbukkit.event.CraftEventFactory.callRedstoneChange(level, pos, state.getValue(RedStoneWireBlock.POWER), newLevel).getNewCurrent();
+ }
+ if (state.is(this.wireBlock) && oldPower != newLevel) {
+ // CraftBukkit end
+ // Paper end - Call BlockRedstoneEvent
if (state.is(this.wireBlock) && !state.getValue(RedStoneWireBlock.POWER).equals(newLevel)) {
int updateFlags = Block.UPDATE_CLIENTS;
if (!shapeUpdateWiresAroundInitialPosition || !initialWire) {
updateFlags |= Block.UPDATE_SKIP_SHAPE_UPDATE_ON_WIRE;
@@ -71,7 +71,7 @@ public class SyncLoadFinder {
final JsonObject worldData = new JsonObject();
worldData.addProperty("name", world.getWorld().getKey().toString());
worldData.addProperty("key", world.getWorld().key().asString());
final List<Pair<ThrowableWithEquals, SyncLoadInformation>> data = new ArrayList<>();
@@ -9,6 +9,8 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import net.minecraft.resources.Identifier;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
@@ -18,6 +20,18 @@ public final class CommandUtil {
private CommandUtil() {
}
public static List<String> getWorldSuggestions(Server server, boolean withWildcard) {
List<World> worlds = server.getWorlds();
List<String> worldKeys = new ArrayList<>(worlds.size() + (withWildcard ? 1 : 0));
if (withWildcard) {
worldKeys.add("*");
}
for (World world : worlds) {
worldKeys.add(world.key().asString());
}
return worldKeys;
}
// Code from Mojang - copyright them
public static List<String> getListMatchingLast(
final CommandSender sender,
@@ -4,7 +4,9 @@ import com.google.common.collect.Maps;
import io.papermc.paper.FeatureHooks;
import io.papermc.paper.command.CommandUtil;
import io.papermc.paper.command.PaperSubcommand;
import io.papermc.paper.util.MCUtil;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -21,7 +23,6 @@ import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.ChunkPos;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Bukkit;
import org.bukkit.HeightMap;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
@@ -48,8 +49,12 @@ public final class EntityCommand implements PaperSubcommand {
public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
if (args.length == 1) {
return CommandUtil.getListMatchingLast(sender, args, "help", "list");
} else if (args.length == 2) {
return CommandUtil.getListMatchingLast(sender, args, BuiltInRegistries.ENTITY_TYPE.keySet());
} else if (args.length > 1 && args[0].toLowerCase(Locale.ROOT).equals("list")) {
if (args.length == 2) {
return CommandUtil.getListMatchingLast(sender, args, BuiltInRegistries.ENTITY_TYPE.keySet());
} else if (args.length == 3) {
return CommandUtil.getListMatchingLast(sender, args, CommandUtil.getWorldSuggestions(sender.getServer(), false));
}
}
return Collections.emptyList();
}
@@ -60,58 +65,55 @@ public final class EntityCommand implements PaperSubcommand {
private void listEntities(final CommandSender sender, final String[] args) {
// help
if (args.length < 1 || !args[0].toLowerCase(Locale.ROOT).equals("list")) {
sender.sendMessage(text("Use /paper entity [list] help for more information on a specific command", RED));
sender.sendMessage(text("Use /paper entity list [filter] [world] to get entity info that matches the optional filter.", RED));
return;
}
if ("list".equals(args[0].toLowerCase(Locale.ROOT))) {
String filter = "*";
if (args.length > 1) {
if (args[1].toLowerCase(Locale.ROOT).equals("help")) {
sender.sendMessage(text("Use /paper entity list [filter] [worldName] to get entity info that matches the optional filter.", RED));
return;
}
filter = args[1];
}
final String cleanfilter = filter.replace("?", ".?").replace("*", ".*?");
final String cleanFilter = filter.replace("?", ".?").replace("*", ".*?");
Set<Identifier> names = BuiltInRegistries.ENTITY_TYPE.keySet().stream()
.filter(n -> n.toString().matches(cleanfilter))
.filter(n -> n.toString().matches(cleanFilter))
.collect(Collectors.toSet());
if (names.isEmpty()) {
sender.sendMessage(text("Invalid filter, does not match any entities. Use /paper entity list for a proper list", RED));
sender.sendMessage(text("Usage: /paper entity list [filter] [worldName]", RED));
sender.sendMessage(text("Usage: /paper entity list [filter] [world]", RED));
return;
}
String worldName;
final @Nullable World world;
if (args.length > 2) {
worldName = args[2];
} else if (sender instanceof Player) {
worldName = ((Player) sender).getWorld().getKey().toString();
@Nullable NamespacedKey key = NamespacedKey.fromString(args[2]);
world = key == null ? null : sender.getServer().getWorld(key);
if (world == null) {
sender.sendMessage(text("Could not load world for " + args[2] + ". Please select a valid world.", RED));
sender.sendMessage(text("Usage: /paper entity list [filter] [world]", RED));
return;
}
} else if (sender instanceof Player player) {
world = player.getWorld();
} else {
sender.sendMessage(text("Please specify the name of a world", RED));
sender.sendMessage(text("Please specify the key of a world", RED));
sender.sendMessage(text("To do so without a filter, specify '*' as the filter", RED));
sender.sendMessage(text("Usage: /paper entity list [filter] [worldKey]", RED));
sender.sendMessage(text("Usage: /paper entity list [filter] [world]", RED));
return;
}
Map<Identifier, MutablePair<Integer, Map<ChunkPos, Integer>>> list = Maps.newHashMap();
@Nullable NamespacedKey worldKey = NamespacedKey.fromString(worldName);
@Nullable World bukkitWorld;
if (worldKey == null || (bukkitWorld = Bukkit.getWorld(worldKey)) == null) {
sender.sendMessage(text("Could not load world for " + worldName + ". Please select a valid world.", RED));
sender.sendMessage(text("Usage: /paper entity list [filter] [worldKey]", RED));
return;
}
ServerLevel world = ((CraftWorld) bukkitWorld).getHandle();
Map<Identifier, Integer> nonEntityTicking = Maps.newHashMap();
ServerChunkCache chunkProviderServer = world.getChunkSource();
FeatureHooks.getAllEntities(world).forEach(e -> {
Map<Identifier, MutablePair<Integer, Map<ChunkPos, Integer>>> list = new HashMap<>();
ServerLevel level = ((CraftWorld) world).getHandle();
Map<Identifier, Integer> nonEntityTicking = new HashMap<>();
ServerChunkCache chunkProviderServer = level.getChunkSource();
FeatureHooks.getAllEntities(level).forEach(e -> {
Identifier key = EntityType.getKey(e.getType());
MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));
ChunkPos chunk = e.chunkPosition();
info.left++;
info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1);
if (!world.isPositionEntityTicking(e.blockPosition()) || (e instanceof net.minecraft.world.entity.Marker && !world.paperConfig().entities.markers.tick)) { // Paper - Configurable marker ticking
if (!level.isPositionEntityTicking(e.blockPosition()) || (e instanceof net.minecraft.world.entity.Marker && !level.paperConfig().entities.markers.tick)) { // Paper - Configurable marker ticking
nonEntityTicking.merge(key, 1, Integer::sum);
}
});
@@ -131,7 +133,7 @@ public final class EntityCommand implements PaperSubcommand {
final int z = (e.getKey().z() << 4) + 8;
final Component message = text(" " + e.getValue() + ": " + e.getKey().x() + ", " + e.getKey().z() + (chunkProviderServer.isPositionTicking(e.getKey().pack()) ? " (Ticking)" : " (Non-Ticking)"))
.hoverEvent(HoverEvent.showText(text("Click to teleport to chunk", GREEN)))
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/minecraft:execute as @s in " + world.getWorld().getKey() + " run tp " + x + " " + (world.getWorld().getHighestBlockYAt(x, z, HeightMap.MOTION_BLOCKING) + 1) + " " + z));
.clickEvent(ClickEvent.runCommand("/minecraft:execute as @s in " + MCUtil.getLevelName(level) + " run tp " + x + " " + (level.getWorld().getHighestBlockYAt(x, z, HeightMap.MOTION_BLOCKING) + 1) + " " + z));
sender.sendMessage(message);
});
} else {
@@ -8,7 +8,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.ToIntFunction;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.JoinConfiguration;
@@ -56,17 +55,15 @@ public final class MobcapsCommand implements PaperSubcommand {
@Override
public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
return switch (subCommand) {
case "mobcaps" -> CommandUtil.getListMatchingLast(sender, args, this.suggestMobcaps(args));
case "mobcaps" -> CommandUtil.getListMatchingLast(sender, args, this.suggestMobcaps(sender, args));
case "playermobcaps" -> CommandUtil.getListMatchingLast(sender, args, this.suggestPlayerMobcaps(sender, args));
default -> throw new IllegalArgumentException();
};
}
private List<String> suggestMobcaps(final String[] args) {
private List<String> suggestMobcaps(final CommandSender sender, String[] args) {
if (args.length == 1) {
final List<String> worlds = new ArrayList<>(Bukkit.getWorlds().stream().map(World::getKey).map(NamespacedKey::toString).toList());
worlds.add("*");
return worlds;
return CommandUtil.getWorldSuggestions(sender.getServer(), true);
}
return Collections.emptyList();
@@ -92,17 +89,17 @@ public final class MobcapsCommand implements PaperSubcommand {
if (sender instanceof Player player) {
worlds = List.of(player.getWorld());
} else {
sender.sendMessage(Component.text("Must specify a world! ex: '/paper mobcaps overworld'", NamedTextColor.RED));
sender.sendMessage(Component.text("Must specify a world! ex: '/paper mobcaps minecraft:overworld'", NamedTextColor.RED));
return;
}
} else if (args.length == 1) {
final String input = args[0];
if (input.equals("*")) {
worlds = Bukkit.getWorlds();
worlds = Bukkit.getServer().getWorlds();
} else {
final @Nullable Key worldKey = NamespacedKey.fromString(input);
final @Nullable World world;
if (worldKey == null || (world = Bukkit.getWorld(worldKey)) == null) {
final @Nullable NamespacedKey worldKey = NamespacedKey.fromString(input);
final @Nullable World world = worldKey == null ? null : sender.getServer().getWorld(worldKey);
if (world == null) {
sender.sendMessage(Component.text("'" + input + "' is not a valid world!", NamedTextColor.RED));
return;
} else {
@@ -126,7 +123,7 @@ public final class MobcapsCommand implements PaperSubcommand {
}
sender.sendMessage(Component.join(JoinConfiguration.noSeparators(),
Component.text("Mobcaps for world: "),
Component.text(world.getKey().toString(), NamedTextColor.AQUA),
Component.text(world.key().asString(), NamedTextColor.AQUA),
Component.text(" (" + chunks + " spawnable chunks)")
));
@@ -13,8 +13,9 @@ import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.minecraft.server.MinecraftServer;
@@ -38,7 +39,10 @@ public final class SyncLoadInfoCommand implements PaperSubcommand {
@Override
public List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
return CommandUtil.getListMatchingLast(sender, args, "clear");
if (args.length == 1) {
return CommandUtil.getListMatchingLast(sender, args, "clear");
}
return Collections.emptyList();
}
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss");
@@ -53,7 +57,7 @@ public final class SyncLoadInfoCommand implements PaperSubcommand {
return;
}
if (args.length > 0 && args[0].equals("clear")) {
if (args.length > 0 && args[0].toLowerCase(Locale.ROOT).equals("clear")) {
SyncLoadFinder.clear();
sender.sendMessage(text("Sync load data cleared.", GRAY));
return;
@@ -192,11 +192,16 @@ public class GlobalConfiguration 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 {
@@ -11,9 +11,9 @@ import io.papermc.paper.configuration.mapping.InnerClassFieldDiscoverer;
import io.papermc.paper.configuration.mapping.MergeMap;
import io.papermc.paper.configuration.serializer.ComponentSerializer;
import io.papermc.paper.configuration.serializer.EnumValueSerializer;
import io.papermc.paper.configuration.serializer.IdentifierSerializer;
import io.papermc.paper.configuration.serializer.NbtPathSerializer;
import io.papermc.paper.configuration.serializer.ServerboundPacketClassSerializer;
import io.papermc.paper.configuration.serializer.IdentifierSerializer;
import io.papermc.paper.configuration.serializer.StringRepresentableSerializer;
import io.papermc.paper.configuration.serializer.collection.TableSerializer;
import io.papermc.paper.configuration.serializer.collection.map.FastutilMapSerializer;
@@ -54,7 +54,6 @@ import java.util.List;
import java.util.Locale;
import java.util.function.Function;
import java.util.function.Supplier;
import net.kyori.adventure.key.Key;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.component.DataComponentType;
@@ -64,8 +63,8 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.gamerules.GameRules;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.gamerules.GameRules;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import org.apache.commons.lang3.RandomStringUtils;
import org.bukkit.configuration.ConfigurationSection;
@@ -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
};
}
@@ -477,6 +477,12 @@ public class WorldConfiguration extends ConfigurationPart {
public class UnsupportedSettings extends ConfigurationPart {
public boolean fixInvulnerableEndCrystalExploit = true;
public boolean disableWorldTickingWhenEmpty = false;
public Ticking ticking;
public class Ticking extends ConfigurationPart {
public boolean chunks = true;
public boolean blockEntities = true;
}
}
public Hopper hopper;
@@ -128,7 +128,6 @@ public final class LegacyPaperConfig {
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");
@@ -1,6 +1,5 @@
package io.papermc.paper.connection;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.mojang.logging.LogUtils;
import io.papermc.paper.event.connection.configuration.AsyncPlayerConnectionConfigureEvent;
import java.util.concurrent.ExecutorService;
@@ -15,8 +14,9 @@ import org.slf4j.Logger;
public class PaperConfigurationTask implements ConfigurationTask {
private static final Logger LOGGER = LogUtils.getClassLogger();
public static final ExecutorService CONFIGURATION_POOL = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("Configuration Thread #%d")
.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).build());
public static final ExecutorService CONFIGURATION_POOL = Executors.newThreadPerTaskExecutor(
Thread.ofVirtual().name("Configuration Thread #", 0).uncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).factory()
);
public static final ConfigurationTask.Type TYPE = new ConfigurationTask.Type("paper_event_handling");
@@ -21,6 +21,10 @@ import org.bukkit.inventory.meta.trim.ArmorTrim;
import org.bukkit.map.MapCursor;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.util.BoundChecker.requireNonNegative;
import static io.papermc.paper.util.BoundChecker.requirePositive;
import static io.papermc.paper.util.BoundChecker.requireRange;
public final class ItemComponentTypesBridgesImpl implements ItemComponentTypesBridge {
@Override
@@ -194,8 +198,7 @@ public final class ItemComponentTypesBridgesImpl implements ItemComponentTypesBr
@Override
public UseCooldown.Builder useCooldown(final float seconds) {
Preconditions.checkArgument(seconds > 0, "seconds must be positive, was %s", seconds);
return new PaperUseCooldown.BuilderImpl(seconds);
return new PaperUseCooldown.BuilderImpl(requirePositive(seconds, "seconds"));
}
@Override
@@ -232,11 +235,8 @@ public final class ItemComponentTypesBridgesImpl implements ItemComponentTypesBr
@Override
public PaperOminousBottleAmplifier ominousBottleAmplifier(final int amplifier) {
Preconditions.checkArgument(OminousBottleAmplifier.MIN_AMPLIFIER <= amplifier && amplifier <= OminousBottleAmplifier.MAX_AMPLIFIER,
"amplifier must be between %s-%s, was %s", OminousBottleAmplifier.MIN_AMPLIFIER, OminousBottleAmplifier.MAX_AMPLIFIER, amplifier
);
return new PaperOminousBottleAmplifier(
new OminousBottleAmplifier(amplifier)
new OminousBottleAmplifier(requireRange(amplifier, "amplifier", OminousBottleAmplifier.MIN_AMPLIFIER, OminousBottleAmplifier.MAX_AMPLIFIER))
);
}
@@ -282,9 +282,8 @@ public final class ItemComponentTypesBridgesImpl implements ItemComponentTypesBr
@Override
public KineticWeapon.Condition kineticWeaponCondition(int maxDurationTicks, float minSpeed, float minRelativeSpeed) {
Preconditions.checkArgument(maxDurationTicks >= 0, "maxDurationTicks must be non-negative");
return new PaperKineticWeapon.PaperKineticWeaponCondition(new net.minecraft.world.item.component.KineticWeapon.Condition(
maxDurationTicks, minSpeed, minRelativeSpeed
maxDurationTicks, minSpeed, requireNonNegative(minRelativeSpeed, "minRelativeSpeed")
));
}
}
Loaded 100 of 156 files, more files were not shown because too many files have changed in this diff. Show more